Merge pull request #5953 from mensinda/isystem

Add is_system to dependency
pull/6001/head
Jussi Pakkanen 5 years ago committed by GitHub
commit 51fef880b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      docs/markdown/Reference-manual.md
  2. 11
      docs/markdown/snippets/force_system.md
  3. 15
      mesonbuild/build.py
  4. 18
      mesonbuild/compilers/compilers.py
  5. 9
      mesonbuild/compilers/d.py
  6. 9
      mesonbuild/compilers/mixins/gnu.py
  7. 12
      mesonbuild/compilers/mixins/visualstudio.py
  8. 34
      mesonbuild/dependencies/base.py
  9. 25
      mesonbuild/interpreter.py
  10. 16
      run_unittests.py
  11. 3
      test cases/common/157 wrap file should not failed/subprojects/foo-1.0/foo.c
  12. 2
      test cases/common/157 wrap file should not failed/subprojects/foo-1.0/meson.build
  13. 28
      test cases/common/226 include_type dependency/meson.build
  14. 3
      test cases/common/226 include_type dependency/subprojects/subDep/meson.build

@ -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,

@ -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.

@ -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):

@ -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):

@ -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

@ -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]:

@ -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

@ -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):

@ -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'])

@ -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

@ -0,0 +1,2 @@
project('shared lib', 'c')
libfoo = shared_library('foo', 'foo.c')

@ -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')

@ -0,0 +1,3 @@
project('subDep', ['cpp'])
subDep_dep = declare_dependency(compile_args : [])
Loading…
Cancel
Save