auto select static or shared when linking both_libraries together

pull/13609/head
Charles Brunet 12 months ago committed by Dylan Baker
parent 2d6915a598
commit 0fc363021e
  1. 3
      docs/markdown/Builtin-options.md
  2. 7
      docs/markdown/snippets/default_both_libraries.md
  3. 35
      mesonbuild/build.py
  4. 10
      mesonbuild/interpreter/interpreter.py
  5. 65
      test cases/common/273 both libraries/meson.build
  6. 1
      test cases/common/273 both libraries/meson.options
  7. 10
      test cases/common/273 both libraries/src/both_libraries.c
  8. 5
      test cases/common/273 both libraries/src/both_libraries.h
  9. 6
      test cases/common/273 both libraries/src/library.c
  10. 2
      test cases/common/273 both libraries/src/main.c
  11. 4
      test cases/common/273 both libraries/test.json

@ -187,6 +187,9 @@ with previous meson versions), 'static', or 'auto'. With auto, the value from
`default_library` option is used, unless it is 'both', in which case 'shared'
is used instead.
When `default_both_libraries` is 'auto', passing a [[@both_libs]] dependecy
in [[both_libraries]] will link the static dependency with the static lib,
and the shared dependency with the shared lib.
## Base options

@ -2,3 +2,10 @@
`both_libraries` targets used to be considered as a shared library by default.
There is now the `default_both_libraries` option to change this default.
When `default_both_libraries` is 'auto', [[both_libraries]] with dependencies
that are [[@both_libs]] themselves will link with the same kind of library.
For example, if `libA` is a [[@both_libs]] and `libB` is a [[@both_libs]]
linked with `libA` (or with an internal dependency on `libA`),
the static lib of `libB` will link with the static lib of `libA`, and the
shared lib of `libA` will link with the shared lib of `libB`.

@ -138,14 +138,6 @@ def get_target_macos_dylib_install_name(ld) -> str:
return ''.join(name)
def extract_targets_as_list(
kwargs: T.Dict[str, T.Sequence[LibTypes]],
key: T.Literal['link_with', 'link_whole'],
self_libs: T.List[LibTypes]) -> T.List[LibTypes]:
lib_list = listify(kwargs.get(key, [])) + self_libs
return [t.get_default_object() if isinstance(t, BothLibraries) else t for t in lib_list]
class InvalidArguments(MesonException):
pass
@ -791,8 +783,8 @@ class BuildTarget(Target):
# we have to call process_compilers() first and we need to process libraries
# from link_with and link_whole first.
# See https://github.com/mesonbuild/meson/pull/11957#issuecomment-1629243208.
link_targets = extract_targets_as_list(kwargs, 'link_with', self.link_targets)
link_whole_targets = extract_targets_as_list(kwargs, 'link_whole', self.link_whole_targets)
link_targets = self.extract_targets_as_list(kwargs, 'link_with')
link_whole_targets = self.extract_targets_as_list(kwargs, 'link_whole')
self.link_targets.clear()
self.link_whole_targets.clear()
self.link(link_targets)
@ -1740,6 +1732,20 @@ class BuildTarget(Target):
'a file object, a Custom Target, or a Custom Target Index')
self.process_link_depends(path)
def extract_targets_as_list(self, kwargs: T.Dict[str, T.Union[LibTypes, T.Sequence[LibTypes]]], key: T.Literal['link_with', 'link_whole']) -> T.List[LibTypes]:
bl_type = self.environment.coredata.get_option(OptionKey('default_both_libraries'))
if bl_type == 'auto':
bl_type = 'static' if isinstance(self, StaticLibrary) else 'shared'
def _resolve_both_libs(lib: LibTypes) -> LibTypes:
if isinstance(lib, BothLibraries):
return lib.get(bl_type)
return lib
self_libs: T.List[LibTypes] = self.link_targets if key == 'link_with' else self.link_whole_targets
lib_list = listify(kwargs.get(key, [])) + self_libs
return [_resolve_both_libs(t) for t in lib_list]
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'.
@ -2495,7 +2501,14 @@ class BothLibraries(SecondLevelHolder):
def __repr__(self) -> str:
return f'<BothLibraries: static={repr(self.static)}; shared={repr(self.shared)}>'
def get_default_object(self) -> BuildTarget:
def get(self, lib_type: T.Literal['static', 'shared', 'auto']) -> T.Union[StaticLibrary, SharedLibrary]:
if lib_type == 'static':
return self.static
if lib_type == 'shared':
return self.shared
return self.get_default_object()
def get_default_object(self) -> T.Union[StaticLibrary, SharedLibrary]:
if self._preferred_library == 'shared':
return self.shared
elif self._preferred_library == 'static':

