From f508b4cf80cfe924e87b9f2032299425706fff4a Mon Sep 17 00:00:00 2001 From: Daniel Mensinger Date: Tue, 24 Sep 2019 18:47:39 +0200 Subject: use getters for dependency access --- mesonbuild/build.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 4ec742d..0c3d982 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -1029,12 +1029,12 @@ This will become a hard error in a future Meson release.''') self.link(l) for l in dep.whole_libraries: self.link_whole(l) - if dep.compile_args or dep.link_args: + if dep.get_compile_args() or dep.get_link_args(): # Those parts that are external. extpart = dependencies.InternalDependency('undefined', [], - dep.compile_args, - dep.link_args, + dep.get_compile_args(), + dep.get_link_args(), [], [], [], []) self.external_deps.append(extpart) # Deps of deps. -- cgit v1.1 From 8593506b7ba73e3025d7f94c4ea793af94a10e51 Mon Sep 17 00:00:00 2001 From: Daniel Mensinger Date: Tue, 24 Sep 2019 22:37:22 +0200 Subject: add is_system kwarg to dependency Also adds the is_system and as_system methods to the dependency holder. --- mesonbuild/dependencies/base.py | 28 +++++++++++++++++++++++++++- mesonbuild/interpreter.py | 30 +++++++++++++++++++++++++++--- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 4e95c94..e5cb4bf 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -104,6 +104,14 @@ class Dependency: return methods + @classmethod + def _process_is_system_kw(cls, kwargs): + if 'is_system' not in kwargs: + return False + if not isinstance(kwargs['is_system'], bool): + raise DependencyException('The is_system kwarg must be a boolean type') + return kwargs['is_system'] + def __init__(self, type_name, kwargs): self.name = "null" self.version = None @@ -117,6 +125,7 @@ class Dependency: self.raw_link_args = None self.sources = [] self.methods = self._process_method_kw(kwargs) + self.is_system = self._process_is_system_kw(kwargs) self.ext_deps = [] # type: List[Dependency] def __repr__(self): @@ -124,7 +133,21 @@ class Dependency: return s.format(self.__class__.__name__, self.name, self.is_found) def get_compile_args(self): - return self.compile_args + if not self.is_system: + return self.compile_args + + system_args = [] + for i in self.compile_args: + if i.startswith('-I') or i.startswith('/I'): + # -isystem and -idirafter, both mark directories as system + # directories. However, both affect the search oder, which + # can lead to nasty bugs with -isystem: + # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70129 + system_args += ['-idirafter' + i[2:]] + else: + system_args += [i] + + return system_args def get_link_args(self, raw=False): if raw and self.raw_link_args is not None: @@ -152,6 +175,9 @@ class Dependency: else: return 'unknown' + def get_is_system(self) -> bool: + return self.is_system + def get_exe_args(self, compiler): return [] diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 0aa4b37..adb854e 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -34,13 +34,12 @@ from .interpreterbase import ObjectHolder from .modules import ModuleReturnValue from .cmake import CMakeInterpreter -from pathlib import Path +from pathlib import Path, PurePath import os, shutil, uuid -import re, shlex +import re, shlex, copy import subprocess from collections import namedtuple from itertools import chain -from pathlib import PurePath import functools from typing import Sequence, List, Union, Optional, Dict, Any @@ -413,6 +412,8 @@ class DependencyHolder(InterpreterObject, ObjectHolder): 'get_configtool_variable': self.configtool_method, 'get_variable': self.variable_method, 'partial_dependency': self.partial_dependency_method, + 'is_system': self.is_system_method, + 'as_system': self.as_system_method, }) def found(self): @@ -474,6 +475,27 @@ class DependencyHolder(InterpreterObject, ObjectHolder): def variable_method(self, args, kwargs): return self.held_object.get_variable(**kwargs) + @FeatureNew('dep.is_system', '0.52.0') + @noPosargs + @permittedKwargs({}) + def is_system_method(self, args, kwargs): + return self.held_object.get_is_system() + + @FeatureNew('dep.as_system', '0.52.0') + @permittedKwargs({}) + def as_system_method(self, args, kwargs): + args = listify(args) + new_is_system = True + if len(args) > 1: + raise InterpreterException('as_system takes only one optional value') + if len(args) == 1: + if not isinstance(args[0], bool): + raise InterpreterException('as_system takes only a boolean value') + new_is_system = args[0] + new_dep = copy.deepcopy(self.held_object) + new_dep.is_system = new_is_system + return DependencyHolder(new_dep, self.subproject) + class ExternalProgramHolder(InterpreterObject, ObjectHolder): def __init__(self, ep): InterpreterObject.__init__(self) @@ -1998,6 +2020,7 @@ permitted_kwargs = {'add_global_arguments': {'language', 'native'}, 'version', 'private_headers', 'cmake_args', + 'is_system', }, 'declare_dependency': {'include_directories', 'link_with', @@ -3049,6 +3072,7 @@ external dependencies (including libraries) must go to "dependencies".''') elif name == 'openmp': FeatureNew('OpenMP Dependency', '0.46.0').use(self.subproject) + @FeatureNewKwargs('dependency', '0.52.0', ['is_system']) @FeatureNewKwargs('dependency', '0.50.0', ['not_found_message', 'cmake_module_path', 'cmake_args']) @FeatureNewKwargs('dependency', '0.49.0', ['disabler']) @FeatureNewKwargs('dependency', '0.40.0', ['method']) -- cgit v1.1 From c6938bd57997c6e5af57d0a58a6753f0ef4ca1d6 Mon Sep 17 00:00:00 2001 From: Daniel Mensinger Date: Tue, 24 Sep 2019 22:51:30 +0200 Subject: Handle -idirafter in unix_args_to_native --- mesonbuild/compilers/d.py | 9 ++++++++- mesonbuild/compilers/mixins/visualstudio.py | 12 ++++++++++++ mesonbuild/dependencies/base.py | 2 +- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py index 5e0c173..346f18e 100644 --- a/mesonbuild/compilers/d.py +++ b/mesonbuild/compilers/d.py @@ -285,7 +285,14 @@ class DmdLikeCompilerMixin: if arg.startswith('-isystem='): dcargs.append('-I=' + arg[9:]) else: - dcargs.append('-I') + dcargs.append('-I' + arg[8:]) + continue + elif arg.startswith('-idirafter'): + # same as -isystem, but appends the path instead + if arg.startswith('-idirafter='): + dcargs.append('-I=' + arg[11:]) + else: + dcargs.append('-I' + arg[10:]) continue elif arg.startswith('-L/') or arg.startswith('-L./'): # we need to handle cases where -L is set by e.g. a pkg-config diff --git a/mesonbuild/compilers/mixins/visualstudio.py b/mesonbuild/compilers/mixins/visualstudio.py index 48a2229..9fddbb4 100644 --- a/mesonbuild/compilers/mixins/visualstudio.py +++ b/mesonbuild/compilers/mixins/visualstudio.py @@ -228,6 +228,18 @@ class VisualStudioLikeCompiler(metaclass=abc.ABCMeta): continue else: i = name + '.lib' + elif i.startswith('-isystem'): + # just use /I for -isystem system include path s + if i.startswith('-isystem='): + i = '/I' + i[9:] + else: + i = '/I' + i[8:] + elif i.startswith('-idirafter'): + # same as -isystem, but appends the path instead + if i.startswith('-idirafter='): + i = '/I' + i[11:] + else: + i = '/I' + i[10:] # -pthread in link flags is only used on Linux elif i == '-pthread': continue diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index e5cb4bf..cbf9c44 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -105,7 +105,7 @@ class Dependency: return methods @classmethod - def _process_is_system_kw(cls, kwargs): + def _process_is_system_kw(cls, kwargs): if 'is_system' not in kwargs: return False if not isinstance(kwargs['is_system'], bool): -- cgit v1.1 From 942f145de9744b2ffce0c01e153b18a6ea471b9d Mon Sep 17 00:00:00 2001 From: Daniel Mensinger Date: Tue, 24 Sep 2019 23:12:01 +0200 Subject: added docs --- docs/markdown/Reference-manual.md | 11 +++++++++++ docs/markdown/snippets/is_system.md | 9 +++++++++ 2 files changed, 20 insertions(+) create mode 100644 docs/markdown/snippets/is_system.md diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index 176cde4..25c803d 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -461,6 +461,10 @@ arguments: You can also specify multiple restrictions by passing a list to this keyword argument, such as: `['>=3.14.0', '<=4.1.0']`. These requirements are never met if the version is unknown. +- `is_system` *(added 0.52.0)* is a boolean flag, marking the dependency + as a system dependency. System dependencies may be handled differently + on some platforms, for instance using `-isystem` instead of `-I`, where + possible. The default value is `false`. - other [library-specific](Dependencies.md#dependencies-with-custom-lookup-functionality) keywords may also be accepted (e.g. `modules` specifies submodules to use for @@ -2224,6 +2228,13 @@ an external dependency with the following methods: `unknown` if the dependency provider doesn't support determining the version. + - `is_system()` returns whether the dependency object was marked as a + system dependency + + - `as_system(value)` returns a copy of the dependency object, which has changed + the value of `is_system` to `value`. The `value` argument is optional and + defaults to `true`. + - `partial_dependency(compile_args : false, link_args : false, links : false, includes : false, source : false)` *(Added 0.46.0)* returns a new dependency object with the same name, version, found status, diff --git a/docs/markdown/snippets/is_system.md b/docs/markdown/snippets/is_system.md new file mode 100644 index 0000000..cb1da0a --- /dev/null +++ b/docs/markdown/snippets/is_system.md @@ -0,0 +1,9 @@ +## Added `is_system` kwarg to `dependency` + +Similar to `include_directories()`, the `dependency()` function now +also has a `is_system` kwarg. If it is enabled, all include directories +of the dependency are marked as system dependencies. + +Additionally, it is also possible to check and change the `is_system` +state of an existing dependency object with the new `is_system()` and +`as_system()` methods. -- cgit v1.1 From 061deec9939b35d0e0707e07fc1e9e762f419457 Mon Sep 17 00:00:00 2001 From: Daniel Mensinger Date: Tue, 24 Sep 2019 23:28:34 +0200 Subject: added test case for is_system dependency --- .../common/226 is_system dependency/meson.build | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 test cases/common/226 is_system dependency/meson.build diff --git a/test cases/common/226 is_system dependency/meson.build b/test cases/common/226 is_system dependency/meson.build new file mode 100644 index 0000000..e96cd0a --- /dev/null +++ b/test cases/common/226 is_system dependency/meson.build @@ -0,0 +1,20 @@ +project( + 'dependency is_system', + ['c', 'cpp'], +) + +dep = dependency('zlib', method: 'pkg-config', required : false) +if not dep.found() + error('MESON_SKIP_TEST zlib was not found') +endif + +assert(dep.is_system() == false, 'is_system must default to false') + +dep_sys = dep.as_system() +assert(dep_sys.is_system() == true, 'as_system must default to true') + +dep2 = dependency('zlib', method: 'pkg-config', is_system : true) +assert(dep2.is_system() == true, 'is_system must be true when set') + +dep2_sys = dep2.as_system(false) +assert(dep2_sys.is_system() == false, 'as_system must set is_system correctly') -- cgit v1.1 From a7c4682be1e379ba655b7ea25e68d73f1605d62d Mon Sep 17 00:00:00 2001 From: Daniel Mensinger Date: Tue, 24 Sep 2019 23:58:29 +0200 Subject: Also add support for declare_dependency objects --- mesonbuild/build.py | 4 +++- test cases/common/226 is_system dependency/meson.build | 7 +++++++ .../common/226 is_system dependency/subprojects/subDep/meson.build | 3 +++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 test cases/common/226 is_system dependency/subprojects/subDep/meson.build diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 0c3d982..e9b2a4a 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -1150,7 +1150,7 @@ You probably should put it in link_with instead.''') raise MesonException('File %s does not exist.' % f) self.pch[language] = pchlist - def add_include_dirs(self, args): + def add_include_dirs(self, args, set_is_system: typing.Optional[bool] = None): ids = [] for a in args: # FIXME same hack, forcibly unpack from holder. @@ -1159,6 +1159,8 @@ You probably should put it in link_with instead.''') if not isinstance(a, IncludeDirs): raise InvalidArguments('Include directory to be added is not an include directory object.') ids.append(a) + if set_is_system is not None: + ids = [IncludeDirs(x.get_curdir(), x.get_incdirs(), set_is_system, x.get_extra_build_dirs()) for x in ids] self.include_dirs += ids def add_compiler_args(self, language, args): diff --git a/test cases/common/226 is_system dependency/meson.build b/test cases/common/226 is_system dependency/meson.build index e96cd0a..a3f60d2 100644 --- a/test cases/common/226 is_system dependency/meson.build +++ b/test cases/common/226 is_system dependency/meson.build @@ -18,3 +18,10 @@ assert(dep2.is_system() == true, 'is_system must be true when set') dep2_sys = dep2.as_system(false) assert(dep2_sys.is_system() == false, 'as_system must set is_system correctly') + +sp = subproject('subDep') +sp_dep = sp.get_variable('subDep_dep') +assert(sp_dep.is_system() == false, 'default is false') + +sp_dep_sys = sp_dep.as_system(true) +assert(sp_dep_sys.is_system() == true, 'changing is_system works') diff --git a/test cases/common/226 is_system dependency/subprojects/subDep/meson.build b/test cases/common/226 is_system dependency/subprojects/subDep/meson.build new file mode 100644 index 0000000..c3e87c4 --- /dev/null +++ b/test cases/common/226 is_system dependency/subprojects/subDep/meson.build @@ -0,0 +1,3 @@ +project('subDep', ['cpp']) + +subDep_dep = declare_dependency(compile_args : []) -- cgit v1.1 From b1b8a7a7e356297741c3c8e5996928ff244578c8 Mon Sep 17 00:00:00 2001 From: Daniel Mensinger Date: Sun, 29 Sep 2019 20:37:11 +0200 Subject: Use -isystem instead of -idirafter --- mesonbuild/compilers/compilers.py | 18 +++++++++++++++++- mesonbuild/dependencies/base.py | 6 +----- run_unittests.py | 16 ++++++++++++++++ 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 2c9508b..5fb58ac 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -420,7 +420,7 @@ class CompilerArgs(list): # Arg prefixes that override by prepending instead of appending prepend_prefixes = ('-I', '-L') # Arg prefixes and args that must be de-duped by returning 2 - dedup2_prefixes = ('-I', '-L', '-D', '-U') + dedup2_prefixes = ('-I', '-isystem', '-L', '-D', '-U') dedup2_suffixes = () dedup2_args = () # Arg prefixes and args that must be de-duped by returning 1 @@ -548,6 +548,22 @@ class CompilerArgs(list): # Last occurrence of a library new.insert(group_end + 1, '-Wl,--end-group') new.insert(group_start, '-Wl,--start-group') + # Remove system/default include paths added with -isystem + if hasattr(self.compiler, 'get_default_include_dirs'): + default_dirs = self.compiler.get_default_include_dirs() + bad_idx_list = [] + for i, each in enumerate(new): + # Remove the -isystem and the path if the path is a dafault path + if (each == '-isystem' and + i < (len(new) - 1) and + new[i + 1] in default_dirs): + bad_idx_list += [i, i + 1] + elif each.startswith('-isystem=') and each[9:] in default_dirs: + bad_idx_list += [i] + elif each.startswith('-isystem') and each[8:] in default_dirs: + bad_idx_list += [i] + for i in reversed(bad_idx_list): + new.pop(i) return self.compiler.unix_args_to_native(new) def append_direct(self, arg): diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index cbf9c44..5584fbc 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -139,11 +139,7 @@ class Dependency: system_args = [] for i in self.compile_args: if i.startswith('-I') or i.startswith('/I'): - # -isystem and -idirafter, both mark directories as system - # directories. However, both affect the search oder, which - # can lead to nasty bugs with -isystem: - # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70129 - system_args += ['-idirafter' + i[2:]] + system_args += ['-isystem' + i[2:]] else: system_args += [i] diff --git a/run_unittests.py b/run_unittests.py index d6c81a1..bfd7a54 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -447,6 +447,8 @@ class InternalTests(unittest.TestCase): ## Test --start/end-group linker = mesonbuild.linkers.GnuDynamicLinker([], MachineChoice.HOST, 'fake', '-Wl,') gcc = mesonbuild.compilers.GnuCCompiler([], 'fake', mesonbuild.compilers.CompilerType.GCC_STANDARD, False, MachineChoice.HOST, linker=linker) + ## Ensure that the fake compiler is never called by overriding the relevant function + gcc.get_default_include_dirs = lambda: ['/usr/include', '/usr/share/include', '/usr/local/include'] ## Test that 'direct' append and extend works l = cargsfunc(gcc, ['-Lfoodir', '-lfoo']) self.assertEqual(l.to_native(copy=True), ['-Lfoodir', '-Wl,--start-group', '-lfoo', '-Wl,--end-group']) @@ -469,6 +471,20 @@ class InternalTests(unittest.TestCase): l.append('-Wl,-ldl') self.assertEqual(l.to_native(copy=True), ['-Lfoo', '-Lfoodir', '-Wl,--start-group', '-lfoo', '-Lbardir', '-lbar', '-lbar', '/libbaz.a', '-Wl,--export-dynamic', '-Wl,-ldl', '-Wl,--end-group']) + def test_compiler_args_remove_system(self): + cargsfunc = mesonbuild.compilers.CompilerArgs + ## Test --start/end-group + linker = mesonbuild.linkers.GnuDynamicLinker([], MachineChoice.HOST, 'fake', '-Wl,') + gcc = mesonbuild.compilers.GnuCCompiler([], 'fake', mesonbuild.compilers.CompilerType.GCC_STANDARD, False, MachineChoice.HOST, linker=linker) + ## Ensure that the fake compiler is never called by overriding the relevant function + gcc.get_default_include_dirs = lambda: ['/usr/include', '/usr/share/include', '/usr/local/include'] + ## Test that 'direct' append and extend works + l = cargsfunc(gcc, ['-Lfoodir', '-lfoo']) + self.assertEqual(l.to_native(copy=True), ['-Lfoodir', '-Wl,--start-group', '-lfoo', '-Wl,--end-group']) + ## Test that to_native removes all system includes + l += ['-isystem/usr/include', '-isystem=/usr/share/include', '-DSOMETHING_IMPORTANT=1', '-isystem', '/usr/local/include'] + self.assertEqual(l.to_native(copy=True), ['-Lfoodir', '-Wl,--start-group', '-lfoo', '-Wl,--end-group', '-DSOMETHING_IMPORTANT=1']) + def test_string_templates_substitution(self): dictfunc = mesonbuild.mesonlib.get_filenames_templates_dict substfunc = mesonbuild.mesonlib.substitute_values -- cgit v1.1 From e5c720ff607cdf3101de031ff3a36f434d77b0d1 Mon Sep 17 00:00:00 2001 From: Daniel Mensinger Date: Sun, 29 Sep 2019 20:43:22 +0200 Subject: Move generate_system_dependency to Dependency --- mesonbuild/dependencies/base.py | 4 ++++ mesonbuild/interpreter.py | 5 ++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 5584fbc..1ccc343 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -222,6 +222,10 @@ class Dependency: return default_value raise DependencyException('No default provided for dependency {!r}, which is not pkg-config, cmake, or config-tool based.'.format(self)) + def generate_system_dependency(self, is_system: bool) -> typing.Type['Dependency']: + new_dep = copy.deepcopy(self) + new_dep.is_system = is_system + return new_dep class InternalDependency(Dependency): def __init__(self, version, incdirs, compile_args, link_args, libraries, whole_libraries, sources, ext_deps): diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index adb854e..eb0eaf7 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -36,7 +36,7 @@ from .cmake import CMakeInterpreter from pathlib import Path, PurePath import os, shutil, uuid -import re, shlex, copy +import re, shlex import subprocess from collections import namedtuple from itertools import chain @@ -492,8 +492,7 @@ class DependencyHolder(InterpreterObject, ObjectHolder): if not isinstance(args[0], bool): raise InterpreterException('as_system takes only a boolean value') new_is_system = args[0] - new_dep = copy.deepcopy(self.held_object) - new_dep.is_system = new_is_system + new_dep = self.held_object.generate_system_dependency(new_is_system) return DependencyHolder(new_dep, self.subproject) class ExternalProgramHolder(InterpreterObject, ObjectHolder): -- cgit v1.1 From 73d52266b5cf8e6b62d715328f0c66b1734c3026 Mon Sep 17 00:00:00 2001 From: Daniel Mensinger Date: Sun, 29 Sep 2019 21:27:05 +0200 Subject: Use include_type instead of is_system --- docs/markdown/Reference-manual.md | 17 +++---- docs/markdown/snippets/force_system.md | 11 +++++ docs/markdown/snippets/is_system.md | 9 ---- mesonbuild/build.py | 11 +++-- mesonbuild/dependencies/base.py | 52 +++++++++++++--------- mesonbuild/interpreter.py | 16 +++---- .../subprojects/foo-1.0/foo.c | 3 ++ .../subprojects/foo-1.0/meson.build | 2 + .../common/226 include_type dependency/meson.build | 27 +++++++++++ .../subprojects/subDep/meson.build | 3 ++ .../common/226 is_system dependency/meson.build | 27 ----------- .../subprojects/subDep/meson.build | 3 -- 12 files changed, 99 insertions(+), 82 deletions(-) create mode 100644 docs/markdown/snippets/force_system.md delete mode 100644 docs/markdown/snippets/is_system.md create mode 100644 test cases/common/157 wrap file should not failed/subprojects/foo-1.0/foo.c create mode 100644 test cases/common/157 wrap file should not failed/subprojects/foo-1.0/meson.build create mode 100644 test cases/common/226 include_type dependency/meson.build create mode 100644 test cases/common/226 include_type dependency/subprojects/subDep/meson.build delete mode 100644 test cases/common/226 is_system dependency/meson.build delete mode 100644 test cases/common/226 is_system dependency/subprojects/subDep/meson.build diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index 25c803d..c50a611 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -461,10 +461,12 @@ arguments: You can also specify multiple restrictions by passing a list to this keyword argument, such as: `['>=3.14.0', '<=4.1.0']`. These requirements are never met if the version is unknown. -- `is_system` *(added 0.52.0)* is a boolean flag, marking the dependency - as a system dependency. System dependencies may be handled differently - on some platforms, for instance using `-isystem` instead of `-I`, where - possible. The default value is `false`. +- `include_type` *(added 0.52.0)* is an enum flag, marking how the dependency + flags should be converted. Supported values are `'preserve'`, `'system'` and + `'non-system'`. System dependencies may be handled differently on some + platforms, for instance, using `-isystem` instead of `-I`, where possible. + If `include_type` is set to `'preserve'`, no additional conversion will be + performed. The default value is `'preserve'`. - other [library-specific](Dependencies.md#dependencies-with-custom-lookup-functionality) keywords may also be accepted (e.g. `modules` specifies submodules to use for @@ -2228,12 +2230,11 @@ an external dependency with the following methods: `unknown` if the dependency provider doesn't support determining the version. - - `is_system()` returns whether the dependency object was marked as a - system dependency + - `include_type()` returns whether the value set by the `include_type` kwarg - `as_system(value)` returns a copy of the dependency object, which has changed - the value of `is_system` to `value`. The `value` argument is optional and - defaults to `true`. + the value of `include_type` to `value`. The `value` argument is optional and + defaults to `'preserve'`. - `partial_dependency(compile_args : false, link_args : false, links : false, includes : false, source : false)` *(Added 0.46.0)* returns diff --git a/docs/markdown/snippets/force_system.md b/docs/markdown/snippets/force_system.md new file mode 100644 index 0000000..fd983e0 --- /dev/null +++ b/docs/markdown/snippets/force_system.md @@ -0,0 +1,11 @@ +## Added `include_type` kwarg to `dependency` + +The `dependency()` function now has a `include_type` kwarg. It can take the +values `'preserve'`, `'system'` and `'non-system'`. If it is set to `'system'`, +all include directories of the dependency are marked as system dependencies. + +The default value of `include_type` is `'preserve'`. + +Additionally, it is also possible to check and change the `include_type` +state of an existing dependency object with the new `include_type()` and +`as_system()` methods. diff --git a/docs/markdown/snippets/is_system.md b/docs/markdown/snippets/is_system.md deleted file mode 100644 index cb1da0a..0000000 --- a/docs/markdown/snippets/is_system.md +++ /dev/null @@ -1,9 +0,0 @@ -## Added `is_system` kwarg to `dependency` - -Similar to `include_directories()`, the `dependency()` function now -also has a `is_system` kwarg. If it is enabled, all include directories -of the dependency are marked as system dependencies. - -Additionally, it is also possible to check and change the `is_system` -state of an existing dependency object with the new `is_system()` and -`as_system()` methods. diff --git a/mesonbuild/build.py b/mesonbuild/build.py index e9b2a4a..267bd16 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -1024,7 +1024,7 @@ This will become a hard error in a future Meson release.''') if isinstance(dep, dependencies.InternalDependency): # Those parts that are internal. self.process_sourcelist(dep.sources) - self.add_include_dirs(dep.include_directories) + self.add_include_dirs(dep.include_directories, dep.get_include_type()) for l in dep.libraries: self.link(l) for l in dep.whole_libraries: @@ -1150,7 +1150,7 @@ You probably should put it in link_with instead.''') raise MesonException('File %s does not exist.' % f) self.pch[language] = pchlist - def add_include_dirs(self, args, set_is_system: typing.Optional[bool] = None): + def add_include_dirs(self, args, set_is_system: typing.Optional[str] = None): ids = [] for a in args: # FIXME same hack, forcibly unpack from holder. @@ -1159,8 +1159,11 @@ You probably should put it in link_with instead.''') if not isinstance(a, IncludeDirs): raise InvalidArguments('Include directory to be added is not an include directory object.') ids.append(a) - if set_is_system is not None: - ids = [IncludeDirs(x.get_curdir(), x.get_incdirs(), set_is_system, x.get_extra_build_dirs()) for x in ids] + if set_is_system is None: + set_is_system = 'preserve' + if set_is_system != 'preserve': + is_system = set_is_system == 'system' + ids = [IncludeDirs(x.get_curdir(), x.get_incdirs(), is_system, x.get_extra_build_dirs()) for x in ids] self.include_dirs += ids def add_compiler_args(self, language, args): diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 1ccc343..3c55a56 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -105,12 +105,14 @@ class Dependency: return methods @classmethod - def _process_is_system_kw(cls, kwargs): - if 'is_system' not in kwargs: - return False - if not isinstance(kwargs['is_system'], bool): - raise DependencyException('The is_system kwarg must be a boolean type') - return kwargs['is_system'] + def _process_include_type_kw(cls, kwargs) -> str: + if 'include_type' not in kwargs: + return 'preserve' + if not isinstance(kwargs['include_type'], str): + raise DependencyException('The include_type kwarg must be a string type') + if kwargs['include_type'] not in ['preserve', 'system', 'non-system']: + raise DependencyException("include_type may only be one of ['preserve', 'system', 'non-system']") + return kwargs['include_type'] def __init__(self, type_name, kwargs): self.name = "null" @@ -125,7 +127,7 @@ class Dependency: self.raw_link_args = None self.sources = [] self.methods = self._process_method_kw(kwargs) - self.is_system = self._process_is_system_kw(kwargs) + self.include_type = self._process_include_type_kw(kwargs) self.ext_deps = [] # type: List[Dependency] def __repr__(self): @@ -133,17 +135,23 @@ class Dependency: return s.format(self.__class__.__name__, self.name, self.is_found) def get_compile_args(self): - if not self.is_system: - return self.compile_args - - system_args = [] - for i in self.compile_args: - if i.startswith('-I') or i.startswith('/I'): - system_args += ['-isystem' + i[2:]] - else: - system_args += [i] - - return system_args + if self.include_type == 'system': + converted = [] + for i in self.compile_args: + if i.startswith('-I') or i.startswith('/I'): + converted += ['-isystem' + i[2:]] + else: + converted += [i] + return converted + if self.include_type == 'non-system': + converted = [] + for i in self.compile_args: + if i.startswith('-isystem'): + converted += ['-I' + i[8:]] + else: + converted += [i] + return converted + return self.compile_args def get_link_args(self, raw=False): if raw and self.raw_link_args is not None: @@ -171,8 +179,8 @@ class Dependency: else: return 'unknown' - def get_is_system(self) -> bool: - return self.is_system + def get_include_type(self) -> str: + return self.include_type def get_exe_args(self, compiler): return [] @@ -222,9 +230,9 @@ class Dependency: return default_value raise DependencyException('No default provided for dependency {!r}, which is not pkg-config, cmake, or config-tool based.'.format(self)) - def generate_system_dependency(self, is_system: bool) -> typing.Type['Dependency']: + def generate_system_dependency(self, include_type: str) -> typing.Type['Dependency']: new_dep = copy.deepcopy(self) - new_dep.is_system = is_system + new_dep.include_type = self._process_include_type_kw({'include_type': include_type}) return new_dep class InternalDependency(Dependency): diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index eb0eaf7..eae5a16 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -412,7 +412,7 @@ class DependencyHolder(InterpreterObject, ObjectHolder): 'get_configtool_variable': self.configtool_method, 'get_variable': self.variable_method, 'partial_dependency': self.partial_dependency_method, - 'is_system': self.is_system_method, + 'include_type': self.include_type_method, 'as_system': self.as_system_method, }) @@ -475,22 +475,20 @@ class DependencyHolder(InterpreterObject, ObjectHolder): def variable_method(self, args, kwargs): return self.held_object.get_variable(**kwargs) - @FeatureNew('dep.is_system', '0.52.0') + @FeatureNew('dep.include_type', '0.52.0') @noPosargs @permittedKwargs({}) - def is_system_method(self, args, kwargs): - return self.held_object.get_is_system() + def include_type_method(self, args, kwargs): + return self.held_object.get_include_type() @FeatureNew('dep.as_system', '0.52.0') @permittedKwargs({}) def as_system_method(self, args, kwargs): args = listify(args) - new_is_system = True + new_is_system = 'system' if len(args) > 1: raise InterpreterException('as_system takes only one optional value') if len(args) == 1: - if not isinstance(args[0], bool): - raise InterpreterException('as_system takes only a boolean value') new_is_system = args[0] new_dep = self.held_object.generate_system_dependency(new_is_system) return DependencyHolder(new_dep, self.subproject) @@ -2019,7 +2017,7 @@ permitted_kwargs = {'add_global_arguments': {'language', 'native'}, 'version', 'private_headers', 'cmake_args', - 'is_system', + 'include_type', }, 'declare_dependency': {'include_directories', 'link_with', @@ -3071,7 +3069,7 @@ external dependencies (including libraries) must go to "dependencies".''') elif name == 'openmp': FeatureNew('OpenMP Dependency', '0.46.0').use(self.subproject) - @FeatureNewKwargs('dependency', '0.52.0', ['is_system']) + @FeatureNewKwargs('dependency', '0.52.0', ['include_type']) @FeatureNewKwargs('dependency', '0.50.0', ['not_found_message', 'cmake_module_path', 'cmake_args']) @FeatureNewKwargs('dependency', '0.49.0', ['disabler']) @FeatureNewKwargs('dependency', '0.40.0', ['method']) diff --git a/test cases/common/157 wrap file should not failed/subprojects/foo-1.0/foo.c b/test cases/common/157 wrap file should not failed/subprojects/foo-1.0/foo.c new file mode 100644 index 0000000..019f2ba --- /dev/null +++ b/test cases/common/157 wrap file should not failed/subprojects/foo-1.0/foo.c @@ -0,0 +1,3 @@ +int dummy_func() { + return 42; +} diff --git a/test cases/common/157 wrap file should not failed/subprojects/foo-1.0/meson.build b/test cases/common/157 wrap file should not failed/subprojects/foo-1.0/meson.build new file mode 100644 index 0000000..318e81d --- /dev/null +++ b/test cases/common/157 wrap file should not failed/subprojects/foo-1.0/meson.build @@ -0,0 +1,2 @@ +project('shared lib', 'c') +libfoo = shared_library('foo', 'foo.c') diff --git a/test cases/common/226 include_type dependency/meson.build b/test cases/common/226 include_type dependency/meson.build new file mode 100644 index 0000000..eaac820 --- /dev/null +++ b/test cases/common/226 include_type dependency/meson.build @@ -0,0 +1,27 @@ +project( + 'dependency include_type', + ['c', 'cpp'], +) + +dep = dependency('zlib', method: 'pkg-config', required : false) +if not dep.found() + error('MESON_SKIP_TEST zlib was not found') +endif + +assert(dep.include_type() == 'preserve', 'include_type must default to "preserve"') + +dep_sys = dep.as_system() +assert(dep_sys.include_type() == 'system', 'as_system must return a system dep') + +dep2 = dependency('zlib', method: 'pkg-config', include_type : 'system') +assert(dep2.include_type() == 'system', 'include_type must be true when set') + +dep2_sys = dep2.as_system('non-system') +assert(dep2_sys.include_type() == 'non-system', 'as_system must set include_type correctly') + +sp = subproject('subDep') +sp_dep = sp.get_variable('subDep_dep') +assert(sp_dep.include_type() == 'preserve', 'default is preserve') + +sp_dep_sys = sp_dep.as_system('system') +assert(sp_dep_sys.include_type() == 'system', 'changing include_type works') diff --git a/test cases/common/226 include_type dependency/subprojects/subDep/meson.build b/test cases/common/226 include_type dependency/subprojects/subDep/meson.build new file mode 100644 index 0000000..c3e87c4 --- /dev/null +++ b/test cases/common/226 include_type dependency/subprojects/subDep/meson.build @@ -0,0 +1,3 @@ +project('subDep', ['cpp']) + +subDep_dep = declare_dependency(compile_args : []) diff --git a/test cases/common/226 is_system dependency/meson.build b/test cases/common/226 is_system dependency/meson.build deleted file mode 100644 index a3f60d2..0000000 --- a/test cases/common/226 is_system dependency/meson.build +++ /dev/null @@ -1,27 +0,0 @@ -project( - 'dependency is_system', - ['c', 'cpp'], -) - -dep = dependency('zlib', method: 'pkg-config', required : false) -if not dep.found() - error('MESON_SKIP_TEST zlib was not found') -endif - -assert(dep.is_system() == false, 'is_system must default to false') - -dep_sys = dep.as_system() -assert(dep_sys.is_system() == true, 'as_system must default to true') - -dep2 = dependency('zlib', method: 'pkg-config', is_system : true) -assert(dep2.is_system() == true, 'is_system must be true when set') - -dep2_sys = dep2.as_system(false) -assert(dep2_sys.is_system() == false, 'as_system must set is_system correctly') - -sp = subproject('subDep') -sp_dep = sp.get_variable('subDep_dep') -assert(sp_dep.is_system() == false, 'default is false') - -sp_dep_sys = sp_dep.as_system(true) -assert(sp_dep_sys.is_system() == true, 'changing is_system works') diff --git a/test cases/common/226 is_system dependency/subprojects/subDep/meson.build b/test cases/common/226 is_system dependency/subprojects/subDep/meson.build deleted file mode 100644 index c3e87c4..0000000 --- a/test cases/common/226 is_system dependency/subprojects/subDep/meson.build +++ /dev/null @@ -1,3 +0,0 @@ -project('subDep', ['cpp']) - -subDep_dep = declare_dependency(compile_args : []) -- cgit v1.1 From 66c129c52f8af07107c6a5f91853f44ab08525a2 Mon Sep 17 00:00:00 2001 From: Daniel Mensinger Date: Thu, 3 Oct 2019 17:02:44 +0200 Subject: cache all gnulike_default_include_dirs invocations --- mesonbuild/compilers/mixins/gnu.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/mesonbuild/compilers/mixins/gnu.py b/mesonbuild/compilers/mixins/gnu.py index 998b86c..f4ce5b9 100644 --- a/mesonbuild/compilers/mixins/gnu.py +++ b/mesonbuild/compilers/mixins/gnu.py @@ -84,14 +84,13 @@ gnu_color_args = { } # type: typing.Dict[str, typing.List[str]] -# TODO: The result from calling compiler should be cached. So that calling this -# function multiple times don't add latency. -def gnulike_default_include_dirs(compiler: typing.List[str], lang: str) -> typing.List[str]: +@functools.lru_cache(maxsize=None) +def gnulike_default_include_dirs(compiler: typing.Tuple[str], lang: str) -> typing.List[str]: if lang == 'cpp': lang = 'c++' env = os.environ.copy() env["LC_ALL"] = 'C' - cmd = compiler + ['-x{}'.format(lang), '-E', '-v', '-'] + cmd = list(compiler) + ['-x{}'.format(lang), '-E', '-v', '-'] p = subprocess.Popen( cmd, stdin=subprocess.DEVNULL, @@ -171,7 +170,7 @@ class GnuLikeCompiler(metaclass=abc.ABCMeta): return gnulike_instruction_set_args.get(instruction_set, None) def get_default_include_dirs(self) -> typing.List[str]: - return gnulike_default_include_dirs(self.exelist, self.language) + return gnulike_default_include_dirs(tuple(self.exelist), self.language) @abc.abstractmethod def openmp_flags(self) -> typing.List[str]: -- cgit v1.1 From 47e20b3004b41261c01b1a46898252924f031f1d Mon Sep 17 00:00:00 2001 From: Daniel Mensinger Date: Sun, 6 Oct 2019 14:23:12 +0200 Subject: Updated include_type test case --- test cases/common/226 include_type dependency/meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/test cases/common/226 include_type dependency/meson.build b/test cases/common/226 include_type dependency/meson.build index eaac820..fafceaf 100644 --- a/test cases/common/226 include_type dependency/meson.build +++ b/test cases/common/226 include_type dependency/meson.build @@ -25,3 +25,4 @@ assert(sp_dep.include_type() == 'preserve', 'default is preserve') sp_dep_sys = sp_dep.as_system('system') assert(sp_dep_sys.include_type() == 'system', 'changing include_type works') +assert(sp_dep.include_type() == 'preserve', 'as_system must not mutate the original object') -- cgit v1.1