aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJussi Pakkanen <jpakkane@gmail.com>2019-10-06 17:33:12 +0300
committerGitHub <noreply@github.com>2019-10-06 17:33:12 +0300
commit51fef880b6a12e82955d5b93df7ffed0ae2f1478 (patch)
tree327575ae53cc7e25389ee6af1a02861c8296b9ad
parent5bbea6be05c9740aedcd7f170c24a6b2c098cd01 (diff)
parent47e20b3004b41261c01b1a46898252924f031f1d (diff)
downloadmeson-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.md12
-rw-r--r--docs/markdown/snippets/force_system.md11
-rw-r--r--mesonbuild/build.py15
-rw-r--r--mesonbuild/compilers/compilers.py18
-rw-r--r--mesonbuild/compilers/d.py9
-rw-r--r--mesonbuild/compilers/mixins/gnu.py9
-rw-r--r--mesonbuild/compilers/mixins/visualstudio.py12
-rw-r--r--mesonbuild/dependencies/base.py34
-rw-r--r--mesonbuild/interpreter.py25
-rwxr-xr-xrun_unittests.py16
-rw-r--r--test cases/common/157 wrap file should not failed/subprojects/foo-1.0/foo.c3
-rw-r--r--test cases/common/157 wrap file should not failed/subprojects/foo-1.0/meson.build2
-rw-r--r--test cases/common/226 include_type dependency/meson.build28
-rw-r--r--test cases/common/226 include_type dependency/subprojects/subDep/meson.build3
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 : [])