@ -31,7 +31,7 @@ from ..interpreterbase import InterpreterException, InvalidArguments, InvalidCod
from ..interpreterbase import Disabler, disablerIfNotFound
from ..interpreterbase import FeatureNew, FeatureDeprecated, FeatureBroken, FeatureNewKwargs
from ..interpreterbase import ObjectHolder, ContextManagerObject
from ..interpreterbase import stringifyUserArguments
from ..interpreterbase import stringifyUserArguments, resolve_second_level_holders
from ..modules import ExtensionModule, ModuleObject, MutableModuleObject, NewExtensionModule, NotFoundExtensionModule
from ..optinterpreter import optname_regex
@ -1876,6 +1876,7 @@ class Interpreter(InterpreterBase, HoldableObject):
@permittedKwargs(known_library_kwargs)
@typed_pos_args('both_libraries', str, varargs=SOURCES_VARARGS)
@typed_kwargs('both_libraries', *LIBRARY_KWS, allow_unknown=True)
@noSecondLevelHolderResolving
def func_both_lib(self, node: mparser.BaseNode,
args: T.Tuple[str, SourcesVarargsType],
kwargs: kwtypes.Library) -> build.BothLibraries:
@ -1893,6 +1894,7 @@ class Interpreter(InterpreterBase, HoldableObject):
@permittedKwargs(known_library_kwargs)
@typed_pos_args('library', str, varargs=SOURCES_VARARGS)
@typed_kwargs('library', *LIBRARY_KWS, allow_unknown=True)
@noSecondLevelHolderResolving
def func_library(self, node: mparser.BaseNode,
args: T.Tuple[str, SourcesVarargsType],
kwargs: kwtypes.Library) -> build.Executable:
@ -1910,12 +1912,16 @@ class Interpreter(InterpreterBase, HoldableObject):
@permittedKwargs(known_build_target_kwargs)
@typed_pos_args('build_target', str, varargs=SOURCES_VARARGS)
@typed_kwargs('build_target', *BUILD_TARGET_KWS, allow_unknown=True)
@noSecondLevelHolderResolving
def func_build_target(self, node: mparser.BaseNode,
args: T.Tuple[str, SourcesVarargsType],
kwargs: kwtypes.BuildTarget
) -> T.Union[build.Executable, build.StaticLibrary, build.SharedLibrary,
build.SharedModule, build.BothLibraries, build.Jar]:
target_type = kwargs['target_type']
if target_type not in {'both_libraries', 'library'}:
args, kwargs = resolve_second_level_holders(args, kwargs)
if target_type == 'executable':
return self.build_target(node, args, kwargs, build.Executable)
elif target_type == 'shared_library':
@ -3272,8 +3278,10 @@ class Interpreter(InterpreterBase, HoldableObject):
default_library = self.coredata.get_option(OptionKey('default_library', subproject=self.subproject))
assert isinstance(default_library, str), 'for mypy'
if default_library == 'shared':
args, kwargs = resolve_second_level_holders(args, kwargs)
return self.build_target(node, args, T.cast('kwtypes.StaticLibrary', kwargs), build.SharedLibrary)
elif default_library == 'static':
args, kwargs = resolve_second_level_holders(args, kwargs)
return self.build_target(node, args, T.cast('kwtypes.SharedLibrary', kwargs), build.StaticLibrary)
elif default_library == 'both':
return self.build_both_libraries(node, args, kwargs)

@ -7,38 +7,81 @@ project(
expected = 0
with_bl = both_libraries(
'with_bl',
files('src/both_libraries.c'),
c_shared_args: ['-DEXPORT'],
)
with_bl_dep = declare_dependency(
link_with: with_bl,
)
if get_option('use_dep')
lib_deps = [with_bl_dep]
lib_links = []
else
lib_deps = []
lib_links = [with_bl]
endif
with_library = library(
'with_library',
files('src/library.c'),
c_shared_args: ['-DEXPORT'],
link_with: lib_links,
dependencies: lib_deps,
)
with_library_dep = declare_dependency(
link_with: with_library,
)
if get_option('default_library') == 'shared'
expected += 1
if get_option('default_both_libraries') in ['shared', 'auto']
expected += 1
endif
elif get_option('default_library') == 'both'
if get_option('default_both_libraries') in ['shared', 'auto']
expected += 2
endif
else
if get_option('default_both_libraries') == 'shared'
expected += 1
endif
endif
if get_option('use_dep')
main_deps = [with_library_dep]
main_links = []
else
main_deps = []
main_links = [with_library]
endif
mainlink = executable(
'mainlink',
main = executable(
'main',
files('src/main.c'),
c_args: [f'-DEXPECTED=@expected@'],
link_with: [with_library],
link_with: main_links,
dependencies: main_deps,
)
test('link with', mainlink)
test('test both libs', main)
maindep = executable(
'maindep',
files('src/main.c'),
c_args: [f'-DEXPECTED=@expected@'],
dependencies: [with_library_dep],
)
test('use dep', maindep)
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.
main_static = executable(
'main_static',
files('src/main.c'),
c_args: [f'-DEXPECTED=0'],
link_with: with_library.get_static_lib(),
)
test('test static', main_static)
endif

@ -0,0 +1 @@
option('use_dep', type: 'boolean', value: false)

@ -0,0 +1,10 @@
#include "both_libraries.h"
int both_libraries_function(void)
{
#if defined EXPORT
return 1;
#else
return 0;
#endif
}

@ -0,0 +1,5 @@
#pragma once
#include "api.h"
int API both_libraries_function(void);

@ -1,10 +1,12 @@
#include "library.h"
#include "both_libraries.h"
int library_function(void)
{
int sum = both_libraries_function();
#if defined EXPORT
return 1;
return sum + 1;
#else
return 0;
return sum;
#endif
}

@ -4,5 +4,5 @@
int main(void)
{
int sum = library_function();
return sum == EXPECTED ? 0 : sum;
return sum == EXPECTED ? 0 : 1;
}

@ -10,6 +10,10 @@
{ "val": "shared" },
{ "val": "static" },
{ "val": "auto" }
],
"use_dep": [
{ "val": false },
{ "val": true }
]
}
}

Loading…
Cancel
Save