shared_module: Add soname when used as a link target

Emit a detailed deprecation warning that explains what to do instead.
Also add a unittest.

```
DEPRECATION: target prog links against shared module mymod, which is incorrect.
             This will be an error in the future, so please use shared_library() for mymod instead.
             If shared_module() was used for mymod because it has references to undefined symbols,
             use shared_libary() with `override_options: ['b_lundef=false']` instead.
```

Fixes https://github.com/mesonbuild/meson/issues/9492
pull/9667/head
Nirbheek Chauhan 3 years ago
parent dc5b0cf50c
commit 54b2fc3f57
  1. 7
      docs/yaml/functions/shared_library.yaml
  2. 9
      docs/yaml/functions/shared_module.yaml
  3. 2
      mesonbuild/backend/ninjabackend.py
  4. 16
      mesonbuild/build.py
  5. 2
      test cases/failing/75 link with shared module on osx/test.json
  6. 5
      test cases/unit/1 soname/main.c
  7. 13
      test cases/unit/1 soname/meson.build
  8. 6
      unittests/allplatformstests.py
  9. 18
      unittests/linuxliketests.py

@ -2,13 +2,6 @@ name: shared_library
returns: lib
description: Builds a shared library with the given sources.
notes:
- |
Linking to a shared module is not supported on some
platforms, notably OSX. Consider using a
[[shared_library]] instead, if you need to both
`dlopen()` and link with a library.
posargs_inherit: _build_target_base
varargs_inherit: _build_target_base
kwargs_inherit: _build_target_base

@ -13,6 +13,15 @@ description: |
you will need to set the `export_dynamic` argument of the executable to
`true`.
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
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.
posargs_inherit: _build_target_base
varargs_inherit: _build_target_base
kwargs_inherit: _build_target_base

@ -2785,7 +2785,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
commands += linker.get_std_shared_lib_link_args()
# All shared libraries are PIC
commands += linker.get_pic_args()
if not isinstance(target, build.SharedModule):
if not isinstance(target, build.SharedModule) or target.backwards_compat_want_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,

@ -1574,11 +1574,16 @@ You probably should put it in link_with instead.''')
if isinstance(link_target, SharedModule):
if self.environment.machines[self.for_machine].is_darwin():
raise MesonException(
'target links against shared modules. This is not permitted on OSX')
f'target {self.name} links against shared module {link_target.name}. This is not permitted on OSX')
else:
mlog.warning('target links against shared modules. This '
'is not recommended as it is not supported on some '
'platforms')
mlog.deprecation(f'target {self.name} links against shared module {link_target.name}, which is incorrect.'
'\n '
f'This will be an error in the future, so please use shared_library() for {link_target.name} instead.'
'\n '
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
return
class Generator(HoldableObject):
@ -2235,6 +2240,9 @@ class SharedModule(SharedLibrary):
raise MesonException('Shared modules must not specify the soversion kwarg.')
super().__init__(name, subdir, subproject, for_machine, sources, objects, environment, kwargs)
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
def get_default_install_dir(self, environment) -> T.Tuple[str, str]:
return environment.get_shared_module_dir(), '{moduledir_shared}'

@ -1,7 +1,7 @@
{
"stdout": [
{
"line": "test cases/failing/75 link with shared module on osx/meson.build:8:0: ERROR: target links against shared modules. This is not permitted on OSX"
"line": "test cases/failing/75 link with shared module on osx/meson.build:8:0: ERROR: target prog links against shared module mymodule. This is not permitted on OSX"
}
]
}

@ -0,0 +1,5 @@
int versioned_func (void);
int main (void) {
return versioned_func();
}

@ -20,3 +20,16 @@ shared_library('settosame', 'versioned.c',
install : true,
soversion : '7.8.9',
version : '7.8.9')
shared_module('some_module', 'versioned.c',
install: true)
module1 = shared_module('linked_module1', 'versioned.c',
install: true)
module2 = shared_module('linked_module2', 'versioned.c',
install: true)
module2_dep = declare_dependency(link_with: module2)
executable('main1', 'main.c', link_with: module1)
executable('main2', 'main.c', dependencies: module2_dep)

@ -1950,8 +1950,10 @@ class AllPlatformTests(BasePlatformTests):
"""
tdir = os.path.join(self.unit_test_dir, '30 shared_mod linking')
out = self.init(tdir)
msg = ('WARNING: target links against shared modules. This is not '
'recommended as it is not supported on some platforms')
msg = ('''DEPRECATION: target prog links against shared module mymod, which is incorrect.
This will be an error in the future, so please use shared_library() for mymod instead.
If shared_module() was used for mymod because it has references to undefined symbols,
use shared_libary() with `override_options: ['b_lundef=false']` instead.''')
self.assertIn(msg, out)
def test_mixed_language_linker_check(self):

@ -438,6 +438,24 @@ class LinuxlikeTests(BasePlatformTests):
self.assertEqual(get_soname(bothset), 'libbothset.so.1.2.3')
self.assertEqual(len(self.glob_sofiles_without_privdir(bothset[:-3] + '*')), 3)
# A shared_module that is not linked to anything
module = os.path.join(libpath, 'libsome_module.so')
self.assertPathExists(module)
self.assertFalse(os.path.islink(module))
self.assertEqual(get_soname(module), None)
# A shared_module that is not linked to an executable with link_with:
module = os.path.join(libpath, 'liblinked_module1.so')
self.assertPathExists(module)
self.assertFalse(os.path.islink(module))
self.assertEqual(get_soname(module), 'liblinked_module1.so')
# A shared_module that is not linked to an executable with dependencies:
module = os.path.join(libpath, 'liblinked_module2.so')
self.assertPathExists(module)
self.assertFalse(os.path.islink(module))
self.assertEqual(get_soname(module), 'liblinked_module2.so')
def test_soname(self):
self._test_soname_impl(self.builddir, False)

Loading…
Cancel
Save