Skip to content

Commit

Permalink
interpreter: add <lang>_(static|shared)_args
Browse files Browse the repository at this point in the history
Which allow passing arguments specifically to the static or shared
libraries.

For design, this is all handled in the interpreter, by the build layer
the arguments are combined into the existing fields. This limits changes
required in the mid and backend layers
  • Loading branch information
dcbaker committed Sep 26, 2023
1 parent f69fd1e commit 14b39de
Show file tree
Hide file tree
Showing 12 changed files with 124 additions and 8 deletions.
9 changes: 9 additions & 0 deletions docs/markdown/snippets/shared_static_only_args.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
## `<lang>_(shared|static)_args` for both_library, library, and build_target

We now allow passing arguments like `c_static_args` and `c_shared_args`. This
allows a `both_library` to have arguments specific to either the shared or
static library, as well as common arguments to both.

There is a drawback to this, since Meson now cannot re-use object files between
the static and shared targets. This could lead to much higher compilation time
when using a `both_library` if there are many sources.
6 changes: 6 additions & 0 deletions docs/yaml/functions/library.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ description: |
The keyword arguments for this are the same as for
[[build_target]]
warnings:
- using <lang>_shared_args and/or <lang>_static_args may lead to much higher
compilation times with both_library, as object files cannot be shared between
the static and shared targets. It is guaranteed to not duplicate the build if
these arguments are empty arrays

posargs_inherit: _build_target_base
varargs_inherit: _build_target_base
kwargs_inherit:
Expand Down
19 changes: 19 additions & 0 deletions docs/yaml/functions/shared_library.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ posargs_inherit: _build_target_base
varargs_inherit: _build_target_base
kwargs_inherit: _build_target_base

warnings:
- using <lang>_shared_args may lead to much higher compilation times with
both_library, as object files cannot be shared between the static and shared
targets. It is guaranteed to not duplicate the build if this is an empty array

kwargs:
version:
type: str
Expand Down Expand Up @@ -52,3 +57,17 @@ kwargs:
Set the specific ABI to compile (when compiling rust).
- 'rust' (default): Create a "dylib" crate.
- 'c': Create a "cdylib" crate.
<lang>_shared_args:
type: list[str]
since: 1.3.0
description:
Arguments that are only passed to a shared library

vala_shared_args:
type: list[str | file]
since: 1.3.0
description:
Arguments that are only passed to a shared library

Like `vala_args`, [[files]] is allowed in addition to string
19 changes: 19 additions & 0 deletions docs/yaml/functions/static_library.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ posargs_inherit: _build_target_base
varargs_inherit: _build_target_base
kwargs_inherit: _build_target_base

warnings:
- using <lang>_static_args may lead to much higher compilation times with
both_library, as object files cannot be shared between the static and shared
targets. It is guaranteed to not duplicate the build if this is an empty array

kwargs:
pic:
type: bool
Expand All @@ -31,3 +36,17 @@ kwargs:
Set the specific ABI to compile (when compiling rust).
- 'rust' (default): Create a "rlib" crate.
- 'c': Create a "staticlib" crate.
<lang>_static_args:
type: list[str]
since: 1.3.0
description:
Arguments that are only passed to a static library

vala_shared_args:
type: list[str | file]
since: 1.3.0
description:
Arguments that are only passed to a shared library

Like `vala_args`, [[files]] is allowed in addition to string
4 changes: 2 additions & 2 deletions mesonbuild/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,9 @@
cs_kwargs)

known_exe_kwargs = known_build_target_kwargs | {'implib', 'export_dynamic', 'pie'}
known_shlib_kwargs = known_build_target_kwargs | {'version', 'soversion', 'vs_module_defs', 'darwin_versions', 'rust_abi'}
known_shlib_kwargs = known_build_target_kwargs | {f'{l}_shared_args' for l in all_languages} | {'version', 'soversion', 'vs_module_defs', 'darwin_versions', 'rust_abi'}
known_shmod_kwargs = known_build_target_kwargs | {'vs_module_defs', 'rust_abi'}
known_stlib_kwargs = known_build_target_kwargs | {'pic', 'prelink', 'rust_abi'}
known_stlib_kwargs = known_build_target_kwargs | {f'{l}_static_args' for l in all_languages} | {'pic', 'prelink', 'rust_abi'}
known_jar_kwargs = known_exe_kwargs | {'main_class', 'java_resources'}

