diff --git a/docs/yaml/functions/shared_module.yaml b/docs/yaml/functions/shared_module.yaml index ff374e763656..20bd5c48802c 100644 --- a/docs/yaml/functions/shared_module.yaml +++ b/docs/yaml/functions/shared_module.yaml @@ -15,12 +15,18 @@ description: | notes: - | - *Linking to a shared module is deprecated, and will be an error in the future*. - It used to be allowed because it was the only way to have a shared-library-like target that + *Linking to a shared module on platforms other than Android is deprecated, and will be an error + in the future*. + It was previously allowed because it was the only way to have a shared-library-like target that contained references to undefined symbols. However, since 0.40.0, the `override_options:` - [[build_target]] keyword argument can be used to create such a [[shared_library]], and shared - modules have other characteristics that make them incompatible with linking, such as a lack of - SONAME. Linking to shared modules also does not work on some platforms, such as on macOS / iOS. + [[build_target]] keyword argument can be used to create such a [[shared_library]] by passing + `override_options: 'b_lundef=false'`. Shared modules have other characteristics that make + them incompatible with linking, such as a lack of SONAME. + On macOS and iOS, linking to shared modules is disallowed by the linker, so we disallow it at + configure time. + On Android, if a shared module `foo` uses symbols from another shared module `bar`, `foo` must + also be linked to `bar`. Hence, linking one shared module to another will always be allowed when + building for Android. posargs_inherit: _build_target_base varargs_inherit: _build_target_base diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index f4df7898ae56..560fe5335486 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -2792,7 +2792,7 @@ def get_target_type_link_args(self, target, linker): commands += linker.get_std_shared_lib_link_args() # All shared libraries are PIC commands += linker.get_pic_args() - if not isinstance(target, build.SharedModule) or target.backwards_compat_want_soname: + if not isinstance(target, build.SharedModule) or target.force_soname: # Add -Wl,-soname arguments on Linux, -install_name on OS X commands += linker.get_soname_args( self.environment, target.prefix, target.name, target.suffix, diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 782f59ca3a9c..ee034ed1ac0a 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -1588,10 +1588,15 @@ def check_module_linking(self): Warn if shared modules are linked with target: (link_with) #2865 ''' for link_target in self.link_targets: - if isinstance(link_target, SharedModule) and not link_target.backwards_compat_want_soname: + if isinstance(link_target, SharedModule) and not link_target.force_soname: if self.environment.machines[self.for_machine].is_darwin(): raise MesonException( f'target {self.name} links against shared module {link_target.name}. This is not permitted on OSX') + elif self.environment.machines[self.for_machine].is_android() and isinstance(self, SharedModule): + # Android requires shared modules that use symbols from other shared modules to + # be linked before they can be dlopen()ed in the correct order. Not doing so + # leads to a missing symbol error: https://github.com/android/ndk/issues/201 + link_target.force_soname = True else: mlog.deprecation(f'target {self.name} links against shared module {link_target.name}, which is incorrect.' '\n ' @@ -1600,7 +1605,7 @@ def check_module_linking(self): f'If shared_module() was used for {link_target.name} because it has references to undefined symbols,' '\n ' 'use shared_libary() with `override_options: [\'b_lundef=false\']` instead.') - link_target.backwards_compat_want_soname = True + link_target.force_soname = True class Generator(HoldableObject): def __init__(self, exe: T.Union['Executable', programs.ExternalProgram], @@ -2269,7 +2274,7 @@ def __init__(self, name, subdir, subproject, for_machine: MachineChoice, sources self.typename = 'shared module' # We need to set the soname in cases where build files link the module # to build targets, see: https://github.com/mesonbuild/meson/issues/9492 - self.backwards_compat_want_soname = False + self.force_soname = False def get_default_install_dir(self, environment) -> T.Tuple[str, str]: return environment.get_shared_module_dir(), '{moduledir_shared}'