diff --git a/docs/markdown/snippets/shared_static_only_args.md b/docs/markdown/snippets/shared_static_only_args.md new file mode 100644 index 000000000000..027fe4460726 --- /dev/null +++ b/docs/markdown/snippets/shared_static_only_args.md @@ -0,0 +1,5 @@ +## `_(shared|static)_args` for both_library + +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. diff --git a/docs/yaml/functions/shared_library.yaml b/docs/yaml/functions/shared_library.yaml index 956fb2cb2ce1..9c656c6ae11d 100644 --- a/docs/yaml/functions/shared_library.yaml +++ b/docs/yaml/functions/shared_library.yaml @@ -44,3 +44,8 @@ kwargs: description: | Specify a Microsoft module definition file for controlling symbol exports, etc., on platforms where that is possible (e.g. Windows). + + _shared_args: + type: str | file + description: + Arguments that are only passed to a shared library diff --git a/docs/yaml/functions/static_library.yaml b/docs/yaml/functions/static_library.yaml index 1d42d600a4b6..a95809df66bc 100644 --- a/docs/yaml/functions/static_library.yaml +++ b/docs/yaml/functions/static_library.yaml @@ -23,3 +23,8 @@ kwargs: If `true` the object files in the target will be prelinked, meaning that it will contain only one prelinked object file rather than the individual object files. + + _static_args: + type: str | file + description: + Arguments that are only passed to a static library diff --git a/mesonbuild/build.py b/mesonbuild/build.py index f3b8b917d382..f161f31477c1 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -113,9 +113,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'} +known_shlib_kwargs = known_build_target_kwargs | {f'{l}_shared_args' for l in all_languages} | {'version', 'soversion', 'vs_module_defs', 'darwin_versions'} known_shmod_kwargs = known_build_target_kwargs | {'vs_module_defs'} -known_stlib_kwargs = known_build_target_kwargs | {'pic', 'prelink'} +known_stlib_kwargs = known_build_target_kwargs | {f'{l}_static_args' for l in all_languages} | {'pic', 'prelink'} known_jar_kwargs = known_exe_kwargs | {'main_class', 'java_resources'} def _process_install_tag(install_tag: T.Optional[T.List[T.Optional[str]]], @@ -141,6 +141,7 @@ def get_target_macos_dylib_install_name(ld) -> str: class InvalidArguments(MesonException): pass + @dataclass(eq=False) class DependencyOverride(HoldableObject): dep: dependencies.Dependency diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index f1a2532b38e8..d989580a1610 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -83,7 +83,9 @@ OVERRIDE_OPTIONS_KW, PRESERVE_PATH_KW, REQUIRED_KW, + SHARED_LIB_LANGUAGE_KWS, SOURCES_KW, + STATIC_LIB_LANGUAGE_KWS, VARIABLES_KW, TEST_KWS, NoneType, @@ -1815,7 +1817,7 @@ def func_executable(self, node: mparser.BaseNode, @permittedKwargs(build.known_stlib_kwargs) @typed_pos_args('static_library', str, varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList, build.StructuredSources, build.ExtractedObjects, build.BuildTarget)) - @typed_kwargs('static_library', *LANGUAGE_KWS, OVERRIDE_OPTIONS_KW, allow_unknown=True) + @typed_kwargs('static_library', *LANGUAGE_KWS, *STATIC_LIB_LANGUAGE_KWS, OVERRIDE_OPTIONS_KW, allow_unknown=True) def func_static_lib(self, node: mparser.BaseNode, args: T.Tuple[str, T.List[BuildTargetSource]], kwargs) -> build.StaticLibrary: @@ -1823,7 +1825,7 @@ def func_static_lib(self, node: mparser.BaseNode, @permittedKwargs(build.known_shlib_kwargs) @typed_pos_args('shared_library', str, varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList, build.StructuredSources, build.ExtractedObjects, build.BuildTarget)) - @typed_kwargs('shared_library', *LANGUAGE_KWS, OVERRIDE_OPTIONS_KW, allow_unknown=True) + @typed_kwargs('shared_library', *LANGUAGE_KWS, *SHARED_LIB_LANGUAGE_KWS, OVERRIDE_OPTIONS_KW, allow_unknown=True) def func_shared_lib(self, node: mparser.BaseNode, args: T.Tuple[str, T.List[BuildTargetSource]], kwargs) -> build.SharedLibrary: @@ -1833,7 +1835,7 @@ def func_shared_lib(self, node: mparser.BaseNode, @permittedKwargs(known_library_kwargs) @typed_pos_args('both_libraries', str, varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList, build.StructuredSources, build.ExtractedObjects, build.BuildTarget)) - @typed_kwargs('both_libraries', *LANGUAGE_KWS, OVERRIDE_OPTIONS_KW, allow_unknown=True) + @typed_kwargs('both_libraries', *LANGUAGE_KWS, *STATIC_LIB_LANGUAGE_KWS, *SHARED_LIB_LANGUAGE_KWS, OVERRIDE_OPTIONS_KW, allow_unknown=True) def func_both_lib(self, node: mparser.BaseNode, args: T.Tuple[str, T.List[BuildTargetSource]], kwargs) -> build.BothLibraries: @@ -1842,7 +1844,7 @@ def func_both_lib(self, node: mparser.BaseNode, @FeatureNew('shared_module', '0.37.0') @permittedKwargs(build.known_shmod_kwargs) @typed_pos_args('shared_module', str, varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList, build.StructuredSources, build.ExtractedObjects, build.BuildTarget)) - @typed_kwargs('shared_module', *LANGUAGE_KWS, OVERRIDE_OPTIONS_KW, allow_unknown=True) + @typed_kwargs('shared_module', *LANGUAGE_KWS, *SHARED_LIB_LANGUAGE_KWS, OVERRIDE_OPTIONS_KW, allow_unknown=True) def func_shared_module(self, node: mparser.BaseNode, args: T.Tuple[str, T.List[BuildTargetSource]], kwargs) -> build.SharedModule: @@ -1850,7 +1852,7 @@ def func_shared_module(self, node: mparser.BaseNode, @permittedKwargs(known_library_kwargs) @typed_pos_args('library', str, varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList, build.StructuredSources, build.ExtractedObjects, build.BuildTarget)) - @typed_kwargs('library', *LANGUAGE_KWS, OVERRIDE_OPTIONS_KW, allow_unknown=True) + @typed_kwargs('library', *LANGUAGE_KWS, *STATIC_LIB_LANGUAGE_KWS, *SHARED_LIB_LANGUAGE_KWS, OVERRIDE_OPTIONS_KW, allow_unknown=True) def func_library(self, node: mparser.BaseNode, args: T.Tuple[str, T.List[BuildTargetSource]], kwargs) -> build.Executable: @@ -1867,7 +1869,7 @@ def func_jar(self, node: mparser.BaseNode, @FeatureNewKwargs('build_target', '0.40.0', ['link_whole', 'override_options']) @permittedKwargs(known_build_target_kwargs) @typed_pos_args('build_target', str, varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList, build.StructuredSources, build.ExtractedObjects, build.BuildTarget)) - @typed_kwargs('build_target', *LANGUAGE_KWS, OVERRIDE_OPTIONS_KW, allow_unknown=True) + @typed_kwargs('build_target', *LANGUAGE_KWS, *STATIC_LIB_LANGUAGE_KWS, *SHARED_LIB_LANGUAGE_KWS, OVERRIDE_OPTIONS_KW, allow_unknown=True) def func_build_target(self, node: mparser.BaseNode, args: T.Tuple[str, T.List[BuildTargetSource]], kwargs) -> T.Union[build.Executable, build.StaticLibrary, build.SharedLibrary, @@ -3263,6 +3265,12 @@ def build_target_decorator_caller(self, node, args, kwargs): raise RuntimeError('Unreachable code') self.kwarg_strings_to_includedirs(kwargs) self.__extract_language_args(kwargs) + if targetclass is build.StaticLibrary: + for lang in compilers.all_languages: + kwargs['language_args'][lang].extend(kwargs[f'{lang}_static_args']) + elif targetclass is build.SharedLibrary: + for lang in compilers.all_languages: + kwargs['language_args'][lang].extend(kwargs[f'{lang}_shared_args']) # Filter out kwargs from other target types. For example 'soversion' # passed to library() when default_library == 'static'. diff --git a/mesonbuild/interpreter/type_checking.py b/mesonbuild/interpreter/type_checking.py index 27d28e8aa27f..fc5ef243a05b 100644 --- a/mesonbuild/interpreter/type_checking.py +++ b/mesonbuild/interpreter/type_checking.py @@ -486,3 +486,6 @@ def link_whole_validator(values: T.List[T.Union[StaticLibrary, CustomTarget, Cus ] LANGUAGE_KWS.append(KwargInfo( 'rust_args', ContainerTypeInfo(list, str), listify=True, default=[], since='0.41.0')) + +STATIC_LIB_LANGUAGE_KWS = [l.evolve(name=f'{l.name.split("_", 1)[0]}_static_args', since='1.3.0') for l in LANGUAGE_KWS] +SHARED_LIB_LANGUAGE_KWS = [l.evolve(name=f'{l.name.split("_", 1)[0]}_shared_args', since='1.3.0') for l in LANGUAGE_KWS] diff --git a/test cases/common/3 static/lib3.c b/test cases/common/3 static/lib3.c new file mode 100644 index 000000000000..f834cf8b8422 --- /dev/null +++ b/test cases/common/3 static/lib3.c @@ -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 diff --git a/test cases/common/3 static/meson.build b/test cases/common/3 static/meson.build index 04ff2f6f301e..92ec9a304c6f 100644 --- a/test cases/common/3 static/meson.build +++ b/test cases/common/3 static/meson.build @@ -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. @@ -12,3 +12,7 @@ endif assert(has_not_changed, 'Static library has changed.') assert(not is_disabler(lib), 'Static library is a disabler.') + +library('lib2', 'lib3.c', c_static_args : ['-DWORK'], c_shared_args : ['-DBREAK']) +static_library('lib3', 'lib3.c', c_static_args : ['-DWORK']) +build_target('lib4', 'lib3.c', c_static_args : ['-DWORK'], target_type : 'static_library') diff --git a/test cases/common/4 shared/libfile2.c b/test cases/common/4 shared/libfile2.c new file mode 100644 index 000000000000..fee1d1efd872 --- /dev/null +++ b/test cases/common/4 shared/libfile2.c @@ -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; +} diff --git a/test cases/common/4 shared/meson.build b/test cases/common/4 shared/meson.build index 1c88bc5877d6..14549417c9dc 100644 --- a/test cases/common/4 shared/meson.build +++ b/test cases/common/4 shared/meson.build @@ -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') @@ -11,3 +11,7 @@ endif assert(has_not_changed, 'Shared library has changed.') assert(not is_disabler(lib), 'Shared library is a disabler.') + +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']) +library('mylib5', 'libfile2.c', c_shared_args : ['-DWORK']) diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py index 438e4fef5c1f..dde033c1155c 100644 --- a/unittests/allplatformstests.py +++ b/unittests/allplatformstests.py @@ -361,7 +361,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.assertTrue(len(targets) >= 1) libname = targets[0]['filename'][0] # Build and get contents of static library self.build()