Link ext bundles with bundle loader option for newer ld64

ld64 shipped with Xcode 14 emits a warning when using `-undefined
dynamic_lookup`.

```
ld: warning: -undefined dynamic_lookup may not work with chained fixups
```

Actually, `-undefined dynamic_lookup` doesn't work when:

1. Link a *shared library* with the option
2. Link it with a program that uses the chained-fixup introduced from
   macOS 12 and iOS 15
because `-undefined dynamic_lookup` uses lazy-bindings and they won't be
bound while dyld fixes-up by traversing chained-fixup info.

However, we build exts as *bundles* and they are loaded only through
`dlopen`, so it's safe to use `-undefined dynamic_lookup` in theory.
So the warning produced by ld64 is false-positive, and it results
failure of option checking in configuration. Therefore, it would be an
option to ignore the warning during our configuration.

On the other hand, `-undefined dynamic_lookup` is already deprecated on
all darwin platforms except for macOS, so it's good time to get rid of
the option. ld64 also provides `-bundle_loader <executable>` option,
which allows to resolve symbols defined in the executable symtab while
linking. It behaves almost the same with `-undefined dynamic_lookup`,
but it makes the following changes:

1. Require that unresolved symbols among input objects must be defined
   in the executable.
2. Lazy symbol binding will lookup only the symtab of the bundle loader
   executable. (`-undefined dynamic_lookup` lookups all symtab as flat
   namespace)

This patch adds `-bundle_loader $(RUBY)` when non-EXTSTATIC
configuration by assuming ruby executable can be linked before building
exts.

See "New Features" subsection under "Linking" section for chained fixup
https://developer.apple.com/documentation/xcode-release-notes/xcode-13-release-notes
This commit is contained in:
Yuta Saito 2022-07-28 17:19:28 +09:00
parent 542040fb83
commit 50d81bfbc1
Notes: git 2022-08-04 16:29:46 +09:00
4 changed files with 15 additions and 3 deletions

View File

@ -3011,6 +3011,12 @@ STATIC=
: ${LDFLAGS=""}
: ${LIBPATHENV=DYLD_FALLBACK_LIBRARY_PATH}
: ${PRELOADENV=DYLD_INSERT_LIBRARIES}
AS_IF([test "x$EXTSTATIC" = x], [
# When building ext bundles, a mach-o bundle needs to know its loader
# program to bind symbols from the ruby executable
EXTDLDFLAGS='-bundle_loader $(BUILTRUBY)'
PREP="$PREP"' $(PROGRAM)'
])
rb_cv_dlopen=yes],
[aix*], [ : ${LDSHARED='$(CC)'}
AS_IF([test "$GCC" = yes], [
@ -3334,7 +3340,7 @@ AS_IF([test x"$cross_compiling" = xyes], [
AC_SUBST(XRUBY_LIBDIR)
AC_SUBST(XRUBY_RUBYLIBDIR)
AC_SUBST(XRUBY_RUBYHDRDIR)
PREP='$(arch)-fake.rb'
PREP="$PREP "'$(arch)-fake.rb'
RUNRUBY_COMMAND='$(MINIRUBY) -I`cd $(srcdir)/lib; pwd`'
RUNRUBY='$(RUNRUBY_COMMAND)'
XRUBY='$(MINIRUBY)'
@ -3344,7 +3350,7 @@ AS_IF([test x"$cross_compiling" = xyes], [
], [
MINIRUBY='./miniruby$(EXEEXT) -I$(srcdir)/lib -I.'
MINIRUBY="$MINIRUBY"' -I$(EXTOUT)/common'
PREP='miniruby$(EXEEXT)'
PREP="$PREP "'miniruby$(EXEEXT)'
RUNRUBY_COMMAND='$(MINIRUBY) $(tooldir)/runruby.rb --extout=$(EXTOUT) $(RUNRUBYOPT)'
RUNRUBY='$(RUNRUBY_COMMAND) --'
XRUBY='$(RUNRUBY)'

View File

@ -22,6 +22,7 @@ TRANSSODIR = $(ENCSODIR)/trans
DLEXT = @DLEXT@
OBJEXT = @OBJEXT@
LIBEXT = @LIBEXT@
EXEEXT = @EXEEXT@
TIMESTAMPDIR = $(EXTOUT)/.timestamp
ENC_TRANS_D = $(TIMESTAMPDIR)/.enc-trans.time
ENC_TRANS_SO_D = $(TIMESTAMPDIR)/.enc-trans.so.time
@ -35,6 +36,7 @@ RUBY_SO_NAME = @RUBY_SO_NAME@
LIBRUBY = @LIBRUBY@
LIBRUBYARG_SHARED = @LIBRUBYARG_SHARED@
LIBRUBYARG_STATIC = $(LIBRUBYARG_SHARED)
BUILTRUBY = $(topdir)/ruby$(EXEEXT)
empty =
AR = @AR@

View File

@ -412,9 +412,12 @@ if CROSS_COMPILING
$ruby = $mflags.defined?("MINIRUBY") || CONFIG['MINIRUBY']
elsif sep = config_string('BUILD_FILE_SEPARATOR')
$ruby = "$(topdir:/=#{sep})#{sep}miniruby" + EXEEXT
else
elsif CONFIG['EXTSTATIC']
$ruby = '$(topdir)/miniruby' + EXEEXT
else
$ruby = '$(topdir)/ruby' + EXEEXT
end
$mflags << "BUILTRUBY=#$ruby"
$ruby = [$ruby]
$ruby << "-I'$(topdir)'"
unless CROSS_COMPILING

View File

@ -2076,6 +2076,7 @@ sitearch = #{CONFIG['sitearch']}
ruby_version = #{RbConfig::CONFIG['ruby_version']}
ruby = #{$ruby.sub(%r[\A#{Regexp.quote(RbConfig::CONFIG['bindir'])}(?=/|\z)]) {'$(bindir)'}}
RUBY = $(ruby#{sep})
BUILTRUBY = $(RUBY)
ruby_headers = #{headers.join(' ')}
RM = #{config_string('RM', &possible_command) || '$(RUBY) -run -e rm -- -f'}