diff options
author | Niklas Claesson <nicke.claesson@gmail.com> | 2019-03-11 19:56:52 +0100 |
---|---|---|
committer | Jussi Pakkanen <jpakkane@gmail.com> | 2019-03-11 20:56:52 +0200 |
commit | dd2c44cdf6f8ed8a969d0666cafb08aaf78a919d (patch) | |
tree | a6057cb899b43c55a820291c93dd62d61e2e0a69 | |
parent | faf3581df6af59c04e66378da129bb2039beab8a (diff) | |
download | meson-dd2c44cdf6f8ed8a969d0666cafb08aaf78a919d.zip meson-dd2c44cdf6f8ed8a969d0666cafb08aaf78a919d.tar.gz meson-dd2c44cdf6f8ed8a969d0666cafb08aaf78a919d.tar.bz2 |
Add static as keyword to find_library
-rw-r--r-- | docs/markdown/Reference-manual.md | 4 | ||||
-rw-r--r-- | docs/markdown/snippets/find_library_static.md | 6 | ||||
-rw-r--r-- | mesonbuild/backend/ninjabackend.py | 4 | ||||
-rw-r--r-- | mesonbuild/compilers/c.py | 35 | ||||
-rw-r--r-- | mesonbuild/compilers/fortran.py | 5 | ||||
-rw-r--r-- | mesonbuild/compilers/vala.py | 2 | ||||
-rw-r--r-- | mesonbuild/dependencies/base.py | 2 | ||||
-rw-r--r-- | mesonbuild/interpreter.py | 12 | ||||
-rwxr-xr-x | run_unittests.py | 10 | ||||
-rw-r--r-- | test cases/linuxlike/14 static dynamic linkage/main.c | 7 | ||||
-rw-r--r-- | test cases/linuxlike/14 static dynamic linkage/meson.build | 20 | ||||
-rwxr-xr-x | test cases/linuxlike/14 static dynamic linkage/verify_static.py | 16 |
12 files changed, 93 insertions, 30 deletions
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index f2b0416..7668fa0 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -1724,7 +1724,9 @@ the following methods: instead of a not-found dependency. *Since 0.50.0* the `has_headers` keyword argument can be a list of header files that must be found as well, using `has_header()` method. All keyword arguments prefixed with `header_` will be - passed down to `has_header()` method with the prefix removed. + passed down to `has_header()` method with the prefix removed. *Since 0.51.0* + the `static` keyword (boolean) can be set to `true` to limit the search to + static libraries and `false` for dynamic/shared. - `first_supported_argument(list_of_strings)`, given a list of strings, returns the first argument that passes the `has_argument` diff --git a/docs/markdown/snippets/find_library_static.md b/docs/markdown/snippets/find_library_static.md new file mode 100644 index 0000000..a1b7fa9 --- /dev/null +++ b/docs/markdown/snippets/find_library_static.md @@ -0,0 +1,6 @@ +## Add keyword `static` to `find_library` + +`find_library` has learned the `static` keyword. They keyword must be a boolean, +where `true` only searches for static libraries and `false` only searches for +dynamic/shared. Leaving the keyword unset will keep the old behavior of first +searching for dynamic and then falling back to static. diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 1e0bb8b..7225b42 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -2459,9 +2459,9 @@ rule FORTRAN_DEP_HACK%s sharedlibs = self.guess_library_absolute_path(linker, libname, search_dirs, shared_patterns) if staticlibs: - guessed_dependencies.append(os.path.realpath(staticlibs)) + guessed_dependencies.append(staticlibs.resolve().as_posix()) if sharedlibs: - guessed_dependencies.append(os.path.realpath(sharedlibs)) + guessed_dependencies.append(sharedlibs.resolve().as_posix()) return guessed_dependencies + absolute_libs diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index 31d6464..d4626d6 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -936,18 +936,17 @@ class CCompiler(Compiler): else: # Linux/BSDs shlibext = ['so'] - patterns = [] # Search priority - if libtype in ('default', 'shared-static'): - patterns += self._get_patterns(env, prefixes, shlibext, True) - patterns += self._get_patterns(env, prefixes, stlibext, False) + if libtype == 'shared-static': + patterns = self._get_patterns(env, prefixes, shlibext, True) + patterns.extend([x for x in self._get_patterns(env, prefixes, stlibext, False) if x not in patterns]) elif libtype == 'static-shared': - patterns += self._get_patterns(env, prefixes, stlibext, False) - patterns += self._get_patterns(env, prefixes, shlibext, True) + patterns = self._get_patterns(env, prefixes, stlibext, False) + patterns.extend([x for x in self._get_patterns(env, prefixes, shlibext, True) if x not in patterns]) elif libtype == 'shared': - patterns += self._get_patterns(env, prefixes, shlibext, True) + patterns = self._get_patterns(env, prefixes, shlibext, True) elif libtype == 'static': - patterns += self._get_patterns(env, prefixes, stlibext, False) + patterns = self._get_patterns(env, prefixes, stlibext, False) else: raise AssertionError('BUG: unknown libtype {!r}'.format(libtype)) return tuple(patterns) @@ -975,11 +974,11 @@ class CCompiler(Compiler): if '*' in pattern: # NOTE: globbing matches directories and broken symlinks # so we have to do an isfile test on it later - return cls._sort_shlibs_openbsd(glob.glob(str(f))) - return [f.as_posix()] + return [Path(x) for x in cls._sort_shlibs_openbsd(glob.glob(str(f)))] + return [f] @staticmethod - def _get_file_from_list(env, files: List[str]) -> str: + def _get_file_from_list(env, files: List[str]) -> Path: ''' We just check whether the library exists. We can't do a link check because the library might have unresolved symbols that require other @@ -987,13 +986,14 @@ class CCompiler(Compiler): architecture. ''' # If not building on macOS for Darwin, do a simple file check + files = [Path(f) for f in files] if not env.machines.host.is_darwin() or not env.machines.build.is_darwin(): for f in files: - if os.path.isfile(f): + if f.is_file(): return f # Run `lipo` and check if the library supports the arch we want for f in files: - if not os.path.isfile(f): + if not f.is_file(): continue archs = darwin_get_object_archs(f) if archs and env.machines.host.cpu_family in archs: @@ -1014,7 +1014,10 @@ class CCompiler(Compiler): # First try if we can just add the library as -l. # Gcc + co seem to prefer builtin lib dirs to -L dirs. # Only try to find std libs if no extra dirs specified. - if not extra_dirs or libname in self.internal_libs: + # The built-in search procedure will always favour .so and then always + # search for .a. This is only allowed if libtype is 'shared-static' + if ((not extra_dirs and libtype == 'shared-static') or + libname in self.internal_libs): args = ['-l' + libname] largs = self.linker_to_compiler_args(self.get_allow_undefined_link_args()) if self.links(code, env, extra_args=(args + largs)): @@ -1044,7 +1047,7 @@ class CCompiler(Compiler): trial = self._get_file_from_list(env, trial) if not trial: continue - return [trial] + return [trial.as_posix()] return None def find_library_impl(self, libname, env, extra_dirs, code, libtype): @@ -1063,7 +1066,7 @@ class CCompiler(Compiler): return None return value[:] - def find_library(self, libname, env, extra_dirs, libtype='default'): + def find_library(self, libname, env, extra_dirs, libtype='shared-static'): code = 'int main(int argc, char **argv) { return 0; }' return self.find_library_impl(libname, env, extra_dirs, code, libtype) diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py index 6c260b6..738a5c6 100644 --- a/mesonbuild/compilers/fortran.py +++ b/mesonbuild/compilers/fortran.py @@ -13,6 +13,7 @@ # limitations under the License. from typing import List import subprocess, os +from pathlib import Path from .c import CCompiler from .compilers import ( @@ -240,7 +241,7 @@ class FortranCompiler(Compiler): def find_library_impl(self, *args): return CCompiler.find_library_impl(self, *args) - def find_library(self, libname, env, extra_dirs, libtype='default'): + def find_library(self, libname, env, extra_dirs, libtype='shared-static'): code = '''program main call exit(0) end program main''' @@ -272,7 +273,7 @@ class FortranCompiler(Compiler): return CCompiler._get_trials_from_pattern(pattern, directory, libname) @staticmethod - def _get_file_from_list(env, files: List[str]) -> str: + def _get_file_from_list(env, files: List[str]) -> Path: return CCompiler._get_file_from_list(env, files) class GnuFortranCompiler(GnuCompiler, FortranCompiler): diff --git a/mesonbuild/compilers/vala.py b/mesonbuild/compilers/vala.py index 1ee46fe..b463f0d 100644 --- a/mesonbuild/compilers/vala.py +++ b/mesonbuild/compilers/vala.py @@ -98,7 +98,7 @@ class ValaCompiler(Compiler): return ['--debug'] return [] - def find_library(self, libname, env, extra_dirs): + def find_library(self, libname, env, extra_dirs, *args): if extra_dirs and isinstance(extra_dirs, str): extra_dirs = [extra_dirs] # Valac always looks in the default vapi dir, so only search there if diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 3c105ab..2ba150b 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -703,7 +703,7 @@ class PkgConfigDependency(ExternalDependency): libs_found = OrderedSet() # Track not-found libraries to know whether to add library paths libs_notfound = [] - libtype = 'static' if self.static else 'default' + libtype = 'static' if self.static else 'shared-static' # Generate link arguments for this library link_args = [] for lib in full_args: diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index e48733a..3c3cfae 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -919,6 +919,7 @@ find_library_permitted_kwargs = set([ 'has_headers', 'required', 'dirs', + 'static', ]) find_library_permitted_kwargs |= set(['header_' + k for k in header_permitted_kwargs]) @@ -1463,6 +1464,7 @@ class CompilerHolder(InterpreterObject): silent=True) return ExternalLibraryHolder(lib, self.subproject) + @FeatureNewKwargs('compiler.find_library', '0.51.0', ['static']) @FeatureNewKwargs('compiler.find_library', '0.50.0', ['has_headers']) @FeatureNewKwargs('compiler.find_library', '0.49.0', ['disabler']) @disablerIfNotFound @@ -1491,9 +1493,15 @@ class CompilerHolder(InterpreterObject): for i in search_dirs: if not os.path.isabs(i): raise InvalidCode('Search directory %s is not an absolute path.' % i) - linkargs = self.compiler.find_library(libname, self.environment, search_dirs) + libtype = 'shared-static' + if 'static' in kwargs: + if not isinstance(kwargs['static'], bool): + raise InterpreterException('static must be a boolean') + libtype = 'static' if kwargs['static'] else 'shared' + linkargs = self.compiler.find_library(libname, self.environment, search_dirs, libtype) if required and not linkargs: - raise InterpreterException('{} library {!r} not found'.format(self.compiler.get_display_language(), libname)) + raise InterpreterException( + '{} library {!r} not found'.format(self.compiler.get_display_language(), libname)) lib = dependencies.ExternalLibrary(libname, linkargs, self.environment, self.compiler.language) return ExternalLibraryHolder(lib, self.subproject) diff --git a/run_unittests.py b/run_unittests.py index 5087414..5de69f6 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -700,16 +700,16 @@ class InternalTests(unittest.TestCase): def _test_all_naming(self, cc, env, patterns, platform): shr = patterns[platform]['shared'] stc = patterns[platform]['static'] + shrstc = shr + tuple([x for x in stc if x not in shr]) + stcshr = stc + tuple([x for x in shr if x not in stc]) p = cc.get_library_naming(env, 'shared') self.assertEqual(p, shr) p = cc.get_library_naming(env, 'static') self.assertEqual(p, stc) p = cc.get_library_naming(env, 'static-shared') - self.assertEqual(p, stc + shr) + self.assertEqual(p, stcshr) p = cc.get_library_naming(env, 'shared-static') - self.assertEqual(p, shr + stc) - p = cc.get_library_naming(env, 'default') - self.assertEqual(p, shr + stc) + self.assertEqual(p, shrstc) # Test find library by mocking up openbsd if platform != 'openbsd': return @@ -724,7 +724,7 @@ class InternalTests(unittest.TestCase): f.write('') with open(os.path.join(tmpdir, 'libfoo.so.70.0.so.1'), 'w') as f: f.write('') - found = cc.find_library_real('foo', env, [tmpdir], '', 'default') + found = cc.find_library_real('foo', env, [tmpdir], '', 'shared-static') self.assertEqual(os.path.basename(found[0]), 'libfoo.so.54.0') def test_find_library_patterns(self): diff --git a/test cases/linuxlike/14 static dynamic linkage/main.c b/test cases/linuxlike/14 static dynamic linkage/main.c new file mode 100644 index 0000000..628a200 --- /dev/null +++ b/test cases/linuxlike/14 static dynamic linkage/main.c @@ -0,0 +1,7 @@ +#include "stdio.h" +#include "zlib.h" + +int main() { + printf("%s\n", zlibVersion()); + return 0; +} diff --git a/test cases/linuxlike/14 static dynamic linkage/meson.build b/test cases/linuxlike/14 static dynamic linkage/meson.build new file mode 100644 index 0000000..fc3c38a --- /dev/null +++ b/test cases/linuxlike/14 static dynamic linkage/meson.build @@ -0,0 +1,20 @@ +project('static dynamic', 'c') + + +cc = meson.get_compiler('c') + +z_default = cc.find_library('z') +z_static = cc.find_library('z', static: true) +z_dynamic = cc.find_library('z', static: false) + +exe_default = executable('main_default', 'main.c', dependencies: [z_default]) +exe_static = executable('main_static', 'main.c', dependencies: [z_static]) +exe_dynamic = executable('main_dynamic', 'main.c', dependencies: [z_dynamic]) + +test('test default', exe_default) +test('test static', exe_static) +test('test dynamic', exe_dynamic) + +test('verify static linking', find_program('verify_static.py'), args:exe_static.full_path()) +test('verify dynamic linking', find_program('verify_static.py'), args:exe_dynamic.full_path(), + should_fail: true) diff --git a/test cases/linuxlike/14 static dynamic linkage/verify_static.py b/test cases/linuxlike/14 static dynamic linkage/verify_static.py new file mode 100755 index 0000000..92cc308 --- /dev/null +++ b/test cases/linuxlike/14 static dynamic linkage/verify_static.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python +"""Test script that checks if zlib was statically linked to executable""" +import subprocess +import sys + +def main(): + """Main function""" + output = subprocess.check_output(['nm', sys.argv[1]]).decode('utf-8') + + if 'T zlibVersion' in output: + sys.exit(0) + + sys.exit(1) + +if __name__ == '__main__': + main() |