diff options
author | Jon Turney <jon.turney@dronecode.org.uk> | 2017-04-14 13:58:21 +0100 |
---|---|---|
committer | Jon Turney <jon.turney@dronecode.org.uk> | 2017-07-20 21:11:56 +0100 |
commit | 3fa3922cea27026d44aef1cdf3ca92d82adc7ced (patch) | |
tree | 512b4bed85b53dfd95add859b0724a1ed84d9754 /mesonbuild | |
parent | b43f4841ba5de2e8bc956eb9fd1f578f90d7ae15 (diff) | |
download | meson-3fa3922cea27026d44aef1cdf3ca92d82adc7ced.zip meson-3fa3922cea27026d44aef1cdf3ca92d82adc7ced.tar.gz meson-3fa3922cea27026d44aef1cdf3ca92d82adc7ced.tar.bz2 |
Support implibs for executables on Windows
Add a boolean 'implib' kwarg to executable(). If true, it is permitted to
use the returned build target object in link_with:
On platforms where this makes sense (e.g. Windows), an implib is generated
for the executable and used when linking. Otherwise, it has no effect.
(Rather than checking if it is a StaticLibrary or SharedLibary, BuildTarget
subclasses gain the is_linkable_target method to test if they can appear in
link_with:)
Also install any executable implib in a similar way to a shared library
implib, i.e. placing the implib in the appropriate place
Add tests of:
- a shared_module containing a reference to a symbol which is known (at link
time) to be provided by the executable
- trying to link with non-implib executables (should fail)
- installing the implib
(This last one needs a little enhancement of the installed file checking as
this is the first install test we have which needs to work with either
MSVC-style or GCC-style implib filenames)
Diffstat (limited to 'mesonbuild')
-rw-r--r-- | mesonbuild/backend/backends.py | 16 | ||||
-rw-r--r-- | mesonbuild/backend/ninjabackend.py | 6 | ||||
-rw-r--r-- | mesonbuild/backend/vs2010backend.py | 4 | ||||
-rw-r--r-- | mesonbuild/build.py | 56 |
4 files changed, 73 insertions, 9 deletions
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index cadb655..f967de0 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -140,7 +140,12 @@ class Backend: return os.path.join(self.get_target_dir(target), link_lib) elif isinstance(target, build.StaticLibrary): return os.path.join(self.get_target_dir(target), target.get_filename()) - raise AssertionError('BUG: Tried to link to something that\'s not a library') + elif isinstance(target, build.Executable): + if target.import_filename: + return os.path.join(self.get_target_dir(target), target.get_import_filename()) + else: + return None + raise AssertionError('BUG: Tried to link to {!r} which is not linkable'.format(target)) def get_target_dir(self, target): if self.environment.coredata.get_builtin_option('layout') == 'mirror': @@ -463,12 +468,13 @@ class Backend: def build_target_link_arguments(self, compiler, deps): args = [] for d in deps: - if not isinstance(d, (build.StaticLibrary, build.SharedLibrary)): + if not (d.is_linkable_target()): raise RuntimeError('Tried to link with a non-library target "%s".' % d.get_basename()) + d_arg = self.get_target_filename_for_linking(d) + if not d_arg: + continue if isinstance(compiler, (compilers.LLVMDCompiler, compilers.DmdDCompiler)): - d_arg = '-L' + self.get_target_filename_for_linking(d) - else: - d_arg = self.get_target_filename_for_linking(d) + d_arg = '-L' + d_arg args.append(d_arg) return args diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 7f974ee..f10d516 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -693,7 +693,8 @@ int dummy; # On toolchains/platforms that use an import library for # linking (separate from the shared library with all the # code), we need to install that too (dll.a/.lib). - if isinstance(t, build.SharedLibrary) and t.get_import_filename(): + if (isinstance(t, build.SharedLibrary) or + isinstance(t, build.Executable)) and t.get_import_filename(): if custom_install_dir: # If the DLL is installed into a custom directory, # install the import library into the same place so @@ -2256,6 +2257,9 @@ rule FORTRAN_DEP_HACK # If gui_app, and that's significant on this platform if target.gui_app and hasattr(linker, 'get_gui_app_args'): commands += linker.get_gui_app_args() + # If implib, and that's significant on this platform (i.e. Windows using either GCC or Visual Studio) + if target.import_filename: + commands += linker.gen_import_library_args(os.path.join(target.subdir, target.import_filename)) elif isinstance(target, build.SharedLibrary): if isinstance(target, build.SharedModule): commands += linker.get_std_shared_module_link_args() diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py index 57b0437..4a92155 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -951,10 +951,12 @@ class Vs2010Backend(backends.Backend): ofile.text = '$(OutDir)%s' % target.get_filename() subsys = ET.SubElement(link, 'SubSystem') subsys.text = subsystem - if isinstance(target, build.SharedLibrary): + if (isinstance(target, build.SharedLibrary) or + isinstance(target, build.Executable)) and target.get_import_filename(): # DLLs built with MSVC always have an import library except when # they're data-only DLLs, but we don't support those yet. ET.SubElement(link, 'ImportLibrary').text = target.get_import_filename() + if isinstance(target, build.SharedLibrary): # Add module definitions file, if provided if target.vs_module_defs: relpath = os.path.join(down, target.vs_module_defs.rel_to_builddir(self.build_to_src)) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index fb56cea..df24c7f 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -74,6 +74,9 @@ known_lib_kwargs.update({'version': True, # Only for shared libs 'rust_crate_type': True, # Only for Rust libs }) +known_exe_kwargs = known_basic_kwargs.copy() +known_exe_kwargs.update({'implib': True, + }) class InvalidArguments(MesonException): pass @@ -841,8 +844,8 @@ You probably should put it in link_with instead.''') for t in flatten(target): if hasattr(t, 'held_object'): t = t.held_object - if not isinstance(t, (StaticLibrary, SharedLibrary)): - raise InvalidArguments('Link target {!r} is not library.'.format(t)) + if not t.is_linkable_target(): + raise InvalidArguments('Link target {!r} is not linkable.'.format(t)) if isinstance(self, SharedLibrary) and isinstance(t, StaticLibrary) 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." @@ -986,6 +989,9 @@ You probably should put it in link_with instead.''') return True return False + def is_linkable_target(self): + return False + class Generator: def __init__(self, args, kwargs): @@ -1122,9 +1128,49 @@ class Executable(BuildTarget): self.filename += '.' + self.suffix self.outputs = [self.filename] + # The import library this target will generate + self.import_filename = None + # The import library that Visual Studio would generate (and accept) + self.vs_import_filename = None + # The import library that GCC would generate (and prefer) + self.gcc_import_filename = None + + # if implib:true appears, this target is linkwith:-able, but that only + # means something on Windows platforms. + self.is_linkwithable = False + if 'implib' in kwargs and kwargs['implib']: + self.is_linkwithable = True + if for_windows(is_cross, environment) or for_cygwin(is_cross, environment): + self.vs_import_filename = '{0}.lib'.format(self.name) + self.gcc_import_filename = 'lib{0}.exe.a'.format(self.name) + + if self.get_using_msvc(): + self.import_filename = self.vs_import_filename + else: + self.import_filename = self.gcc_import_filename + def type_suffix(self): return "@exe" + def check_unknown_kwargs(self, kwargs): + self.check_unknown_kwargs_int(kwargs, known_exe_kwargs) + + def get_import_filename(self): + """ + The name of the import library that will be outputted by the compiler + + Returns None if there is no import library required for this platform + """ + return self.import_filename + + def get_import_filenameslist(self): + if self.import_filename: + return [self.vs_import_filename, self.gcc_import_filename] + return [] + + def is_linkable_target(self): + return self.is_linkwithable + class StaticLibrary(BuildTarget): def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs): if 'pic' not in kwargs and 'b_staticpic' in environment.coredata.base_options: @@ -1176,6 +1222,9 @@ class StaticLibrary(BuildTarget): else: raise InvalidArguments('Invalid rust_crate_type "{0}": must be a string.'.format(rust_crate_type)) + def is_linkable_target(self): + return True + class SharedLibrary(BuildTarget): def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs): self.soversion = None @@ -1405,6 +1454,9 @@ class SharedLibrary(BuildTarget): def type_suffix(self): return "@sha" + def is_linkable_target(self): + return True + # A shared library that is meant to be used with dlopen rather than linking # into something else. class SharedModule(SharedLibrary): |