Add static as keyword to find_library

pull/5063/head
Niklas Claesson 6 years ago committed by Jussi Pakkanen
parent faf3581df6
commit dd2c44cdf6
  1. 4
      docs/markdown/Reference-manual.md
  2. 6
      docs/markdown/snippets/find_library_static.md
  3. 4
      mesonbuild/backend/ninjabackend.py
  4. 35
      mesonbuild/compilers/c.py
  5. 5
      mesonbuild/compilers/fortran.py
  6. 2
      mesonbuild/compilers/vala.py
  7. 2
      mesonbuild/dependencies/base.py
  8. 12
      mesonbuild/interpreter.py
  9. 10
      run_unittests.py
  10. 7
      test cases/linuxlike/14 static dynamic linkage/main.c
  11. 20
      test cases/linuxlike/14 static dynamic linkage/meson.build
  12. 16
      test cases/linuxlike/14 static dynamic linkage/verify_static.py

@ -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`

@ -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.

@ -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

@ -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)

@ -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):

@ -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

@ -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:

@ -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)

@ -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):

@ -0,0 +1,7 @@
#include "stdio.h"
#include "zlib.h"
int main() {
printf("%s\n", zlibVersion());
return 0;
}

@ -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)

@ -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()
Loading…
Cancel
Save