@@ -584,6 +584,34 @@ def do_clean
584
584
exit! ( 0 )
585
585
end
586
586
587
+ # In ruby 3.2, symbol resolution changed on Darwin, to introduce the `-bundle_loader` flag to
588
+ # resolve symbols against the ruby binary.
589
+ #
590
+ # This makes it challenging to build a single extension that works with both a ruby with
591
+ # `--enable-shared` and one with `--disable-shared. To work around that, we choose to add
592
+ # `-flat_namespace` to the link line (later in this file).
593
+ #
594
+ # The `-flat_namespace` line introduces its own behavior change, which is that (similar to on
595
+ # Linux), any symbols in the extension that are exported may now be resolved by shared libraries
596
+ # loaded by the Ruby process. Specifically, that means that libxml2 and libxslt, which are
597
+ # statically linked into the nokogiri bundle, will resolve (at runtime) to a system libxml2 loaded
598
+ # by Ruby on Darwin. And it appears that often Ruby on Darwin does indeed load the system libxml2,
599
+ # and that messes with our assumptions about whether we're running with a patched libxml2 or a
600
+ # vanilla libxml2.
601
+ #
602
+ # We choose to use `-load_hidden` in this case to prevent exporting those symbols from libxml2 and
603
+ # libxslt, which ensures that they will be resolved to the static libraries in the bundle. In other
604
+ # words, when we use `load_hidden`, what happens in the extension stays in the extension.
605
+ #
606
+ # See https://github.com/rake-compiler/rake-compiler-dock/issues/87 for more info.
607
+ #
608
+ # Anyway, this method is the logical bit to tell us when to turn on these workarounds.
609
+ def needs_darwin_linker_hack
610
+ config_cross_build? &&
611
+ darwin? &&
612
+ Gem ::Requirement . new ( "~> 3.2" ) . satisfied_by? ( Gem ::Version . new ( RbConfig ::CONFIG [ "ruby_version" ] . split ( "+" ) . first ) )
613
+ end
614
+
587
615
#
588
616
# main
589
617
#
@@ -690,6 +718,10 @@ def do_clean
690
718
cross_build_p = config_cross_build?
691
719
message "Cross build is #{ cross_build_p ? "enabled" : "disabled" } .\n "
692
720
721
+ if needs_darwin_linker_hack
722
+ append_ldflags ( "-Wl,-flat_namespace" )
723
+ end
724
+
693
725
require "yaml"
694
726
dependencies = YAML . load_file ( File . join ( PACKAGE_ROOT_DIR , "dependencies.yml" ) )
695
727
@@ -941,16 +973,17 @@ def configure
941
973
end . shelljoin
942
974
943
975
if static_p
976
+ static_archive_ld_flag = needs_darwin_linker_hack ? [ "-load_hidden" ] : [ ]
944
977
$libs = $libs. shellsplit . map do |arg |
945
978
case arg
946
979
when "-lxml2"
947
- File . join ( libxml2_recipe . path , "lib" , libflag_to_filename ( arg ) )
980
+ static_archive_ld_flag + [ File . join ( libxml2_recipe . path , "lib" , libflag_to_filename ( arg ) ) ]
948
981
when "-lxslt" , "-lexslt"
949
- File . join ( libxslt_recipe . path , "lib" , libflag_to_filename ( arg ) )
982
+ static_archive_ld_flag + [ File . join ( libxslt_recipe . path , "lib" , libflag_to_filename ( arg ) ) ]
950
983
else
951
984
arg
952
985
end
953
- end . shelljoin
986
+ end . flatten . shelljoin
954
987
end
955
988
956
989
ensure_func ( "xmlParseDoc" , "libxml/parser.h" )
0 commit comments