diff --git a/docs/markdown/snippets/dep_as_static.md b/docs/markdown/snippets/dep_as_static.md new file mode 100644 index 000000000000..d084bcd869a3 --- /dev/null +++ b/docs/markdown/snippets/dep_as_static.md @@ -0,0 +1,10 @@ +## Allow the use of static version of `both_libraries` in internal dependencies + +Internal dependencies can now choose the static version +of a `both_libraries` linked library. This allows to use the same +dependency objects for building either a static or a shared library from +the same hierarchy of dependencies. + +`dep` object returned by [[declare_dependency]] now has `.as_static()` method, +to convert it to a dependency that prefer the `static` version of the linked + [[both_libraries]] targets. diff --git a/docs/yaml/objects/dep.yaml b/docs/yaml/objects/dep.yaml index d847690f0dd5..dc925c1a485f 100644 --- a/docs/yaml/objects/dep.yaml +++ b/docs/yaml/objects/dep.yaml @@ -210,3 +210,16 @@ methods: pkgconfig_define: type: list[str] description: See [[dep.get_pkgconfig_variable]] + + - name: as_static + returns: dep + since: 1.3.0 + description: | + Only dependencies created with [[declare_dependency]], + returns a copy of the dependency object that prefer the `static` version + of [[both_libraries]]. + + kwargs: + recursive: + type: bool + description: If true, this is recursively applied to dependencies diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 72e9f44d99ac..287772ab84d9 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -355,6 +355,15 @@ def generate_link_whole_dependency(self) -> Dependency: new_dep.libraries = [] return new_dep + def get_as_static(self, recursive: bool) -> Dependency: + from ..build import BothLibraries + + new_dep = copy.copy(self) + new_dep.libraries = [lib.static if isinstance(lib, BothLibraries) else lib for lib in self.libraries] + if recursive: + new_dep.ext_deps = [dep.get_as_static(True) if isinstance(dep, InternalDependency) else dep for dep in self.ext_deps] + return new_dep + class HasNativeKwarg: def __init__(self, kwargs: T.Dict[str, T.Any]): self.for_machine = self.get_for_machine_from_kwargs(kwargs) diff --git a/mesonbuild/interpreter/interpreterobjects.py b/mesonbuild/interpreter/interpreterobjects.py index f1f8ea8fbc23..3da8810ac47e 100644 --- a/mesonbuild/interpreter/interpreterobjects.py +++ b/mesonbuild/interpreter/interpreterobjects.py @@ -41,6 +41,10 @@ class EnvironmentSeparatorKW(TypedDict): separator: str + class InternalDependencyAsStaticKW(TypedDict): + + recursive: bool + _ERROR_MSG_KW: KwargInfo[T.Optional[str]] = KwargInfo('error_message', (str, NoneType)) @@ -455,6 +459,7 @@ def __init__(self, dep: Dependency, interpreter: 'Interpreter'): 'include_type': self.include_type_method, 'as_system': self.as_system_method, 'as_link_whole': self.as_link_whole_method, + 'as_static': self.as_static_method, }) def found(self) -> bool: @@ -559,6 +564,17 @@ def as_link_whole_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> D new_dep = self.held_object.generate_link_whole_dependency() return new_dep + @FeatureNew('dependency.as_static', '1.3.0') + @noPosargs + @typed_kwargs( + 'dependency.as_static', + KwargInfo('recursive', bool, default=False), + ) + def as_static_method(self, args: T.List[TYPE_var], kwargs: InternalDependencyAsStaticKW) -> Dependency: + if not isinstance(self.held_object, InternalDependency): + raise InterpreterException('as_static method is only supported on declare_dependency() objects') + return self.held_object.get_as_static(kwargs['recursive']) + _EXTPROG = T.TypeVar('_EXTPROG', bound=ExternalProgram) class _ExternalProgramHolder(ObjectHolder[_EXTPROG]): diff --git a/test cases/common/267 dep as_static/lib1.c b/test cases/common/267 dep as_static/lib1.c new file mode 100644 index 000000000000..4cd123a00db3 --- /dev/null +++ b/test cases/common/267 dep as_static/lib1.c @@ -0,0 +1,4 @@ +int libfunc1(void) +{ + return 1; +} diff --git a/test cases/common/267 dep as_static/lib1.def b/test cases/common/267 dep as_static/lib1.def new file mode 100644 index 000000000000..3f09bb2fb4c7 --- /dev/null +++ b/test cases/common/267 dep as_static/lib1.def @@ -0,0 +1,3 @@ +EXPORTS + + libfunc1 @1 diff --git a/test cases/common/267 dep as_static/lib2.c b/test cases/common/267 dep as_static/lib2.c new file mode 100644 index 000000000000..54eb7524feee --- /dev/null +++ b/test cases/common/267 dep as_static/lib2.c @@ -0,0 +1,4 @@ +int libfunc2(void) +{ + return 2; +} diff --git a/test cases/common/267 dep as_static/lib2.def b/test cases/common/267 dep as_static/lib2.def new file mode 100644 index 000000000000..a5e26d995a9e --- /dev/null +++ b/test cases/common/267 dep as_static/lib2.def @@ -0,0 +1,3 @@ +EXPORTS + + libfunc2 @2 diff --git a/test cases/common/267 dep as_static/lib3.c b/test cases/common/267 dep as_static/lib3.c new file mode 100644 index 000000000000..6ab1beda2d37 --- /dev/null +++ b/test cases/common/267 dep as_static/lib3.c @@ -0,0 +1,4 @@ +int libfunc3(void) +{ + return 3; +} diff --git a/test cases/common/267 dep as_static/lib3.def b/test cases/common/267 dep as_static/lib3.def new file mode 100644 index 000000000000..2a8ab16b5cf9 --- /dev/null +++ b/test cases/common/267 dep as_static/lib3.def @@ -0,0 +1,3 @@ +EXPORTS + + libfunc3 @3 diff --git a/test cases/common/267 dep as_static/lib4.c b/test cases/common/267 dep as_static/lib4.c new file mode 100644 index 000000000000..f841c220891e --- /dev/null +++ b/test cases/common/267 dep as_static/lib4.c @@ -0,0 +1,4 @@ +int libfunc4(void) +{ + return 4; +} diff --git a/test cases/common/267 dep as_static/main.c b/test cases/common/267 dep as_static/main.c new file mode 100644 index 000000000000..787e4d4b1763 --- /dev/null +++ b/test cases/common/267 dep as_static/main.c @@ -0,0 +1,9 @@ +int libfunc1(void); +int libfunc2(void); +int libfunc3(void); +int libfunc4(void); + +int main(void) +{ + return libfunc1() + libfunc2() + libfunc3() + libfunc4() == 10 ? 0 : 1; +} diff --git a/test cases/common/267 dep as_static/meson.build b/test cases/common/267 dep as_static/meson.build new file mode 100644 index 000000000000..825ad6c254bc --- /dev/null +++ b/test cases/common/267 dep as_static/meson.build @@ -0,0 +1,31 @@ +project( + 'as_static', + ['c'], + meson_version: '>= 1.3.0', +) + +lib1 = library('lib1', 'lib1.c', vs_module_defs: 'lib1.def') +dep1 = declare_dependency(link_with: lib1) + +lib2 = both_libraries('lib2', 'lib2.c', vs_module_defs: 'lib2.def') +dep2 = declare_dependency(link_with: lib2) + +lib3 = shared_library('lib3', 'lib3.c', vs_module_defs: 'lib3.def') +dep3 = declare_dependency(link_with: lib3) + +lib4 = static_library('lib4', 'lib4.c') +dep4 = declare_dependency(link_with: lib4) + + +dep_default = declare_dependency(dependencies: [dep1, dep2, dep3, dep4]) +main_default = executable('main_default', 'main.c', dependencies: [dep_default]) +test('default', main_default) + +dep_static = declare_dependency(dependencies: [dep1, dep2, dep3, dep4]).as_static(recursive: true) +main_static = executable('main_static', 'main.c', dependencies: [dep_static]) +test('static', main_static) + + +# FIXME: this doesn't really test that expected lib versions are linked, +# but I don't know how I could test this... +# Maybe should I write a unit test for that? diff --git a/test cases/common/267 dep as_static/test.json b/test cases/common/267 dep as_static/test.json new file mode 100644 index 000000000000..4e49a9ef2923 --- /dev/null +++ b/test cases/common/267 dep as_static/test.json @@ -0,0 +1,11 @@ +{ + "matrix": { + "options": { + "default_library": [ + { "val": "shared" }, + { "val": "static" }, + { "val": "both" } + ] + } + } +}