aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Claessens <xavier.claessens@collabora.com>2018-01-03 11:46:13 -0500
committerXavier Claessens <xavier.claessens@collabora.com>2018-04-03 15:38:01 -0400
commit68f9846b7c584815d821c60fcdff866fe629955a (patch)
treed90a14a8d2e790bea3084e3226d0f5f326e5f482
parent809f01833336be63eb07441e120de2e4f8c4b3c4 (diff)
downloadmeson-68f9846b7c584815d821c60fcdff866fe629955a.zip
meson-68f9846b7c584815d821c60fcdff866fe629955a.tar.gz
meson-68f9846b7c584815d821c60fcdff866fe629955a.tar.bz2
Add both_libraries() to build both shared and static libraries
Also support default_library='both' to make library() build both shared and static libraries. Closes #484
-rw-r--r--docs/markdown/Reference-manual.md33
-rw-r--r--docs/markdown/snippets/both-libraries.md9
-rw-r--r--mesonbuild/coredata.py2
-rw-r--r--mesonbuild/interpreter.py65
-rw-r--r--test cases/common/189 bothlibraries/libfile.c7
-rw-r--r--test cases/common/189 bothlibraries/main.c8
-rw-r--r--test cases/common/189 bothlibraries/meson.build12
-rw-r--r--test cases/common/189 bothlibraries/mylib.h13
8 files changed, 140 insertions, 9 deletions
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md
index 5109b25..d98fc19 100644
--- a/docs/markdown/Reference-manual.md
+++ b/docs/markdown/Reference-manual.md
@@ -112,6 +112,24 @@ run. The behavior of this function is identical to `test` with the
exception that there is no `is_parallel` keyword, because benchmarks
are never run in parallel.
+### both_libraries()
+
+``` meson
+ buildtarget both_libraries(library_name, list_of_sources, ...)
+```
+
+Builds both a static and shared library with the given sources. Positional and
+keyword arguments are otherwise the same as for [`library`](#library). Source
+files will be compiled only once and object files will be reused to build both
+shared and static libraries, unless `b_staticpic` user option or `pic` argument
+are set to false in which case sources will be compiled twice.
+
+The returned [buildtarget](#build-target-object) always represents the shared
+library. In addition it supports the following extra methods:
+
+- `get_shared_lib()` returns the shared library build target
+- `get_static_lib()` returns the static library build target
+
### build_target()
Creates a build target whose type can be set dynamically with the
@@ -885,10 +903,11 @@ dropped. That means that `join_paths('foo', '/bar')` returns `/bar`.
buildtarget library(library_name, list_of_sources, ...)
```
-Builds a library that is either static or shared depending on the
-value of `default_library` user option. You should use this instead of
-[`shared_library`](#shared_library) or
-[`static_library`](#static_library) most of the time. This allows you
+Builds a library that is either static, shared or both depending on the value of
+`default_library` user option. You should use this instead of
+[`shared_library`](#shared_library),
+[`static_library`](#static_library) or
+[`both_libraries`](#both_libraries) most of the time. This allows you
to toggle your entire project (including subprojects) from shared to
static with only one option.
@@ -911,7 +930,8 @@ The keyword arguments for this are the same as for [`executable`](#executable) w
libraries. Defaults to `dylib` for shared libraries and `rlib` for
static libraries.
-`static_library` and `shared_library` also accept these keyword arguments.
+`static_library`, `shared_library` and `both_libraries` also accept these keyword
+arguments.
### message()
@@ -1670,7 +1690,8 @@ These are objects returned by the [functions listed above](#functions).
### `build target` object
A build target is either an [executable](#executable),
-[shared](#shared_library), [static library](#static_library) or
+[shared library](#shared_library), [static library](#static_library),
+[both shared and static library](#both_libraries) or
[shared module](#shared_module).
- `extract_all_objects()` is same as `extract_objects` but returns all
diff --git a/docs/markdown/snippets/both-libraries.md b/docs/markdown/snippets/both-libraries.md
new file mode 100644
index 0000000..1632f63
--- /dev/null
+++ b/docs/markdown/snippets/both-libraries.md
@@ -0,0 +1,9 @@
+## Building both shared and static libraries
+
+A new function `both_libraries()` has been added to build both shared and static
+libraries at the same time. Source files will be compiled only once and object
+files will be reused to build both shared and static libraries, unless
+`b_staticpic` user option or `pic` argument are set to false in which case
+sources will be compiled twice.
+
+The returned `buildtarget` object always represents the shared library.
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index 993effc..88d007a 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -422,7 +422,7 @@ builtin_options = {
'werror': [UserBooleanOption, 'Treat warnings as errors.', False],
'warning_level': [UserComboOption, 'Compiler warning level to use.', ['1', '2', '3'], '1'],
'layout': [UserComboOption, 'Build directory layout.', ['mirror', 'flat'], 'mirror'],
- 'default_library': [UserComboOption, 'Default library type.', ['shared', 'static'], 'shared'],
+ 'default_library': [UserComboOption, 'Default library type.', ['shared', 'static', 'both'], 'shared'],
'backend': [UserComboOption, 'Backend to use.', backendlist, 'ninja'],
'stdsplit': [UserBooleanOption, 'Split stdout and stderr in test logs.', True],
'errorlogs': [UserBooleanOption, "Whether to print the logs from failing tests.", True],
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index 6bd0b97..88565af 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -608,6 +608,29 @@ class SharedLibraryHolder(BuildTargetHolder):
# Set to True only when called from self.func_shared_lib().
target.shared_library_only = False
+class BothLibrariesHolder(BuildTargetHolder):
+ def __init__(self, shared_holder, static_holder, interp):
+ # FIXME: This build target always represents the shared library, but
+ # that should be configurable.
+ super().__init__(shared_holder.held_object, interp)
+ self.shared_holder = shared_holder
+ self.static_holder = static_holder
+ self.methods.update({'get_shared_lib': self.get_shared_lib_method,
+ 'get_static_lib': self.get_static_lib_method,
+ })
+
+ def __repr__(self):
+ r = '<{} {}: {}, {}: {}>'
+ h1 = self.shared_holder.held_object
+ h2 = self.static_holder.held_object
+ return r.format(self.__class__.__name__, h1.get_id(), h1.filename, h2.get_id(), h2.filename)
+
+ def get_shared_lib_method(self, args, kwargs):
+ return self.shared_holder
+
+ def get_static_lib_method(self, args, kwargs):
+ return self.static_holder
+
class SharedModuleHolder(BuildTargetHolder):
def __init__(self, target, interp):
super().__init__(target, interp)
@@ -1458,6 +1481,7 @@ permitted_kwargs = {'add_global_arguments': {'language'},
'shared_library': build.known_shlib_kwargs,
'shared_module': build.known_shmod_kwargs,
'static_library': build.known_stlib_kwargs,
+ 'both_libraries': known_library_kwargs,
'library': known_library_kwargs,
'subdir': {'if_found'},
'subproject': {'version', 'default_options'},
@@ -1559,6 +1583,7 @@ class Interpreter(InterpreterBase):
'shared_library': self.func_shared_lib,
'shared_module': self.func_shared_module,
'static_library': self.func_static_lib,
+ 'both_libraries': self.func_both_lib,
'test': self.func_test,
'vcs_tag': self.func_vcs_tag,
'subdir_done': self.func_subdir_done,
@@ -2492,6 +2517,10 @@ root and issuing %s.
holder.held_object.shared_library_only = True
return holder
+ @permittedKwargs(permitted_kwargs['both_libraries'])
+ def func_both_lib(self, node, args, kwargs):
+ return self.build_both_libraries(node, args, kwargs)
+
@permittedKwargs(permitted_kwargs['shared_module'])
def func_shared_module(self, node, args, kwargs):
return self.build_target(node, args, kwargs, SharedModuleHolder)
@@ -2515,6 +2544,8 @@ root and issuing %s.
return self.build_target(node, args, kwargs, SharedLibraryHolder)
elif target_type == 'static_library':
return self.build_target(node, args, kwargs, StaticLibraryHolder)
+ elif target_type == 'both_libraries':
+ return self.build_both_libraries(node, args, kwargs)
elif target_type == 'library':
return self.build_library(node, args, kwargs)
elif target_type == 'jar':
@@ -3171,10 +3202,40 @@ different subdirectory.
if idname not in self.coredata.target_guids:
self.coredata.target_guids[idname] = str(uuid.uuid4()).upper()
+ def build_both_libraries(self, node, args, kwargs):
+ shared_holder = self.build_target(node, args, kwargs, SharedLibraryHolder)
+
+ # Check if user forces non-PIC static library.
+ pic = True
+ if 'pic' in kwargs:
+ pic = kwargs['pic']
+ elif 'b_staticpic' in self.environment.coredata.base_options:
+ pic = self.environment.coredata.base_options['b_staticpic'].value
+
+ if pic:
+ # Exclude sources from args and kwargs to avoid building them twice
+ static_args = [args[0]]
+ static_kwargs = kwargs.copy()
+ static_kwargs['sources'] = []
+ static_kwargs['objects'] = shared_holder.held_object.extract_all_objects()
+ else:
+ static_args = args
+ static_kwargs = kwargs
+
+ static_holder = self.build_target(node, static_args, static_kwargs, StaticLibraryHolder)
+
+ return BothLibrariesHolder(shared_holder, static_holder, self)
+
def build_library(self, node, args, kwargs):
- if self.coredata.get_builtin_option('default_library') == 'shared':
+ default_library = self.coredata.get_builtin_option('default_library')
+ if default_library == 'shared':
return self.build_target(node, args, kwargs, SharedLibraryHolder)
- return self.build_target(node, args, kwargs, StaticLibraryHolder)
+ elif default_library == 'static':
+ return self.build_target(node, args, kwargs, StaticLibraryHolder)
+ elif default_library == 'both':
+ return self.build_both_libraries(node, args, kwargs)
+ else:
+ raise InterpreterException('Unknown default_library value: %s.', default_library)
def build_target(self, node, args, kwargs, targetholder):
if not args:
diff --git a/test cases/common/189 bothlibraries/libfile.c b/test cases/common/189 bothlibraries/libfile.c
new file mode 100644
index 0000000..085ef3b
--- /dev/null
+++ b/test cases/common/189 bothlibraries/libfile.c
@@ -0,0 +1,7 @@
+#include "mylib.h"
+
+DO_EXPORT int retval = 42;
+
+DO_EXPORT int func() {
+ return retval;
+}
diff --git a/test cases/common/189 bothlibraries/main.c b/test cases/common/189 bothlibraries/main.c
new file mode 100644
index 0000000..03a8e02
--- /dev/null
+++ b/test cases/common/189 bothlibraries/main.c
@@ -0,0 +1,8 @@
+#include "mylib.h"
+
+DO_IMPORT int func();
+DO_IMPORT int retval;
+
+int main(int argc, char **arg) {
+ return func() == retval ? 0 : 1;
+}
diff --git a/test cases/common/189 bothlibraries/meson.build b/test cases/common/189 bothlibraries/meson.build
new file mode 100644
index 0000000..3a13d62
--- /dev/null
+++ b/test cases/common/189 bothlibraries/meson.build
@@ -0,0 +1,12 @@
+project('both libraries linking test', 'c')
+
+both_libs = both_libraries('mylib', 'libfile.c')
+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'],
+ link_with : both_libs.get_static_lib())
+exe_both = executable('prog-both', 'main.c', link_with : both_libs)
+
+test('runtest-shared', exe_shared)
+test('runtest-static', exe_static)
+test('runtest-both', exe_both)
diff --git a/test cases/common/189 bothlibraries/mylib.h b/test cases/common/189 bothlibraries/mylib.h
new file mode 100644
index 0000000..1038a01
--- /dev/null
+++ b/test cases/common/189 bothlibraries/mylib.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#ifdef _WIN32
+ #ifdef STATIC_COMPILATION
+ #define DO_IMPORT extern
+ #else
+ #define DO_IMPORT __declspec(dllimport)
+ #endif
+ #define DO_EXPORT __declspec(dllexport)
+#else
+ #define DO_IMPORT extern
+ #define DO_EXPORT
+#endif