Skip to content

Commit

Permalink
Select static or shared from both_libraries in dep
Browse files Browse the repository at this point in the history
Add `.as_static()` and `.as_shared()` methods to internal dependencies.
Add `prefer_static` keyword to `internal_dependency()`.

Internal dependencies can now choose between static and shared 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 dependecies.
  • Loading branch information
bruchar1 committed Aug 11, 2023
1 parent 03a2a3a commit 105d471
Show file tree
Hide file tree
Showing 20 changed files with 204 additions and 13 deletions.
13 changes: 13 additions & 0 deletions docs/markdown/snippets/dep_as_static.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
## `dep.as_static()` and `dep.as_shared()` functions

Internal dependencies can now choose between static and shared 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 dependecies.

`internal_depencency` now have `.as_static()` and `.as_shared()` methods, to
convert it to a dependency that prefer either version of the linked targets.

Add `prefer_static` keyword to `internal_dependency()`, to set the default
prefered version. Otherwise, uses the `prefer_static` option to select the
prefered version.
8 changes: 8 additions & 0 deletions docs/yaml/functions/declare_dependency.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,11 @@ kwargs:
description: |
a list of object files, to be linked directly into the targets that use the
dependency.
prefer_static:
type: bool
since: 1.3.0
description: |
If `true`, uses the `static` version of linked `both_libraries`.
If `false`, uses the `shared` version of linked `both_libraries`.
If unspecified, this is determined from `prefer_static` option.
26 changes: 26 additions & 0 deletions docs/yaml/objects/dep.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -210,3 +210,29 @@ 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

- name: as_shared
returns: dep
since: 1.3.0
description: |
Only 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
11 changes: 6 additions & 5 deletions mesonbuild/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -1328,15 +1328,16 @@ def add_deps(self, deps):
self.extra_files.extend(f for f in dep.extra_files if f not in self.extra_files)
self.add_include_dirs(dep.include_directories, dep.get_include_type())
self.objects.extend(dep.objects)
self.link_targets.extend(dep.libraries)
self.link_targets.extend(dep.get_libraries())
self.link_whole_targets.extend(dep.whole_libraries)
if dep.get_compile_args() or dep.get_link_args():
# Those parts that are external.
extpart = dependencies.InternalDependency('undefined',
extpart = dependencies.InternalDependency(self.environment,
'undefined',
[],
dep.get_compile_args(),
dep.get_link_args(),
[], [], [], [], [], {}, [], [], [])
[], [], [], [], [], {}, [], [], [], None)
self.external_deps.append(extpart)
# Deps of deps.
self.add_deps(dep.ext_deps)
Expand Down Expand Up @@ -2072,9 +2073,9 @@ def post_init(self) -> None:
# FIXME: In the case of no-std we should not add those libraries,
# but we have no way to know currently.
rustc = self.compilers['rust']
d = dependencies.InternalDependency('undefined', [], [],
d = dependencies.InternalDependency(self.environment, 'undefined', [], [],
rustc.native_static_libs,
[], [], [], [], [], {}, [], [], [])
[], [], [], [], [], {}, [], [], [], None)
self.external_deps.append(d)
# By default a static library is named libfoo.a even on Windows because
# MSVC does not have a consistent convention for what static libraries
Expand Down
36 changes: 33 additions & 3 deletions mesonbuild/dependencies/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,17 +248,21 @@ def generate_system_dependency(self, include_type: str) -> 'Dependency':
new_dep.include_type = self._process_include_type_kw({'include_type': include_type})
return new_dep


