alias_target with both_libs builds both

pull/13609/head
Charles Brunet 12 months ago committed by Dylan Baker
parent 0fc363021e
commit ce1602c1ee
  1. 5
      docs/markdown/snippets/alias_target_of_both_libraries.md
  2. 8
      docs/markdown/snippets/dep_as_shared_as_static.md
  3. 3
      docs/yaml/functions/alias_target.yaml
  4. 25
      docs/yaml/objects/dep.yaml
  5. 23
      mesonbuild/build.py
  6. 22
      mesonbuild/dependencies/base.py
  7. 7
      mesonbuild/interpreter/interpreter.py
  8. 28
      mesonbuild/interpreter/interpreterobjects.py
  9. 1
      test cases/common/178 bothlibraries/meson.build
  10. 28
      test cases/common/273 both libraries/meson.build

@ -0,0 +1,5 @@
## `alias_target` of `both_libraries`
Previously, when passing a [[@both_libs]] object to [[alias_target]], the alias
would only point to the shared library. It now points to both the static and the
shared library.

@ -0,0 +1,8 @@
## New `as_static` and `as_shared` methods on internal dependencies
[[@dep]] object returned by [[declare_dependency]] now has `.as_static()` and
`.as_shared()` methods, to convert to a dependency that prefers the `static`
or the `shared` version of the linked [[@both_libs]] target.
When the same dependency is used without those methods, the
`default_both_libraries` option determines which version is used.

@ -9,6 +9,9 @@ description: |
are built. Dependencies can be any build target. Since 0.60.0, this includes
[[@run_tgt]].
*Since 1.6.0* passing a [[@both_libs]] object builds both shared and
static libraries.
posargs:
target_name:
type: str

@ -221,3 +221,28 @@ methods:
pkgconfig_define:
type: list[str]
description: See [[dep.get_pkgconfig_variable]]
- name: as_static
returns: dep
since: 1.6.0
description: |
Only for 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
- name: as_shared
returns: dep
since: 1.6.0
description: |
Only for dependencies created with [[declare_dependency]],
returns a copy of the dependency object that prefer the `shared` version
of [[both_libraries]].
kwargs:
recursive:
type: bool
description: If true, this is recursively applied to dependencies

