From 3fa3922cea27026d44aef1cdf3ca92d82adc7ced Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Fri, 14 Apr 2017 13:58:21 +0100 Subject: [PATCH 1/5] 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) --- docs/markdown/Reference-manual.md | 1 + mesonbuild/backend/backends.py | 16 +++-- mesonbuild/backend/ninjabackend.py | 6 +- mesonbuild/backend/vs2010backend.py | 4 +- mesonbuild/build.py | 56 ++++++++++++++++- run_project_tests.py | 16 ++++- .../meson.build | 24 ++++++++ .../module.c | 16 +++++ .../prog.c | 60 +++++++++++++++++++ .../57 link with executable/meson.build | 4 ++ .../failing/57 link with executable/module.c | 4 ++ .../failing/57 link with executable/prog.c | 5 ++ .../windows/12 exe implib/installed_files.txt | 4 ++ test cases/windows/12 exe implib/meson.build | 7 +++ test cases/windows/12 exe implib/prog.c | 6 ++ 15 files changed, 218 insertions(+), 11 deletions(-) create mode 100644 test cases/common/154 shared module resolving symbol in executable/meson.build create mode 100644 test cases/common/154 shared module resolving symbol in executable/module.c create mode 100644 test cases/common/154 shared module resolving symbol in executable/prog.c create mode 100644 test cases/failing/57 link with executable/meson.build create mode 100644 test cases/failing/57 link with executable/module.c create mode 100644 test cases/failing/57 link with executable/prog.c create mode 100644 test cases/windows/12 exe implib/installed_files.txt create mode 100644 test cases/windows/12 exe implib/meson.build create mode 100644 test cases/windows/12 exe implib/prog.c diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index e45adf67d..261d89894 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -248,6 +248,7 @@ Executable supports the following keyword arguments. Note that just like the pos - `name_suffix` the string that will be used as the extension for the target by overriding the default. By default on Windows this is `exe` and on other platforms it is omitted. - `build_by_default` causes, when set to true, to have this target be built by default, that is, when invoking plain `ninja`, the default value is true for all built target types, since 0.38.0 - `override_options` takes an array of strings in the same format as `project`'s `default_options` overriding the values of these options for this target only, since 0.40.0 +- `implib` when set to true, an import library is generated for the executable, used when the returned build target object appears elsewhere in `link_with:`, on platforms where this is meaningful (e.g. Windows), since 0.42.0 The list of `sources`, `objects`, and `dependencies` is always flattened, which means you can freely nest and add lists while creating the final list. As a corollary, the best way to handle a 'disabled dependency' is by assigning an empty list `[]` to it and passing it like any other dependency to the `dependencies:` keyword argument. diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index cadb655e8..f967de0c6 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 7f974ee98..f10d5164b 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 57b0437ee..4a92155b6 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 fb56ceaa9..df24c7fbe 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): diff --git a/run_project_tests.py b/run_project_tests.py index 3420946c3..69a778e9c 100755 --- a/run_project_tests.py +++ b/run_project_tests.py @@ -183,7 +183,7 @@ def get_relative_files_list_from_dir(fromdir): paths.append(path) return paths -def platform_fix_name(fname): +def platform_fix_name(fname, compiler): if '?lib' in fname: if mesonlib.is_cygwin(): fname = re.sub(r'\?lib(.*)\.dll$', r'cyg\1.dll', fname) @@ -195,6 +195,16 @@ def platform_fix_name(fname): if mesonlib.is_windows() or mesonlib.is_cygwin(): return fname + '.exe' + if fname.startswith('?msvc:'): + fname = fname[6:] + if compiler != 'cl': + return None + + if fname.startswith('?gcc:'): + fname = fname[5:] + if compiler == 'cl': + return None + return fname def validate_install(srcdir, installdir, compiler): @@ -210,7 +220,9 @@ def validate_install(srcdir, installdir, compiler): elif os.path.exists(info_file): with open(info_file) as f: for line in f: - expected[platform_fix_name(line.strip())] = False + line = platform_fix_name(line.strip(), compiler) + if line: + expected[line] = False # Check if expected files were found for fname in expected: file_path = os.path.join(installdir, fname) diff --git a/test cases/common/154 shared module resolving symbol in executable/meson.build b/test cases/common/154 shared module resolving symbol in executable/meson.build new file mode 100644 index 000000000..06c990282 --- /dev/null +++ b/test cases/common/154 shared module resolving symbol in executable/meson.build @@ -0,0 +1,24 @@ +project('shared module resolving symbol in executable', 'c') + +# The shared module contains a reference to the symbol 'func_from_executable', +# which is always provided by the executable which loads it. This symbol can be +# resolved at run-time by an ELF loader. But when building PE/COFF objects, all +# symbols must be resolved at link-time, so an implib is generated for the +# executable, and the shared module linked with it. +# +# See testcase 125 for an example of the more complex portability gymnastics +# required if we do not know (at link-time) what provides the symbol. + +link_flags = [] +if host_machine.system() != 'windows' + # Needed to export dynamic symbols from the executable + link_flags += ['-rdynamic'] + # Need to add this manually because Meson won't add it automatically because + # it doesn't know that we are loading a module from the build directory. + link_flags += ['-Wl,-rpath,' + meson.current_build_dir()] +endif + +dl = meson.get_compiler('c').find_library('dl', required: false) +e = executable('prog', 'prog.c', dependencies: dl, implib: true, link_args: link_flags) +m = shared_module('module', 'module.c', link_with: e) +test('test', e, args: m) diff --git a/test cases/common/154 shared module resolving symbol in executable/module.c b/test cases/common/154 shared module resolving symbol in executable/module.c new file mode 100644 index 000000000..64374d590 --- /dev/null +++ b/test cases/common/154 shared module resolving symbol in executable/module.c @@ -0,0 +1,16 @@ +#if defined _WIN32 || defined __CYGWIN__ + #define DLL_PUBLIC __declspec(dllexport) +#else + #if defined __GNUC__ + #define DLL_PUBLIC __attribute__ ((visibility("default"))) + #else + #pragma message ("Compiler does not support symbol visibility.") + #define DLL_PUBLIC + #endif +#endif + +extern int func_from_executable(void); + +int DLL_PUBLIC func(void) { + return func_from_executable(); +} diff --git a/test cases/common/154 shared module resolving symbol in executable/prog.c b/test cases/common/154 shared module resolving symbol in executable/prog.c new file mode 100644 index 000000000..746c19280 --- /dev/null +++ b/test cases/common/154 shared module resolving symbol in executable/prog.c @@ -0,0 +1,60 @@ +#include +#include +#ifdef _WIN32 +#include +#else +#include +#endif + +#if defined _WIN32 || defined __CYGWIN__ + #define DLL_PUBLIC __declspec(dllexport) +#else + #if defined __GNUC__ + #define DLL_PUBLIC __attribute__ ((visibility("default"))) + #else + #pragma message ("Compiler does not support symbol visibility.") + #define DLL_PUBLIC + #endif +#endif + +typedef int (*fptr) (void); + +int DLL_PUBLIC +func_from_executable(void) +{ + return 42; +} + +int +main (int argc, char **argv) +{ + int expected, actual; + fptr importedfunc; + +#ifdef _WIN32 + HMODULE h = LoadLibraryA(argv[1]); +#else + void *h = dlopen(argv[1], RTLD_NOW); +#endif + assert(h != NULL); + +#ifdef _WIN32 + importedfunc = (fptr) GetProcAddress (h, "func"); +#else + importedfunc = (fptr) dlsym(h, "func"); +#endif + assert(importedfunc != NULL); + assert(importedfunc != func_from_executable); + + actual = (*importedfunc)(); + expected = func_from_executable(); + assert(actual == expected); + +#ifdef _WIN32 + FreeLibrary(h); +#else + dlclose(h); +#endif + + return 0; +} diff --git a/test cases/failing/57 link with executable/meson.build b/test cases/failing/57 link with executable/meson.build new file mode 100644 index 000000000..186b3e595 --- /dev/null +++ b/test cases/failing/57 link with executable/meson.build @@ -0,0 +1,4 @@ +project('link with exe', 'c') + +e = executable('prog', 'prog.c') +m = shared_module('module', 'module.c', link_with: e) diff --git a/test cases/failing/57 link with executable/module.c b/test cases/failing/57 link with executable/module.c new file mode 100644 index 000000000..dc0124a24 --- /dev/null +++ b/test cases/failing/57 link with executable/module.c @@ -0,0 +1,4 @@ + +int func(void) { + return 42; +} diff --git a/test cases/failing/57 link with executable/prog.c b/test cases/failing/57 link with executable/prog.c new file mode 100644 index 000000000..f3836d7ba --- /dev/null +++ b/test cases/failing/57 link with executable/prog.c @@ -0,0 +1,5 @@ +int +main (int argc, char **argv) +{ + return 0; +} diff --git a/test cases/windows/12 exe implib/installed_files.txt b/test cases/windows/12 exe implib/installed_files.txt new file mode 100644 index 000000000..d0ea8f6c4 --- /dev/null +++ b/test cases/windows/12 exe implib/installed_files.txt @@ -0,0 +1,4 @@ +usr/bin/prog.exe +usr/bin/prog.pdb +?gcc:usr/lib/libprog.exe.a +?msvc:usr/lib/prog.lib diff --git a/test cases/windows/12 exe implib/meson.build b/test cases/windows/12 exe implib/meson.build new file mode 100644 index 000000000..2393e794c --- /dev/null +++ b/test cases/windows/12 exe implib/meson.build @@ -0,0 +1,7 @@ +project('wintest', 'c') + +# Test that we can produce an implib for an executable on Windows, and that it +# is installed along with the executable + +prog = executable('prog', 'prog.c', install: true, implib: true) +test('wintest', prog) diff --git a/test cases/windows/12 exe implib/prog.c b/test cases/windows/12 exe implib/prog.c new file mode 100644 index 000000000..6d5a9f501 --- /dev/null +++ b/test cases/windows/12 exe implib/prog.c @@ -0,0 +1,6 @@ +#include + +int __declspec(dllexport) +main(int argc, char **argv) { + return 0; +} From 3110c209f76b3389c34ce953ae6814ed64d7a898 Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Thu, 22 Jun 2017 17:22:51 +0100 Subject: [PATCH 2/5] Consolidate windows tests which are divided between mingw and msvc --- .../installed_files.txt | 11 ---- .../7 mingw dll versioning/meson.build | 55 ------------------- .../copyfile.py | 0 .../exe.orig.c | 0 .../8 dll versioning/installed_files.txt | 24 ++++++++ .../lib.c | 0 .../meson.build | 8 +-- .../windows/8 msvc dll versioning/exe.orig.c | 9 --- .../8 msvc dll versioning/installed_files.txt | 13 ----- .../windows/8 msvc dll versioning/lib.c | 6 -- 10 files changed, 26 insertions(+), 100 deletions(-) delete mode 100644 test cases/windows/7 mingw dll versioning/installed_files.txt delete mode 100644 test cases/windows/7 mingw dll versioning/meson.build rename test cases/windows/{8 msvc dll versioning => 8 dll versioning}/copyfile.py (100%) rename test cases/windows/{7 mingw dll versioning => 8 dll versioning}/exe.orig.c (100%) create mode 100644 test cases/windows/8 dll versioning/installed_files.txt rename test cases/windows/{7 mingw dll versioning => 8 dll versioning}/lib.c (100%) rename test cases/windows/{8 msvc dll versioning => 8 dll versioning}/meson.build (88%) delete mode 100644 test cases/windows/8 msvc dll versioning/exe.orig.c delete mode 100644 test cases/windows/8 msvc dll versioning/installed_files.txt delete mode 100644 test cases/windows/8 msvc dll versioning/lib.c diff --git a/test cases/windows/7 mingw dll versioning/installed_files.txt b/test cases/windows/7 mingw dll versioning/installed_files.txt deleted file mode 100644 index 26e14a7d8..000000000 --- a/test cases/windows/7 mingw dll versioning/installed_files.txt +++ /dev/null @@ -1,11 +0,0 @@ -usr/bin/?libsome-0.dll -usr/lib/libsome.dll.a -usr/bin/?libnoversion.dll -usr/lib/libnoversion.dll.a -usr/bin/?libonlyversion-1.dll -usr/lib/libonlyversion.dll.a -usr/bin/?libonlysoversion-5.dll -usr/lib/libonlysoversion.dll.a -usr/libexec/?libcustomdir.dll -usr/libexec/libcustomdir.dll.a -usr/lib/?libmodule.dll diff --git a/test cases/windows/7 mingw dll versioning/meson.build b/test cases/windows/7 mingw dll versioning/meson.build deleted file mode 100644 index 1d6562c58..000000000 --- a/test cases/windows/7 mingw dll versioning/meson.build +++ /dev/null @@ -1,55 +0,0 @@ -project('mingw dll versioning', 'c') - -cc = meson.get_compiler('c') - -if cc.get_id() == 'msvc' - error('MESON_SKIP_TEST: test is only for MinGW') -endif - -# Test that MinGW/GCC creates correctly-named dll files and dll.a files, -# and also installs them in the right place -some = shared_library('some', 'lib.c', - version : '1.2.3', - soversion : '0', - install : true) - -noversion = shared_library('noversion', 'lib.c', - install : true) - -onlyversion = shared_library('onlyversion', 'lib.c', - version : '1.4.5', - install : true) - -onlysoversion = shared_library('onlysoversion', 'lib.c', - # Also test that int soversion is acceptable - soversion : 5, - install : true) - -# Hack to make the executables below depend on the shared libraries above -# without actually adding them as `link_with` dependencies since we want to try -# linking to them with -lfoo linker arguments. -out = custom_target('library-dependency-hack', - input : 'exe.orig.c', - output : 'exe.c', - depends : [some, noversion, onlyversion, onlysoversion], - command : ['cp', '@INPUT@', '@OUTPUT@']) - -# Manually test if the linker can find the above libraries -# i.e., whether they were generated with the right naming scheme -test('manually linked 1', executable('manuallink1', out, - link_args : ['-L.', '-lsome'])) - -test('manually linked 2', executable('manuallink2', out, - link_args : ['-L.', '-lnoversion'])) - -test('manually linked 3', executable('manuallink3', out, - link_args : ['-L.', '-lonlyversion'])) - -test('manually linked 4', executable('manuallink4', out, - link_args : ['-L.', '-lonlysoversion'])) - -shared_library('customdir', 'lib.c', - install : true, - install_dir : get_option('libexecdir')) - -shared_module('module', 'lib.c', install : true) diff --git a/test cases/windows/8 msvc dll versioning/copyfile.py b/test cases/windows/8 dll versioning/copyfile.py similarity index 100% rename from test cases/windows/8 msvc dll versioning/copyfile.py rename to test cases/windows/8 dll versioning/copyfile.py diff --git a/test cases/windows/7 mingw dll versioning/exe.orig.c b/test cases/windows/8 dll versioning/exe.orig.c similarity index 100% rename from test cases/windows/7 mingw dll versioning/exe.orig.c rename to test cases/windows/8 dll versioning/exe.orig.c diff --git a/test cases/windows/8 dll versioning/installed_files.txt b/test cases/windows/8 dll versioning/installed_files.txt new file mode 100644 index 000000000..a1e9b2d7a --- /dev/null +++ b/test cases/windows/8 dll versioning/installed_files.txt @@ -0,0 +1,24 @@ +?msvc:usr/bin/some-0.dll +?msvc:usr/bin/some-0.pdb +?msvc:usr/lib/some.lib +?msvc:usr/bin/noversion.dll +?msvc:usr/bin/noversion.pdb +?msvc:usr/lib/noversion.lib +?msvc:usr/bin/onlyversion-1.dll +?msvc:usr/lib/onlyversion.lib +?msvc:usr/bin/onlysoversion-5.dll +?msvc:usr/lib/onlysoversion.lib +?msvc:usr/libexec/customdir.dll +?msvc:usr/libexec/customdir.lib +?msvc:usr/lib/module.dll +?gcc:usr/bin/?libsome-0.dll +?gcc:usr/lib/libsome.dll.a +?gcc:usr/bin/?libnoversion.dll +?gcc:usr/lib/libnoversion.dll.a +?gcc:usr/bin/?libonlyversion-1.dll +?gcc:usr/lib/libonlyversion.dll.a +?gcc:usr/bin/?libonlysoversion-5.dll +?gcc:usr/lib/libonlysoversion.dll.a +?gcc:usr/libexec/?libcustomdir.dll +?gcc:usr/libexec/libcustomdir.dll.a +?gcc:usr/lib/?libmodule.dll diff --git a/test cases/windows/7 mingw dll versioning/lib.c b/test cases/windows/8 dll versioning/lib.c similarity index 100% rename from test cases/windows/7 mingw dll versioning/lib.c rename to test cases/windows/8 dll versioning/lib.c diff --git a/test cases/windows/8 msvc dll versioning/meson.build b/test cases/windows/8 dll versioning/meson.build similarity index 88% rename from test cases/windows/8 msvc dll versioning/meson.build rename to test cases/windows/8 dll versioning/meson.build index 407474790..80acf880a 100644 --- a/test cases/windows/8 msvc dll versioning/meson.build +++ b/test cases/windows/8 dll versioning/meson.build @@ -2,12 +2,8 @@ project('msvc dll versioning', 'c') cc = meson.get_compiler('c') -if cc.get_id() != 'msvc' - error('MESON_SKIP_TEST: test is only for msvc') -endif - -# Test that MSVC creates correctly-named dll files and .lib files, -# and also installs them in the right place +# Test that we create correctly-named dll and import lib files, +# and also install them in the right place some = shared_library('some', 'lib.c', version : '1.2.3', soversion : '0', diff --git a/test cases/windows/8 msvc dll versioning/exe.orig.c b/test cases/windows/8 msvc dll versioning/exe.orig.c deleted file mode 100644 index 86c4adc38..000000000 --- a/test cases/windows/8 msvc dll versioning/exe.orig.c +++ /dev/null @@ -1,9 +0,0 @@ -int myFunc (void); - -int -main (int argc, char *argv[]) -{ - if (myFunc() == 55) - return 0; - return 1; -} diff --git a/test cases/windows/8 msvc dll versioning/installed_files.txt b/test cases/windows/8 msvc dll versioning/installed_files.txt deleted file mode 100644 index df4334381..000000000 --- a/test cases/windows/8 msvc dll versioning/installed_files.txt +++ /dev/null @@ -1,13 +0,0 @@ -usr/bin/some-0.dll -usr/bin/some-0.pdb -usr/lib/some.lib -usr/bin/noversion.dll -usr/bin/noversion.pdb -usr/lib/noversion.lib -usr/bin/onlyversion-1.dll -usr/lib/onlyversion.lib -usr/bin/onlysoversion-5.dll -usr/lib/onlysoversion.lib -usr/libexec/customdir.dll -usr/libexec/customdir.lib -usr/lib/module.dll diff --git a/test cases/windows/8 msvc dll versioning/lib.c b/test cases/windows/8 msvc dll versioning/lib.c deleted file mode 100644 index cf7dfdd07..000000000 --- a/test cases/windows/8 msvc dll versioning/lib.c +++ /dev/null @@ -1,6 +0,0 @@ -#ifdef _WIN32 -__declspec(dllexport) -#endif -int myFunc() { - return 55; -} From 8f859a510506318f91f639b67807a3dbdd4d0fbc Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Thu, 22 Jun 2017 20:18:15 +0100 Subject: [PATCH 3/5] Make the name of the executable implib configurable --- docs/markdown/Reference-manual.md | 2 +- mesonbuild/build.py | 11 +++++++---- test cases/windows/12 exe implib/installed_files.txt | 6 +++++- test cases/windows/12 exe implib/meson.build | 8 ++++---- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index 261d89894..4989cef61 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -248,7 +248,7 @@ Executable supports the following keyword arguments. Note that just like the pos - `name_suffix` the string that will be used as the extension for the target by overriding the default. By default on Windows this is `exe` and on other platforms it is omitted. - `build_by_default` causes, when set to true, to have this target be built by default, that is, when invoking plain `ninja`, the default value is true for all built target types, since 0.38.0 - `override_options` takes an array of strings in the same format as `project`'s `default_options` overriding the values of these options for this target only, since 0.40.0 -- `implib` when set to true, an import library is generated for the executable, used when the returned build target object appears elsewhere in `link_with:`, on platforms where this is meaningful (e.g. Windows), since 0.42.0 +- `implib` when set to true, an import library is generated for the executable (the name of the import library is based on *exe_name*). Alternatively, when set to a string, that gives the base name for the import library. The import library is used when the returned build target object appears in `link_with:` elsewhere. Only has any effect on platforms where that is meaningful (e.g. Windows). Since 0.42.0 The list of `sources`, `objects`, and `dependencies` is always flattened, which means you can freely nest and add lists while creating the final list. As a corollary, the best way to handle a 'disabled dependency' is by assigning an empty list `[]` to it and passing it like any other dependency to the `dependencies:` keyword argument. diff --git a/mesonbuild/build.py b/mesonbuild/build.py index df24c7fbe..89b96f5be 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -1135,14 +1135,17 @@ class Executable(BuildTarget): # 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. + # if implib 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']: + implib_basename = self.name + '.exe' + if not isinstance(kwargs['implib'], bool): + implib_basename = 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) + self.vs_import_filename = '{0}.lib'.format(implib_basename) + self.gcc_import_filename = 'lib{0}.a'.format(implib_basename) if self.get_using_msvc(): self.import_filename = self.vs_import_filename diff --git a/test cases/windows/12 exe implib/installed_files.txt b/test cases/windows/12 exe implib/installed_files.txt index d0ea8f6c4..bd2abe92b 100644 --- a/test cases/windows/12 exe implib/installed_files.txt +++ b/test cases/windows/12 exe implib/installed_files.txt @@ -1,4 +1,8 @@ usr/bin/prog.exe usr/bin/prog.pdb +usr/bin/prog2.exe +usr/bin/prog2.pdb ?gcc:usr/lib/libprog.exe.a -?msvc:usr/lib/prog.lib +?gcc:usr/lib/libburble.a +?msvc:usr/lib/prog.exe.lib +?msvc:usr/lib/burble.lib diff --git a/test cases/windows/12 exe implib/meson.build b/test cases/windows/12 exe implib/meson.build index 2393e794c..2526c651a 100644 --- a/test cases/windows/12 exe implib/meson.build +++ b/test cases/windows/12 exe implib/meson.build @@ -1,7 +1,7 @@ project('wintest', 'c') -# Test that we can produce an implib for an executable on Windows, and that it -# is installed along with the executable +# Test that we can produce an implib for an executable on Windows, and that it's +# name can be set, and that it is installed along with the executable -prog = executable('prog', 'prog.c', install: true, implib: true) -test('wintest', prog) +executable('prog', 'prog.c', install: true, implib: true) +executable('prog2', 'prog.c', install: true, implib: 'burble') From 8ebdbfb0f664c0a7dee1c88635a89cedfcfe92b5 Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Thu, 29 Jun 2017 20:52:20 +0100 Subject: [PATCH 4/5] Use full_path() rather than adding current_build_dir() as rpath in test common/154 --- .../meson.build | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/test cases/common/154 shared module resolving symbol in executable/meson.build b/test cases/common/154 shared module resolving symbol in executable/meson.build index 06c990282..34a75f140 100644 --- a/test cases/common/154 shared module resolving symbol in executable/meson.build +++ b/test cases/common/154 shared module resolving symbol in executable/meson.build @@ -13,12 +13,9 @@ link_flags = [] if host_machine.system() != 'windows' # Needed to export dynamic symbols from the executable link_flags += ['-rdynamic'] - # Need to add this manually because Meson won't add it automatically because - # it doesn't know that we are loading a module from the build directory. - link_flags += ['-Wl,-rpath,' + meson.current_build_dir()] endif dl = meson.get_compiler('c').find_library('dl', required: false) e = executable('prog', 'prog.c', dependencies: dl, implib: true, link_args: link_flags) m = shared_module('module', 'module.c', link_with: e) -test('test', e, args: m) +test('test', e, args: m.full_path()) From 887e4d131857bf44eea1566adae9b79c610e3e86 Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Thu, 20 Jul 2017 21:08:52 +0100 Subject: [PATCH 5/5] Add to release note --- docs/markdown/Release-notes-for-0.42.0.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/markdown/Release-notes-for-0.42.0.md b/docs/markdown/Release-notes-for-0.42.0.md index 3374d3b01..3a12f0231 100644 --- a/docs/markdown/Release-notes-for-0.42.0.md +++ b/docs/markdown/Release-notes-for-0.42.0.md @@ -65,3 +65,8 @@ A new experimental module to compile code with many different SIMD instruction sets and selecting the best one at runtime. This module is unstable, meaning its API is subject to change in later releases. It might also be removed altogether. + +## Import libraries for executables on Windows + +The new keyword `implib` to `executable()` allows generation of an import +library for the executable.