files: # Copyright 2012-2017 The Meson development team
  
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at
  
  #     http://www.apache.org/licenses/LICENSE-2.0
  
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  
  import os, pickle, re, shlex, subprocess, sys
  from collections import OrderedDict
  from pathlib import PurePath
  
  from . import backends
  from .. import modules
  from .. import environment, mesonlib
  from .. import build
  from .. import mlog
  from .. import dependencies
  from .. import compilers
  from ..compilers import CompilerArgs
  from ..linkers import ArLinker
  from ..mesonlib import File, MesonException, OrderedSet
  from ..mesonlib import get_compiler_for_source
  from .backends import CleanTrees, InstallData
  from ..build import InvalidArguments
  
  if mesonlib.is_windows():
      quote_func = lambda s: '"{}"'.format(s)
      execute_wrapper = 'cmd /c'
      rmfile_prefix = 'del /f /s /q {} &&'
  else:
      quote_func = shlex.quote
      execute_wrapper = ''
      rmfile_prefix = 'rm -f {} &&'
  
  def ninja_quote(text, is_build_line=False):
      if is_build_line:
          qcs = ('$', ' ', ':')
      else:
          qcs = ('$', ' ')
      for char in qcs:
          text = text.replace(char, '$' + char)
      if '\n' in text:
          errmsg = '''Ninja does not support newlines in rules. The content was:
  
  %s
  
  Please report this error with a test case to the Meson bug tracker.''' % text
          raise MesonException(errmsg)
      return text
  
  
  class NinjaBuildElement:
      def __init__(self, all_outputs, outfilenames, rule, infilenames):
          if isinstance(outfilenames, str):
              self.outfilenames = [outfilenames]
          else:
              self.outfilenames = outfilenames
          assert(isinstance(rule, str))
          self.rule = rule
          if isinstance(infilenames, str):
              self.infilenames = [infilenames]
          else:
              self.infilenames = infilenames
          self.deps = set()
          self.orderdeps = set()
          self.elems = []
          self.all_outputs = all_outputs
  
      def add_dep(self, dep):
          if isinstance(dep, list):
              self.deps.update(dep)
          else:
              self.deps.add(dep)
  
      def add_orderdep(self, dep):
          if isinstance(dep, list):
              self.orderdeps.update(dep)
          else:
              self.orderdeps.add(dep)
  
      def add_item(self, name, elems):
          if isinstance(elems, str):
              elems = [elems]
          self.elems.append((name, elems))
  
      def write(self, outfile):
          self.check_outputs()
          line = 'build %s: %s %s' % (' '.join([ninja_quote(i, True) for i in self.outfilenames]),
                                      self.rule,
                                      ' '.join([ninja_quote(i, True) for i in self.infilenames]))
          if len(self.deps) > 0:
              line += ' | ' + ' '.join([ninja_quote(x, True) for x in self.deps])
          if len(self.orderdeps) > 0:
              line += ' || ' + ' '.join([ninja_quote(x, True) for x in self.orderdeps])
          line += '\n'
          # This is the only way I could find to make this work on all
          # platforms including Windows command shell. Slash is a dir separator
          # on Windows, too, so all characters are unambiguous and, more importantly,
          # do not require quoting, unless explicitely specified, which is necessary for
          # the csc compiler.
          line = line.replace('\\', '/')
          outfile.write(line)
  
          # All the entries that should remain unquoted
          raw_names = {'DEPFILE', 'DESC', 'pool', 'description'}
  
          for e in self.elems:
              (name, elems) = e
              should_quote = name not in raw_names
              line = ' %s = ' % name
              noq_templ = "%s"
              newelems = []
              for i in elems:
                  if not should_quote or i == '&&': # Hackety hack hack
                      quoter = ninja_quote
                  else:
                      quoter = lambda x: ninja_quote(quote_func(x))
                  i = i.replace('\\', '\\\\')
                  if quote_func('') == '""':
                      i = i.replace('"', '\\"')
                  newelems.append(quoter(i))
              line += ' '.join(newelems)
              line += '\n'
              outfile.write(line)
          outfile.write('\n')
  
      def check_outputs(self):
          for n in self.outfilenames:
              if n in self.all_outputs:
                  raise MesonException('Multiple producers for Ninja target "%s". Please rename your targets.' % n)
              self.all_outputs[n] = True
  
  class NinjaBackend(backends.Backend):
  
      def __init__(self, build):
          super().__init__(build)
          self.name = 'ninja'
          self.ninja_filename = 'build.ninja'
          self.target_arg_cache = {}
          self.fortran_deps = {}
          self.all_outputs = {}
  
      def create_target_alias(self, to_target, outfile):
          # We need to use aliases for targets that might be used as directory
          # names to workaround a Ninja bug that breaks `ninja -t clean`.
          # This is used for 'reserved' targets such as 'test', 'install',
          # 'benchmark', etc, and also for RunTargets.
          # https://github.com/mesonbuild/meson/issues/1644
          if not to_target.startswith('meson-'):
              m = 'Invalid usage of create_target_alias with {!r}'
              raise AssertionError(m.format(to_target))
          from_target = to_target[len('meson-'):]
          elem = NinjaBuildElement(self.all_outputs, from_target, 'phony', to_target)
          elem.write(outfile)
  
      def detect_vs_dep_prefix(self, tempfilename):
          '''VS writes its dependency in a locale dependent format.
          Detect the search prefix to use.'''
          for compiler in self.build.compilers.values():
              # Have to detect the dependency format
              if compiler.id == 'msvc':
                  break
          else:
              # None of our compilers are MSVC, we're done.
              return open(tempfilename, 'a')
          filename = os.path.join(self
  
  [... the rest is omitted ...]
files: mesonbuild/backend/ninjabackend.py
files: # Copyright 2012-2017 The Meson development team
  
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at
  
  #     http://www.apache.org/licenses/LICENSE-2.0
  
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  
  import os, pickle, re, shlex, subprocess, sys
  from collections import OrderedDict
  from pathlib import PurePath
  
  from . import backends
  from .. import modules
  from .. import environment, mesonlib
  from .. import build
  from .. import mlog
  from .. import dependencies
  from .. import compilers
  from ..compilers import CompilerArgs
  from ..linkers import ArLinker
  from ..mesonlib import File, MesonException, OrderedSet
  from ..mesonlib import get_compiler_for_source
  from .backends import CleanTrees, InstallData
  from ..build import InvalidArguments
  
  if mesonlib.is_windows():
      quote_func = lambda s: '"{}"'.format(s)
      execute_wrapper = 'cmd /c'
      rmfile_prefix = 'del /f /s /q {} &&'
  else:
      quote_func = shlex.quote
      execute_wrapper = ''
      rmfile_prefix = 'rm -f {} &&'
  
  def ninja_quote(text, is_build_line=False):
      if is_build_line:
          qcs = ('$', ' ', ':')
      else:
          qcs = ('$', ' ')
      for char in qcs:
          text = text.replace(char, '$' + char)
      if '\n' in text:
          errmsg = '''Ninja does not support newlines in rules. The content was:
  
  %s
  
  Please report this error with a test case to the Meson bug tracker.''' % text
          raise MesonException(errmsg)
      return text
  
  
  class NinjaBuildElement:
      def __init__(self, all_outputs, outfilenames, rule, infilenames):
          if isinstance(outfilenames, str):
              self.outfilenames = [outfilenames]
          else:
              self.outfilenames = outfilenames
          assert(isinstance(rule, str))
          self.rule = rule
          if isinstance(infilenames, str):
              self.infilenames = [infilenames]
          else:
              self.infilenames = infilenames
          self.deps = set()
          self.orderdeps = set()
          self.elems = []
          self.all_outputs = all_outputs
  
      def add_dep(self, dep):
          if isinstance(dep, list):
              self.deps.update(dep)
          else:
              self.deps.add(dep)
  
      def add_orderdep(self, dep):
          if isinstance(dep, list):
              self.orderdeps.update(dep)
          else:
              self.orderdeps.add(dep)
  
      def add_item(self, name, elems):
          if isinstance(elems, str):
              elems = [elems]
          self.elems.append((name, elems))
  
      def write(self, outfile):
          self.check_outputs()
          line = 'build %s: %s %s' % (' '.join([ninja_quote(i, True) for i in self.outfilenames]),
                                      self.rule,
                                      ' '.join([ninja_quote(i, True) for i in self.infilenames]))
          if len(self.deps) > 0:
              line += ' | ' + ' '.join([ninja_quote(x, True) for x in self.deps])
          if len(self.orderdeps) > 0:
              line += ' || ' + ' '.join([ninja_quote(x, True) for x in self.orderdeps])
          line += '\n'
          # This is the only way I could find to make this work on all
          # platforms including Windows command shell. Slash is a dir separator
          # on Windows, too, so all characters are unambiguous and, more importantly,
          # do not require quoting, unless explicitely specified, which is necessary for
          # the csc compiler.
          line = line.replace('\\', '/')
          outfile.write(line)
  
          # All the entries that should remain unquoted
          raw_names = {'DEPFILE', 'DESC', 'pool', 'description'}
  
          for e in self.elems:
              (name, elems) = e
              should_quote = name not in raw_names
              line = ' %s = ' % name
              noq_templ = "%s"
              newelems = []
              for i in elems:
                  if not should_quote or i == '&&': # Hackety hack hack
                      quoter = ninja_quote
                  else:
                      quoter = lambda x: ninja_quote(quote_func(x))
                  i = i.replace('\\', '\\\\')
                  if quote_func('') == '""':
                      i = i.replace('"', '\\"')
                  newelems.append(quoter(i))
              line += ' '.join(newelems)
              line += '\n'
              outfile.write(line)
          outfile.write('\n')
  
      def check_outputs(self):
          for n in self.outfilenames:
              if n in self.all_outputs:
                  raise MesonException('Multiple producers for Ninja target "%s". Please rename your targets.' % n)
              self.all_outputs[n] = True
  
  class NinjaBackend(backends.Backend):
  
      def __init__(self, build):
          super().__init__(build)
          self.name = 'ninja'
          self.ninja_filename = 'build.ninja'
          self.target_arg_cache = {}
          self.fortran_deps = {}
          self.all_outputs = {}
  
      def create_target_alias(self, to_target, outfile):
          # We need to use aliases for targets that might be used as directory
          # names to workaround a Ninja bug that breaks `ninja -t clean`.
          # This is used for 'reserved' targets such as 'test', 'install',
          # 'benchmark', etc, and also for RunTargets.
          # https://github.com/mesonbuild/meson/issues/1644
          if not to_target.startswith('meson-'):
              m = 'Invalid usage of create_target_alias with {!r}'
              raise AssertionError(m.format(to_target))
          from_target = to_target[len('meson-'):]
          elem = NinjaBuildElement(self.all_outputs, from_target, 'phony', to_target)
          elem.write(outfile)
  
      def detect_vs_dep_prefix(self, tempfilename):
          '''VS writes its dependency in a locale dependent format.
          Detect the search prefix to use.'''
          for compiler in self.build.compilers.values():
              # Have to detect the dependency format
              if compiler.id == 'msvc':
                  break
          else:
              # None of our compilers are MSVC, we're done.
              return open(tempfilename, 'a')
          filename = os.path.join(self
  
  [... the rest is omitted ...]
files: mesonbuild/backend/ninjabackend.py
files: # Copyright 2012-2017 The Meson development team
  
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at
  
  #     http://www.apache.org/licenses/LICENSE-2.0
  
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  
  import copy, os, re
  from collections import OrderedDict
  import itertools, pathlib
  
  from . import environment
  from . import dependencies
  from . import mlog
  from .mesonlib import File, MesonException, listify, extract_as_list
  from .mesonlib import typeslistify, stringlistify, classify_unity_sources
  from .mesonlib import get_filenames_templates_dict, substitute_values
  from .mesonlib import for_windows, for_darwin, for_cygwin, for_android
  from .compilers import is_object, clike_langs, sort_clike, lang_suffixes
  
  known_basic_kwargs = {'install': True,
                        'c_pch': True,
                        'cpp_pch': True,
                        'c_args': True,
                        'objc_args': True,
                        'objcpp_args': True,
                        'cpp_args': True,
                        'cs_args': True,
                        'vala_args': True,
                        'fortran_args': True,
                        'd_args': True,
                        'd_import_dirs': True,
                        'd_unittest': True,
                        'd_module_versions': True,
                        'java_args': True,
                        'rust_args': True,
                        'link_args': True,
                        'link_depends': True,
                        'link_with': True,
                        'link_whole': True,
                        'implicit_include_directories': True,
                        'include_directories': True,
                        'dependencies': True,
                        'install_dir': True,
                        'main_class': True,
                        'name_suffix': True,
                        'gui_app': True,
                        'extra_files': True,
                        'install_rpath': True,
                        'build_rpath': True,
                        'resources': True,
                        'sources': True,
                        'objects': True,
                        'native': True,
                        'build_by_default': True,
                        'override_options': True,
                        }
  
  # These contain kwargs supported by both static and shared libraries. These are
  # combined here because a library() call might be shared_library() or
  # static_library() at runtime based on the configuration.
  # FIXME: Find a way to pass that info down here so we can have proper target
  # kwargs checking when specifically using shared_library() or static_library().
  known_lib_kwargs = known_basic_kwargs.copy()
  known_lib_kwargs.update({'version': True, # Only for shared libs
                           'soversion': True, # Only for shared libs
                           'name_prefix': True,
                           'vs_module_defs': True, # Only for shared libs
                           'vala_header': True,
                           'vala_vapi': True,
                           'vala_gir': True,
                           'pic': True, # Only for static libs
                           'rust_crate_type': True, # Only for Rust libs
                           })
  
  known_exe_kwargs = known_basic_kwargs.copy()
  known_exe_kwargs.update({'implib': True,
                           'export_dynamic': True
                           })
  
  class InvalidArguments(MesonException):
      pass
  
  class Build:
      """A class that holds the status of one build including
      all dependencies and so on.
      """
  
      def __init__(self, environment):
          self.project_name = 'name of master project'
          self.project_version = None
          self.environment = environment
          self.projects = {}
          self.targets = OrderedDict()
          self.compilers = OrderedDict()
          self.cross_compilers = OrderedDict()
          self.global_args = {}
          self.projects_args = {}
          self.global_link_args = {}
          self.projects_link_args = {}
          self.tests = []
          self.benchmarks = []
          self.headers = []
          self.man = []
          self.data = []
          self.static_linker = None
          self.static_cross_linker = None
          self.subprojects = {}
          self.install_scripts = []
          self.postconf_scripts = []
          self.install_dirs = []
          self.dep_manifest_name = None
          self.dep_manifest = {}
          self.cross_stdlibs = {}
          self.test_setups = {}
  
      def add_compiler(self, compiler):
          if self.static_linker is None and compiler.needs_static_linker():
              self.static_linker = self.environment.detect_static_linker(compiler)
          lang = compiler.get_language()
          if lang not in self.compilers:
              self.compilers[lang] = compiler
  
      def add_cross_compiler(self, compiler):
          if not self.cross_compilers:
              self.static_cross_linker = self.environment.detect_static_linker(compiler)
          lang = compiler.get_language()
          if lang not in self.cross_compilers:
              self.cross_compilers[lang] = compiler
  
      def get_project(self):
          return self.projects['']
  
      def get_targets(self):
          return self.targets
  
      def get_tests(self):
          return self.tests
  
      def get_benchmarks(self):
          return self.benchmarks
  
      def get_headers(self):
          return self.headers
  
      def get_man(self):
          return self.man
  
      def get_data(self):
          return self.data
  
      def get_install_subdirs(self):
          return self.install_dirs
  
      def get_global_args(self, compiler):
          return self.global_args.get(compiler.get_language(), [])
  
      def get_project_args(self, compiler, project):
          args = self.projects_args.get(project)
          if not args:
              return []
          return args.get(compiler.get_language(), [])
  
      def get_global_link_args(self, compiler):
          return self.global_link_args.get(compiler.get_language(), [])
  
      def get_project_link_args(self, compiler, project):
          link_args = self.projects_link_args.get(project)
          if not link_args:
              return []
  
          return link_args.get(compiler.get_language(), [])
  
  class IncludeDirs:
      def __init__(self, curdir, dirs, is_system, extra_build_dirs=None):
          self.curdir = curdir
          self.incdirs = dirs
          self.is_system = is_system
          # Interpreter has validated that all given directories
          # actually exist.
          if extra_build_dirs is None:
              self.extra_build_dirs = []
          else:
              self.extra_build_dirs = extra_build_dirs
  
      def __repr__(self):
          r = '<{} {}/{}>'
          return r.format(self.__class__.__name__, self.curdir, self.incdirs)
  
  
  
  [... the rest is omitted ...]
files: mesonbuild/build.py
files: # Copyright 2012-2017 The Meson development team
  
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at
  
  #     http://www.apache.org/licenses/LICENSE-2.0
  
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  
  import copy, os, re
  from collections import OrderedDict
  import itertools, pathlib
  
  from . import environment
  from . import dependencies
  from . import mlog
  from .mesonlib import File, MesonException, listify, extract_as_list
  from .mesonlib import typeslistify, stringlistify, classify_unity_sources
  from .mesonlib import get_filenames_templates_dict, substitute_values
  from .mesonlib import for_windows, for_darwin, for_cygwin, for_android
  from .compilers import is_object, clike_langs, sort_clike, lang_suffixes
  
  known_basic_kwargs = {'install': True,
                        'c_pch': True,
                        'cpp_pch': True,
                        'c_args': True,
                        'objc_args': True,
                        'objcpp_args': True,
                        'cpp_args': True,
                        'cs_args': True,
                        'vala_args': True,
                        'fortran_args': True,
                        'd_args': True,
                        'd_import_dirs': True,
                        'd_unittest': True,
                        'd_module_versions': True,
                        'java_args': True,
                        'rust_args': True,
                        'link_args': True,
                        'link_depends': True,
                        'link_with': True,
                        'link_whole': True,
                        'implicit_include_directories': True,
                        'include_directories': True,
                        'dependencies': True,
                        'install_dir': True,
                        'main_class': True,
                        'name_suffix': True,
                        'gui_app': True,
                        'extra_files': True,
                        'install_rpath': True,
                        'build_rpath': True,
                        'resources': True,
                        'sources': True,
                        'objects': True,
                        'native': True,
                        'build_by_default': True,
                        'override_options': True,
                        }
  
  # These contain kwargs supported by both static and shared libraries. These are
  # combined here because a library() call might be shared_library() or
  # static_library() at runtime based on the configuration.
  # FIXME: Find a way to pass that info down here so we can have proper target
  # kwargs checking when specifically using shared_library() or static_library().
  known_lib_kwargs = known_basic_kwargs.copy()
  known_lib_kwargs.update({'version': True, # Only for shared libs
                           'soversion': True, # Only for shared libs
                           'name_prefix': True,
                           'vs_module_defs': True, # Only for shared libs
                           'vala_header': True,
                           'vala_vapi': True,
                           'vala_gir': True,
                           'pic': True, # Only for static libs
                           'rust_crate_type': True, # Only for Rust libs
                           })
  
  known_exe_kwargs = known_basic_kwargs.copy()
  known_exe_kwargs.update({'implib': True,
                           'export_dynamic': True
                           })
  
  class InvalidArguments(MesonException):
      pass
  
  class Build:
      """A class that holds the status of one build including
      all dependencies and so on.
      """
  
      def __init__(self, environment):
          self.project_name = 'name of master project'
          self.project_version = None
          self.environment = environment
          self.projects = {}
          self.targets = OrderedDict()
          self.compilers = OrderedDict()
          self.cross_compilers = OrderedDict()
          self.global_args = {}
          self.projects_args = {}
          self.global_link_args = {}
          self.projects_link_args = {}
          self.tests = []
          self.benchmarks = []
          self.headers = []
          self.man = []
          self.data = []
          self.static_linker = None
          self.static_cross_linker = None
          self.subprojects = {}
          self.install_scripts = []
          self.postconf_scripts = []
          self.install_dirs = []
          self.dep_manifest_name = None
          self.dep_manifest = {}
          self.cross_stdlibs = {}
          self.test_setups = {}
  
      def add_compiler(self, compiler):
          if self.static_linker is None and compiler.needs_static_linker():
              self.static_linker = self.environment.detect_static_linker(compiler)
          lang = compiler.get_language()
          if lang not in self.compilers:
              self.compilers[lang] = compiler
  
      def add_cross_compiler(self, compiler):
          if not self.cross_compilers:
              self.static_cross_linker = self.environment.detect_static_linker(compiler)
          lang = compiler.get_language()
          if lang not in self.cross_compilers:
              self.cross_compilers[lang] = compiler
  
      def get_project(self):
          return self.projects['']
  
      def get_targets(self):
          return self.targets
  
      def get_tests(self):
          return self.tests
  
      def get_benchmarks(self):
          return self.benchmarks
  
      def get_headers(self):
          return self.headers
  
      def get_man(self):
          return self.man
  
      def get_data(self):
          return self.data
  
      def get_install_subdirs(self):
          return self.install_dirs
  
      def get_global_args(self, compiler):
          return self.global_args.get(compiler.get_language(), [])
  
      def get_project_args(self, compiler, project):
          args = self.projects_args.get(project)
          if not args:
              return []
          return args.get(compiler.get_language(), [])
  
      def get_global_link_args(self, compiler):
          return self.global_link_args.get(compiler.get_language(), [])
  
      def get_project_link_args(self, compiler, project):
          link_args = self.projects_link_args.get(project)
          if not link_args:
              return []
  
          return link_args.get(compiler.get_language(), [])
  
  class IncludeDirs:
      def __init__(self, curdir, dirs, is_system, extra_build_dirs=None):
          self.curdir = curdir
          self.incdirs = dirs
          self.is_system = is_system
          # Interpreter has validated that all given directories
          # actually exist.
          if extra_build_dirs is None:
              self.extra_build_dirs = []
          else:
              self.extra_build_dirs = extra_build_dirs
  
      def __repr__(self):
          r = '<{} {}/{}>'
          return r.format(self.__class__.__name__, self.curdir, self.incdirs)
  
  
  
  [... the rest is omitted ...]
files: mesonbuild/build.py
files: # Copyright 2012-2017 The Meson development team
  
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at
  
  #     http://www.apache.org/licenses/LICENSE-2.0
  
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  
  import os.path, subprocess
  
  from ..mesonlib import EnvironmentException, version_compare
  
  from .compilers import (
      GCC_STANDARD,
      d_dmd_buildtype_args,
      d_gdc_buildtype_args,
      d_ldc_buildtype_args,
      get_gcc_soname_args,
      gnu_color_args,
      Compiler,
      CompilerArgs,
  )
  
  d_feature_args = {'gcc':  {'unittest': '-funittest',
                             'version': '-fversion',
                             'import_dir': '-J'
                             },
                    'llvm': {'unittest': '-unittest',
                             'version': '-d-version',
                             'import_dir': '-J'
                             },
                    'dmd':  {'unittest': '-unittest',
                             'version': '-version',
                             'import_dir': '-J'
                             }
                    }
  
  class DCompiler(Compiler):
      def __init__(self, exelist, version, is_cross, **kwargs):
          self.language = 'd'
          super().__init__(exelist, version, **kwargs)
          self.id = 'unknown'
          self.is_cross = is_cross
  
      def sanity_check(self, work_dir, environment):
          source_name = os.path.join(work_dir, 'sanity.d')
          output_name = os.path.join(work_dir, 'dtest')
          with open(source_name, 'w') as ofile:
              ofile.write('''void main() {
  }
  ''')
          pc = subprocess.Popen(self.exelist + self.get_output_args(output_name) + [source_name], cwd=work_dir)
          pc.wait()
          if pc.returncode != 0:
              raise EnvironmentException('D compiler %s can not compile programs.' % self.name_string())
          if subprocess.call(output_name) != 0:
              raise EnvironmentException('Executables created by D compiler %s are not runnable.' % self.name_string())
  
      def needs_static_linker(self):
          return True
  
      def name_string(self):
          return ' '.join(self.exelist)
  
      def get_linker_exelist(self):
          return self.exelist[:]
  
      def get_preprocess_only_args(self):
          return ['-E']
  
      def get_compile_only_args(self):
          return ['-c']
  
      def depfile_for_object(self, objfile):
          return objfile + '.' + self.get_depfile_suffix()
  
      def get_depfile_suffix(self):
          return 'deps'
  
      def get_pic_args(self):
          return ['-fPIC']
  
      def get_std_shared_lib_link_args(self):
          return ['-shared']
  
      def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, is_shared_module):
          # 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)
  
      def get_feature_args(self, kwargs, build_to_src):
          res = []
          if 'unittest' in kwargs:
              unittest = kwargs.pop('unittest')
              unittest_arg = d_feature_args[self.id]['unittest']
              if not unittest_arg:
                  raise EnvironmentException('D compiler %s does not support the "unittest" feature.' % self.name_string())
              if unittest:
                  res.append(unittest_arg)
  
          if 'versions' in kwargs:
              versions = kwargs.pop('versions')
              if not isinstance(versions, list):
                  versions = [versions]
  
              version_arg = d_feature_args[self.id]['version']
              if not version_arg:
                  raise EnvironmentException('D compiler %s does not support the "feature versions" feature.' % self.name_string())
              for v in versions:
                  res.append('{0}={1}'.format(version_arg, v))
  
          if 'import_dirs' in kwargs:
              import_dirs = kwargs.pop('import_dirs')
              if not isinstance(import_dirs, list):
                  import_dirs = [import_dirs]
  
              import_dir_arg = d_feature_args[self.id]['import_dir']
              if not import_dir_arg:
                  raise EnvironmentException('D compiler %s does not support the "string import directories" feature.' % self.name_string())
              for idir_obj in import_dirs:
                  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:
              raise EnvironmentException('Unknown D compiler feature(s) selected: %s' % ', '.join(kwargs.keys()))
  
          return res
  
      def get_buildtype_linker_args(self, buildtype):
          return []
  
      def get_std_exe_link_args(self):
          return []
  
      def build_rpath_args(self, build_dir, from_dir, rpath_paths, build_rpath, install_rpath):
          # This method is to be used by LDC and DMD.
          # GDC can deal with the verbatim flags.
          if not rpath_paths and not install_rpath:
              return []
          paths = ':'.join([os.path.join(build_dir, p) for p in rpath_paths])
          if build_rpath != '':
              paths += ':' + build_rpath
          if len(paths) < len(install_rpath):
              padding = 'X' * (len(install_rpath) - len(paths))
              if not paths:
                  paths = padding
              else:
                  paths = paths + ':' + padding
          return ['-L-rpath={}'.format(paths)]
  
      def _get_compiler_check_args(self, env, extra_args, dependencies, mode='compile'):
          if extra_args is None:
              extra_args = []
          elif isinstance(extra_args, str):
              extra_args = [extra_args]
          if dependencies is None:
              dependencies = []
          elif not isinstance(dependencies, list):
              dependencies = [dependencies]
          # Collect compiler arguments
          args = CompilerArgs(self)
          for d in dependencies:
              # Add compile flags needed by dependencies
              args += d.get_compile_args()
              if mode == 'link':
                  # Add link flags needed to find dependencies
                  args += d.get_link_args()
  
          if mode == 'compile':
              # Add DFLAGS from the env
              args += env.coredata.ex
  
  [... the rest is omitted ...]
files: mesonbuild/compilers/d.py
files: # Copyright 2012-2017 The Meson development team
  
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at
  
  #     http://www.apache.org/licenses/LICENSE-2.0
  
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  
  import os.path, subprocess
  
  from ..mesonlib import EnvironmentException, version_compare
  
  from .compilers import (
      GCC_STANDARD,
      d_dmd_buildtype_args,
      d_gdc_buildtype_args,
      d_ldc_buildtype_args,
      get_gcc_soname_args,
      gnu_color_args,
      Compiler,
      CompilerArgs,
  )
  
  d_feature_args = {'gcc':  {'unittest': '-funittest',
                             'version': '-fversion',
                             'import_dir': '-J'
                             },
                    'llvm': {'unittest': '-unittest',
                             'version': '-d-version',
                             'import_dir': '-J'
                             },
                    'dmd':  {'unittest': '-unittest',
                             'version': '-version',
                             'import_dir': '-J'
                             }
                    }
  
  class DCompiler(Compiler):
      def __init__(self, exelist, version, is_cross, **kwargs):
          self.language = 'd'
          super().__init__(exelist, version, **kwargs)
          self.id = 'unknown'
          self.is_cross = is_cross
  
      def sanity_check(self, work_dir, environment):
          source_name = os.path.join(work_dir, 'sanity.d')
          output_name = os.path.join(work_dir, 'dtest')
          with open(source_name, 'w') as ofile:
              ofile.write('''void main() {
  }
  ''')
          pc = subprocess.Popen(self.exelist + self.get_output_args(output_name) + [source_name], cwd=work_dir)
          pc.wait()
          if pc.returncode != 0:
              raise EnvironmentException('D compiler %s can not compile programs.' % self.name_string())
          if subprocess.call(output_name) != 0:
              raise EnvironmentException('Executables created by D compiler %s are not runnable.' % self.name_string())
  
      def needs_static_linker(self):
          return True
  
      def name_string(self):
          return ' '.join(self.exelist)
  
      def get_linker_exelist(self):
          return self.exelist[:]
  
      def get_preprocess_only_args(self):
          return ['-E']
  
      def get_compile_only_args(self):
          return ['-c']
  
      def depfile_for_object(self, objfile):
          return objfile + '.' + self.get_depfile_suffix()
  
      def get_depfile_suffix(self):
          return 'deps'
  
      def get_pic_args(self):
          return ['-fPIC']
  
      def get_std_shared_lib_link_args(self):
          return ['-shared']
  
      def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, is_shared_module):
          # 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)
  
      def get_feature_args(self, kwargs):
          res = []
          if 'unittest' in kwargs:
              unittest = kwargs.pop('unittest')
              unittest_arg = d_feature_args[self.id]['unittest']
              if not unittest_arg:
                  raise EnvironmentException('D compiler %s does not support the "unittest" feature.' % self.name_string())
              if unittest:
                  res.append(unittest_arg)
  
          if 'versions' in kwargs:
              versions = kwargs.pop('versions')
              if not isinstance(versions, list):
                  versions = [versions]
  
              version_arg = d_feature_args[self.id]['version']
              if not version_arg:
                  raise EnvironmentException('D compiler %s does not support the "feature versions" feature.' % self.name_string())
              for v in versions:
                  res.append('{0}={1}'.format(version_arg, v))
  
          if 'import_dirs' in kwargs:
              import_dirs = kwargs.pop('import_dirs')
              if not isinstance(import_dirs, list):
                  import_dirs = [import_dirs]
  
              import_dir_arg = d_feature_args[self.id]['import_dir']
              if not import_dir_arg:
                  raise EnvironmentException('D compiler %s does not support the "string import directories" feature.' % self.name_string())
              for d in import_dirs:
                  res.append('{0}{1}'.format(import_dir_arg, d))
  
          if kwargs:
              raise EnvironmentException('Unknown D compiler feature(s) selected: %s' % ', '.join(kwargs.keys()))
  
          return res
  
      def get_buildtype_linker_args(self, buildtype):
          return []
  
      def get_std_exe_link_args(self):
          return []
  
      def build_rpath_args(self, build_dir, from_dir, rpath_paths, build_rpath, install_rpath):
          # This method is to be used by LDC and DMD.
          # GDC can deal with the verbatim flags.
          if not rpath_paths and not install_rpath:
              return []
          paths = ':'.join([os.path.join(build_dir, p) for p in rpath_paths])
          if build_rpath != '':
              paths += ':' + build_rpath
          if len(paths) < len(install_rpath):
              padding = 'X' * (len(install_rpath) - len(paths))
              if not paths:
                  paths = padding
              else:
                  paths = paths + ':' + padding
          return ['-L-rpath={}'.format(paths)]
  
      def _get_compiler_check_args(self, env, extra_args, dependencies, mode='compile'):
          if extra_args is None:
              extra_args = []
          elif isinstance(extra_args, str):
              extra_args = [extra_args]
          if dependencies is None:
              dependencies = []
          elif not isinstance(dependencies, list):
              dependencies = [dependencies]
          # Collect compiler arguments
          args = CompilerArgs(self)
          for d in dependencies:
              # Add compile flags needed by dependencies
              args += d.get_compile_args()
              if mode == 'link':
                  # Add link flags needed to find dependencies
                  args += d.get_link_args()
  
          if mode == 'compile':
              # Add DFLAGS from the env
              args += env.coredata.external_args[self.language]
          elif mode == 'link':
              # Add LDFLAGS from the env
              args += env.coredata.external_link_args[self.language]
          # extra_args must override all other arguments, so we add them last
          args += extra_args
          return args
  
      def compiles(self, code, env, extra_args=None, dependencies=None, mode='compile'):
          args = self._get_compiler_check_args(env, extra_args, dependencies,
  
  [... the rest is omitted ...]
files: mesonbuild/compilers/d.py
files: # Copyright 2012-2018 The Meson development team
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at
  
  #     http://www.apache.org/licenses/LICENSE-2.0
  
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  
  from . import mparser
  from . import environment
  from . import coredata
  from . import dependencies
  from . import mlog
  from . import build
  from . import optinterpreter
  from . import compilers
  from .wrap import wrap, WrapMode
  from . import mesonlib
  from .mesonlib import FileMode, Popen_safe, listify, extract_as_list
  from .dependencies import ExternalProgram
  from .dependencies import InternalDependency, Dependency, DependencyException
  from .interpreterbase import InterpreterBase
  from .interpreterbase import check_stringlist, noPosargs, noKwargs, stringArgs, permittedKwargs
  from .interpreterbase import InterpreterException, InvalidArguments, InvalidCode
  from .interpreterbase import InterpreterObject, MutableInterpreterObject, Disabler
  from .modules import ModuleReturnValue
  
  import os, sys, shutil, uuid
  import re, shlex
  from collections import namedtuple
  from pathlib import PurePath
  
  import importlib
  
  
  def stringifyUserArguments(args):
      if isinstance(args, list):
          return '[%s]' % ', '.join([stringifyUserArguments(x) for x in args])
      elif isinstance(args, int):
          return str(args)
      elif isinstance(args, str):
          return "'%s'" % args
      raise InvalidArguments('Function accepts only strings, integers, lists and lists thereof.')
  
  
  class ObjectHolder:
      def __init__(self, obj):
          self.held_object = obj
  
      def __repr__(self):
          return '<Holder: {!r}>'.format(self.held_object)
  
  
  class TryRunResultHolder(InterpreterObject):
      def __init__(self, res):
          super().__init__()
          self.res = res
          self.methods.update({'returncode': self.returncode_method,
                               'compiled': self.compiled_method,
                               'stdout': self.stdout_method,
                               'stderr': self.stderr_method,
                               })
  
      def returncode_method(self, args, kwargs):
          return self.res.returncode
  
      def compiled_method(self, args, kwargs):
          return self.res.compiled
  
      def stdout_method(self, args, kwargs):
          return self.res.stdout
  
      def stderr_method(self, args, kwargs):
          return self.res.stderr
  
  class RunProcess(InterpreterObject):
  
      def __init__(self, cmd, args, source_dir, build_dir, subdir, mesonintrospect, in_builddir=False):
          super().__init__()
          if not isinstance(cmd, ExternalProgram):
              raise AssertionError('BUG: RunProcess must be passed an ExternalProgram')
          pc, self.stdout, self.stderr = self.run_command(cmd, args, source_dir, build_dir, subdir, mesonintrospect, in_builddir)
          self.returncode = pc.returncode
          self.methods.update({'returncode': self.returncode_method,
                               'stdout': self.stdout_method,
                               'stderr': self.stderr_method,
                               })
  
      def run_command(self, cmd, args, source_dir, build_dir, subdir, mesonintrospect, in_builddir):
          command_array = cmd.get_command() + args
          env = {'MESON_SOURCE_ROOT': source_dir,
                 'MESON_BUILD_ROOT': build_dir,
                 'MESON_SUBDIR': subdir,
                 'MESONINTROSPECT': ' '.join([shlex.quote(x) for x in mesonintrospect]),
                 }
          if in_builddir:
              cwd = os.path.join(build_dir, subdir)
          else:
              cwd = os.path.join(source_dir, subdir)
          child_env = os.environ.copy()
          child_env.update(env)
          mlog.debug('Running command:', ' '.join(command_array))
          try:
              p, o, e = Popen_safe(command_array, env=child_env, cwd=cwd)
              mlog.debug('--- stdout----')
              mlog.debug(o)
              mlog.debug('----stderr----')
              mlog.debug(e)
              mlog.debug('')
              return p, o, e
          except FileNotFoundError:
              raise InterpreterException('Could not execute command "%s".' % ' '.join(command_array))
  
      def returncode_method(self, args, kwargs):
          return self.returncode
  
      def stdout_method(self, args, kwargs):
          return self.stdout
  
      def stderr_method(self, args, kwargs):
          return self.stderr
  
  class ConfigureFileHolder(InterpreterObject, ObjectHolder):
  
      def __init__(self, subdir, sourcename, targetname, configuration_data):
          InterpreterObject.__init__(self)
          ObjectHolder.__init__(self, build.ConfigureFile(subdir, sourcename,
                                                          targetname, configuration_data))
  
  
  class EnvironmentVariablesHolder(MutableInterpreterObject, ObjectHolder):
      def __init__(self):
          MutableInterpreterObject.__init__(self)
          ObjectHolder.__init__(self, build.EnvironmentVariables())
          self.methods.update({'set': self.set_method,
                               'append': self.append_method,
                               'prepend': self.prepend_method,
                               })
  
      def __repr__(self):
          repr_str = "<{0}: {1}>"
          return repr_str.format(self.__class__.__name__, self.held_object.envvars)
  
      @stringArgs
      def add_var(self, method, args, kwargs):
          if not isinstance(kwargs.get("separator", ""), str):
              raise InterpreterException("EnvironmentVariablesHolder methods 'separator'"
                                         " argument needs to be a string.")
          if len(args) < 2:
              raise InterpreterException("EnvironmentVariablesHolder methods require at least"
                                         "2 arguments, first is the name of the variable and"
                                         " following one are values")
          self.held_object.envvars.append((method, args[0], args[1:], kwargs))
  
      def set_method(self, args, kwargs):
          self.add_var(self.held_object.set, args, kwargs)
  
      def append_method(self, args, kwargs):
          self.add_var(self.held_object.append, args, kwargs)
  
      def prepend_method(self, args, kwargs):
          self.add_var(self.held_object.prepend, args, kwargs)
  
  
  class ConfigurationDataHolder(MutableInterpreterObject, ObjectHolder):
      def __init__(self):
          MutableInterpreterObject.__init__(self)
          self.used = False # These objects become immutable after use in configure_file.
          ObjectHolder.__init__(self, build.ConfigurationData())
          self.methods.update({'set': self.set_method,
                               'set10': self.set10_method,
                               'set_quoted': self.set_quoted_method,
                               'has': self.has_method,
                               'get': self.get_method,
                               'get_unqu
  
  [... the rest is omitted ...]
files: mesonbuild/interpreter.py
files: # Copyright 2012-2018 The Meson development team
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at
  
  #     http://www.apache.org/licenses/LICENSE-2.0
  
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  
  from . import mparser
  from . import environment
  from . import coredata
  from . import dependencies
  from . import mlog
  from . import build
  from . import optinterpreter
  from . import compilers
  from .wrap import wrap, WrapMode
  from . import mesonlib
  from .mesonlib import FileMode, Popen_safe, listify, extract_as_list
  from .dependencies import ExternalProgram
  from .dependencies import InternalDependency, Dependency, DependencyException
  from .interpreterbase import InterpreterBase
  from .interpreterbase import check_stringlist, noPosargs, noKwargs, stringArgs, permittedKwargs
  from .interpreterbase import InterpreterException, InvalidArguments, InvalidCode
  from .interpreterbase import InterpreterObject, MutableInterpreterObject, Disabler
  from .modules import ModuleReturnValue
  
  import os, sys, shutil, uuid
  import re, shlex
  from collections import namedtuple
  from pathlib import PurePath
  
  import importlib
  
  def stringifyUserArguments(args):
      if isinstance(args, list):
          return '[%s]' % ', '.join([stringifyUserArguments(x) for x in args])
      elif isinstance(args, int):
          return str(args)
      elif isinstance(args, str):
          return "'%s'" % args
      raise InvalidArguments('Function accepts only strings, integers, lists and lists thereof.')
  
  
  class ObjectHolder:
      def __init__(self, obj):
          self.held_object = obj
  
      def __repr__(self):
          return '<Holder: {!r}>'.format(self.held_object)
  
  
  class TryRunResultHolder(InterpreterObject):
      def __init__(self, res):
          super().__init__()
          self.res = res
          self.methods.update({'returncode': self.returncode_method,
                               'compiled': self.compiled_method,
                               'stdout': self.stdout_method,
                               'stderr': self.stderr_method,
                               })
  
      def returncode_method(self, args, kwargs):
          return self.res.returncode
  
      def compiled_method(self, args, kwargs):
          return self.res.compiled
  
      def stdout_method(self, args, kwargs):
          return self.res.stdout
  
      def stderr_method(self, args, kwargs):
          return self.res.stderr
  
  class RunProcess(InterpreterObject):
  
      def __init__(self, cmd, args, source_dir, build_dir, subdir, mesonintrospect, in_builddir=False):
          super().__init__()
          if not isinstance(cmd, ExternalProgram):
              raise AssertionError('BUG: RunProcess must be passed an ExternalProgram')
          pc, self.stdout, self.stderr = self.run_command(cmd, args, source_dir, build_dir, subdir, mesonintrospect, in_builddir)
          self.returncode = pc.returncode
          self.methods.update({'returncode': self.returncode_method,
                               'stdout': self.stdout_method,
                               'stderr': self.stderr_method,
                               })
  
      def run_command(self, cmd, args, source_dir, build_dir, subdir, mesonintrospect, in_builddir):
          command_array = cmd.get_command() + args
          env = {'MESON_SOURCE_ROOT': source_dir,
                 'MESON_BUILD_ROOT': build_dir,
                 'MESON_SUBDIR': subdir,
                 'MESONINTROSPECT': ' '.join([shlex.quote(x) for x in mesonintrospect]),
                 }
          if in_builddir:
              cwd = os.path.join(build_dir, subdir)
          else:
              cwd = os.path.join(source_dir, subdir)
          child_env = os.environ.copy()
          child_env.update(env)
          mlog.debug('Running command:', ' '.join(command_array))
          try:
              p, o, e = Popen_safe(command_array, env=child_env, cwd=cwd)
              mlog.debug('--- stdout----')
              mlog.debug(o)
              mlog.debug('----stderr----')
              mlog.debug(e)
              mlog.debug('')
              return p, o, e
          except FileNotFoundError:
              raise InterpreterException('Could not execute command "%s".' % ' '.join(command_array))
  
      def returncode_method(self, args, kwargs):
          return self.returncode
  
      def stdout_method(self, args, kwargs):
          return self.stdout
  
      def stderr_method(self, args, kwargs):
          return self.stderr
  
  class ConfigureFileHolder(InterpreterObject, ObjectHolder):
  
      def __init__(self, subdir, sourcename, targetname, configuration_data):
          InterpreterObject.__init__(self)
          ObjectHolder.__init__(self, build.ConfigureFile(subdir, sourcename,
                                                          targetname, configuration_data))
  
  
  class EnvironmentVariablesHolder(MutableInterpreterObject, ObjectHolder):
      def __init__(self):
          MutableInterpreterObject.__init__(self)
          ObjectHolder.__init__(self, build.EnvironmentVariables())
          self.methods.update({'set': self.set_method,
                               'append': self.append_method,
                               'prepend': self.prepend_method,
                               })
  
      def __repr__(self):
          repr_str = "<{0}: {1}>"
          return repr_str.format(self.__class__.__name__, self.held_object.envvars)
  
      @stringArgs
      def add_var(self, method, args, kwargs):
          if not isinstance(kwargs.get("separator", ""), str):
              raise InterpreterException("EnvironmentVariablesHolder methods 'separator'"
                                         " argument needs to be a string.")
          if len(args) < 2:
              raise InterpreterException("EnvironmentVariablesHolder methods require at least"
                                         "2 arguments, first is the name of the variable and"
                                         " following one are values")
          self.held_object.envvars.append((method, args[0], args[1:], kwargs))
  
      def set_method(self, args, kwargs):
          self.add_var(self.held_object.set, args, kwargs)
  
      def append_method(self, args, kwargs):
          self.add_var(self.held_object.append, args, kwargs)
  
      def prepend_method(self, args, kwargs):
          self.add_var(self.held_object.prepend, args, kwargs)
  
  
  class ConfigurationDataHolder(MutableInterpreterObject, ObjectHolder):
      def __init__(self):
          MutableInterpreterObject.__init__(self)
          self.used = False # These objects become immutable after use in configure_file.
          ObjectHolder.__init__(self, build.ConfigurationData())
          self.methods.update({'set': self.set_method,
                               'set10': self.set10_method,
                               'set_quoted': self.set_quoted_method,
                               'has': self.has_method,
                               'get': self.get_method,
                               'get_unqu
  
  [... the rest is omitted ...]
files: mesonbuild/interpreter.py
files: project('D Features', 'd')
  
  # 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')
  
  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',
      'app.d',
      d_import_dirs: [data_dir]
  )
  test('dapp_menu_t_fail', e_plain, should_fail: true)
  test('dapp_menu_t', e_plain, args: ['menu'])
  
  
  # test feature versions and string imports
  e_versions = executable('dapp_versions',
      'app.d',
      d_import_dirs: [data_dir],
      d_module_versions: ['No_Menu', 'With_People']
  )
  test('dapp_versions_t_fail', e_versions, args: ['menu'], should_fail: true)
  test('dapp_versions_t', e_versions, args: ['people'])
  
  # test everything and unittests
  e_test = executable('dapp_test',
      'app.d',
      d_import_dirs: [data_dir],
      d_module_versions: ['No_Menu', 'With_People'],
      d_unittest: true
  )
  test('dapp_test', e_test)
  
  
  [... the rest is omitted ...]
files: test cases/d/9 features/meson.build
files: project('D Features', 'd')
  
  # directory for data
  data_dir = join_paths(meson.current_source_dir(), 'data')
  
  e_plain = executable('dapp_menu',
      'app.d',
      d_import_dirs: [data_dir]
  )
  test('dapp_menu_t_fail', e_plain, should_fail: true)
  test('dapp_menu_t', e_plain, args: ['menu'])
  
  # test feature versions and string imports
  e_versions = executable('dapp_versions',
      'app.d',
      d_import_dirs: [data_dir],
      d_module_versions: ['No_Menu', 'With_People']
  )
  test('dapp_versions_t_fail', e_versions, args: ['menu'], should_fail: true)
  test('dapp_versions_t', e_versions, args: ['people'])
  
  # test everything and unittests
  e_test = executable('dapp_test',
      'app.d',
      d_import_dirs: [data_dir],
      d_module_versions: ['No_Menu', 'With_People'],
      d_unittest: true
  )
  test('dapp_test', e_test)
  
  
  [... the rest is omitted ...]
files: test cases/d/9 features/meson.build