summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJussi Pakkanen <jpakkane@gmail.com>2018-12-29 18:57:21 +0200
committerGitHub <noreply@github.com>2018-12-29 18:57:21 +0200
commit3b495c397ec1baffe99d63031f2b03301b7f6ba5 (patch)
tree660439db681ece26c622af11eff2535c507fca1c
parent3d7c32a34e9d7a1f0e0c5c701f1afdf411b0194c (diff)
parentb6cede2928e80d6bd0512c82ad6787c03faae1e6 (diff)
downloadmeson-3b495c397ec1baffe99d63031f2b03301b7f6ba5.tar.gz
Merge pull request #4672 from xclaesse/find-library-headers
find_library: Add 'has_headers' kwarg
-rw-r--r--docs/markdown/Reference-manual.md16
-rw-r--r--docs/markdown/snippets/find_library_header.md21
-rw-r--r--mesonbuild/interpreter.py98
-rw-r--r--test cases/common/209 find_library and headers/foo.h1
-rw-r--r--test cases/common/209 find_library and headers/meson.build23
5 files changed, 120 insertions, 39 deletions
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md
index 8d0d123e3..92a7aed7e 100644
--- a/docs/markdown/Reference-manual.md
+++ b/docs/markdown/Reference-manual.md
@@ -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`
@@ -1760,7 +1763,9 @@ the following methods:
the `prefix` keyword. In order to look for headers in a specific
directory you can use `args : '-I/extra/include/dir`, but this
should only be used in exceptional cases for includes that can't be
- detected via pkg-config and passed via `dependencies`.
+ detected via pkg-config and passed via `dependencies`. Since *0.50.0* the
+ `required` keyword argument can be used to abort if the header cannot be
+ found.
- `has_header` returns true if the specified header *exists*, and is
faster than `check_header()` since it only does a pre-processor check.
@@ -1769,13 +1774,16 @@ the following methods:
the `prefix` keyword. In order to look for headers in a specific
directory you can use `args : '-I/extra/include/dir`, but this
should only be used in exceptional cases for includes that can't be
- detected via pkg-config and passed via `dependencies`.
+ detected via pkg-config and passed via `dependencies`. Since *0.50.0* the
+ `required` keyword argument can be used to abort if the header cannot be
+ found.
- `has_header_symbol(headername, symbolname)` allows one to detect
whether a particular symbol (function, variable, #define, type
definition, etc) is declared in the specified header, you can
specify external dependencies to use with `dependencies` keyword
- argument.
+ argument. Since *0.50.0* the `required` keyword argument can be used to abort
+ if the symbol cannot be found.
- `has_member(typename, membername)` takes two arguments, type name
and member name and returns true if the type has the specified
diff --git a/docs/markdown/snippets/find_library_header.md b/docs/markdown/snippets/find_library_header.md
new file mode 100644
index 000000000..55597abc5
--- /dev/null
+++ b/docs/markdown/snippets/find_library_header.md
@@ -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('.'))
+```
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index 6fef4a90a..0571eba92 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -86,8 +86,8 @@ class FeatureOptionHolder(InterpreterObject, ObjectHolder):
def auto_method(self, args, kwargs):
return self.held_object.is_auto()
-def extract_required_kwarg(kwargs, subproject, feature_check=None):
- val = kwargs.get('required', True)
+def extract_required_kwarg(kwargs, subproject, feature_check=None, default=True):
+ val = kwargs.get('required', default)
disabled = False
required = False
feature = None
@@ -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)
@@ -1344,13 +1361,8 @@ class CompilerHolder(InterpreterObject):
return result
@FeatureNew('compiler.check_header', '0.47.0')
- @permittedKwargs({
- 'prefix',
- 'no_builtin_args',
- 'include_directories',
- 'args',
- 'dependencies',
- })
+ @FeatureNewKwargs('compiler.check_header', '0.50.0', ['required'])
+ @permittedKwargs(header_permitted_kwargs)
def check_header_method(self, args, kwargs):
if len(args) != 1:
raise InterpreterException('check_header method takes exactly one argument.')
@@ -1359,25 +1371,26 @@ class CompilerHolder(InterpreterObject):
prefix = kwargs.get('prefix', '')
if not isinstance(prefix, str):
raise InterpreterException('Prefix argument of has_header must be a string.')
+ disabled, required, feature = extract_required_kwarg(kwargs, self.subproject, default=False)
+ if disabled:
+ mlog.log('Check usable header', mlog.bold(hname, True), 'skipped: feature', mlog.bold(feature), 'disabled')
+ return False
extra_args = functools.partial(self.determine_args, kwargs)
deps, msg = self.determine_dependencies(kwargs)
haz = self.compiler.check_header(hname, prefix, self.environment,
extra_args=extra_args,
dependencies=deps)
- if haz:
+ if required and not haz:
+ raise InterpreterException('{} header {!r} not usable'.format(self.compiler.get_display_language(), hname))
+ elif haz:
h = mlog.green('YES')
else:
h = mlog.red('NO')
mlog.log('Check usable header', mlog.bold(hname, True), msg, h)
return haz
- @permittedKwargs({
- 'prefix',
- 'no_builtin_args',
- 'include_directories',
- 'args',
- 'dependencies',
- })
+ @FeatureNewKwargs('compiler.has_header', '0.50.0', ['required'])
+ @permittedKwargs(header_permitted_kwargs)
def has_header_method(self, args, kwargs):
if len(args) != 1:
raise InterpreterException('has_header method takes exactly one argument.')
@@ -1386,24 +1399,25 @@ class CompilerHolder(InterpreterObject):
prefix = kwargs.get('prefix', '')
if not isinstance(prefix, str):
raise InterpreterException('Prefix argument of has_header must be a string.')
+ disabled, required, feature = extract_required_kwarg(kwargs, self.subproject, default=False)
+ if disabled:
+ mlog.log('Has header', mlog.bold(hname, True), 'skipped: feature', mlog.bold(feature), 'disabled')
+ return False
extra_args = functools.partial(self.determine_args, kwargs)
deps, msg = self.determine_dependencies(kwargs)
haz = self.compiler.has_header(hname, prefix, self.environment,
extra_args=extra_args, dependencies=deps)
- if haz:
+ if required and not haz:
+ raise InterpreterException('{} header {!r} not found'.format(self.compiler.get_display_language(), hname))
+ elif haz:
h = mlog.green('YES')
else:
h = mlog.red('NO')
mlog.log('Has header', mlog.bold(hname, True), msg, h)
return haz
- @permittedKwargs({
- 'prefix',
- 'no_builtin_args',
- 'include_directories',
- 'args',
- 'dependencies',
- })
+ @FeatureNewKwargs('compiler.has_header_symbol', '0.50.0', ['required'])
+ @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.')
@@ -1413,24 +1427,35 @@ class CompilerHolder(InterpreterObject):
prefix = kwargs.get('prefix', '')
if not isinstance(prefix, str):
raise InterpreterException('Prefix argument of has_header_symbol must be a string.')
+ disabled, required, feature = extract_required_kwarg(kwargs, self.subproject, default=False)
+ if disabled:
+ mlog.log('Header <{0}> has symbol'.format(hname), mlog.bold(symbol, True), 'skipped: feature', mlog.bold(feature), 'disabled')
+ return False
extra_args = functools.partial(self.determine_args, kwargs)
deps, msg = self.determine_dependencies(kwargs)
haz = self.compiler.has_header_symbol(hname, symbol, prefix, self.environment,
extra_args=extra_args,
dependencies=deps)
- if haz:
+ if required and not haz:
+ raise InterpreterException('{} symbol {} not found in header {}'.format(self.compiler.get_display_language(), symbol, hname))
+ elif haz:
h = mlog.green('YES')
else:
h = mlog.red('NO')
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:
@@ -1442,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:
diff --git a/test cases/common/209 find_library and headers/foo.h b/test cases/common/209 find_library and headers/foo.h
new file mode 100644
index 000000000..014e06e82
--- /dev/null
+++ b/test cases/common/209 find_library and headers/foo.h
@@ -0,0 +1 @@
+#define VAL 42
diff --git a/test cases/common/209 find_library and headers/meson.build b/test cases/common/209 find_library and headers/meson.build
new file mode 100644
index 000000000..bcd71f12a
--- /dev/null
+++ b/test cases/common/209 find_library and headers/meson.build
@@ -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')