diff options
author | Jussi Pakkanen <jpakkane@gmail.com> | 2019-10-06 17:33:12 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-10-06 17:33:12 +0300 |
commit | 51fef880b6a12e82955d5b93df7ffed0ae2f1478 (patch) | |
tree | 327575ae53cc7e25389ee6af1a02861c8296b9ad | |
parent | 5bbea6be05c9740aedcd7f170c24a6b2c098cd01 (diff) | |
parent | 47e20b3004b41261c01b1a46898252924f031f1d (diff) | |
download | meson-51fef880b6a12e82955d5b93df7ffed0ae2f1478.zip meson-51fef880b6a12e82955d5b93df7ffed0ae2f1478.tar.gz meson-51fef880b6a12e82955d5b93df7ffed0ae2f1478.tar.bz2 |
Merge pull request #5953 from mensinda/isystem
Add is_system to dependency
-rw-r--r-- | docs/markdown/Reference-manual.md | 12 | ||||
-rw-r--r-- | docs/markdown/snippets/force_system.md | 11 | ||||
-rw-r--r-- | mesonbuild/build.py | 15 | ||||
-rw-r--r-- | mesonbuild/compilers/compilers.py | 18 | ||||
-rw-r--r-- | mesonbuild/compilers/d.py | 9 | ||||
-rw-r--r-- | mesonbuild/compilers/mixins/gnu.py | 9 | ||||
-rw-r--r-- | mesonbuild/compilers/mixins/visualstudio.py | 12 | ||||
-rw-r--r-- | mesonbuild/dependencies/base.py | 34 | ||||
-rw-r--r-- | mesonbuild/interpreter.py | 25 | ||||
-rwxr-xr-x | run_unittests.py | 16 | ||||
-rw-r--r-- | test cases/common/157 wrap file should not failed/subprojects/foo-1.0/foo.c | 3 | ||||
-rw-r--r-- | test cases/common/157 wrap file should not failed/subprojects/foo-1.0/meson.build | 2 | ||||
-rw-r--r-- | test cases/common/226 include_type dependency/meson.build | 28 | ||||
-rw-r--r-- | test cases/common/226 include_type dependency/subprojects/subDep/meson.build | 3 |
14 files changed, 183 insertions, 14 deletions
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index cd87646..862c60a 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -464,6 +464,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. +- `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 @@ -2227,6 +2233,12 @@ an external dependency with the following methods: `unknown` if the dependency provider doesn't support determining the version. + - `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 `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 a new dependency object with the same name, version, found status, 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/mesonbuild/build.py b/mesonbuild/build.py index 4ec742d..267bd16 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -1024,17 +1024,17 @@ 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: 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. @@ -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[str] = None): ids = [] for a in args: # FIXME same hack, forcibly unpack from holder. @@ -1159,6 +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 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/compilers/compilers.py b/mesonbuild/compilers/compilers.py index b79fa41..ac74fc3 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/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/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]: 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 4e95c94..3c55a56 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -104,6 +104,16 @@ class Dependency: return methods + @classmethod + 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" self.version = None @@ -117,6 +127,7 @@ class Dependency: self.raw_link_args = None self.sources = [] self.methods = self._process_method_kw(kwargs) + self.include_type = self._process_include_type_kw(kwargs) self.ext_deps = [] # type: List[Dependency] def __repr__(self): @@ -124,6 +135,22 @@ class Dependency: return s.format(self.__class__.__name__, self.name, self.is_found) def get_compile_args(self): + 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): @@ -152,6 +179,9 @@ class Dependency: else: return 'unknown' + def get_include_type(self) -> str: + return self.include_type + def get_exe_args(self, compiler): return [] @@ -200,6 +230,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, include_type: str) -> typing.Type['Dependency']: + new_dep = copy.deepcopy(self) + new_dep.include_type = self._process_include_type_kw({'include_type': include_type}) + 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 ec7a7b2..1d76a1d 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 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, + 'include_type': self.include_type_method, + 'as_system': self.as_system_method, }) def found(self): @@ -474,6 +475,24 @@ class DependencyHolder(InterpreterObject, ObjectHolder): def variable_method(self, args, kwargs): return self.held_object.get_variable(**kwargs) + @FeatureNew('dep.include_type', '0.52.0') + @noPosargs + @permittedKwargs({}) + 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 = 'system' + if len(args) > 1: + raise InterpreterException('as_system takes only one optional value') + if len(args) == 1: + new_is_system = args[0] + new_dep = self.held_object.generate_system_dependency(new_is_system) + return DependencyHolder(new_dep, self.subproject) + class ExternalProgramHolder(InterpreterObject, ObjectHolder): def __init__(self, ep): InterpreterObject.__init__(self) @@ -2000,6 +2019,7 @@ permitted_kwargs = {'add_global_arguments': {'language', 'native'}, 'version', 'private_headers', 'cmake_args', + 'include_type', }, 'declare_dependency': {'include_directories', 'link_with', @@ -3050,6 +3070,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', ['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/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 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..fafceaf --- /dev/null +++ b/test cases/common/226 include_type dependency/meson.build @@ -0,0 +1,28 @@ +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') +assert(sp_dep.include_type() == 'preserve', 'as_system must not mutate the original object') 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 : []) |