Add option to link the entire contents of a static library to a target.

pull/1549/head
Jussi Pakkanen 8 years ago
parent 79208fd9c4
commit d152c1b5d5
  1. 9
      mesonbuild/backend/ninjabackend.py
  2. 29
      mesonbuild/build.py
  3. 19
      mesonbuild/compilers.py
  4. 7
      test cases/common/145 whole archive/dylib.c
  5. 7
      test cases/common/145 whole archive/libfile.c
  6. 14
      test cases/common/145 whole archive/meson.build
  7. 21
      test cases/common/145 whole archive/mylib.h
  8. 5
      test cases/common/145 whole archive/prog.c

@ -2126,6 +2126,10 @@ rule FORTRAN_DEP_HACK
raise RuntimeError('Unknown build target type.')
return commands
def get_link_whole_args(self, linker, target):
target_args = self.build_target_link_arguments(linker, target.link_whole_targets)
return linker.get_link_whole_for(target_args)
def generate_link(self, target, outfile, outname, obj_list, linker, extra_args=[]):
if isinstance(target, build.StaticLibrary):
linker_base = 'STATIC'
@ -2165,6 +2169,11 @@ rule FORTRAN_DEP_HACK
# Add link args specific to this BuildTarget type, such as soname args,
# PIC, import library generation, etc.
commands += self.get_target_type_link_args(target, linker)
# Archives that are copied wholesale in the result. Must be before any
# other link targets so missing symbols from whole archives are found in those.
if not isinstance(target, build.StaticLibrary):
commands += self.get_link_whole_args(linker, target)
if not isinstance(target, build.StaticLibrary):
# Add link args added using add_project_link_arguments()
commands += self.build.get_project_link_args(linker, target.subproject)

