diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index 01052b018..c28939739 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -2426,6 +2426,13 @@ an external dependency with the following methods: the value of `include_type` to `value`. The `value` argument is optional and defaults to `'preserve'`. + - `as_link_whole()` *Since 0.56.0* Only dependencies created with + `declare_dependency()`, returns a copy of the dependency object with all + link_with arguments changed to link_whole. This is useful for example for + fallback dependency from a subproject built with `default_library=static`. + Note that all `link_with` objects must be static libraries otherwise an error + will be raised when trying to `link_whole` a shared library. + - `partial_dependency(compile_args : false, link_args : false, links : false, includes : false, sources : false)` *(since 0.46.0)*: returns a new dependency object with the same name, version, found status, diff --git a/docs/markdown/snippets/as_link_whole.md b/docs/markdown/snippets/as_link_whole.md new file mode 100644 index 000000000..39f12892d --- /dev/null +++ b/docs/markdown/snippets/as_link_whole.md @@ -0,0 +1,12 @@ +## `dep.as_link_whole()` + +Dependencies created with `declare_dependency()` now has new method `as_link_whole()`. +It returns a copy of the dependency object with all link_with arguments changed +to link_whole. This is useful for example for fallback dependency from a +subproject built with `default_library=static`. + +```meson +somelib = static_library('somelib', ...) +dep = declare_dependency(..., link_with: somelib) +library('someotherlib', ..., dependencies: dep.as_link_whole()) +``` diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 8d2f7597c..aa513ba33 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -295,6 +295,11 @@ class InternalDependency(Dependency): return val raise DependencyException('Could not get an internal variable and no default provided for {!r}'.format(self)) + def generate_link_whole_dependency(self) -> T.Type['Dependency']: + new_dep = copy.deepcopy(self) + new_dep.whole_libraries += new_dep.libraries + new_dep.libraries = [] + return new_dep class HasNativeKwarg: def __init__(self, kwargs): diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index bc162ac8a..3af5b5100 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -431,6 +431,7 @@ class DependencyHolder(InterpreterObject, ObjectHolder): 'partial_dependency': self.partial_dependency_method, 'include_type': self.include_type_method, 'as_system': self.as_system_method, + 'as_link_whole': self.as_link_whole_method, }) def found(self): @@ -511,6 +512,15 @@ class DependencyHolder(InterpreterObject, ObjectHolder): new_dep = self.held_object.generate_system_dependency(new_is_system) return DependencyHolder(new_dep, self.subproject) + @FeatureNew('dep.as_link_whole', '0.56.0') + @permittedKwargs({}) + @noPosargs + def as_link_whole_method(self, args, kwargs): + if not isinstance(self.held_object, InternalDependency): + raise InterpreterException('as_link_whole method is only supported on declare_dependency() objects') + new_dep = self.held_object.generate_link_whole_dependency() + return DependencyHolder(new_dep, self.subproject) + class ExternalProgramHolder(InterpreterObject, ObjectHolder): def __init__(self, ep, subproject, backend=None): InterpreterObject.__init__(self) diff --git a/run_unittests.py b/run_unittests.py index 5524c9e05..32b3d34de 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -7294,6 +7294,16 @@ c = ['{0}'] ''')) self.init(d, override_envvars={'PKG_CONFIG_LIBDIR': privatedir}) + def test_as_link_whole(self): + testdir = os.path.join(self.unit_test_dir, '79 as link whole') + self.init(testdir) + with open(os.path.join(self.privatedir, 'bar1.pc')) as f: + content = f.read() + self.assertIn('-lfoo', content) + with open(os.path.join(self.privatedir, 'bar2.pc')) as f: + content = f.read() + self.assertNotIn('-lfoo', content) + class BaseLinuxCrossTests(BasePlatformTests): # Don't pass --libdir when cross-compiling. We have tests that # check whether meson auto-detects it correctly. diff --git a/test cases/unit/79 as link whole/bar.c b/test cases/unit/79 as link whole/bar.c new file mode 100644 index 000000000..79dea9d0f --- /dev/null +++ b/test cases/unit/79 as link whole/bar.c @@ -0,0 +1,6 @@ +int bar(void); + +int bar(void) +{ + return 0; +} diff --git a/test cases/unit/79 as link whole/foo.c b/test cases/unit/79 as link whole/foo.c new file mode 100644 index 000000000..ffeee82fe --- /dev/null +++ b/test cases/unit/79 as link whole/foo.c @@ -0,0 +1,6 @@ +int foo(void); + +int foo(void) +{ + return 0; +} diff --git a/test cases/unit/79 as link whole/meson.build b/test cases/unit/79 as link whole/meson.build new file mode 100644 index 000000000..6bc208f1b --- /dev/null +++ b/test cases/unit/79 as link whole/meson.build @@ -0,0 +1,11 @@ +project('as-link-whole', 'c') + +foo = static_library('foo', 'foo.c', install: true) +dep = declare_dependency(link_with: foo) +bar1 = library('bar1', 'bar.c', dependencies: dep) +bar2 = library('bar2', 'bar.c', dependencies: dep.as_link_whole()) + +# bar1.pc should have -lfoo but not bar2.pc +pkg = import('pkgconfig') +pkg.generate(bar1) +pkg.generate(bar2)