Skip to content

Commit

Permalink
shared module: Allow linking on Android
Browse files Browse the repository at this point in the history
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:
android/ndk#201

We need to always allow linking for this. Also add a soname, although
it's not confirmed that it's needed, and it doesn't really hurt if it
isn't needed.
  • Loading branch information
nirbheek committed Mar 11, 2022
1 parent 20abea2 commit 2ec2a4e
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 9 deletions.
16 changes: 11 additions & 5 deletions docs/yaml/functions/shared_module.yaml
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion mesonbuild/backend/ninjabackend.py
Expand Up @@ -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,
Expand Down
11 changes: 8 additions & 3 deletions mesonbuild/build.py
Expand Up @@ -1601,10 +1601,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 '
Expand All @@ -1613,7 +1618,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],
Expand Down Expand Up @@ -2278,7 +2283,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}'
Expand Down

0 comments on commit 2ec2a4e

Please sign in to comment.