Extension linking does (not) work with Xcode 14 (macOS 12.6)
tombruijn opened this issue · 3 comments
The linker shipped with XCode Version 14.0 (14A309) currently does not break linking for Ruby apps on macOS 12.6.
# In this repo's root:
$ rake extension:install
checking for appsignal_start() in -lappsignal... yes
checking for appsignal-agent in /Users/tombruijn/appsignal/ruby/ext... yes
creating Makefile
compiling appsignal_extension.c
linking shared-object appsignal_extension.bundle
ld: warning: -undefined dynamic_lookup may not work with chained fixups
Xcode Version 13.4.1 (13F100), from macOS 12.5
$ man ld
-undefined treatment
Specifies how undefined symbols are to be treated. Options are: error, warning, suppress, or dynamic_lookup. The default
is error.
You can also have this older version of Xcode installed on macOS 12.6.
New Xcode Version 14.0 (14A309), from macOS 12.6
$ man ld
-undefined treatment
Specifies how undefined symbols are to be treated. Options are: error, warning, suppress, or dynamic_lookup. The default is error. Note:
dynamic_lookup that depends on lazy binding will not work with chained fixups.
See how it says "dynamic_lookup that depends on lazy binding will not work with chained fixups", the thing the new error is about.
"Workarounds"
Unnecessary for now, but may be useful for future macOS/Xcode updates
- Do not upgrade Xcode to Version (currently) 14 or newer
- Downgrade Xcode
Related issues
We fixed this same issue for Elixir in this PR that explicitly tells the linker the symbols are undefined and set at runtime. We can't exactly use the same fix because we don't have a Makefile in the Ruby gem. It's generated by Ruby based on the ext/extconf.rb
file.
- Relevant Ruby lang issue: https://bugs.ruby-lang.org/issues/19005
Our Ruby gem doesn't set -Wl,-fatal_warnings
like we do in our Elixir package. That means it doesn't fail to install the Ruby extension, just print a bunch of warnings. Especially when dynamic_lookup
is removed.
This will become an issue when Apple removes dynamic_lookup
behavior in what I assume is a future Xcode update. That's what the warning is for right? The "chained fixups" seem to be the linker default now.
Ruby sets the DLDFLAGS
linker option -Wl,-undefined,dynamic_lookup
upon require "mkmf"
. This may change in Ruby issue 19005 and future Ruby releases.
Going to put this issue on hold for now. Let us know on this issue or support@appsignal.com if you do run into this issue:
A workaround to this issue, based on commit 0a1ad80, is:
(I won't apply this workaround, because it seems to continue to work for now.)
diff --git ext/extconf.rb ext/extconf.rb
index 87696f8a..16566131 100644
--- ext/extconf.rb
+++ ext/extconf.rb
@@ -44,6 +44,34 @@ def install
# to fail on start.
$LDFLAGS += " -static-libgcc" # rubocop:disable Style/GlobalVars
report["build"]["flags"]["LDFLAGS"] = $LDFLAGS # rubocop:disable Style/GlobalVars
+ elsif AGENT_PLATFORM == "darwin"
+ functions = %w[
+ _rb_add_event_hook
+ _rb_cObject
+ _rb_data_object_wrap
+ _rb_debug_rstring_null_ptr
+ _rb_define_class_under
+ _rb_define_method
+ _rb_define_module
+ _rb_define_singleton_method
+ _rb_eTypeError
+ _rb_enc_associate
+ _rb_fix2int
+ _rb_num2dbl
+ _rb_num2long
+ _rb_obj_classname
+ _rb_raise
+ _rb_str_new
+ _rb_unexpected_type
+ _rb_utf8_encoding
+ ].map do |function|
+ "-Wl,-U,#{function}"
+ end
+ # rubocop:disable Style/GlobalVars
+ $DLDFLAGS.slice! "-Wl,-undefined,dynamic_lookup"
+ $DLDFLAGS += " -undefined error #{functions.join(" ")}"
+ report["build"]["flags"]["DLDFLAGS"] = $DLDFLAGS
+ # rubocop:enable Style/GlobalVars
end
create_makefile "appsignal_extension"
successful_installation
Alternative workaround with a symbols file:
diff --git ext/extconf.rb ext/extconf.rb
index 87696f8a..e0aab288 100644
--- ext/extconf.rb
+++ ext/extconf.rb
@@ -44,6 +44,12 @@ def install
# to fail on start.
$LDFLAGS += " -static-libgcc" # rubocop:disable Style/GlobalVars
report["build"]["flags"]["LDFLAGS"] = $LDFLAGS # rubocop:disable Style/GlobalVars
+ elsif AGENT_PLATFORM == "darwin"
+ # rubocop:disable Style/GlobalVars
+ $DLDFLAGS.slice! "-Wl,-undefined,dynamic_lookup"
+ $DLDFLAGS += " -Wl,-undefined error -Wl,-exported_symbols_list #{File.join(__dir__, "symbols.sym")}"
+ report["build"]["flags"]["DLDFLAGS"] = $DLDFLAGS
+ # rubocop:enable Style/GlobalVars
end
create_makefile "appsignal_extension"
successful_installation
diff --git ext/symbols.sym ext/symbols.sym
index e69de29b..e448e69d 100644
--- ext/symbols.sym
+++ ext/symbols.sym
@@ -0,0 +1,18 @@
+_rb_add_event_hook
+_rb_cObject
+_rb_data_object_wrap
+_rb_debug_rstring_null_ptr
+_rb_define_class_under
+_rb_define_method
+_rb_define_module
+_rb_define_singleton_method
+_rb_eTypeError
+_rb_enc_associate
+_rb_fix2int
+_rb_num2dbl
+_rb_num2long
+_rb_obj_classname
+_rb_raise
+_rb_str_new
+_rb_unexpected_type
+_rb_utf8_encoding
FYI.. https://issues.guix.gnu.org/issue/57849
Looks like using -Wl,-w
will help.
Thanks for the suggestion! I see that -w
will "Suppress all warning messages". I'd rather see the warning message, in case something breaks in a future macOS version.
People that install the AppSignal gem already don't see this warning, because it's wrapped and hidden by the Ruby gems installer. We're the only ones seeing this warning now when we run the rake extension:install
task.