Add prelinking support for static libraries.
This commit is contained in:
parent
6e39dcad2f
commit
c21b04ba08
|
@ -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
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
## 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 currently only
|
||||
supported for the GNU toolchain, patches to add it to other compilers
|
||||
are most welcome.
|
|
@ -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 []
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -1200,6 +1200,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: str, obj_list: T.List[str]) -> T.List[str]:
|
||||
raise EnvironmentException('{} does not know how to do prelinking.'.format(self.id))
|
||||
|
||||
def get_args_from_envvars(lang: str,
|
||||
for_machine: MachineChoice,
|
||||
|
|
|
@ -394,3 +394,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: str, obj_list: T.List[str]) -> T.List[str]:
|
||||
return ['-r', '-o', prelink_name] + obj_list
|
||||
|
|
|
@ -7389,6 +7389,32 @@ class LinuxlikeTests(BasePlatformTests):
|
|||
content = f.read()
|
||||
self.assertNotIn('-lfoo', content)
|
||||
|
||||
def test_prelinking(self):
|
||||
# Prelinking currently only works on recently new GNU toolchains.
|
||||
# Skip everything else. When support for other toolchains is added,
|
||||
# remove limitations as necessary.
|
||||
if is_osx():
|
||||
raise unittest.SkipTest('Prelinking not supported on Darwin.')
|
||||
if 'clang' in os.environ.get('CC', 'dummy'):
|
||||
raise unittest.SkipTest('Prelinking not supported with Clang.')
|
||||
gccver = subprocess.check_output(['cc', '--version'])
|
||||
if b'7.5.0' in gccver:
|
||||
raise unittest.SkipTest('GCC on Bionic is too old to be supported.')
|
||||
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.
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#include<private_header.h>
|
||||
|
||||
int round1_b() {
|
||||
return round1_c();
|
||||
}
|
||||
|
||||
int round2_b() {
|
||||
return round2_c();
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#include<private_header.h>
|
||||
|
||||
int round1_c() {
|
||||
return round1_d();
|
||||
}
|
||||
|
||||
int round2_c() {
|
||||
return round2_d();
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#include<private_header.h>
|
||||
|
||||
int round1_d() {
|
||||
return round2_a();
|
||||
}
|
||||
|
||||
int round2_d() {
|
||||
return 42;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
||||
|
|
@ -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();
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
int public_func();
|
Loading…
Reference in New Issue