@ -37,6 +37,7 @@ known_basic_kwargs = {'install': True,
'link_args': True,
'link_depends': True,
'link_with': True,
'link_whole': True,
'include_directories': True,
'dependencies': True,
'install_dir': True,
@ -314,6 +315,7 @@ class BuildTarget(Target):
self.external_deps = []
self.include_dirs = []
self.link_targets = []
self.link_whole_targets = []
self.link_depends = []
self.name_prefix_set = False
self.name_suffix_set = False
@ -560,6 +562,15 @@ class BuildTarget(Target):
if hasattr(linktarget, "held_object"):
linktarget = linktarget.held_object
self.link(linktarget)
lwhole = kwargs.get('link_whole', [])
if not isinstance(lwhole, list):
lwhole = [lwhole]
for linktarget in lwhole:
# Sorry for this hack. Keyword targets are kept in holders
# in kwargs. Unpack here without looking at the exact type.
if hasattr(linktarget, "held_object"):
linktarget = linktarget.held_object
self.link_whole(linktarget)
c_pchlist = kwargs.get('c_pch', [])
if not isinstance(c_pchlist, list):
c_pchlist = [c_pchlist]
@ -698,7 +709,7 @@ class BuildTarget(Target):
def get_dependencies(self):
transitive_deps = []
for t in self.link_targets:
for t in self.link_targets + self.link_whole_targets:
transitive_deps.append(t)
if isinstance(t, StaticLibrary):
transitive_deps += t.get_dependencies()
@ -790,6 +801,22 @@ You probably should put it in link_with instead.''')
raise InvalidArguments('Tried to mix cross built and native libraries in target {!r}'.format(self.name))
self.link_targets.append(t)
def link_whole(self, target):
if not isinstance(target, list):
target = [target]
for t in target:
if hasattr(t, 'held_object'):
t = t.held_object
if not isinstance(t, StaticLibrary):
raise InvalidArguments('{!r} is not a static library.'.format(t))
if isinstance(self, SharedLibrary) and not t.pic:
msg = "Can't link non-PIC static library {!r} into shared library {!r}. ".format(t.name, self.name)
msg += "Use the 'pic' option to static_library to build with PIC."
raise InvalidArguments(msg)
if self.is_cross != t.is_cross:
raise InvalidArguments('Tried to mix cross built and native libraries in target {!r}'.format(self.name))
self.link_whole_targets.append(t)
def add_pch(self, language, pchlist):
if len(pchlist) == 0:
return

@ -707,6 +707,11 @@ class Compiler:
def get_std_shared_module_link_args(self):
return self.get_std_shared_lib_link_args()
def get_link_whole_for(self, args):
if isinstance(args, list) and len(args) == 0:
return []
raise EnvironmentException('Language %s does not support linking whole archives.' % self.language)
class CCompiler(Compiler):
def __init__(self, exelist, version, is_cross, exe_wrapper=None):
# If a child ObjC or CPP class has already set it, don't set it ourselves
@ -2274,6 +2279,11 @@ class VisualStudioCCompiler(CCompiler):
pdbarr += ['pdb']
return ['/DEBUG', '/PDB:' + '.'.join(pdbarr)]
def get_link_whole_for(self, args):
# Only since VS2015
return ['/WHOLEARCHIVE:' + x for x in args]
class VisualStudioCPPCompiler(VisualStudioCCompiler, CPPCompiler):
def __init__(self, exelist, version, is_cross, exe_wrap):
self.language = 'cpp'
@ -2425,6 +2435,10 @@ class GnuCompiler:
return ['-bundle']
return ['-shared']
def get_link_whole_for(self, args):
return ['-Wl,--whole-archive'] + args + ['-Wl,--no-whole-archive']
class GnuCCompiler(GnuCompiler, CCompiler):
def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None, defines=None):
CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper)
@ -2460,6 +2474,7 @@ class GnuCCompiler(GnuCompiler, CCompiler):
def get_std_shared_lib_link_args(self):
return ['-shared']
class GnuCPPCompiler(GnuCompiler, CPPCompiler):
def __init__(self, exelist, version, gcc_type, is_cross, exe_wrap, defines):
@ -2589,6 +2604,10 @@ class ClangCompiler:
return ['-bundle', '-Wl,-undefined,dynamic_lookup']
return ['-shared']
def get_link_whole_for(self, args):
return ['-Wl,--whole-archive'] + args + ['-Wl,--no-whole-archive']
class ClangCCompiler(ClangCompiler, CCompiler):
def __init__(self, exelist, version, clang_type, is_cross, exe_wrapper=None):
CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper)

@ -0,0 +1,7 @@
#define BUILDING_DLL
#include<mylib.h>
int func2() {
return 42;
}

@ -0,0 +1,7 @@
#define BUILDING_DLL
#include<mylib.h>
int func1() {
return 42;
}

@ -0,0 +1,14 @@
project('whole archive', 'c')
stlib = static_library('allofme', 'libfile.c')
# Nothing in dylib.c uses func1, so the linker would throw it
# away and thus linking the exe would fail.
dylib = shared_library('shlib', 'dylib.c',
link_whole : stlib)
exe = executable('prog', 'prog.c',
link_with : dylib)
test('prog', exe)

@ -0,0 +1,21 @@
#pragma once
/* Both funcs here for simplicity. */
#if defined _WIN32 || defined __CYGWIN__
#if defined BUILDING_DLL
#define DLL_PUBLIC __declspec(dllexport)
#else
#define DLL_PUBLIC __declspec(dllimport)
#endif
#else
#if defined __GNUC__
#define DLL_PUBLIC __attribute__ ((visibility("default")))
#else
#pragma message ("Compiler does not support symbol visibility.")
#define DLL_PUBLIC
#endif
#endif
int DLL_PUBLIC func1();
int DLL_PUBLIC func2();

@ -0,0 +1,5 @@
#include<mylib.h>
int main(int argc, char **argv) {
return func1() - func2();
}
Loading…
Cancel
Save