diff options
author | Jussi Pakkanen <jpakkane@gmail.com> | 2020-11-14 16:43:00 +0200 |
---|---|---|
committer | Jussi Pakkanen <jpakkane@gmail.com> | 2020-11-14 21:57:12 +0200 |
commit | 1bb5c8a4fb625d5ff296d0f31fc3b3cc92580d62 (patch) | |
tree | c5b1521d43a8ab02725e5626d2e51ba330fb7b55 | |
parent | 59cacbbfc17dffe4aede1dfaa93bd5e1a3e994b2 (diff) | |
download | meson-prelink.zip meson-prelink.tar.gz meson-prelink.tar.bz2 |
Add prelinking support for static libraries.prelink
-rw-r--r-- | docs/markdown/Reference-manual.md | 4 | ||||
-rw-r--r-- | docs/markdown/snippets/prelink.md | 5 | ||||
-rw-r--r-- | mesonbuild/backend/ninjabackend.py | 21 | ||||
-rw-r--r-- | mesonbuild/build.py | 22 | ||||
-rw-r--r-- | mesonbuild/compilers/compilers.py | 2 | ||||
-rw-r--r-- | mesonbuild/compilers/mixins/gnu.py | 3 | ||||
-rwxr-xr-x | run_unittests.py | 16 | ||||
-rw-r--r-- | test cases/unit/87 prelinking/file1.c | 14 | ||||
-rw-r--r-- | test cases/unit/87 prelinking/file2.c | 9 | ||||
-rw-r--r-- | test cases/unit/87 prelinking/file3.c | 9 | ||||
-rw-r--r-- | test cases/unit/87 prelinking/file4.c | 9 | ||||
-rw-r--r-- | test cases/unit/87 prelinking/main.c | 10 | ||||
-rw-r--r-- | test cases/unit/87 prelinking/meson.build | 8 | ||||
-rw-r--r-- | test cases/unit/87 prelinking/private_header.h | 11 | ||||
-rw-r--r-- | test cases/unit/87 prelinking/public_header.h | 3 |
15 files changed, 144 insertions, 2 deletions
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index aeaeccb..f490f5f 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -1574,6 +1574,10 @@ has one argument the others don't have: option has no effect on Windows and OS X since it doesn't make sense on Windows and PIC cannot be disabled on OS X. +- `prelink` *since0.57.0*: 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. + ### subdir() ``` meson diff --git a/docs/markdown/snippets/prelink.md b/docs/markdown/snippets/prelink.md new file mode 100644 index 0000000..017c33c --- /dev/null +++ b/docs/markdown/snippets/prelink.md @@ -0,0 +1,5 @@ +## Add support for prelinked static libraries + +The static library gains a new `prelink` keyword argument that can be +used to prelink object files in that target. This is mostly useful in +embedded projects.
\ No newline at end of file diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index c3c5705..f34849d 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -840,7 +840,11 @@ int dummy; for src in self.generate_unity_files(target, unity_src): obj_list.append(self.generate_single_compile(target, src, True, unity_deps + header_deps)) linker, stdlib_args = self.determine_linker_and_stdlib_args(target) - elem = self.generate_link(target, outname, obj_list, linker, pch_objects, stdlib_args=stdlib_args) + if isinstance(target, build.StaticLibrary) and target.prelink: + final_obj_list = self.generate_prelink(target, obj_list) + else: + final_obj_list = obj_list + elem = self.generate_link(target, outname, final_obj_list, linker, pch_objects, stdlib_args=stdlib_args) self.generate_shlib_aliases(target, self.get_target_dir(target)) self.add_build(elem) @@ -2683,6 +2687,21 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) return guessed_dependencies + absolute_libs + def generate_prelink(self, target, obj_list): + assert(isinstance(target, build.StaticLibrary)) + prelink_name = os.path.join(self.get_target_private_dir(target), target.name + '-prelink.o') + elem = NinjaBuildElement(self.all_outputs, [prelink_name], 'CUSTOM_COMMAND', obj_list) + + prelinker = target.get_prelinker() + cmd = prelinker.exelist[:] + cmd += prelinker.get_prelink_args(prelink_name, obj_list) + + cmd = self.replace_paths(target, cmd) + elem.add_item('COMMAND', cmd) + elem.add_item('description', 'Prelinking {}.'.format(prelink_name)) + self.add_build(elem) + return [prelink_name] + def generate_link(self, target, outname, obj_list, linker, extra_args=None, stdlib_args=None): extra_args = extra_args if extra_args is not None else [] stdlib_args = stdlib_args if stdlib_args is not None else [] diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 36d4e19..5b7a679 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -102,7 +102,7 @@ known_build_target_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_shmod_kwargs = known_build_target_kwargs | {'vs_module_defs'} -known_stlib_kwargs = known_build_target_kwargs | {'pic'} +known_stlib_kwargs = known_build_target_kwargs | {'pic', 'prelink'} known_jar_kwargs = known_exe_kwargs | {'main_class'} @lru_cache(maxsize=None) @@ -1280,6 +1280,23 @@ You probably should put it in link_with instead.''') return langs + def get_prelinker(self): + all_compilers = self.environment.coredata.compilers[self.for_machine] + if self.link_language: + comp = all_compilers[self.link_language] + return comp + for l in clink_langs: + if l in self.compilers: + try: + prelinker = all_compilers[l] + except KeyError: + raise MesonException( + 'Could not get a prelinker linker for build target {!r}. ' + 'Requires a compiler for language "{}", but that is not ' + 'a project language.'.format(self.name, l)) + return prelinker + raise MesonException('Could not determine prelinker for {!r}.'.format(self.name)) + def get_clink_dynamic_linker_and_stdlibs(self): ''' We use the order of languages in `clink_langs` to determine which @@ -1674,6 +1691,9 @@ class StaticLibrary(BuildTarget): self.suffix = 'a' self.filename = self.prefix + self.name + '.' + self.suffix self.outputs = [self.filename] + self.prelink = kwargs.get('prelink', False) + if not isinstance(self.prelink, bool): + raise InvalidArguments('Prelink keyword argument must be a boolean.') def get_link_deps_mapping(self, prefix, environment): return {} diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 81d48d2..7d1d427 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -1205,6 +1205,8 @@ class Compiler(metaclass=abc.ABCMeta): # TODO: using a TypeDict here would improve this raise EnvironmentError('{} does not implement get_feature_args'.format(self.id)) + def get_prelink_args(self, prelink_name, obj_list): + raise EnvironmentException('{} does not know how to do prelinking.'.format(self.id)) def get_args_from_envvars(lang: str, for_machine: MachineChoice, diff --git a/mesonbuild/compilers/mixins/gnu.py b/mesonbuild/compilers/mixins/gnu.py index 5771ad8..d3fa77d 100644 --- a/mesonbuild/compilers/mixins/gnu.py +++ b/mesonbuild/compilers/mixins/gnu.py @@ -396,3 +396,6 @@ class GnuCompiler(GnuLikeCompiler): # GCC only warns about unknown or ignored attributes, so force an # error. return ['-Werror=attributes'] + + def get_prelink_args(self, prelink_name, obj_list): + return ['-r', '-o', prelink_name] + obj_list diff --git a/run_unittests.py b/run_unittests.py index 7f7df36..be7a2e4 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -7456,6 +7456,22 @@ class LinuxlikeTests(BasePlatformTests): content = f.read() self.assertNotIn('-lfoo', content) + def test_prelinking(self): + testdir = os.path.join(self.unit_test_dir, '87 prelinking') + self.init(testdir) + self.build() + outlib = os.path.join(self.builddir, 'libprelinked.a') + ar = shutil.which('ar') + self.assertTrue(os.path.exists(outlib)) + self.assertTrue(ar is not None) + p = subprocess.run([ar, 't', outlib], + stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL, + universal_newlines=True, timeout=1) + obj_files = p.stdout.strip().split('\n') + self.assertEqual(len(obj_files), 1) + self.assertTrue(obj_files[0].endswith('-prelink.o')) + class BaseLinuxCrossTests(BasePlatformTests): # Don't pass --libdir when cross-compiling. We have tests that # check whether meson auto-detects it correctly. diff --git a/test cases/unit/87 prelinking/file1.c b/test cases/unit/87 prelinking/file1.c new file mode 100644 index 0000000..9f0e265 --- /dev/null +++ b/test cases/unit/87 prelinking/file1.c @@ -0,0 +1,14 @@ +#include<public_header.h> +#include<private_header.h> + +int public_func() { + return round1_a(); +} + +int round1_a() { + return round1_b(); +} + +int round2_a() { + return round2_b(); +} diff --git a/test cases/unit/87 prelinking/file2.c b/test cases/unit/87 prelinking/file2.c new file mode 100644 index 0000000..ce3b115 --- /dev/null +++ b/test cases/unit/87 prelinking/file2.c @@ -0,0 +1,9 @@ +#include<private_header.h> + +int round1_b() { + return round1_c(); +} + +int round2_b() { + return round2_c(); +} diff --git a/test cases/unit/87 prelinking/file3.c b/test cases/unit/87 prelinking/file3.c new file mode 100644 index 0000000..85052be --- /dev/null +++ b/test cases/unit/87 prelinking/file3.c @@ -0,0 +1,9 @@ +#include<private_header.h> + +int round1_c() { + return round1_d(); +} + +int round2_c() { + return round2_d(); +} diff --git a/test cases/unit/87 prelinking/file4.c b/test cases/unit/87 prelinking/file4.c new file mode 100644 index 0000000..622364e --- /dev/null +++ b/test cases/unit/87 prelinking/file4.c @@ -0,0 +1,9 @@ +#include<private_header.h> + +int round1_d() { + return round2_a(); +} + +int round2_d() { + return 42; +} diff --git a/test cases/unit/87 prelinking/main.c b/test cases/unit/87 prelinking/main.c new file mode 100644 index 0000000..09a2e5c --- /dev/null +++ b/test cases/unit/87 prelinking/main.c @@ -0,0 +1,10 @@ +#include<public_header.h> +#include<stdio.h> + +int main(int argc, char **argv) { + if(public_func() != 42) { + printf("Something failed.\n"); + return 1; + } + return 0; +} diff --git a/test cases/unit/87 prelinking/meson.build b/test cases/unit/87 prelinking/meson.build new file mode 100644 index 0000000..3dbf88e --- /dev/null +++ b/test cases/unit/87 prelinking/meson.build @@ -0,0 +1,8 @@ +project('prelinking', 'c') + +liba = static_library('prelinked', 'file1.c', 'file2.c', 'file3.c', 'file4.c', + prelink: true) +exe = executable('testprog', 'main.c', + link_with: liba) +test('prelinked', exe) +
\ No newline at end of file diff --git a/test cases/unit/87 prelinking/private_header.h b/test cases/unit/87 prelinking/private_header.h new file mode 100644 index 0000000..f24b621 --- /dev/null +++ b/test cases/unit/87 prelinking/private_header.h @@ -0,0 +1,11 @@ +#pragma once + +int round1_a(); +int round1_b(); +int round1_c(); +int round1_d(); + +int round2_a(); +int round2_b(); +int round2_c(); +int round2_d(); diff --git a/test cases/unit/87 prelinking/public_header.h b/test cases/unit/87 prelinking/public_header.h new file mode 100644 index 0000000..0cd6786 --- /dev/null +++ b/test cases/unit/87 prelinking/public_header.h @@ -0,0 +1,3 @@ +#pragma once + +int public_func(); |