@ -1746,6 +1746,10 @@ class BuildTarget(Target):
lib_list = listify(kwargs.get(key, [])) + self_libs
return [_resolve_both_libs(t) for t in lib_list]
def get(self, lib_type: T.Literal['static', 'shared', 'auto']) -> LibTypes:
"""Base case used by BothLibraries"""
return self
class FileInTargetPrivateDir:
"""Represents a file with the path '/path/to/build/target_private_dir/fname'.
target_private_dir is the return value of get_target_private_dir which is e.g. 'subdir/target.p'.
@ -2501,7 +2505,7 @@ class BothLibraries(SecondLevelHolder):
def __repr__(self) -> str:
return f'<BothLibraries: static={repr(self.static)}; shared={repr(self.shared)}>'
def get(self, lib_type: T.Literal['static', 'shared', 'auto']) -> T.Union[StaticLibrary, SharedLibrary]:
def get(self, lib_type: T.Literal['static', 'shared', 'auto']) -> LibTypes:
if lib_type == 'static':
return self.static
if lib_type == 'shared':
@ -2575,6 +2579,10 @@ class CustomTargetBase:
def get_internal_static_libraries_recurse(self, result: OrderedSet[BuildTargetTypes]) -> None:
pass
def get(self, lib_type: T.Literal['static', 'shared', 'auto']) -> LibTypes:
"""Base case used by BothLibraries"""
return self
class CustomTarget(Target, CustomTargetBase, CommandBase):
typename = 'custom'
@ -2896,14 +2904,23 @@ class AliasTarget(RunTarget):
typename = 'alias'
def __init__(self, name: str, dependencies: T.Sequence['Target'],
def __init__(self, name: str, dependencies: T.Sequence[T.Union[Target, BothLibraries]],
subdir: str, subproject: str, environment: environment.Environment):
super().__init__(name, [], dependencies, subdir, subproject, environment)
super().__init__(name, [], list(self._deps_generator(dependencies)), subdir, subproject, environment)
def __repr__(self):
repr_str = "<{0} {1}>"
return repr_str.format(self.__class__.__name__, self.get_id())
@staticmethod
def _deps_generator(dependencies: T.Sequence[T.Union[Target, BothLibraries]]) -> T.Iterator[Target]:
for dep in dependencies:
if isinstance(dep, BothLibraries):
yield dep.shared
yield dep.static
else:
yield dep
class Jar(BuildTarget):
known_kwargs = known_jar_kwargs

@ -248,6 +248,14 @@ class Dependency(HoldableObject):
new_dep.include_type = self._process_include_type_kw({'include_type': include_type})
return new_dep
def get_as_static(self, recursive: bool) -> Dependency:
"""Used as base case for internal_dependency"""
return self
def get_as_shared(self, recursive: bool) -> Dependency:
"""Used as base case for internal_dependency"""
return self
class InternalDependency(Dependency):
def __init__(self, version: str, incdirs: T.List['IncludeDirs'], compile_args: T.List[str],
link_args: T.List[str],
@ -345,6 +353,20 @@ class InternalDependency(Dependency):
new_dep.libraries = []
return new_dep
def get_as_static(self, recursive: bool) -> Dependency:
new_dep = copy.copy(self)
new_dep.libraries = [lib.get('static') for lib in self.libraries]
if recursive:
new_dep.ext_deps = [dep.get_as_static(True) for dep in self.ext_deps]
return new_dep
def get_as_shared(self, recursive: bool) -> Dependency:
new_dep = copy.copy(self)
new_dep.libraries = [lib.get('shared') for lib in self.libraries]
if recursive:
new_dep.ext_deps = [dep.get_as_shared(True) 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)

@ -2165,10 +2165,11 @@ class Interpreter(InterpreterBase, HoldableObject):
return tg
@FeatureNew('alias_target', '0.52.0')
@typed_pos_args('alias_target', str, varargs=build.Target, min_varargs=1)
@typed_pos_args('alias_target', str, varargs=(build.Target, build.BothLibraries), min_varargs=1)
@noKwargs
def func_alias_target(self, node: mparser.BaseNode, args: T.Tuple[str, T.List[build.Target]],
kwargs: 'TYPE_kwargs') -> build.AliasTarget:
@noSecondLevelHolderResolving
def func_alias_target(self, node: mparser.BaseNode, args: T.Tuple[str, T.List[T.Union[build.Target, build.BothLibraries]]],
kwargs: TYPE_kwargs) -> build.AliasTarget:
name, deps = args
if any(isinstance(d, build.RunTarget) for d in deps):
FeatureNew.single_use('alias_target that depends on run_targets', '0.60.0', self.subproject)

@ -41,6 +41,10 @@ if T.TYPE_CHECKING:
separator: str
class InternalDependencyAsKW(TypedDict):
recursive: bool
_ERROR_MSG_KW: KwargInfo[T.Optional[str]] = KwargInfo('error_message', (str, NoneType))
@ -462,6 +466,8 @@ class DependencyHolder(ObjectHolder[Dependency]):
'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,
'as_shared': self.as_shared_method,
})
def found(self) -> bool:
@ -580,6 +586,28 @@ class DependencyHolder(ObjectHolder[Dependency]):
new_dep = self.held_object.generate_link_whole_dependency()
return new_dep
@FeatureNew('dependency.as_static', '1.6.0')
@noPosargs
@typed_kwargs(
'dependency.as_static',
KwargInfo('recursive', bool, default=False),
)
def as_static_method(self, args: T.List[TYPE_var], kwargs: InternalDependencyAsKW) -> 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'])
@FeatureNew('dependency.as_shared', '1.6.0')
@noPosargs
@typed_kwargs(
'dependency.as_shared',
KwargInfo('recursive', bool, default=False),
)
def as_shared_method(self, args: T.List[TYPE_var], kwargs: InternalDependencyAsKW) -> Dependency:
if not isinstance(self.held_object, InternalDependency):
raise InterpreterException('as_shared method is only supported on declare_dependency() objects')
return self.held_object.get_as_shared(kwargs['recursive'])
_EXTPROG = T.TypeVar('_EXTPROG', bound=ExternalProgram)
class _ExternalProgramHolder(ObjectHolder[_EXTPROG]):

@ -2,6 +2,7 @@ project('both libraries linking test', 'c', 'cpp')
both_libs = both_libraries('mylib', 'libfile.c')
dep = declare_dependency(link_with: both_libs)
alias_target('alias', both_libs)
exe_shared = executable('prog-shared', 'main.c', link_with : both_libs.get_shared_lib())
exe_static = executable('prog-static', 'main.c',
c_args : ['-DSTATIC_COMPILATION'],

@ -77,11 +77,37 @@ test('test both libs', main)
if get_option('default_library') == 'both' and get_option('default_both_libraries') == 'auto'
# With those options, even if the both_libraries defaults to 'shared',
# 'static' version is used when linking to the static part of another both_libraries.
if get_option('use_dep')
main_static_deps = [with_library_dep.as_static(recursive: true)]
main_static_links = []
else
main_static_deps = []
main_static_links = [with_library.get_static_lib()]
endif
main_static = executable(
'main_static',
files('src/main.c'),
c_args: [f'-DEXPECTED=0'],
link_with: with_library.get_static_lib(),
link_with: main_static_links,
dependencies: main_static_deps,
)
test('test static', main_static)
if get_option('use_dep')
main_shared_deps = [with_library_dep.as_shared(recursive: true)]
main_shared_links = []
else
main_shared_deps = []
main_shared_links = [with_library.get_shared_lib()]
endif
main_shared = executable(
'main_shared',
files('src/main.c'),
c_args: [f'-DEXPECTED=2'],
link_with: main_shared_links,
dependencies: main_shared_deps,
)
test('test shared', main_shared)
endif

Loading…
Cancel
Save