aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild
diff options
context:
space:
mode:
authorJon Turney <jon.turney@dronecode.org.uk>2017-04-14 13:58:21 +0100
committerJon Turney <jon.turney@dronecode.org.uk>2017-07-20 21:11:56 +0100
commit3fa3922cea27026d44aef1cdf3ca92d82adc7ced (patch)
tree512b4bed85b53dfd95add859b0724a1ed84d9754 /mesonbuild
parentb43f4841ba5de2e8bc956eb9fd1f578f90d7ae15 (diff)
downloadmeson-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.py16
-rw-r--r--mesonbuild/backend/ninjabackend.py6
-rw-r--r--mesonbuild/backend/vs2010backend.py4
-rw-r--r--mesonbuild/build.py56
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):