class InternalDependency(Dependency):
def __init__(self, version: str, incdirs: T.List['IncludeDirs'], compile_args: T.List[str],
def __init__(self, environment: Environment,
version: str, incdirs: T.List['IncludeDirs'], compile_args: T.List[str],
link_args: T.List[str],
libraries: T.List[LibTypes],
whole_libraries: T.List[T.Union[StaticLibrary, CustomTarget, CustomTargetIndex]],
sources: T.Sequence[T.Union[mesonlib.File, GeneratedTypes, StructuredSources]],
extra_files: T.Sequence[mesonlib.File],
ext_deps: T.List[Dependency], variables: T.Dict[str, str],
d_module_versions: T.List[T.Union[str, int]], d_import_dirs: T.List['IncludeDirs'],
objects: T.List['ExtractedObjects']):
objects: T.List['ExtractedObjects'],
prefer_static: T.Optional[bool]):
super().__init__(DependencyTypeName('internal'), {})
self.env = environment
self.version = version
self.is_found = True
self.include_directories = incdirs
Expand All @@ -275,6 +279,7 @@ def __init__(self, version: str, incdirs: T.List['IncludeDirs'], compile_args: T
self.d_features['versions'] = d_module_versions
if d_import_dirs:
self.d_features['import_dirs'] = d_import_dirs
self.prefer_static = environment.coredata.get_option(OptionKey('prefer_static')) if prefer_static is None else prefer_static

def __deepcopy__(self, memo: T.Dict[int, 'InternalDependency']) -> 'InternalDependency':
result = self.__class__.__new__(self.__class__)
Expand All @@ -283,6 +288,8 @@ def __deepcopy__(self, memo: T.Dict[int, 'InternalDependency']) -> 'InternalDepe
for k, v in self.__dict__.items():
if k in {'libraries', 'whole_libraries'}:
setattr(result, k, copy.copy(v))
elif k == 'env':
setattr(result, k, v) # no need for duplicating environment
else:
setattr(result, k, copy.deepcopy(v, memo))
return result
Expand Down Expand Up @@ -322,9 +329,10 @@ def get_partial_dependency(self, *, compile_args: bool = False,
compile_args=compile_args, link_args=link_args, links=links,
includes=includes, sources=sources) for d in self.ext_deps]
return InternalDependency(
self.env,
self.version, final_includes, final_compile_args,
final_link_args, final_libraries, final_whole_libraries,
final_sources, final_extra_files, final_deps, self.variables, [], [], [])
final_sources, final_extra_files, final_deps, self.variables, [], [], [], self.prefer_static)

def get_include_dirs(self) -> T.List['IncludeDirs']:
return self.include_directories
Expand Down Expand Up @@ -355,6 +363,28 @@ def generate_link_whole_dependency(self) -> Dependency:
new_dep.libraries = []
return new_dep

def get_as_static(self, recursive: bool) -> Dependency:
new_dep = copy.deepcopy(self)
new_dep.prefer_static = True
if recursive:
new_dep.ext_deps = [dep.get_as_static(True) if isinstance(dep, InternalDependency) else dep for dep in new_dep.ext_deps]
return new_dep

def get_as_shared(self, recursive: bool) -> Dependency:
new_dep = copy.deepcopy(self)
new_dep.prefer_static = False
if recursive:
new_dep.ext_deps = [dep.get_as_shared(True) if isinstance(dep, InternalDependency) else dep for dep in new_dep.ext_deps]
return new_dep

def get_libraries(self) -> T.Generator[LibTypes, None, None]:
from ..build import BothLibraries
for lib in self.libraries:
if isinstance(lib, BothLibraries):
yield lib.static if self.prefer_static else lib.shared
else:
yield lib

class HasNativeKwarg:
def __init__(self, kwargs: T.Dict[str, T.Any]):
self.for_machine = self.get_for_machine_from_kwargs(kwargs)
Expand Down
6 changes: 4 additions & 2 deletions mesonbuild/interpreter/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,7 @@ def func_files(self, node: mparser.FunctionNode, args: T.Tuple[T.List[str]], kwa
VARIABLES_KW.evolve(since='0.54.0', since_values={list: '0.56.0'}),
KwargInfo('version', (str, NoneType)),
KwargInfo('objects', ContainerTypeInfo(list, build.ExtractedObjects), listify=True, default=[], since='1.1.0'),
KwargInfo('prefer_static', T.Optional[bool], default=None, since='1.3.0'),
)
def func_declare_dependency(self, node: mparser.BaseNode, args: T.List[TYPE_var],
kwargs: kwtypes.FuncDeclareDependency) -> dependencies.Dependency:
Expand All @@ -709,6 +710,7 @@ def func_declare_dependency(self, node: mparser.BaseNode, args: T.List[TYPE_var]
d_module_versions = kwargs['d_module_versions']
d_import_dirs = self.extract_incdirs(kwargs, 'd_import_dirs')
srcdir = Path(self.environment.source_dir)
prefer_static = kwargs['prefer_static']
# convert variables which refer to an -uninstalled.pc style datadir
for k, v in variables.items():
try:
Expand All @@ -721,10 +723,10 @@ def func_declare_dependency(self, node: mparser.BaseNode, args: T.List[TYPE_var]
if p.is_absolute() and p.is_dir() and srcdir / self.root_subdir in [p] + list(Path(os.path.abspath(p)).parents):
variables[k] = P_OBJ.DependencyVariableString(v)

dep = dependencies.InternalDependency(version, incs, compile_args,
dep = dependencies.InternalDependency(self.environment, version, incs, compile_args,
link_args, libs, libs_whole, sources, extra_files,
deps, variables, d_module_versions, d_import_dirs,
objects)
objects, prefer_static)
return dep

@typed_pos_args('assert', bool, optargs=[str])
Expand Down
24 changes: 24 additions & 0 deletions mesonbuild/interpreter/interpreterobjects.py
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,8 @@ 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,
'as_shared': self.as_shared_method,
})

