Use include_directories for D impdirs.

Change the code to store D properties as plain data. Only convert them
to compiler flags in the backend. This also means we can fully parse D
arguments without needing to know the compiler being used.
pull/3139/head
Jussi Pakkanen 7 years ago
parent 8a68dc0179
commit ea3b54d402
  1. 3
      mesonbuild/backend/ninjabackend.py
  2. 10
      mesonbuild/build.py
  3. 14
      mesonbuild/compilers/d.py
  4. 38
      mesonbuild/interpreter.py
  5. 17
      test cases/d/9 features/meson.build

@ -2257,6 +2257,9 @@ rule FORTRAN_DEP_HACK
depelem.write(outfile) depelem.write(outfile)
commands += compiler.get_module_outdir_args(self.get_target_private_dir(target)) commands += compiler.get_module_outdir_args(self.get_target_private_dir(target))
if compiler.language == 'd':
commands += compiler.get_feature_args(target.d_features, self.build_to_src)
element = NinjaBuildElement(self.all_outputs, rel_obj, compiler_name, rel_src) element = NinjaBuildElement(self.all_outputs, rel_obj, compiler_name, rel_src)
for d in header_deps: for d in header_deps:
if isinstance(d, File): if isinstance(d, File):

@ -355,6 +355,7 @@ class BuildTarget(Target):
self.extra_args = {} self.extra_args = {}
self.generated = [] self.generated = []
self.extra_files = [] self.extra_files = []
self.d_features = {}
# Sources can be: # Sources can be:
# 1. Pre-existing source files in the source tree # 1. Pre-existing source files in the source tree
# 2. Pre-existing sources generated by configure_file in the build tree # 2. Pre-existing sources generated by configure_file in the build tree
@ -682,12 +683,15 @@ just like those detected with the dependency() function.''')
dfeature_versions = kwargs.get('d_module_versions', None) dfeature_versions = kwargs.get('d_module_versions', None)
if dfeature_versions: if dfeature_versions:
dfeatures['versions'] = dfeature_versions dfeatures['versions'] = dfeature_versions
dfeature_import_dirs = kwargs.get('d_import_dirs', None) if 'd_import_dirs' in kwargs:
if dfeature_import_dirs: dfeature_import_dirs = extract_as_list(kwargs, 'd_import_dirs', unholder=True)
for d in dfeature_import_dirs:
if not isinstance(d, IncludeDirs):
raise InvalidArguments('Arguments to d_import_dirs must be include_directories.')
dfeatures['import_dirs'] = dfeature_import_dirs dfeatures['import_dirs'] = dfeature_import_dirs
if dfeatures: if dfeatures:
if 'd' in self.compilers: if 'd' in self.compilers:
self.add_compiler_args('d', self.compilers['d'].get_feature_args(dfeatures)) self.d_features = dfeatures
self.link_args = extract_as_list(kwargs, 'link_args') self.link_args = extract_as_list(kwargs, 'link_args')
for i in self.link_args: for i in self.link_args:

@ -93,7 +93,7 @@ class DCompiler(Compiler):
# FIXME: Make this work for Windows, MacOS and cross-compiling # FIXME: Make this work for Windows, MacOS and cross-compiling
return get_gcc_soname_args(GCC_STANDARD, prefix, shlib_name, suffix, path, soversion, is_shared_module) return get_gcc_soname_args(GCC_STANDARD, prefix, shlib_name, suffix, path, soversion, is_shared_module)
def get_feature_args(self, kwargs): def get_feature_args(self, kwargs, build_to_src):
res = [] res = []
if 'unittest' in kwargs: if 'unittest' in kwargs:
unittest = kwargs.pop('unittest') unittest = kwargs.pop('unittest')
@ -122,8 +122,16 @@ class DCompiler(Compiler):
import_dir_arg = d_feature_args[self.id]['import_dir'] import_dir_arg = d_feature_args[self.id]['import_dir']
if not import_dir_arg: if not import_dir_arg:
raise EnvironmentException('D compiler %s does not support the "string import directories" feature.' % self.name_string()) raise EnvironmentException('D compiler %s does not support the "string import directories" feature.' % self.name_string())
for d in import_dirs: for idir_obj in import_dirs:
res.append('{0}{1}'.format(import_dir_arg, d)) basedir = idir_obj.get_curdir()
for idir in idir_obj.get_incdirs():
# Avoid superfluous '/.' at the end of paths when d is '.'
if idir not in ('', '.'):
expdir = os.path.join(basedir, idir)
else:
expdir = basedir
srctreedir = os.path.join(build_to_src, expdir)
res.append('{0}{1}'.format(import_dir_arg, srctreedir))
if kwargs: if kwargs:
raise EnvironmentException('Unknown D compiler feature(s) selected: %s' % ', '.join(kwargs.keys())) raise EnvironmentException('Unknown D compiler feature(s) selected: %s' % ', '.join(kwargs.keys()))

@ -37,6 +37,7 @@ from pathlib import PurePath
import importlib import importlib
def stringifyUserArguments(args): def stringifyUserArguments(args):
if isinstance(args, list): if isinstance(args, list):
return '[%s]' % ', '.join([stringifyUserArguments(x) for x in args]) return '[%s]' % ', '.join([stringifyUserArguments(x) for x in args])
@ -247,7 +248,7 @@ class ConfigurationDataHolder(MutableInterpreterObject, ObjectHolder):
return val return val
def get(self, name): def get(self, name):
return self.held_object.values[name] # (val, desc) return self.held_object.values[name] # (val, desc)
def keys(self): def keys(self):
return self.held_object.values.keys() return self.held_object.values.keys()
@ -816,7 +817,8 @@ class CompilerHolder(InterpreterObject):
''' '''
if not hasattr(self.compiler, 'get_feature_args'): if not hasattr(self.compiler, 'get_feature_args'):
raise InterpreterException('This {} compiler has no feature arguments.'.format(self.compiler.get_display_language())) raise InterpreterException('This {} compiler has no feature arguments.'.format(self.compiler.get_display_language()))
return self.compiler.get_feature_args({'unittest': 'true'}) build_to_src = os.path.relpath(self.environment.get_source_dir(), self.environment.get_build_dir())
return self.compiler.get_feature_args({'unittest': 'true'}, build_to_src)
def has_member_method(self, args, kwargs): def has_member_method(self, args, kwargs):
if len(args) != 2: if len(args) != 2:
@ -1309,6 +1311,7 @@ class MesonMain(InterpreterObject):
return args[1] return args[1]
raise InterpreterException('Unknown cross property: %s.' % propname) raise InterpreterException('Unknown cross property: %s.' % propname)
pch_kwargs = set(['c_pch', 'cpp_pch']) pch_kwargs = set(['c_pch', 'cpp_pch'])
lang_arg_kwargs = set([ lang_arg_kwargs = set([
@ -2847,12 +2850,17 @@ root and issuing %s.
@permittedKwargs(permitted_kwargs['include_directories']) @permittedKwargs(permitted_kwargs['include_directories'])
@stringArgs @stringArgs
def func_include_directories(self, node, args, kwargs): def func_include_directories(self, node, args, kwargs):
return self.build_incdir_object(args, kwargs.get('is_system', False))
def build_incdir_object(self, incdir_strings, is_system=False):
if not isinstance(is_system, bool):
raise InvalidArguments('Is_system must be boolean.')
src_root = self.environment.get_source_dir() src_root = self.environment.get_source_dir()
build_root = self.environment.get_build_dir() build_root = self.environment.get_build_dir()
absbase_src = os.path.join(src_root, self.subdir) absbase_src = os.path.join(src_root, self.subdir)
absbase_build = os.path.join(build_root, self.subdir) absbase_build = os.path.join(build_root, self.subdir)
for a in args: for a in incdir_strings:
if a.startswith(src_root): if a.startswith(src_root):
raise InvalidArguments('''Tried to form an absolute path to a source dir. You should not do that but use raise InvalidArguments('''Tried to form an absolute path to a source dir. You should not do that but use
relative paths instead. relative paths instead.
@ -2875,10 +2883,7 @@ different subdirectory.
absdir_build = os.path.join(absbase_build, a) absdir_build = os.path.join(absbase_build, a)
if not os.path.isdir(absdir_src) and not os.path.isdir(absdir_build): if not os.path.isdir(absdir_src) and not os.path.isdir(absdir_build):
raise InvalidArguments('Include dir %s does not exist.' % a) raise InvalidArguments('Include dir %s does not exist.' % a)
is_system = kwargs.get('is_system', False) i = IncludeDirsHolder(build.IncludeDirs(self.subdir, incdir_strings, is_system))
if not isinstance(is_system, bool):
raise InvalidArguments('Is_system must be boolean.')
i = IncludeDirsHolder(build.IncludeDirs(self.subdir, args, is_system))
return i return i
@permittedKwargs(permitted_kwargs['add_test_setup']) @permittedKwargs(permitted_kwargs['add_test_setup'])
@ -3106,6 +3111,7 @@ different subdirectory.
else: else:
mlog.debug('Unknown target type:', str(targetholder)) mlog.debug('Unknown target type:', str(targetholder))
raise RuntimeError('Unreachable code') raise RuntimeError('Unreachable code')
self.kwarg_strings_to_includedirs(kwargs)
target = targetclass(name, self.subdir, self.subproject, is_cross, sources, objs, self.environment, kwargs) target = targetclass(name, self.subdir, self.subproject, is_cross, sources, objs, self.environment, kwargs)
if is_cross: if is_cross:
self.add_cross_stdlib_info(target) self.add_cross_stdlib_info(target)
@ -3114,6 +3120,23 @@ different subdirectory.
self.project_args_frozen = True self.project_args_frozen = True
return l return l
def kwarg_strings_to_includedirs(self, kwargs):
if 'd_import_dirs' in kwargs:
items = mesonlib.extract_as_list(kwargs, 'd_import_dirs')
cleaned_items = []
for i in items:
if isinstance(i, str):
# BW compatibility. This was permitted so we must support it
# for a few releases so people can transition to "correct"
# path declarations.
if i.startswith(self.environment.get_source_dir()):
mlog.warning('''Building a path to the source dir is not supported. Use a relative path instead.
This will become a hard error in the future.''')
i = os.path.relpath(i, os.path.join(self.environment.get_source_dir(), self.subdir))
i = self.build_incdir_object([i])
cleaned_items.append(i)
kwargs['d_import_dirs'] = cleaned_items
def get_used_languages(self, target): def get_used_languages(self, target):
result = {} result = {}
for i in target.sources: for i in target.sources:
@ -3152,6 +3175,7 @@ different subdirectory.
if idx >= len(arg_strings): if idx >= len(arg_strings):
raise InterpreterException('Format placeholder @{}@ out of range.'.format(idx)) raise InterpreterException('Format placeholder @{}@ out of range.'.format(idx))
return arg_strings[idx] return arg_strings[idx]
return re.sub(r'@(\d+)@', arg_replace, templ) return re.sub(r'@(\d+)@', arg_replace, templ)
# Only permit object extraction from the same subproject # Only permit object extraction from the same subproject

@ -1,8 +1,22 @@
project('D Features', 'd') project('D Features', 'd')
# directory for data # ONLY FOR BACKWARDS COMPATIBILITY.
# DO NOT DO THIS IN NEW CODE!
# USE include_directories() INSTEAD OF BUILDING
# STRINGS TO PATHS MANUALLY!
data_dir = join_paths(meson.current_source_dir(), 'data') data_dir = join_paths(meson.current_source_dir(), 'data')
e_plain_bcompat = executable('dapp_menu_bcompat',
'app.d',
d_import_dirs: [data_dir]
)
test('dapp_menu_t_fail_bcompat', e_plain_bcompat, should_fail: true)
test('dapp_menu_t_bcompat', e_plain_bcompat, args: ['menu'])
# directory for data
# This is the correct way to do this.
data_dir = include_directories('data')
e_plain = executable('dapp_menu', e_plain = executable('dapp_menu',
'app.d', 'app.d',
d_import_dirs: [data_dir] d_import_dirs: [data_dir]
@ -10,6 +24,7 @@ e_plain = executable('dapp_menu',
test('dapp_menu_t_fail', e_plain, should_fail: true) test('dapp_menu_t_fail', e_plain, should_fail: true)
test('dapp_menu_t', e_plain, args: ['menu']) test('dapp_menu_t', e_plain, args: ['menu'])
# test feature versions and string imports # test feature versions and string imports
e_versions = executable('dapp_versions', e_versions = executable('dapp_versions',
'app.d', 'app.d',

Loading…
Cancel
Save