find_library: Add 'has_headers' kwarg

A library without its headers is often useless, so it is common to check
them together.
pull/4672/head
Xavier Claessens 6 years ago
parent ff2aa5a9ef
commit b6cede2928
  1. 5
      docs/markdown/Reference-manual.md
  2. 21
      docs/markdown/snippets/find_library_header.md
  3. 70
      mesonbuild/interpreter.py
  4. 1
      test cases/common/209 find_library and headers/foo.h
  5. 23
      test cases/common/209 find_library and headers/meson.build

@ -1704,7 +1704,10 @@ the following methods:
option can also be passed to the `required` keyword argument.
*Since 0.49.0* if the keyword argument `disabler` is `true` and the
dependency couldn't be found, return a [disabler object](#disabler-object)
instead of a not-found dependency.
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.
- `first_supported_argument(list_of_strings)`, given a list of
strings, returns the first argument that passes the `has_argument`

@ -0,0 +1,21 @@
## Find library with its headers
The `find_library()` method can now also verify if the library's headers are
found in a single call, using the `has_header()` method internally.
```meson
# Aborts if the 'z' library is found but not its header file
zlib = find_library('z', has_headers : 'zlib.h')
# Returns not-found if the 'z' library is found but not its header file
zlib = find_library('z', has_headers : 'zlib.h', required : false)
```
Any keyword argument with the `header_` prefix passed to `find_library()` will
be passed to the `has_header()` method with the prefix removed.
```meson
libfoo = find_library('foo',
has_headers : ['foo.h', 'bar.h'],
header_prefix : '#include <baz.h>',
header_include_directories : include_directories('.'))
```

@ -900,6 +900,23 @@ class SubprojectHolder(InterpreterObject, ObjectHolder):
raise InvalidArguments('Requested variable "{0}" not found.'.format(varname))
return self.held_object.variables[varname]
header_permitted_kwargs = set([
'required',
'prefix',
'no_builtin_args',
'include_directories',
'args',
'dependencies',
])
find_library_permitted_kwargs = set([
'has_headers',
'required',
'dirs',
])
find_library_permitted_kwargs |= set(['header_' + k for k in header_permitted_kwargs])
class CompilerHolder(InterpreterObject):
def __init__(self, compiler, env, subproject):
InterpreterObject.__init__(self)
@ -1345,14 +1362,7 @@ class CompilerHolder(InterpreterObject):
@FeatureNew('compiler.check_header', '0.47.0')
@FeatureNewKwargs('compiler.check_header', '0.50.0', ['required'])
@permittedKwargs({
'required',
'prefix',
'no_builtin_args',
'include_directories',
'args',
'dependencies',
})
@permittedKwargs(header_permitted_kwargs)
def check_header_method(self, args, kwargs):
if len(args) != 1:
raise InterpreterException('check_header method takes exactly one argument.')
@ -1380,14 +1390,7 @@ class CompilerHolder(InterpreterObject):
return haz
@FeatureNewKwargs('compiler.has_header', '0.50.0', ['required'])
@permittedKwargs({
'required',
'prefix',
'no_builtin_args',
'include_directories',
'args',
'dependencies',
})
@permittedKwargs(header_permitted_kwargs)
def has_header_method(self, args, kwargs):
if len(args) != 1:
raise InterpreterException('has_header method takes exactly one argument.')
@ -1414,14 +1417,7 @@ class CompilerHolder(InterpreterObject):
return haz
@FeatureNewKwargs('compiler.has_header_symbol', '0.50.0', ['required'])
@permittedKwargs({
'required',
'prefix',
'no_builtin_args',
'include_directories',
'args',
'dependencies',
})
@permittedKwargs(header_permitted_kwargs)
def has_header_symbol_method(self, args, kwargs):
if len(args) != 2:
raise InterpreterException('has_header_symbol method takes exactly two arguments.')
@ -1449,12 +1445,17 @@ class CompilerHolder(InterpreterObject):
mlog.log('Header <{0}> has symbol'.format(hname), mlog.bold(symbol, True), msg, h)
return haz
def notfound_library(self, libname):
lib = dependencies.ExternalLibrary(libname, None,
self.environment,
self.compiler.language,
silent=True)
return ExternalLibraryHolder(lib, self.subproject)
@FeatureNewKwargs('compiler.find_library', '0.50.0', ['has_headers'])
@FeatureNewKwargs('compiler.find_library', '0.49.0', ['disabler'])
@disablerIfNotFound
@permittedKwargs({
'required',
'dirs',
})
@permittedKwargs(find_library_permitted_kwargs)
def find_library_method(self, args, kwargs):
# TODO add dependencies support?
if len(args) != 1:
@ -1466,11 +1467,14 @@ class CompilerHolder(InterpreterObject):
disabled, required, feature = extract_required_kwarg(kwargs, self.subproject)
if disabled:
mlog.log('Library', mlog.bold(libname), 'skipped: feature', mlog.bold(feature), 'disabled')
lib = dependencies.ExternalLibrary(libname, None,
self.environment,
self.compiler.language,
silent=True)
return ExternalLibraryHolder(lib, self.subproject)
return self.notfound_library(libname)
has_header_kwargs = {k[7:]: v for k, v in kwargs.items() if k.startswith('header_')}
has_header_kwargs['required'] = required
headers = mesonlib.stringlistify(kwargs.get('has_headers', []))
for h in headers:
if not self.has_header_method([h], has_header_kwargs):
return self.notfound_library(libname)
search_dirs = mesonlib.stringlistify(kwargs.get('dirs', []))
for i in search_dirs:

@ -0,0 +1,23 @@
project('find library and headers', 'c')
cc = meson.get_compiler('c')
if not cc.find_library('z', required : false).found()
error('MESON_SKIP_TEST: zlib not found.')
endif
lib = cc.find_library('z',
has_headers : 'foo.h',
required : false)
assert(not lib.found(), 'Header should be missing')
lib = cc.find_library('z',
has_headers : 'foo.h',
header_include_directories : include_directories('.'))
assert(lib.found(), 'Header should be found')
lib = cc.find_library('z',
has_headers : ['foo.h', 'bar.h'],
header_include_directories : include_directories('.'),
required : false)
assert(not lib.found(), 'One header should be missing')
Loading…
Cancel
Save