Skip to content

Commit

Permalink
ext(darwin): make sure symbols will be resolved correctly
Browse files Browse the repository at this point in the history
  • Loading branch information
flavorjones committed Dec 28, 2022
1 parent 82c3d9e commit dc2670c
Showing 1 changed file with 36 additions and 3 deletions.
39 changes: 36 additions & 3 deletions ext/nokogiri/extconf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,34 @@ def do_clean
exit!(0)
end

# In ruby 3.2, symbol resolution changed on Darwin, to introduce the `-bundle_loader` flag to
# resolve symbols against the ruby binary.
#
# This makes it challenging to build a single extension that works with both a ruby with
# `--enable-shared` and one with `--disable-shared. To work around that, we choose to add
# `-flat_namespace` to the link line (later in this file).
#
# The `-flat_namespace` line introduces its own behavior change, which is that (similar to on
# Linux), any symbols in the extension that are exported may now be resolved by shared libraries
# loaded by the Ruby process. Specifically, that means that libxml2 and libxslt, which are
# statically linked into the nokogiri bundle, will resolve (at runtime) to a system libxml2 loaded
# by Ruby on Darwin. And it appears that often Ruby on Darwin does indeed load the system libxml2,
# and that messes with our assumptions about whether we're running with a patched libxml2 or a
# vanilla libxml2.
#
# We choose to use `-load_hidden` in this case to prevent exporting those symbols from libxml2 and
# libxslt, which ensures that they will be resolved to the static libraries in the bundle. In other
# words, when we use `load_hidden`, what happens in the extension stays in the extension.
#
# See https://github.com/rake-compiler/rake-compiler-dock/issues/87 for more info.
#
# Anyway, this method is the logical bit to tell us when to turn on these workarounds.
def needs_darwin_linker_hack
config_cross_build? &&
darwin? &&
Gem::Requirement.new("~> 3.2").satisfied_by?(Gem::Version.new(RbConfig::CONFIG["ruby_version"].split("+").first))
end

#
# main
#
Expand Down Expand Up @@ -690,6 +718,10 @@ def do_clean
cross_build_p = config_cross_build?
message "Cross build is #{cross_build_p ? "enabled" : "disabled"}.\n"

if needs_darwin_linker_hack
append_ldflags("-Wl,-flat_namespace")
end

require "yaml"
dependencies = YAML.load_file(File.join(PACKAGE_ROOT_DIR, "dependencies.yml"))

Expand Down Expand Up @@ -941,16 +973,17 @@ def configure
end.shelljoin

if static_p
static_archive_ld_flag = needs_darwin_linker_hack ? ["-load_hidden"] : []
$libs = $libs.shellsplit.map do |arg|
case arg
when "-lxml2"
File.join(libxml2_recipe.path, "lib", libflag_to_filename(arg))
static_archive_ld_flag + [File.join(libxml2_recipe.path, "lib", libflag_to_filename(arg))]
when "-lxslt", "-lexslt"
File.join(libxslt_recipe.path, "lib", libflag_to_filename(arg))
static_archive_ld_flag + [File.join(libxslt_recipe.path, "lib", libflag_to_filename(arg))]
else
arg
end
end.shelljoin
end.flatten.shelljoin
end

ensure_func("xmlParseDoc", "libxml/parser.h")
Expand Down

0 comments on commit dc2670c

Please sign in to comment.