aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--authors.txt2
-rw-r--r--mesonbuild/backend/backends.py66
-rw-r--r--mesonbuild/backend/ninjabackend.py31
-rw-r--r--mesonbuild/backend/vs2010backend.py8
-rw-r--r--mesonbuild/backend/vs2017backend.py2
-rw-r--r--mesonbuild/build.py51
-rw-r--r--mesonbuild/compilers.py16
-rw-r--r--mesonbuild/coredata.py52
-rw-r--r--mesonbuild/interpreter.py14
-rw-r--r--mesonbuild/mesonlib.py14
-rw-r--r--mesonbuild/modules/python3.py22
-rw-r--r--mesonbuild/wrap/wrap.py2
-rwxr-xr-xrun_tests.py11
-rwxr-xr-xrun_unittests.py88
-rw-r--r--test cases/common/139 override options/four.c9
-rw-r--r--test cases/common/139 override options/meson.build8
-rw-r--r--test cases/common/139 override options/one.c3
-rw-r--r--test cases/common/139 override options/three.c7
-rw-r--r--test cases/common/139 override options/two.c6
-rw-r--r--test cases/common/141 c cpp and asm/main.c8
-rw-r--r--test cases/common/141 c cpp and asm/main.cpp11
-rw-r--r--test cases/common/141 c cpp and asm/meson.build23
-rw-r--r--test cases/common/141 c cpp and asm/retval-arm.S8
-rw-r--r--test cases/common/141 c cpp and asm/retval-x86.S8
-rw-r--r--test cases/common/141 c cpp and asm/retval-x86_64.S8
-rw-r--r--test cases/common/141 c cpp and asm/somelib.c3
-rw-r--r--test cases/common/141 c cpp and asm/symbol-underscore.h5
-rw-r--r--test cases/common/16 configure file/meson.build5
-rw-r--r--test cases/common/9 header install/meson.build2
-rw-r--r--test cases/python3/1 basic/meson.build10
-rw-r--r--test cases/unit/5 compiler detection/meson.build2
-rw-r--r--test cases/unit/6 std override/meson.build10
-rw-r--r--test cases/unit/6 std override/prog03.cpp6
-rw-r--r--test cases/unit/6 std override/prog11.cpp6
-rw-r--r--test cases/unit/6 std override/progp.cpp6
35 files changed, 461 insertions, 72 deletions
diff --git a/authors.txt b/authors.txt
index 5bd0ba9..d982dfa 100644
--- a/authors.txt
+++ b/authors.txt
@@ -72,4 +72,6 @@ Aaron Small
Joe Baldino
Peter Harris
Roger Boerdijk
+melak47
+Philipp Ittershagen
Dylan Baker
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index 99be172..5517fbd 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -76,6 +76,24 @@ class TestSerialisation:
self.workdir = workdir
self.extra_paths = extra_paths
+class OptionProxy:
+ def __init__(self, name, value):
+ self.name = name
+ self.value = value
+
+class OptionOverrideProxy:
+ '''Mimic an option list but transparently override
+ selected option values.'''
+ def __init__(self, overrides, options):
+ self.overrides = overrides
+ self.options = options
+
+ def __getitem__(self, option_name):
+ base_opt = self.options[option_name]
+ if option_name in self.overrides:
+ return OptionProxy(base_opt.name, base_opt.validate_value(self.overrides[option_name]))
+ return base_opt
+
# This class contains the basic functionality that is needed by all backends.
# Feel free to move stuff in and out of it as you see fit.
class Backend:
@@ -103,6 +121,12 @@ class Backend:
def get_target_filename_abs(self, target):
return os.path.join(self.environment.get_build_dir(), self.get_target_filename(target))
+ def get_option_for_target(self, option_name, target):
+ if option_name in target.option_overrides:
+ override = target.option_overrides[option_name]
+ return self.environment.coredata.validate_option_value(option_name, override)
+ return self.environment.coredata.get_builtin_option(option_name)
+
def get_target_filename_for_linking(self, target):
# On some platforms (msvc for instance), the file that is used for
# dynamic linking is not the same as the dynamic library itself. This
@@ -152,8 +176,10 @@ class Backend:
compsrcs = classify_unity_sources(target.compilers.values(), unity_src)
def init_language_file(suffix):
- outfilename = os.path.join(self.get_target_private_dir_abs(target),
- self.get_unity_source_filename(target, suffix))
+ unity_src_name = self.get_unity_source_filename(target, suffix)
+ unity_src_subdir = self.get_target_private_dir_abs(target)
+ outfilename = os.path.join(unity_src_subdir,
+ unity_src_name)
outfileabs = os.path.join(self.environment.get_build_dir(),
outfilename)
outfileabs_tmp = outfileabs + '.tmp'
@@ -161,7 +187,7 @@ class Backend:
outfileabs_tmp_dir = os.path.dirname(outfileabs_tmp)
if not os.path.exists(outfileabs_tmp_dir):
os.makedirs(outfileabs_tmp_dir)
- result.append(outfilename)
+ result.append(mesonlib.File(True, unity_src_subdir, unity_src_name))
return open(outfileabs_tmp, 'w')
# For each language, generate a unity source file and return the list
@@ -186,7 +212,7 @@ class Backend:
elif isinstance(obj, mesonlib.File):
obj_list.append(obj.rel_to_builddir(self.build_to_src))
elif isinstance(obj, build.ExtractedObjects):
- obj_list += self.determine_ext_objs(obj, proj_dir_to_build_root)
+ obj_list += self.determine_ext_objs(target, obj, proj_dir_to_build_root)
else:
raise MesonException('Unknown data type in object list.')
return obj_list
@@ -261,32 +287,34 @@ class Backend:
raise MesonException(m.format(target.name))
return l
- def object_filename_from_source(self, target, source):
+ def object_filename_from_source(self, target, source, is_unity):
if isinstance(source, mesonlib.File):
source = source.fname
# foo.vala files compile down to foo.c and then foo.c.o, not foo.vala.o
if source.endswith('.vala'):
+ if is_unity:
+ return source[:-5] + '.c.' + self.environment.get_object_suffix()
source = os.path.join(self.get_target_private_dir(target), source[:-5] + '.c')
return source.replace('/', '_').replace('\\', '_') + '.' + self.environment.get_object_suffix()
- def determine_ext_objs(self, extobj, proj_dir_to_build_root):
+ def determine_ext_objs(self, target, extobj, proj_dir_to_build_root):
result = []
targetdir = self.get_target_private_dir(extobj.target)
# With unity builds, there's just one object that contains all the
# sources, and we only support extracting all the objects in this mode,
# so just return that.
- if self.environment.coredata.get_builtin_option('unity'):
+ if self.get_option_for_target('unity', target):
comp = get_compiler_for_source(extobj.target.compilers.values(),
extobj.srclist[0])
- # The unity object name uses the full absolute path of the source file
- osrc = os.path.join(self.get_target_private_dir_abs(extobj.target),
- self.get_unity_source_filename(extobj.target,
- comp.get_default_suffix()))
- objname = self.object_filename_from_source(extobj.target, osrc)
+ # There is a potential conflict here, but it is unlikely that
+ # anyone both enables unity builds and has a file called foo-unity.cpp.
+ osrc = self.get_unity_source_filename(extobj.target,
+ comp.get_default_suffix())
+ objname = self.object_filename_from_source(extobj.target, osrc, True)
objpath = os.path.join(proj_dir_to_build_root, targetdir, objname)
return [objpath]
for osrc in extobj.srclist:
- objname = self.object_filename_from_source(extobj.target, osrc)
+ objname = self.object_filename_from_source(extobj.target, osrc, False)
objpath = os.path.join(proj_dir_to_build_root, targetdir, objname)
result.append(objpath)
return result
@@ -338,6 +366,8 @@ class Backend:
# various sources in the order in which they must override each other
# starting from hard-coded defaults followed by build options and so on.
commands = CompilerArgs(compiler)
+
+ copt_proxy = OptionOverrideProxy(target.option_overrides, self.environment.coredata.compiler_options)
# First, the trivial ones that are impossible to override.
#
# Add -nostdinc/-nostdinc++ if needed; can't be overriden
@@ -348,19 +378,19 @@ class Backend:
# we weren't explicitly asked to not emit warnings (for Vala, f.ex)
if no_warn_args:
commands += compiler.get_no_warn_args()
- elif self.environment.coredata.get_builtin_option('buildtype') != 'plain':
- commands += compiler.get_warn_args(self.environment.coredata.get_builtin_option('warning_level'))
+ elif self.get_option_for_target('buildtype', target) != 'plain':
+ commands += compiler.get_warn_args(self.get_option_for_target('warning_level', target))
# Add -Werror if werror=true is set in the build options set on the
# command-line or default_options inside project(). This only sets the
# action to be done for warnings if/when they are emitted, so it's ok
# to set it after get_no_warn_args() or get_warn_args().
- if self.environment.coredata.get_builtin_option('werror'):
+ if self.get_option_for_target('werror', target):
commands += compiler.get_werror_args()
# Add compile args for c_* or cpp_* build options set on the
# command-line or default_options inside project().
- commands += compiler.get_option_compile_args(self.environment.coredata.compiler_options)
+ commands += compiler.get_option_compile_args(copt_proxy)
# Add buildtype args: optimization level, debugging, etc.
- commands += compiler.get_buildtype_args(self.environment.coredata.get_builtin_option('buildtype'))
+ commands += compiler.get_buildtype_args(self.get_option_for_target('buildtype', target))
# Add compile args added using add_project_arguments()
commands += self.build.get_project_args(compiler, target.subproject)
# Add compile args added using add_global_arguments()
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index f29a7be..bc51ace 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -336,7 +336,7 @@ int dummy;
outname = self.get_target_filename(target)
obj_list = []
use_pch = self.environment.coredata.base_options.get('b_pch', False)
- is_unity = self.environment.coredata.get_builtin_option('unity')
+ is_unity = self.get_option_for_target('unity', target)
if use_pch and target.has_pch():
pch_objects = self.generate_pch(target, outfile)
else:
@@ -433,7 +433,7 @@ int dummy;
obj_list += self.flatten_object_list(target)
if is_unity:
for src in self.generate_unity_files(target, unity_src):
- obj_list.append(self.generate_single_compile(target, outfile, RawFilename(src), True, unity_deps + header_deps))
+ obj_list.append(self.generate_single_compile(target, outfile, src, True, unity_deps + header_deps))
linker = self.determine_linker(target)
elem = self.generate_link(target, outfile, outname, obj_list, linker, pch_objects)
self.generate_shlib_aliases(target, self.get_target_dir(target))
@@ -627,9 +627,9 @@ int dummy;
pickle.dump(d, ofile)
def generate_target_install(self, d):
- should_strip = self.environment.coredata.get_builtin_option('strip')
for t in self.build.get_targets().values():
if t.should_install():
+ should_strip = self.get_option_for_target('strip', t)
# Find the installation directory. FIXME: Currently only one
# installation directory is supported for each target
outdir = t.get_custom_install_dir()
@@ -843,7 +843,7 @@ int dummy;
return args, deps
def generate_cs_target(self, target, outfile):
- buildtype = self.environment.coredata.get_builtin_option('buildtype')
+ buildtype = self.get_option_for_target('buildtype', target)
fname = target.get_filename()
outname_rel = os.path.join(self.get_target_dir(target), fname)
src_list = target.get_sources()
@@ -877,7 +877,7 @@ int dummy;
def generate_single_java_compile(self, src, target, compiler, outfile):
args = []
- args += compiler.get_buildtype_args(self.environment.coredata.get_builtin_option('buildtype'))
+ args += compiler.get_buildtype_args(self.get_option_for_target('buildtype', target))
args += self.build.get_global_args(compiler)
args += self.build.get_project_args(compiler, target.subproject)
args += target.get_java_args()
@@ -1010,7 +1010,7 @@ int dummy;
args = []
args += self.build.get_global_args(valac)
args += self.build.get_project_args(valac, target.subproject)
- args += valac.get_buildtype_args(self.environment.coredata.get_builtin_option('buildtype'))
+ args += valac.get_buildtype_args(self.get_option_for_target('buildtype', target))
# Tell Valac to output everything in our private directory. Sadly this
# means it will also preserve the directory components of Vala sources
# found inside the build tree (generated sources).
@@ -1033,7 +1033,7 @@ int dummy;
girname = os.path.join(self.get_target_dir(target), target.vala_gir)
args += ['--gir', os.path.join('..', target.vala_gir)]
valac_outputs.append(girname)
- if self.environment.coredata.get_builtin_option('werror'):
+ if self.get_option_for_target('werror', target):
args += valac.get_werror_args()
for d in target.get_external_deps():
if isinstance(d, dependencies.PkgConfigDependency):
@@ -1088,7 +1088,7 @@ int dummy;
else:
raise InvalidArguments('Unknown target type for rustc.')
args.append(cratetype)
- args += rustc.get_buildtype_args(self.environment.coredata.get_builtin_option('buildtype'))
+ args += rustc.get_buildtype_args(self.get_option_for_target('buildtype', target))
depfile = os.path.join(target.subdir, target.name + '.d')
args += ['--emit', 'dep-info={}'.format(depfile), '--emit', 'link']
args += ['-o', os.path.join(target.subdir, target.get_filename())]
@@ -1810,13 +1810,15 @@ rule FORTRAN_DEP_HACK
return incs
def _generate_single_compile(self, target, compiler, is_generated=False):
+ base_proxy = backends.OptionOverrideProxy(target.option_overrides,
+ self.environment.coredata.base_options)
# Create an empty commands list, and start adding arguments from
# various sources in the order in which they must override each other
commands = CompilerArgs(compiler)
# Add compiler args for compiling this target derived from 'base' build
# options passed on the command-line, in default_options, etc.
# These have the lowest priority.
- commands += compilers.get_base_compile_args(self.environment.coredata.base_options,
+ commands += compilers.get_base_compile_args(base_proxy,
compiler)
# The code generated by valac is usually crap and has tons of unused
# variables and such, so disable warnings for Vala C sources.
@@ -1888,6 +1890,11 @@ rule FORTRAN_DEP_HACK
raise AssertionError('BUG: sources should not contain headers {!r}'.format(src))
if isinstance(src, RawFilename) and src.fname.endswith('.h'):
raise AssertionError('BUG: sources should not contain headers {!r}'.format(src.fname))
+
+ if isinstance(src, str) and src.endswith('.h'):
+ raise AssertionError('BUG: sources should not contain headers {!r}'.format(src))
+ if isinstance(src, RawFilename) and src.fname.endswith('.h'):
+ raise AssertionError('BUG: sources should not contain headers {!r}'.format(src.fname))
compiler = get_compiler_for_source(target.compilers.values(), src)
key = (target, compiler, is_generated)
if key in self.target_arg_cache:
@@ -1905,6 +1912,10 @@ rule FORTRAN_DEP_HACK
abs_src = src.fname
else:
abs_src = os.path.join(self.environment.get_build_dir(), src.fname)
+ elif isinstance(src, mesonlib.File):
+ rel_src = src.rel_to_builddir(self.build_to_src)
+ abs_src = src.absolute_path(self.environment.get_source_dir(),
+ self.environment.get_build_dir())
elif is_generated:
raise AssertionError('BUG: broken generated source file handling for {!r}'.format(src))
else:
@@ -2145,7 +2156,7 @@ rule FORTRAN_DEP_HACK
# Add things like /NOLOGO; usually can't be overriden
commands += linker.get_linker_always_args()
# Add buildtype linker args: optimization level, etc.
- commands += linker.get_buildtype_linker_args(self.environment.coredata.get_builtin_option('buildtype'))
+ commands += linker.get_buildtype_linker_args(self.get_option_for_target('buildtype', target))
# Add /DEBUG and the pdb filename when using MSVC
commands += self.get_link_debugfile_args(linker, target, outname)
# Add link args specific to this BuildTarget type, such as soname args,
diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
index 8c0cce6..7afbc0d 100644
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -87,7 +87,7 @@ class Vs2010Backend(backends.Backend):
self.vs_version = '2010'
self.windows_target_platform_version = None
- def object_filename_from_source(self, target, source):
+ def object_filename_from_source(self, target, source, is_unity=False):
basename = os.path.basename(source.fname)
filename_without_extension = '.'.join(basename.split('.')[:-1])
if basename in self.sources_conflicts[target.get_id()]:
@@ -601,6 +601,8 @@ class Vs2010Backend(backends.Backend):
# Prefix to use to access the source tree's subdir from the vcxproj dir
proj_to_src_dir = os.path.join(proj_to_src_root, target.subdir)
(sources, headers, objects, languages) = self.split_sources(target.sources)
+ if self.get_option_for_target('unity', target):
+ sources = self.generate_unity_files(target, sources)
compiler = self._get_cl_compiler(target)
buildtype_args = compiler.get_buildtype_args(self.buildtype)
buildtype_link_args = compiler.get_buildtype_linker_args(self.buildtype)
@@ -690,7 +692,7 @@ class Vs2010Backend(backends.Backend):
elif '/Od' in o_flags:
ET.SubElement(type_config, 'Optimization').text = 'Disabled'
# Warning level
- warning_level = self.environment.coredata.get_builtin_option('warning_level')
+ warning_level = self.get_option_for_target('warning_level', target)
ET.SubElement(type_config, 'WarningLevel').text = 'Level' + warning_level
# End configuration
ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.props')
@@ -844,7 +846,7 @@ class Vs2010Backend(backends.Backend):
ET.SubElement(clconf, 'MinimalRebuild').text = 'true'
ET.SubElement(clconf, 'FunctionLevelLinking').text = 'true'
pch_node = ET.SubElement(clconf, 'PrecompiledHeader')
- if self.environment.coredata.get_builtin_option('werror'):
+ if self.get_option_for_target('werror', target):
ET.SubElement(clconf, 'TreatWarningAsError').text = 'true'
# Note: SuppressStartupBanner is /NOLOGO and is 'true' by default
pch_sources = {}
diff --git a/mesonbuild/backend/vs2017backend.py b/mesonbuild/backend/vs2017backend.py
index 8301790..35d56f3 100644
--- a/mesonbuild/backend/vs2017backend.py
+++ b/mesonbuild/backend/vs2017backend.py
@@ -24,4 +24,4 @@ class Vs2017Backend(Vs2010Backend):
self.platform_toolset = 'v141'
self.vs_version = '2017'
# WindowsSDKVersion should be set by command prompt.
- self.windows_target_platform_version = os.getenv('WindowsSDKVersion', None)
+ self.windows_target_platform_version = os.getenv('WindowsSDKVersion', None).rstrip('\\')
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index 41e21e3..1246f3e 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -12,15 +12,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import copy, os, re
+from collections import OrderedDict
+
from . import environment
from . import dependencies
from . import mlog
-import copy, os, re
from .mesonlib import File, MesonException
from .mesonlib import flatten, stringlistify, classify_unity_sources
from .mesonlib import get_filenames_templates_dict, substitute_values
from .environment import for_windows, for_darwin
-from .compilers import is_object, clike_langs, lang_suffixes
+from .compilers import is_object, clike_langs, sort_clike, lang_suffixes
known_basic_kwargs = {'install': True,
'c_pch': True,
@@ -47,6 +49,7 @@ known_basic_kwargs = {'install': True,
'objects': True,
'native': True,
'build_by_default': True,
+ 'override_options': True,
}
# These contain kwargs supported by both static and shared libraries. These are
@@ -270,6 +273,7 @@ class Target:
self.build_by_default = build_by_default
self.install = False
self.build_always = False
+ self.option_overrides = {}
def get_basename(self):
return self.name
@@ -282,6 +286,20 @@ class Target:
self.build_by_default = kwargs['build_by_default']
if not isinstance(self.build_by_default, bool):
raise InvalidArguments('build_by_default must be a boolean value.')
+ self.option_overrides = self.parse_overrides(kwargs)
+
+ def parse_overrides(self, kwargs):
+ result = {}
+ overrides = stringlistify(kwargs.get('override_options', []))
+ for o in overrides:
+ if '=' not in o:
+ raise InvalidArguments('Overrides must be of form "key=value"')
+ k, v = o.split('=', 1)
+ k = k.strip()
+ v = v.strip()
+ result[k] = v
+ return result
+
class BuildTarget(Target):
def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
@@ -291,7 +309,7 @@ class BuildTarget(Target):
self.is_unity = environment.coredata.get_builtin_option('unity')
self.environment = environment
self.sources = []
- self.compilers = {}
+ self.compilers = OrderedDict()
self.objects = []
self.external_deps = []
self.include_dirs = []
@@ -391,13 +409,6 @@ class BuildTarget(Target):
raise InvalidArguments(msg)
@staticmethod
- def can_compile_sources(compiler, sources):
- for s in sources:
- if compiler.can_compile(s):
- return True
- return False
-
- @staticmethod
def can_compile_remove_sources(compiler, sources):
removed = False
for s in sources[:]:
@@ -442,13 +453,18 @@ class BuildTarget(Target):
if not s.endswith(lang_suffixes['vala']):
sources.append(s)
if sources:
- # Add compilers based on the above sources
- for lang, compiler in compilers.items():
- # We try to be conservative because sometimes people add files
- # in the list of sources that we can't determine the type based
- # just on the suffix.
- if self.can_compile_sources(compiler, sources):
- self.compilers[lang] = compiler
+ # For each source, try to add one compiler that can compile it.
+ # It's ok if no compilers can do so, because users are expected to
+ # be able to add arbitrary non-source files to the sources list.
+ for s in sources:
+ for lang, compiler in compilers.items():
+ if compiler.can_compile(s):
+ if lang not in self.compilers:
+ self.compilers[lang] = compiler
+ break
+ # Re-sort according to clike_langs
+ self.compilers = OrderedDict(sorted(self.compilers.items(),
+ key=lambda t: sort_clike(t[0])))
else:
# No source files, target consists of only object files of unknown
# origin. Just add the first clike compiler that we have and hope
@@ -1237,6 +1253,7 @@ class CustomTarget(Target):
'depend_files': True,
'depfile': True,
'build_by_default': True,
+ 'override_options': True,
}
def __init__(self, name, subdir, kwargs, absolute_paths=False):
diff --git a/mesonbuild/compilers.py b/mesonbuild/compilers.py
index f16a05f..5e7db24 100644
--- a/mesonbuild/compilers.py
+++ b/mesonbuild/compilers.py
@@ -57,6 +57,17 @@ clike_suffixes += ('h', 'll', 's')
# All these are only for C-like languages; see `clike_langs` above.
+def sort_clike(lang):
+ '''
+ Sorting function to sort the list of languages according to
+ reversed(compilers.clike_langs) and append the unknown langs in the end.
+ The purpose is to prefer C over C++ for files that can be compiled by
+ both such as assembly, C, etc. Also applies to ObjC, ObjC++, etc.
+ '''
+ if lang not in clike_langs:
+ return 1
+ return -clike_langs.index(lang)
+
def is_header(fname):
if hasattr(fname, 'fname'):
fname = fname.fname
@@ -514,6 +525,11 @@ class Compiler:
self.version = version
self.base_options = []
+ def __repr__(self):
+ repr_str = "<{0}: v{1} `{2}`>"
+ return repr_str.format(self.__class__.__name__, self.version,
+ ' '.join(self.exelist))
+
def can_compile(self, src):
if hasattr(src, 'fname'):
src = src.fname
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index 9562211..67516e7 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -14,8 +14,10 @@
import pickle, os, uuid
from pathlib import PurePath
+from collections import OrderedDict
from .mesonlib import MesonException, commonpath
from .mesonlib import default_libdir, default_libexecdir, default_prefix
+import ast
version = '0.40.0.dev1'
backendlist = ['ninja', 'vs', 'vs2010', 'vs2015', 'vs2017', 'xcode']
@@ -30,6 +32,12 @@ class UserOption:
def parse_string(self, valuestring):
return valuestring
+ # Check that the input is a valid value and return the
+ # "cleaned" or "native" version. For example the Boolean
+ # option could take the string "true" and return True.
+ def validate_value(self, value):
+ raise RuntimeError('Derived option class did not override validate_value.')
+
class UserStringOption(UserOption):
def __init__(self, name, description, value, choices=None):
super().__init__(name, description, choices)
@@ -43,6 +51,10 @@ class UserStringOption(UserOption):
self.validate(newvalue)
self.value = newvalue
+ def validate_value(self, value):
+ self.validate(value)
+ return value
+
class UserBooleanOption(UserOption):
def __init__(self, name, description, value):
super().__init__(name, description, [True, False])
@@ -70,6 +82,9 @@ class UserBooleanOption(UserOption):
def __bool__(self):
return self.value
+ def validate_value(self, value):
+ return self.tobool(value)
+
class UserComboOption(UserOption):
def __init__(self, name, description, choices, value):
super().__init__(name, description, choices)
@@ -86,22 +101,36 @@ class UserComboOption(UserOption):
raise MesonException('Value "%s" for combo option "%s" is not one of the choices. Possible choices are: %s.' % (newvalue, self.name, optionsstring))
self.value = newvalue
+ def validate_value(self, value):
+ if value not in self.choices:
+ raise MesonException('Value %s not one of accepted values.' % value)
+ return value
+
class UserStringArrayOption(UserOption):
def __init__(self, name, description, value, **kwargs):
super().__init__(name, description, kwargs.get('choices', []))
self.set_value(value)
- def set_value(self, newvalue):
- if isinstance(newvalue, str):
- if not newvalue.startswith('['):
- raise MesonException('Valuestring does not define an array: ' + newvalue)
- newvalue = eval(newvalue, {}, {}) # Yes, it is unsafe.
+ def validate(self, value):
+ if isinstance(value, str):
+ if not value.startswith('['):
+ raise MesonException('Valuestring does not define an array: ' + value)
+ newvalue = ast.literal_eval(value)
+ else:
+ newvalue = value
if not isinstance(newvalue, list):
raise MesonException('"{0}" should be a string array, but it is not'.format(str(newvalue)))
for i in newvalue:
if not isinstance(i, str):
raise MesonException('String array element "{0}" is not a string.'.format(str(newvalue)))
- self.value = newvalue
+ return newvalue
+
+ def set_value(self, newvalue):
+ self.value = self.validate(newvalue)
+
+ def validate_value(self, value):
+ self.validate(value)
+ return value
# This class contains all data that must persist over multiple
# invocations of Meson. It is roughly the same thing as
@@ -128,8 +157,8 @@ class CoreData:
else:
self.cross_file = None
self.wrap_mode = options.wrap_mode
- self.compilers = {}
- self.cross_compilers = {}
+ self.compilers = OrderedDict()
+ self.cross_compilers = OrderedDict()
self.deps = {}
self.modules = {}
# Only to print a warning if it changes between Meson invocations.
@@ -203,6 +232,13 @@ class CoreData:
raise RuntimeError('Tried to set unknown builtin option %s.' % optname)
self.builtins[optname].set_value(value)
+ def validate_option_value(self, option_name, override_value):
+ for opts in (self.builtins, self.base_options, self.compiler_options, self.user_options):
+ if option_name in opts:
+ opt = opts[option_name]
+ return opt.validate_value(override_value)
+ raise MesonException('Tried to validate unknown option %s.' % option_name)
+
def load(filename):
load_fail_msg = 'Coredata file {!r} is corrupted. Try with a fresh build tree.'.format(filename)
try:
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index 7ee4bb9..af2c17d 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -1613,6 +1613,8 @@ class Interpreter(InterpreterBase):
@stringArgs
def func_project(self, node, args, kwargs):
+ if len(args) < 1:
+ raise InvalidArguments('Not enough arguments to project(). Needs at least the project name.')
default_options = kwargs.get('default_options', [])
if self.environment.first_invocation and (len(default_options) > 0 or
len(self.default_project_options) > 0):
@@ -1625,8 +1627,6 @@ class Interpreter(InterpreterBase):
)
oi.process(self.option_file)
self.build.environment.merge_options(oi.options)
- if len(args) < 2:
- raise InvalidArguments('Not enough arguments to project(). Needs at least the project name and one language')
self.active_projectname = args[0]
self.project_version = kwargs.get('version', 'undefined')
if self.build.project_version is None:
@@ -1755,7 +1755,7 @@ class Interpreter(InterpreterBase):
def add_languages(self, args, required):
success = True
need_cross_compiler = self.environment.is_cross_build() and self.environment.cross_info.need_cross_compiler()
- for lang in args:
+ for lang in sorted(args, key=compilers.sort_clike):
lang = lang.lower()
if lang in self.coredata.compilers:
comp = self.coredata.compilers[lang]
@@ -2290,7 +2290,11 @@ class Interpreter(InterpreterBase):
inputfile = inputfile[0]
if not isinstance(inputfile, (str, mesonlib.File)):
raise InterpreterException('Input must be a string or a file')
- ifile_abs = os.path.join(self.environment.source_dir, self.subdir, inputfile)
+ if isinstance(inputfile, str):
+ inputfile = os.path.join(self.subdir, inputfile)
+ else:
+ inputfile = inputfile.relative_name()
+ ifile_abs = os.path.join(self.environment.source_dir, inputfile)
elif 'command' in kwargs and '@INPUT@' in kwargs['command']:
raise InterpreterException('@INPUT@ used as command argument, but no input file specified.')
# Validate output
@@ -2309,7 +2313,7 @@ class Interpreter(InterpreterBase):
if inputfile is not None:
# Normalize the path of the conffile to avoid duplicates
# This is especially important to convert '/' to '\' on Windows
- conffile = os.path.normpath(os.path.join(self.subdir, inputfile))
+ conffile = os.path.normpath(inputfile)
if conffile not in self.build_def_files:
self.build_def_files.append(conffile)
os.makedirs(os.path.join(self.environment.build_dir, self.subdir), exist_ok=True)
diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py
index c7368d5..ba52219 100644
--- a/mesonbuild/mesonlib.py
+++ b/mesonbuild/mesonlib.py
@@ -121,16 +121,18 @@ class File:
self.is_built = is_built
self.subdir = subdir
self.fname = fname
+ assert(isinstance(self.subdir, str))
+ assert(isinstance(self.fname, str))
def __str__(self):
- return os.path.join(self.subdir, self.fname)
+ return self.relative_name()
def __repr__(self):
ret = '<File: {0}'
if not self.is_built:
ret += ' (not built)'
ret += '>'
- return ret.format(os.path.join(self.subdir, self.fname))
+ return ret.format(self.relative_name())
@staticmethod
def from_source_file(source_root, subdir, fname):
@@ -148,15 +150,15 @@ class File:
def rel_to_builddir(self, build_to_src):
if self.is_built:
- return os.path.join(self.subdir, self.fname)
+ return self.relative_name()
else:
return os.path.join(build_to_src, self.subdir, self.fname)
def absolute_path(self, srcdir, builddir):
+ absdir = srcdir
if self.is_built:
- return os.path.join(builddir, self.subdir, self.fname)
- else:
- return os.path.join(srcdir, self.subdir, self.fname)
+ absdir = builddir
+ return os.path.join(absdir, self.relative_name())
def endswith(self, ending):
return self.fname.endswith(ending)
diff --git a/mesonbuild/modules/python3.py b/mesonbuild/modules/python3.py
index 53e28c4..9f01043 100644
--- a/mesonbuild/modules/python3.py
+++ b/mesonbuild/modules/python3.py
@@ -13,11 +13,13 @@
# limitations under the License.
import sys
+import sysconfig
from .. import mesonlib, dependencies
from . import ExtensionModule
from mesonbuild.modules import ModuleReturnValue
+
class Python3Module(ExtensionModule):
def __init__(self):
super().__init__()
@@ -45,5 +47,25 @@ class Python3Module(ExtensionModule):
py3 = dependencies.ExternalProgram('python3', sys.executable, silent=True)
return ModuleReturnValue(py3, [py3])
+ def language_version(self, state, args, kwargs):
+ if args or kwargs:
+ raise mesonlib.MesonException('language_version() takes no arguments.')
+ return ModuleReturnValue(sysconfig.get_python_version(), [])
+
+ def sysconfig_path(self, state, args, kwargs):
+ if len(args) != 1:
+ raise mesonlib.MesonException('sysconfig_path() requires passing the name of path to get.')
+ if kwargs:
+ raise mesonlib.MesonException('sysconfig_path() does not accept keywords.')
+ path_name = args[0]
+ valid_names = sysconfig.get_path_names()
+ if path_name not in valid_names:
+ raise mesonlib.MesonException('{} is not a valid path name {}.'.format(path_name, valid_names))
+
+ # Get a relative path without a prefix, e.g. lib/python3.6/site-packages
+ path = sysconfig.get_path(path_name, vars={'base': ''})[1:]
+ return ModuleReturnValue(path, [])
+
+
def initialize():
return Python3Module()
diff --git a/mesonbuild/wrap/wrap.py b/mesonbuild/wrap/wrap.py
index fcacc16..67e4700 100644
--- a/mesonbuild/wrap/wrap.py
+++ b/mesonbuild/wrap/wrap.py
@@ -39,7 +39,7 @@ def build_ssl_context():
return ctx
def quiet_git(cmd):
- pc = subprocess.Popen(['git'] + cmd, stdout=subprocess.PIPE)
+ pc = subprocess.Popen(['git'] + cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = pc.communicate()
if pc.returncode != 0:
return False, err
diff --git a/run_tests.py b/run_tests.py
index 5025057..02aa701 100755
--- a/run_tests.py
+++ b/run_tests.py
@@ -21,6 +21,12 @@ import subprocess
import platform
from mesonbuild import mesonlib
+def using_vs_backend():
+ for arg in sys.argv[1:]:
+ if arg.startswith('--backend=vs'):
+ return True
+ return False
+
if __name__ == '__main__':
returncode = 0
# Running on a developer machine? Be nice!
@@ -32,7 +38,10 @@ if __name__ == '__main__':
units += ['LinuxlikeTests']
elif mesonlib.is_windows():
units += ['WindowsTests']
- returncode += subprocess.call([sys.executable, 'run_unittests.py', '-v'] + units)
+ # Unit tests always use the Ninja backend, so just skip them if we're
+ # testing the VS backend
+ if not using_vs_backend():
+ returncode += subprocess.call([sys.executable, 'run_unittests.py', '-v'] + units)
# Ubuntu packages do not have a binary without -6 suffix.
if shutil.which('arm-linux-gnueabihf-gcc-6') and not platform.machine().startswith('arm'):
print('Running cross compilation tests.\n')
diff --git a/run_unittests.py b/run_unittests.py
index 66f8205..0656f88 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -880,6 +880,73 @@ class AllPlatformTests(BasePlatformTests):
self.assertEqual(wcc.get_exelist(), wrappercc)
self.assertEqual(wlinker.get_exelist(), wrapperlinker)
+ def test_always_prefer_c_compiler_for_asm(self):
+ testdir = os.path.join(self.common_test_dir, '141 c cpp and asm')
+ # Skip if building with MSVC
+ env = Environment(testdir, self.builddir, self.meson_command,
+ get_fake_options(self.prefix), [])
+ if env.detect_c_compiler(False).get_id() == 'msvc':
+ raise unittest.SkipTest('MSVC can\'t compile assembly')
+ self.init(testdir)
+ commands = {'c-asm': {}, 'cpp-asm': {}, 'cpp-c-asm': {}, 'c-cpp-asm': {}}
+ for cmd in self.get_compdb():
+ # Get compiler
+ split = shlex.split(cmd['command'])
+ if split[0] == 'ccache':
+ compiler = split[1]
+ else:
+ compiler = split[0]
+ # Classify commands
+ if 'Ic-asm' in cmd['command']:
+ if cmd['file'].endswith('.S'):
+ commands['c-asm']['asm'] = compiler
+ elif cmd['file'].endswith('.c'):
+ commands['c-asm']['c'] = compiler
+ else:
+ raise AssertionError('{!r} found in cpp-asm?'.format(cmd['command']))
+ elif 'Icpp-asm' in cmd['command']:
+ if cmd['file'].endswith('.S'):
+ commands['cpp-asm']['asm'] = compiler
+ elif cmd['file'].endswith('.cpp'):
+ commands['cpp-asm']['cpp'] = compiler
+ else:
+ raise AssertionError('{!r} found in cpp-asm?'.format(cmd['command']))
+ elif 'Ic-cpp-asm' in cmd['command']:
+ if cmd['file'].endswith('.S'):
+ commands['c-cpp-asm']['asm'] = compiler
+ elif cmd['file'].endswith('.c'):
+ commands['c-cpp-asm']['c'] = compiler
+ elif cmd['file'].endswith('.cpp'):
+ commands['c-cpp-asm']['cpp'] = compiler
+ else:
+ raise AssertionError('{!r} found in c-cpp-asm?'.format(cmd['command']))
+ elif 'Icpp-c-asm' in cmd['command']:
+ if cmd['file'].endswith('.S'):
+ commands['cpp-c-asm']['asm'] = compiler
+ elif cmd['file'].endswith('.c'):
+ commands['cpp-c-asm']['c'] = compiler
+ elif cmd['file'].endswith('.cpp'):
+ commands['cpp-c-asm']['cpp'] = compiler
+ else:
+ raise AssertionError('{!r} found in cpp-c-asm?'.format(cmd['command']))
+ else:
+ raise AssertionError('Unknown command {!r} found'.format(cmd['command']))
+ # Check that .S files are always built with the C compiler
+ self.assertEqual(commands['c-asm']['asm'], commands['c-asm']['c'])
+ self.assertEqual(commands['c-asm']['asm'], commands['cpp-asm']['asm'])
+ self.assertEqual(commands['cpp-asm']['asm'], commands['c-cpp-asm']['c'])
+ self.assertEqual(commands['c-cpp-asm']['asm'], commands['c-cpp-asm']['c'])
+ self.assertEqual(commands['cpp-c-asm']['asm'], commands['cpp-c-asm']['c'])
+ self.assertNotEqual(commands['cpp-asm']['asm'], commands['cpp-asm']['cpp'])
+ self.assertNotEqual(commands['c-cpp-asm']['c'], commands['c-cpp-asm']['cpp'])
+ self.assertNotEqual(commands['cpp-c-asm']['c'], commands['cpp-c-asm']['cpp'])
+ # Check that the c-asm target is always linked with the C linker
+ build_ninja = os.path.join(self.builddir, 'build.ninja')
+ with open(build_ninja, 'r', encoding='utf-8') as f:
+ contents = f.read()
+ m = re.search('build c-asm.*: c_LINKER', contents)
+ self.assertIsNotNone(m, msg=contents)
+
class WindowsTests(BasePlatformTests):
'''
@@ -1261,6 +1328,27 @@ class LinuxlikeTests(BasePlatformTests):
# The chown failed nonfatally if we're not root
self.assertEqual(0, statf.st_uid)
+ def test_cpp_std_override(self):
+ testdir = os.path.join(self.unit_test_dir, '6 std override')
+ self.init(testdir)
+ compdb = self.get_compdb()
+ for i in compdb:
+ if 'prog03' in i['file']:
+ c03_comp = i['command']
+ if 'prog11' in i['file']:
+ c11_comp = i['command']
+ if 'progp' in i['file']:
+ plain_comp = i['command']
+ self.assertNotEqual(len(plain_comp), 0)
+ self.assertIn('-std=c++03', c03_comp)
+ self.assertNotIn('-std=c++11', c03_comp)
+ self.assertIn('-std=c++11', c11_comp)
+ self.assertNotIn('-std=c++03', c11_comp)
+ self.assertNotIn('-std=c++03', plain_comp)
+ self.assertNotIn('-std=c++11', plain_comp)
+ # Now werror
+ self.assertIn('-Werror', plain_comp)
+ self.assertNotIn('-Werror', c03_comp)
class RewriterTests(unittest.TestCase):
diff --git a/test cases/common/139 override options/four.c b/test cases/common/139 override options/four.c
new file mode 100644
index 0000000..54f8491
--- /dev/null
+++ b/test cases/common/139 override options/four.c
@@ -0,0 +1,9 @@
+int func();
+
+static int duplicate_func() {
+ return -4;
+}
+
+int main(int argc, char **argv) {
+ return duplicate_func() + func();
+}
diff --git a/test cases/common/139 override options/meson.build b/test cases/common/139 override options/meson.build
new file mode 100644
index 0000000..0db0513
--- /dev/null
+++ b/test cases/common/139 override options/meson.build
@@ -0,0 +1,8 @@
+project('option override', 'c',
+ default_options : 'unity=true')
+
+executable('mustunity', 'one.c', 'two.c')
+executable('notunity', 'three.c', 'four.c',
+ override_options : ['unity=false'])
+
+
diff --git a/test cases/common/139 override options/one.c b/test cases/common/139 override options/one.c
new file mode 100644
index 0000000..14fe9d6
--- /dev/null
+++ b/test cases/common/139 override options/one.c
@@ -0,0 +1,3 @@
+static int hidden_func() {
+ return 0;
+}
diff --git a/test cases/common/139 override options/three.c b/test cases/common/139 override options/three.c
new file mode 100644
index 0000000..305a575
--- /dev/null
+++ b/test cases/common/139 override options/three.c
@@ -0,0 +1,7 @@
+static int duplicate_func() {
+ return 4;
+}
+
+int func() {
+ return duplicate_func();
+}
diff --git a/test cases/common/139 override options/two.c b/test cases/common/139 override options/two.c
new file mode 100644
index 0000000..04b1d3f
--- /dev/null
+++ b/test cases/common/139 override options/two.c
@@ -0,0 +1,6 @@
+/*
+ * Requires a Unity build. Otherwise hidden_func is not specified.
+ */
+int main(int argc, char **argv) {
+ return hidden_func();
+}
diff --git a/test cases/common/141 c cpp and asm/main.c b/test cases/common/141 c cpp and asm/main.c
new file mode 100644
index 0000000..8976723
--- /dev/null
+++ b/test cases/common/141 c cpp and asm/main.c
@@ -0,0 +1,8 @@
+#include <stdio.h>
+
+int get_retval(void);
+
+int main(int argc, char **argv) {
+ printf("C seems to be working.\n");
+ return get_retval();
+}
diff --git a/test cases/common/141 c cpp and asm/main.cpp b/test cases/common/141 c cpp and asm/main.cpp
new file mode 100644
index 0000000..c089870
--- /dev/null
+++ b/test cases/common/141 c cpp and asm/main.cpp
@@ -0,0 +1,11 @@
+#include <iostream>
+
+extern "C" {
+ int get_retval(void);
+ int get_cval(void);
+}
+
+int main(int argc, char **argv) {
+ std::cout << "C++ seems to be working." << std::endl;
+ return get_retval();
+}
diff --git a/test cases/common/141 c cpp and asm/meson.build b/test cases/common/141 c cpp and asm/meson.build
new file mode 100644
index 0000000..2c3610e
--- /dev/null
+++ b/test cases/common/141 c cpp and asm/meson.build
@@ -0,0 +1,23 @@
+project('c cpp and asm', 'c', 'cpp')
+
+cpu = host_machine.cpu_family()
+cc = meson.get_compiler('c')
+
+supported_cpus = ['arm', 'x86', 'x86_64']
+
+if not supported_cpus.contains(cpu)
+ error('MESON_SKIP_TEST unsupported cpu:' + cpu)
+endif
+
+if meson.get_compiler('c').get_id() == 'msvc'
+ error('MESON_SKIP_TEST MSVC can\'t compile assembly')
+endif
+
+if cc.symbols_have_underscore_prefix()
+ add_project_arguments('-DMESON_TEST__UNDERSCORE_SYMBOL', language: 'c')
+endif
+
+test('test-c-asm', executable('c-asm', ['main.c', 'retval-' + cpu + '.S']))
+test('test-cpp-asm', executable('cpp-asm', ['main.cpp', 'retval-' + cpu + '.S']))
+test('test-c-cpp-asm', executable('c-cpp-asm', ['somelib.c', 'main.cpp', 'retval-' + cpu + '.S']))
+test('test-cpp-c-asm', executable('cpp-c-asm', ['main.cpp', 'somelib.c', 'retval-' + cpu + '.S']))
diff --git a/test cases/common/141 c cpp and asm/retval-arm.S b/test cases/common/141 c cpp and asm/retval-arm.S
new file mode 100644
index 0000000..8b37197
--- /dev/null
+++ b/test cases/common/141 c cpp and asm/retval-arm.S
@@ -0,0 +1,8 @@
+#include "symbol-underscore.h"
+
+.text
+.globl SYMBOL_NAME(get_retval)
+
+SYMBOL_NAME(get_retval):
+ mov r0, #0
+ mov pc, lr
diff --git a/test cases/common/141 c cpp and asm/retval-x86.S b/test cases/common/141 c cpp and asm/retval-x86.S
new file mode 100644
index 0000000..06bd75c
--- /dev/null
+++ b/test cases/common/141 c cpp and asm/retval-x86.S
@@ -0,0 +1,8 @@
+#include "symbol-underscore.h"
+
+.text
+.globl SYMBOL_NAME(get_retval)
+
+SYMBOL_NAME(get_retval):
+ xorl %eax, %eax
+ retl
diff --git a/test cases/common/141 c cpp and asm/retval-x86_64.S b/test cases/common/141 c cpp and asm/retval-x86_64.S
new file mode 100644
index 0000000..638921e
--- /dev/null
+++ b/test cases/common/141 c cpp and asm/retval-x86_64.S
@@ -0,0 +1,8 @@
+#include "symbol-underscore.h"
+
+.text
+.globl SYMBOL_NAME(get_retval)
+
+SYMBOL_NAME(get_retval):
+ xorl %eax, %eax
+ retq
diff --git a/test cases/common/141 c cpp and asm/somelib.c b/test cases/common/141 c cpp and asm/somelib.c
new file mode 100644
index 0000000..e585b8e
--- /dev/null
+++ b/test cases/common/141 c cpp and asm/somelib.c
@@ -0,0 +1,3 @@
+int get_cval (void) {
+ return 0;
+}
diff --git a/test cases/common/141 c cpp and asm/symbol-underscore.h b/test cases/common/141 c cpp and asm/symbol-underscore.h
new file mode 100644
index 0000000..d0f3ef9
--- /dev/null
+++ b/test cases/common/141 c cpp and asm/symbol-underscore.h
@@ -0,0 +1,5 @@
+#if defined(MESON_TEST__UNDERSCORE_SYMBOL)
+# define SYMBOL_NAME(name) _##name
+#else
+# define SYMBOL_NAME(name) name
+#endif
diff --git a/test cases/common/16 configure file/meson.build b/test cases/common/16 configure file/meson.build
index 8271ca3..8ffc28c 100644
--- a/test cases/common/16 configure file/meson.build
+++ b/test cases/common/16 configure file/meson.build
@@ -22,6 +22,11 @@ e = executable('inctest', 'prog.c',
cfile)
test('inctest', e)
+# Test if we can also pass files() as input
+configure_file(input : files('config.h.in'),
+ output : 'config2.h',
+ configuration : conf)
+
# Now generate a header file with an external script.
genprog = import('python3').find_python()
scriptfile = '@0@/generator.py'.format(meson.current_source_dir())
diff --git a/test cases/common/9 header install/meson.build b/test cases/common/9 header install/meson.build
index 7f3ce51..7dfbddb 100644
--- a/test cases/common/9 header install/meson.build
+++ b/test cases/common/9 header install/meson.build
@@ -1,4 +1,4 @@
-project('header install', 'c')
+project('header install')
as_array = ['subdir.h']
diff --git a/test cases/python3/1 basic/meson.build b/test cases/python3/1 basic/meson.build
index 9d5f874..111b717 100644
--- a/test cases/python3/1 basic/meson.build
+++ b/test cases/python3/1 basic/meson.build
@@ -3,6 +3,16 @@ project('python sample', 'c')
py3_mod = import('python3')
py3 = py3_mod.find_python()
+py3_version = py3_mod.language_version()
+if py3_version.version_compare('< 3.2')
+ error('Invalid python version!?')
+endif
+
+py3_purelib = py3_mod.sysconfig_path('purelib')
+if not py3_purelib.endswith('site-packages')
+ error('Python3 purelib path seems invalid?')
+endif
+
main = files('prog.py')
test('toplevel', py3, args : main)
diff --git a/test cases/unit/5 compiler detection/meson.build b/test cases/unit/5 compiler detection/meson.build
index 5491c64..8b47bd4 100644
--- a/test cases/unit/5 compiler detection/meson.build
+++ b/test cases/unit/5 compiler detection/meson.build
@@ -3,6 +3,6 @@ project('trivial test',
meson_version : '>=0.27.0')
executable('trivialc', 'trivial.c')
-executable('trivialcpp', 'trivial.cpp')
+executable('trivialcpp', 'trivial.cc')
executable('trivialobjc', 'trivial.m')
executable('trivialobjcpp', 'trivial.mm')
diff --git a/test cases/unit/6 std override/meson.build b/test cases/unit/6 std override/meson.build
new file mode 100644
index 0000000..ef2baac
--- /dev/null
+++ b/test cases/unit/6 std override/meson.build
@@ -0,0 +1,10 @@
+project('cpp std override', 'cpp',
+ default_options : ['cpp_std=c++03',
+ 'werror=true'])
+
+executable('plain', 'progp.cpp',
+ override_options : 'cpp_std=none')
+executable('v03', 'prog03.cpp',
+ override_options : 'werror=false')
+executable('v11', 'prog11.cpp',
+ override_options : 'cpp_std=c++11')
diff --git a/test cases/unit/6 std override/prog03.cpp b/test cases/unit/6 std override/prog03.cpp
new file mode 100644
index 0000000..d30abc9
--- /dev/null
+++ b/test cases/unit/6 std override/prog03.cpp
@@ -0,0 +1,6 @@
+#include<iostream>
+
+int main(int argc, char **argv) {
+ std::cout << "I am a c++03 test program.\n";
+ return 0;
+}
diff --git a/test cases/unit/6 std override/prog11.cpp b/test cases/unit/6 std override/prog11.cpp
new file mode 100644
index 0000000..dde1fc0
--- /dev/null
+++ b/test cases/unit/6 std override/prog11.cpp
@@ -0,0 +1,6 @@
+#include<iostream>
+
+int main(int argc, char **argv) {
+ std::cout << "I am a C++11 test program.\n";
+ return 0;
+}
diff --git a/test cases/unit/6 std override/progp.cpp b/test cases/unit/6 std override/progp.cpp
new file mode 100644
index 0000000..b9bd97f
--- /dev/null
+++ b/test cases/unit/6 std override/progp.cpp
@@ -0,0 +1,6 @@
+#include<iostream>
+
+int main(int argc, char **argv) {
+ std::cout << "I am a test program of undefined C++ standard.\n";
+ return 0;
+}