def found(self) -> bool:
Expand Down Expand Up @@ -558,6 +560,28 @@ def as_link_whole_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> D
raise InterpreterException('as_link_whole method is only supported on declare_dependency() objects')
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: TYPE_kwargs) -> 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.3.0')
@noPosargs
@typed_kwargs(
'dependency.as_shared',
KwargInfo('recursive', bool, default=False),
)
def as_shared_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> 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)

Expand Down
1 change: 1 addition & 0 deletions mesonbuild/interpreter/kwargs.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,3 +378,4 @@ class FuncDeclareDependency(TypedDict):
sources: T.List[T.Union[FileOrString, build.GeneratedTypes]]
variables: T.Dict[str, str]
version: T.Optional[str]
prefer_static: T.Optional[bool]
4 changes: 2 additions & 2 deletions mesonbuild/modules/external_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,8 @@ def dependency_method(self, state: 'ModuleState', args: T.Tuple[str], kwargs: 'D
compile_args = [f'-I{abs_includedir}']
link_args = [f'-L{abs_libdir}', f'-l{libname}']
sources = self.target
dep = InternalDependency(version, [], compile_args, link_args, [],
[], [sources], [], [], {}, [], [], [])
dep = InternalDependency(self.env, version, [], compile_args, link_args, [],
[], [sources], [], [], {}, [], [], [], None)
return dep


Expand Down
2 changes: 1 addition & 1 deletion mesonbuild/modules/gnome.py
Original file line number Diff line number Diff line change
Expand Up @@ -2149,7 +2149,7 @@ def generate_vapi(self, state: 'ModuleState', args: T.Tuple[str], kwargs: 'Gener
# - add relevant directories to include dirs
incs = [build.IncludeDirs(state.subdir, ['.'] + vapi_includes, False)]
sources = [vapi_target] + vapi_depends
rv = InternalDependency(None, incs, [], [], link_with, [], sources, [], [], {}, [], [], [])
rv = InternalDependency(self.interpreter.environment, None, incs, [], [], link_with, [], sources, [], [], {}, [], [], [], None)
created_values.append(rv)
return ModuleReturnValue(rv, created_values)

Expand Down
4 changes: 4 additions & 0 deletions test cases/common/267 dep as_static/lib1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
int libfunc1(void)
{
return 1;
}
3 changes: 3 additions & 0 deletions test cases/common/267 dep as_static/lib1.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
EXPORTS

libfunc1 @1
4 changes: 4 additions & 0 deletions test cases/common/267 dep as_static/lib2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
int libfunc2(void)
{
return 2;
}
3 changes: 3 additions & 0 deletions test cases/common/267 dep as_static/lib2.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
EXPORTS

libfunc2 @2
4 changes: 4 additions & 0 deletions test cases/common/267 dep as_static/lib3.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
int libfunc3(void)
{
return 3;
}
3 changes: 3 additions & 0 deletions test cases/common/267 dep as_static/lib3.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
EXPORTS

libfunc3 @3
4 changes: 4 additions & 0 deletions test cases/common/267 dep as_static/lib4.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
int libfunc4(void)
{
return 4;
}
9 changes: 9 additions & 0 deletions test cases/common/267 dep as_static/main.c
Original file line number Diff line number Diff line change
@@ -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;
}
37 changes: 37 additions & 0 deletions test cases/common/267 dep as_static/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
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)
dep2_static = declare_dependency(link_with: lib2, prefer_static: true)
dep2_shared = declare_dependency(link_with: lib2, prefer_static: false)

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)

dep_shared = declare_dependency(dependencies: [dep1, dep2, dep3, dep4]).as_shared(recursive: true)
main_shared = executable('main_shared', 'main.c', dependencies: [dep_shared])
test('shared', main_shared)


# 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?
15 changes: 15 additions & 0 deletions test cases/common/267 dep as_static/test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"matrix": {
"options": {
"default_library": [
{ "val": "shared" },
{ "val": "static" },
{ "val": "both" }
],
"prefer_static": [
{ "val": true },
{ "val": false }
]
}
}
}

0 comments on commit 105d471

Please sign in to comment.