aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/markdown/Cross-compilation.md26
-rw-r--r--docs/markdown/Dependencies.md29
-rw-r--r--docs/markdown/Reference-manual.md2
-rw-r--r--docs/markdown/snippets/system-wide-cross-files.md20
-rw-r--r--mesonbuild/backend/vs2010backend.py10
-rw-r--r--mesonbuild/backend/vs2017backend.py5
-rw-r--r--mesonbuild/compilers/cpp.py4
-rw-r--r--mesonbuild/coredata.py46
-rw-r--r--mesonbuild/dependencies/base.py6
-rw-r--r--mesonbuild/dependencies/misc.py6
-rw-r--r--mesonbuild/interpreter.py2
-rw-r--r--mesonbuild/mlog.py6
-rw-r--r--mesonbuild/modules/gnome.py41
-rw-r--r--mesonbuild/mtest.py54
-rwxr-xr-xrun_unittests.py46
-rw-r--r--test cases/common/167 external program shebang parsing/input.txt1
-rw-r--r--test cases/common/167 external program shebang parsing/main.c72
-rw-r--r--test cases/common/167 external program shebang parsing/meson.build21
-rw-r--r--test cases/common/167 external program shebang parsing/script.int.in2
-rw-r--r--test cases/frameworks/9 wxwidgets/meson.build2
-rw-r--r--test cases/osx/3 has function xcode8/meson.build8
21 files changed, 343 insertions, 66 deletions
diff --git a/docs/markdown/Cross-compilation.md b/docs/markdown/Cross-compilation.md
index f68b1f5..c1ad317 100644
--- a/docs/markdown/Cross-compilation.md
+++ b/docs/markdown/Cross-compilation.md
@@ -257,3 +257,29 @@ then you can access that using the `meson` object like this:
myvar = meson.get_cross_property('somekey')
# myvar now has the value 'somevalue'
```
+
+## Cross file locations
+
+As of version 0.44.0 meson supports loading cross files from system locations
+on Linux and the BSDs. This will be $XDG_DATA_DIRS/meson/cross, or if
+XDG_DATA_DIRS is undefined, then /usr/local/share/meson/cross and
+/usr/share/meson/cross will be tried in that order, for system wide cross
+files. User local files can be put in $XDG_DATA_HOME/meson/cross, or
+~/.local/share/meson/cross if that is undefined.
+
+The order of locations tried is as follows:
+ - A file relative to the local dir
+ - The user local location
+ - The system wide locations in order
+
+Linux and BSD distributions are encouraged to ship cross files either with
+their cross compiler toolchain packages or as a standalone package, and put
+them in one of the system paths referenced above.
+
+These files can be loaded automatically without adding a path to the cross
+file. For example, if a ~/.local/share/meson/cross contains a file called x86-linux,
+then the following command would start a cross build using that cross files:
+
+```sh
+meson builddir/ --cross-file x86-linux
+```
diff --git a/docs/markdown/Dependencies.md b/docs/markdown/Dependencies.md
index dbd21aa..bae3edc 100644
--- a/docs/markdown/Dependencies.md
+++ b/docs/markdown/Dependencies.md
@@ -197,3 +197,32 @@ tools support. You can force one or another via the method keyword:
```meson
wmf_dep = dependency('wmf', method : 'config-tool')
```
+
+## LLVM
+
+Meson has native support for LLVM going back to version LLVM version 3.5.
+It supports a few additional features compared to other config-tool based
+dependencies.
+
+As of 0.44.0 Meson supports the `static` keyword argument for LLVM. Before this
+LLVM >= 3.9 would always dynamically link, while older versions would
+statically link, due to a quirk in `llvm-config`.
+
+### Modules, a.k.a. Components
+
+Meson wraps LLVM's concept of components in it's own modules concept.
+When you need specific components you add them as modules as meson will do the
+right thing:
+
+```meson
+llvm_dep = dependency('llvm', version : '>= 4.0', modules : ['amdgpu'])
+```
+
+As of 0.44.0 it can also take optional modules (these will affect the arguments
+generated for a static link):
+
+```meson
+llvm_dep = dependency(
+ 'llvm', version : '>= 4.0', modules : ['amdgpu'], optional_modules : ['inteljitevents'],
+)
+```
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md
index 424ab58..e6aa9d3 100644
--- a/docs/markdown/Reference-manual.md
+++ b/docs/markdown/Reference-manual.md
@@ -855,6 +855,8 @@ This function prints its argument to stdout.
This function prints its argument to stdout prefixed with WARNING:.
+*Added 0.44.0*
+
### project()
``` meson
diff --git a/docs/markdown/snippets/system-wide-cross-files.md b/docs/markdown/snippets/system-wide-cross-files.md
new file mode 100644
index 0000000..66c454f
--- /dev/null
+++ b/docs/markdown/snippets/system-wide-cross-files.md
@@ -0,0 +1,20 @@
+## System wide and user local cross files
+
+Meson has gained the ability to load cross files from predefined locations
+without passing a full path on Linux and the BSD OSes. User local files will be
+loaded from `$XDG_DATA_HOME/meson/cross`, or if XDG_DATA_HOME is undefined,
+`~/.local/share/meson/cross` will be used.
+
+For system wide paths the values of `$XDG_DATA_DIRS` + `/meson/cross` will be used,
+if XDG_DATA_DIRS is undefined then `/usr/local/share/meson/cross:/usr/share/meson/cross`
+will be used instead.
+
+A file relative to the current working directory will be tried first, then the
+user specific path will be tried before the system wide paths.
+
+Assuming that a file x86-linux is located in one of those places a cross build
+can be started with:
+
+```sh
+meson builddir/ --cross-file x86-linux
+```
diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
index 69ee3e5..ea02580 100644
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -672,9 +672,6 @@ class Vs2010Backend(backends.Backend):
ET.SubElement(type_config, 'DebugInformationFormat').text = 'ProgramDatabase'
elif '/Z7' in buildtype_args:
ET.SubElement(type_config, 'DebugInformationFormat').text = 'OldStyle'
- # Generate Debug info
- if '/DEBUG' in buildtype_link_args:
- ET.SubElement(type_config, 'GenerateDebugInformation').text = 'true'
# Runtime checks
if '/RTC1' in buildtype_args:
ET.SubElement(type_config, 'BasicRuntimeChecks').text = 'EnableFastChecks'
@@ -885,6 +882,9 @@ class Vs2010Backend(backends.Backend):
# vcxproj file (similar to buildtype compiler args) instead of in
# AdditionalOptions?
extra_link_args += compiler.get_buildtype_linker_args(self.buildtype)
+ # Generate Debug info
+ if self.buildtype.startswith('debug'):
+ self.generate_debug_information(link)
if not isinstance(target, build.StaticLibrary):
if isinstance(target, build.SharedModule):
extra_link_args += compiler.get_std_shared_module_link_args()
@@ -1190,3 +1190,7 @@ if %%errorlevel%% neq 0 goto :VCEnd'''
cmd_templ % ('" "'.join(test_command))
ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.targets')
self._prettyprint_vcxproj_xml(ET.ElementTree(root), ofname)
+
+ def generate_debug_information(self, link):
+ # valid values for vs2015 is 'false', 'true', 'DebugFastLink'
+ ET.SubElement(link, 'GenerateDebugInformation').text = 'true'
diff --git a/mesonbuild/backend/vs2017backend.py b/mesonbuild/backend/vs2017backend.py
index fe1d7c7..9098226 100644
--- a/mesonbuild/backend/vs2017backend.py
+++ b/mesonbuild/backend/vs2017backend.py
@@ -13,6 +13,7 @@
# limitations under the License.
import os
+import xml.etree.ElementTree as ET
from .vs2010backend import Vs2010Backend
@@ -27,3 +28,7 @@ class Vs2017Backend(Vs2010Backend):
sdk_version = os.environ.get('WindowsSDKVersion', None)
if sdk_version:
self.windows_target_platform_version = sdk_version.rstrip('\\')
+
+ def generate_debug_information(self, link):
+ # valid values for vs2017 is 'false', 'true', 'DebugFastLink', 'DebugFull'
+ ET.SubElement(link, 'GenerateDebugInformation').text = 'DebugFull'
diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py
index a9093b3..15eb9a0 100644
--- a/mesonbuild/compilers/cpp.py
+++ b/mesonbuild/compilers/cpp.py
@@ -76,7 +76,7 @@ class ClangCPPCompiler(ClangCompiler, CPPCompiler):
def get_options(self):
return {'cpp_std': coredata.UserComboOption('cpp_std', 'C++ language standard to use',
- ['none', 'c++03', 'c++11', 'c++14', 'c++1z',
+ ['none', 'c++98', 'c++03', 'c++11', 'c++14', 'c++1z',
'gnu++11', 'gnu++14', 'gnu++1z'],
'none')}
@@ -102,7 +102,7 @@ class GnuCPPCompiler(GnuCompiler, CPPCompiler):
def get_options(self):
opts = {'cpp_std': coredata.UserComboOption('cpp_std', 'C++ language standard to use',
- ['none', 'c++03', 'c++11', 'c++14', 'c++1z',
+ ['none', 'c++98', 'c++03', 'c++11', 'c++14', 'c++1z',
'gnu++03', 'gnu++11', 'gnu++14', 'gnu++1z'],
'none'),
'cpp_debugstl': coredata.UserBooleanOption('cpp_debugstl',
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index af5a19a..7fbf18a 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -14,6 +14,7 @@
# limitations under the License.
import pickle, os, uuid
+import sys
from pathlib import PurePath
from collections import OrderedDict
from .mesonlib import MesonException, commonpath
@@ -185,10 +186,7 @@ class CoreData:
self.external_preprocess_args = {} # CPPFLAGS only
self.external_args = {} # CPPFLAGS + CFLAGS
self.external_link_args = {} # CFLAGS + LDFLAGS (with MSVC: only LDFLAGS)
- if options.cross_file is not None:
- self.cross_file = os.path.join(os.getcwd(), options.cross_file)
- else:
- self.cross_file = None
+ self.cross_file = self.__load_cross_file(options.cross_file)
self.wrap_mode = options.wrap_mode
self.compilers = OrderedDict()
self.cross_compilers = OrderedDict()
@@ -197,6 +195,46 @@ class CoreData:
# Only to print a warning if it changes between Meson invocations.
self.pkgconf_envvar = os.environ.get('PKG_CONFIG_PATH', '')
+ @staticmethod
+ def __load_cross_file(filename):
+ """Try to load the cross file.
+
+ If the filename is None return None. If the filename is an absolute
+ (after resolving variables and ~), return that absolute path. Next,
+ check if the file is relative to the current source dir. If the path
+ still isn't resolved do the following:
+ Linux + BSD:
+ - $XDG_DATA_HOME/meson/cross (or ~/.local/share/meson/cross if
+ undefined)
+ - $XDG_DATA_DIRS/meson/cross (or
+ /usr/local/share/meson/cross:/usr/share/meson/cross if undefined)
+ - Error
+ *:
+ - Error
+ BSD follows the Linux path and will honor XDG_* if set. This simplifies
+ the implementation somewhat, especially since most BSD users wont set
+ those environment variables.
+ """
+ if filename is None:
+ return None
+ filename = os.path.expanduser(os.path.expandvars(filename))
+ if os.path.isabs(filename):
+ return filename
+ path_to_try = os.path.abspath(filename)
+ if os.path.exists(path_to_try):
+ return path_to_try
+ if sys.platform == 'linux' or 'bsd' in sys.platform.lower():
+ paths = [
+ os.environ.get('XDG_DATA_HOME', os.path.expanduser('~/.local/share')),
+ ] + os.environ.get('XDG_DATA_DIRS', '/usr/local/share:/usr/share').split(':')
+ for path in paths:
+ path_to_try = os.path.join(path, 'meson', 'cross', filename)
+ if os.path.exists(path_to_try):
+ return path_to_try
+ raise MesonException('Cannot find specified cross file: ' + filename)
+
+ raise MesonException('Cannot find specified cross file: ' + filename)
+
def sanitize_prefix(self, prefix):
if not os.path.isabs(prefix):
raise MesonException('prefix value {!r} must be an absolute path'
diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py
index 682182c..a720232 100644
--- a/mesonbuild/dependencies/base.py
+++ b/mesonbuild/dependencies/base.py
@@ -560,7 +560,11 @@ class ExternalProgram:
with open(script) as f:
first_line = f.readline().strip()
if first_line.startswith('#!'):
- commands = first_line[2:].split('#')[0].strip().split()
+ # In a shebang, everything before the first space is assumed to
+ # be the command to run and everything after the first space is
+ # the single argument to pass to that command. So we must split
+ # exactly once.
+ commands = first_line[2:].split('#')[0].strip().split(maxsplit=1)
if mesonlib.is_windows():
# Windows does not have UNIX paths so remove them,
# but don't remove Windows paths
diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py
index e966597..41666a3 100644
--- a/mesonbuild/dependencies/misc.py
+++ b/mesonbuild/dependencies/misc.py
@@ -625,8 +625,10 @@ class Python3Dependency(ExternalDependency):
elif mesonlib.is_osx() and DependencyMethods.EXTRAFRAMEWORK in self.methods:
# In OSX the Python 3 framework does not have a version
# number in its name.
- fw = ExtraFrameworkDependency('python', False, None, self.env,
- self.language, kwargs)
+ # There is a python in /System/Library/Frameworks, but that's
+ # python 2, Python 3 will always bin in /Library
+ fw = ExtraFrameworkDependency(
+ 'python', False, '/Library/Frameworks', self.env, self.language, kwargs)
if fw.found():
self.compile_args = fw.get_compile_args()
self.link_args = fw.get_link_args()
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index b301fee..3e89305 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -1368,7 +1368,7 @@ permitted_kwargs = {'add_global_arguments': {'language'},
'build_target': build_target_kwargs,
'configure_file': {'input', 'output', 'configuration', 'command', 'install_dir', 'capture', 'install'},
'custom_target': {'input', 'output', 'command', 'install', 'install_dir', 'build_always', 'capture', 'depends', 'depend_files', 'depfile', 'build_by_default'},
- 'dependency': {'default_options', 'fallback', 'language', 'method', 'modules', 'native', 'required', 'static', 'version'},
+ 'dependency': {'default_options', 'fallback', 'language', 'method', 'modules', 'optional_modules', 'native', 'required', 'static', 'version'},
'declare_dependency': {'include_directories', 'link_with', 'sources', 'dependencies', 'compile_args', 'link_args', 'version'},
'executable': exe_kwargs,
'find_program': {'required', 'native'},
diff --git a/mesonbuild/mlog.py b/mesonbuild/mlog.py
index 18c1e6a..a0d07ec 100644
--- a/mesonbuild/mlog.py
+++ b/mesonbuild/mlog.py
@@ -18,8 +18,10 @@ import sys, os, platform, io
information about Meson runs. Some output goes to screen,
some to logging dir and some goes to both."""
-colorize_console = platform.system().lower() != 'windows' and os.isatty(sys.stdout.fileno()) and \
- os.environ.get('TERM') != 'dumb'
+if platform.system().lower() == 'windows':
+ colorize_console = os.isatty(sys.stdout.fileno()) and os.environ.get('ANSICON')
+else:
+ colorize_console = os.isatty(sys.stdout.fileno()) and os.environ.get('TERM') != 'dumb'
log_dir = None
log_file = None
log_fname = 'meson-log.txt'
diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py
index 7e61242..f916c2c 100644
--- a/mesonbuild/modules/gnome.py
+++ b/mesonbuild/modules/gnome.py
@@ -220,9 +220,10 @@ class GnomeModule(ExtensionModule):
input_file,
'--generate-dependencies']
+ # Prefer generated files over source files
+ cmd += ['--sourcedir', state.subdir] # Current build dir
for source_dir in source_dirs:
cmd += ['--sourcedir', os.path.join(state.subdir, source_dir)]
- cmd += ['--sourcedir', state.subdir] # Current dir
pc, stdout, stderr = Popen_safe(cmd, cwd=state.environment.get_source_dir())
if pc.returncode != 0:
@@ -240,25 +241,20 @@ class GnomeModule(ExtensionModule):
#
# If there are multiple generated resource files with the same basename
# then this code will get confused.
-
def exists_in_srcdir(f):
return os.path.exists(os.path.join(state.environment.get_source_dir(), f))
- missing_dep_files = [f for f in dep_files if not exists_in_srcdir(f)]
depends = []
subdirs = []
- for missing in missing_dep_files:
- found = False
- missing_basename = os.path.basename(missing)
-
+ for resfile in dep_files[:]:
+ resbasename = os.path.basename(resfile)
for dep in dependencies:
if hasattr(dep, 'held_object'):
dep = dep.held_object
if isinstance(dep, mesonlib.File):
- if dep.fname != missing_basename:
+ if dep.fname != resbasename:
continue
- found = True
- dep_files.remove(missing)
+ dep_files.remove(resfile)
dep_files.append(dep)
subdirs.append(dep.subdir)
break
@@ -266,12 +262,11 @@ class GnomeModule(ExtensionModule):
fname = None
outputs = {(o, os.path.basename(o)) for o in dep.get_outputs()}
for o, baseo in outputs:
- if baseo == missing_basename:
+ if baseo == resbasename:
fname = o
break
if fname is not None:
- found = True
- dep_files.remove(missing)
+ dep_files.remove(resfile)
dep_files.append(
mesonlib.File(
is_built=True,
@@ -280,16 +275,13 @@ class GnomeModule(ExtensionModule):
depends.append(dep)
subdirs.append(dep.get_subdir())
break
- else:
- raise RuntimeError('Unreachable code.')
-
- if not found:
- raise MesonException(
- 'Resource "%s" listed in "%s" was not found. If this is a '
- 'generated file, pass the target that generates it to '
- 'gnome.compile_resources() using the "dependencies" '
- 'keyword argument.' % (missing, input_file))
-
+ else:
+ if not exists_in_srcdir(resfile):
+ raise MesonException(
+ 'Resource "%s" listed in "%s" was not found. If this is a '
+ 'generated file, pass the target that generates it to '
+ 'gnome.compile_resources() using the "dependencies" '
+ 'keyword argument.' % (resfile, input_file))
return dep_files, depends, subdirs
def _get_link_args(self, state, lib, depends=None, include_rpath=False,
@@ -723,7 +715,8 @@ This will become a hard error in the future.''')
@permittedKwargs({'main_xml', 'main_sgml', 'src_dir', 'dependencies', 'install',
'install_dir', 'scan_args', 'scanobjs_args', 'gobject_typesfile',
'fixxref_args', 'html_args', 'html_assets', 'content_files',
- 'mkdb_args', 'ignore_headers', 'include_directories'})
+ 'mkdb_args', 'ignore_headers', 'include_directories',
+ 'namespace', 'mode', 'expand_content_files'})
def gtkdoc(self, state, args, kwargs):
if len(args) != 1:
raise MesonException('Gtkdoc must have one positional argument.')
diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py
index 30322aa..b39f5af 100644
--- a/mesonbuild/mtest.py
+++ b/mesonbuild/mtest.py
@@ -482,35 +482,41 @@ TIMEOUT: %4d
numlen = len('%d' % len(tests))
self.open_log_files()
wrap = self.get_wrapper()
+ startdir = os.getcwd()
+ if self.options.wd:
+ os.chdir(self.options.wd)
- for _ in range(self.options.repeat):
- for i, test in enumerate(tests):
- visible_name = self.get_pretty_suite(test)
-
- if self.options.gdb:
- test.timeout = None
-
- if not test.is_parallel or self.options.gdb:
- self.drain_futures(futures)
- futures = []
- res = self.run_single_test(wrap, test)
- self.print_stats(numlen, tests, visible_name, res, i)
- else:
- if not executor:
- executor = conc.ThreadPoolExecutor(max_workers=self.options.num_processes)
- f = executor.submit(self.run_single_test, wrap, test)
- futures.append((f, numlen, tests, visible_name, i))
+ try:
+ for _ in range(self.options.repeat):
+ for i, test in enumerate(tests):
+ visible_name = self.get_pretty_suite(test)
+
+ if self.options.gdb:
+ test.timeout = None
+
+ if not test.is_parallel or self.options.gdb:
+ self.drain_futures(futures)
+ futures = []
+ res = self.run_single_test(wrap, test)
+ self.print_stats(numlen, tests, visible_name, res, i)
+ else:
+ if not executor:
+ executor = conc.ThreadPoolExecutor(max_workers=self.options.num_processes)
+ f = executor.submit(self.run_single_test, wrap, test)
+ futures.append((f, numlen, tests, visible_name, i))
+ if self.options.repeat > 1 and self.fail_count:
+ break
if self.options.repeat > 1 and self.fail_count:
break
- if self.options.repeat > 1 and self.fail_count:
- break
- self.drain_futures(futures)
- self.print_summary()
- self.print_collected_logs()
+ self.drain_futures(futures)
+ self.print_summary()
+ self.print_collected_logs()
- if self.logfilename:
- print('Full log written to %s' % self.logfilename)
+ if self.logfilename:
+ print('Full log written to %s' % self.logfilename)
+ finally:
+ os.chdir(startdir)
def drain_futures(self, futures):
for i in futures:
diff --git a/run_unittests.py b/run_unittests.py
index 42f4e19..9bf712c 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -18,10 +18,12 @@ import shlex
import subprocess
import re, json
import tempfile
+import textwrap
import os
import shutil
import sys
import unittest
+from unittest import mock
from configparser import ConfigParser
from glob import glob
from pathlib import PurePath
@@ -2269,6 +2271,50 @@ endian = 'little'
self.init(testdir, ['-Db_lto=true'], default_args=False)
self.build('reconfigure')
+ def test_cross_file_system_paths(self):
+ testdir = os.path.join(self.common_test_dir, '1 trivial')
+ cross_content = textwrap.dedent("""\
+ [binaries]
+ c = '/usr/bin/cc'
+ ar = '/usr/bin/ar'
+ strip = '/usr/bin/ar'
+
+ [properties]
+
+ [host_machine]
+ system = 'linux'
+ cpu_family = 'x86'
+ cpu = 'i686'
+ endian = 'little'
+ """)
+
+ with tempfile.TemporaryDirectory() as d:
+ dir_ = os.path.join(d, 'meson', 'cross')
+ os.makedirs(dir_)
+ with tempfile.NamedTemporaryFile('w', dir=dir_, delete=False) as f:
+ f.write(cross_content)
+ name = os.path.basename(f.name)
+
+ with mock.patch.dict(os.environ, {'XDG_DATA_HOME': d}):
+ self.init(testdir, ['--cross-file=' + name], inprocess=True)
+ self.wipe()
+
+ with mock.patch.dict(os.environ, {'XDG_DATA_DIRS': d}):
+ os.environ.pop('XDG_DATA_HOME', None)
+ self.init(testdir, ['--cross-file=' + name], inprocess=True)
+ self.wipe()
+
+ with tempfile.TemporaryDirectory() as d:
+ dir_ = os.path.join(d, '.local', 'share', 'meson', 'cross')
+ os.makedirs(dir_)
+ with tempfile.NamedTemporaryFile('w', dir=dir_, delete=False) as f:
+ f.write(cross_content)
+ name = os.path.basename(f.name)
+
+ with mock.patch('mesonbuild.coredata.os.path.expanduser', lambda x: x.replace('~', d)):
+ self.init(testdir, ['--cross-file=' + name], inprocess=True)
+ self.wipe()
+
class LinuxArmCrossCompileTests(BasePlatformTests):
'''
diff --git a/test cases/common/167 external program shebang parsing/input.txt b/test cases/common/167 external program shebang parsing/input.txt
new file mode 100644
index 0000000..40e30d4
--- /dev/null
+++ b/test cases/common/167 external program shebang parsing/input.txt
@@ -0,0 +1 @@
+some stuff here
diff --git a/test cases/common/167 external program shebang parsing/main.c b/test cases/common/167 external program shebang parsing/main.c
new file mode 100644
index 0000000..a90206b
--- /dev/null
+++ b/test cases/common/167 external program shebang parsing/main.c
@@ -0,0 +1,72 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#ifdef _WIN32
+ #include <io.h>
+ #include <windows.h>
+#else
+ #include <unistd.h>
+#endif
+
+/* Who cares about stack sizes in test programs anyway */
+#define LINE_LENGTH 4096
+
+static int
+intrp_copyfile (char * src, char * dest)
+{
+#ifdef _WIN32
+ if (!CopyFile (src, dest, FALSE))
+ return 1;
+ return 0;
+#else
+ return execlp ("cp", "copyfile", src, dest, NULL);
+#endif
+}
+
+static void
+parser_get_line (FILE * f, char line[LINE_LENGTH])
+{
+ if (!fgets (line, LINE_LENGTH, f))
+ fprintf (stderr, "%s\n", strerror (errno));
+}
+
+int
+main (int argc, char * argv[])
+{
+ FILE *f = NULL;
+ char line[LINE_LENGTH];
+
+ if (argc != 4) {
+ fprintf (stderr, "Invalid number of arguments: %i\n", argc);
+ goto err;
+ }
+
+ if ((f = fopen (argv[1], "r")) == NULL) {
+ fprintf (stderr, "%s\n", strerror (errno));
+ goto err;
+ }
+
+ parser_get_line (f, line);
+
+ if (!line || line[0] != '#' || line[1] != '!') {
+ fprintf (stderr, "Invalid script\n");
+ goto err;
+ }
+
+ parser_get_line (f, line);
+
+ if (!line || strncmp (line, "copy", 4) != 0) {
+ fprintf (stderr, "Syntax error: %s\n", line);
+ goto err;
+ }
+
+ return intrp_copyfile (argv[2], argv[3]);
+
+err:
+ fclose (f);
+ return 1;
+}
diff --git a/test cases/common/167 external program shebang parsing/meson.build b/test cases/common/167 external program shebang parsing/meson.build
new file mode 100644
index 0000000..c1cc5af
--- /dev/null
+++ b/test cases/common/167 external program shebang parsing/meson.build
@@ -0,0 +1,21 @@
+project('shebang parsing', 'c')
+
+interpreter = executable('aninterp', 'main.c', native : true)
+
+cdata = configuration_data()
+cdata.set('INTRP', interpreter.full_path())
+
+f = configure_file(input : 'script.int.in',
+ output : 'script.int',
+ configuration : cdata)
+
+# Test that parsing a shebang with spaces works properly. See `man execve`,
+# specifically the section on "Interpreter scripts" and the one under "NOTES".
+script = find_program(f)
+
+custom_target('interpthis',
+ input : 'input.txt',
+ output : 'output.txt',
+ depends : interpreter,
+ command : [script, '@INPUT@', '@OUTPUT@'],
+ build_by_default : true)
diff --git a/test cases/common/167 external program shebang parsing/script.int.in b/test cases/common/167 external program shebang parsing/script.int.in
new file mode 100644
index 0000000..77ff909
--- /dev/null
+++ b/test cases/common/167 external program shebang parsing/script.int.in
@@ -0,0 +1,2 @@
+#!/usr/bin/env @INTRP@
+copy
diff --git a/test cases/frameworks/9 wxwidgets/meson.build b/test cases/frameworks/9 wxwidgets/meson.build
index da3aa26..5f9419c 100644
--- a/test cases/frameworks/9 wxwidgets/meson.build
+++ b/test cases/frameworks/9 wxwidgets/meson.build
@@ -1,4 +1,4 @@
-project('wxwidgets test', 'cpp')
+project('wxwidgets test', 'cpp', default_options : ['cpp_std=c++11'])
wxd = dependency('wxwidgets', version : '>=5', required : false)
wxd = dependency('wxwidgets', version : '>=3.0.0', required : false)
diff --git a/test cases/osx/3 has function xcode8/meson.build b/test cases/osx/3 has function xcode8/meson.build
index 5fe3e53..0df7365 100644
--- a/test cases/osx/3 has function xcode8/meson.build
+++ b/test cases/osx/3 has function xcode8/meson.build
@@ -7,8 +7,12 @@ sdk_args = ['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/M
args_10_11 = ['-mmacosx-version-min=10.11'] + sdk_args
args_10_12 = ['-mmacosx-version-min=10.12'] + sdk_args
+# XCode 9 location for the macOS 10.13 SDK
+sdk_args = ['-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk']
+args_10_12 = ['-mmacosx-version-min=10.13'] + sdk_args
+
# Test requires XCode 8 which has the MacOSX 10.12 SDK
-if cc.version().version_compare('>=8.0')
+if cc.version().version_compare('>=8.0') and cc.version().version_compare('<9.0')
if cc.has_function('clock_gettime', args : args_10_11, prefix : '#include <time.h>')
error('Should not have found clock_gettime via <time.h> when targeting Mac OS X 10.11')
endif
@@ -22,5 +26,5 @@ if cc.version().version_compare('>=8.0')
error('Did NOT find clock_gettime w/o a prototype when targeting Mac OS X 10.12')
endif
else
- message('Test needs XCode 8, skipping...')
+ error('MESON_SKIP_TEST Test needs XCode 8.')
endif