def _process_install_tag(install_tag: T.Optional[T.List[T.Optional[str]]],
Expand Down
15 changes: 14 additions & 1 deletion mesonbuild/interpreter/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -3180,7 +3180,7 @@ def add_target(self, name: str, tobj: build.Target) -> None:
self.coredata.target_guids[idname] = str(uuid.uuid4()).upper()

@FeatureNew('both_libraries', '0.46.0')
def build_both_libraries(self, node, args, kwargs):
def build_both_libraries(self, node, args, kwargs: T.Dict[str, T.Any]):
shared_lib = self.build_target(node, args, kwargs, build.SharedLibrary)
static_lib = self.build_target(node, args, kwargs, build.StaticLibrary)

Expand All @@ -3196,6 +3196,9 @@ def build_both_libraries(self, node, args, kwargs):
# FIXME: rustc supports generating both libraries in a single invocation,
# but for now compile twice.
reuse_object_files = False
elif any(k.endswith(('static_args', 'shared_args')) and v for k, v in kwargs.items()):
# Ensure not just the keyword arguments exist, but that they are non-empty.
reuse_object_files = False
else:
reuse_object_files = static_lib.pic

Expand Down Expand Up @@ -3307,6 +3310,16 @@ def build_target_decorator_caller(self, node, args, kwargs):
raise RuntimeError('Unreachable code')
self.kwarg_strings_to_includedirs(kwargs)
self.__process_language_args(kwargs)
if targetclass is build.StaticLibrary:
for lang in compilers.all_languages - {'java'}:
deps, args = self.__convert_file_args(kwargs[f'{lang}_static_args'])
kwargs['language_args'][lang].extend(args)
kwargs['depend_files'].extend(deps)
elif targetclass is build.SharedLibrary:
for lang in compilers.all_languages - {'java'}:
deps, args = self.__convert_file_args(kwargs[f'{lang}_shared_args'])
kwargs['language_args'][lang].extend(args)
kwargs['depend_files'].extend(deps)

# Filter out kwargs from other target types. For example 'soversion'
# passed to library() when default_library == 'static'.
Expand Down
9 changes: 7 additions & 2 deletions mesonbuild/interpreter/type_checking.py
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,10 @@ def _convert_darwin_versions(val: T.List[T.Union[str, int]]) -> T.Optional[T.Tup

# Arguments exclusive to StaticLibrary. These are separated to make integrating
# them into build_target easier
_EXCLUSIVE_STATIC_LIB_KWS: T.List[KwargInfo] = []
_EXCLUSIVE_STATIC_LIB_KWS: T.List[KwargInfo] = [
*[l.evolve(name=f'{l.name.split("_", 1)[0]}_static_args', since='1.3.0')
for l in _LANGUAGE_KWS],
]

# The total list of arguments used by StaticLibrary
STATIC_LIB_KWS = [
Expand All @@ -637,7 +640,9 @@ def _convert_darwin_versions(val: T.List[T.Union[str, int]]) -> T.Optional[T.Tup
_EXCLUSIVE_SHARED_LIB_KWS: T.List[KwargInfo] = [
_DARWIN_VERSIONS_KW,
KwargInfo('soversion', (str, int, NoneType), convertor=lambda x: str(x) if x is not None else None),
KwargInfo('version', (str, NoneType), validator=_validate_shlib_version)
KwargInfo('version', (str, NoneType), validator=_validate_shlib_version),
*[l.evolve(name=f'{l.name.split("_", 1)[0]}_shared_args', since='1.3.0')
for l in _LANGUAGE_KWS],
]

# The total list of arguments used by SharedLibrary
Expand Down
11 changes: 11 additions & 0 deletions test cases/common/3 static/lib3.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
int func3(const int x) {
return x + 1;
}

#ifndef WORK
# error "did not get static only C args"
#endif

#ifdef BREAK
# error "got shared only C args, but shouldn't have"
#endif
8 changes: 7 additions & 1 deletion test cases/common/3 static/meson.build
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
project('static library test', 'c')
project('static library test', 'c', default_options : ['default_library=static'])

lib = static_library('mylib', get_option('source'),
link_args : '-THISMUSTNOBEUSED') # Static linker needs to ignore all link args.
Expand All @@ -12,3 +12,9 @@ endif
assert(has_not_changed, 'Static library has changed.')

assert(not is_disabler(lib), 'Static library is a disabler.')

if get_option('default_library') == 'static'
library('lib2', 'lib3.c', c_static_args : ['-DWORK'], c_shared_args : ['-DBREAK'])
endif
static_library('lib3', 'lib3.c', c_static_args : ['-DWORK'])
build_target('lib4', 'lib3.c', c_static_args : ['-DWORK'], target_type : 'static_library')
22 changes: 22 additions & 0 deletions test cases/common/4 shared/libfile2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#if defined _WIN32 || defined __CYGWIN__
#define DLL_PUBLIC __declspec(dllexport)
#else
#if defined __GNUC__
#define DLL_PUBLIC __attribute__ ((visibility("default")))
#else
#pragma message ("Compiler does not support symbol visibility.")
#define DLL_PUBLIC
#endif
#endif

#ifndef WORK
# error "Did not get shared only arguments"
#endif

#ifdef BREAK
# error "got static only C args, but shouldn't have"
#endif

int DLL_PUBLIC libfunc(void) {
return 3;
}
8 changes: 7 additions & 1 deletion test cases/common/4 shared/meson.build
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
project('shared library test', 'c')
project('shared library test', 'c', default_options : ['default_library=shared'])
lib = shared_library('mylib', 'libfile.c')
build_target('mylib2', 'libfile.c', target_type: 'shared_library')

Expand All @@ -11,3 +11,9 @@ endif
assert(has_not_changed, 'Shared library has changed.')

assert(not is_disabler(lib), 'Shared library is a disabler.')

if get_option('default_library') == 'shared'
library('mylib5', 'libfile2.c', c_shared_args : ['-DWORK'])
endif
shared_library('mylib3', 'libfile2.c', c_shared_args : ['-DWORK'])
build_target('mylib4', 'libfile2.c', target_type: 'shared_library', c_shared_args : ['-DWORK'], c_static_args : ['-DBREAK'])
2 changes: 1 addition & 1 deletion unittests/allplatformstests.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ def test_static_library_overwrite(self):
self.init(testdir)
# Get name of static library
targets = self.introspect('--targets')
self.assertEqual(len(targets), 1)
self.assertGreaterEqual(len(targets), 1)
libname = targets[0]['filename'][0]
# Build and get contents of static library
self.build()
Expand Down

0 comments on commit 14b39de

Please sign in to comment.