aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.appveyor.yml9
-rw-r--r--docs/markdown/Continuous-Integration.md19
-rw-r--r--docs/markdown/Reference-tables.md1
-rw-r--r--docs/markdown/Syntax.md2
-rw-r--r--docs/markdown/howtox.md6
-rw-r--r--docs/markdown/snippets/builtin-python.md9
-rw-r--r--mesonbuild/backend/ninjabackend.py4
-rw-r--r--mesonbuild/backend/vs2010backend.py11
-rw-r--r--mesonbuild/backend/xcodebackend.py2
-rw-r--r--mesonbuild/coredata.py4
-rw-r--r--mesonbuild/dependencies/base.py2
-rw-r--r--mesonbuild/environment.py12
-rw-r--r--mesonbuild/interpreter.py2
-rw-r--r--mesonbuild/mesonlib.py73
-rw-r--r--mesonbuild/mesonmain.py94
-rw-r--r--mesonbuild/modules/pkgconfig.py11
-rw-r--r--mesonbuild/modules/python3.py2
-rw-r--r--mesonbuild/mtest.py8
-rw-r--r--mesonbuild/scripts/meson_install.py4
-rw-r--r--mesonbuild/scripts/regen_checker.py15
-rwxr-xr-xmsi/createmsi.py4
-rwxr-xr-xrun_project_tests.py27
-rwxr-xr-xrun_tests.py27
-rwxr-xr-xrun_unittests.py29
-rw-r--r--test cases/common/16 configure file/config5.h.in1
-rw-r--r--test cases/common/16 configure file/config6.h.in19
-rw-r--r--test cases/common/16 configure file/meson.build22
-rw-r--r--test cases/common/16 configure file/prog5.c6
-rw-r--r--test cases/common/16 configure file/prog6.c11
-rw-r--r--test cases/common/164 subproject dir name collision/a.c (renamed from test cases/common/163 subproject dir name collision/a.c)0
-rw-r--r--test cases/common/164 subproject dir name collision/custom_subproject_dir/B/b.c (renamed from test cases/common/163 subproject dir name collision/custom_subproject_dir/B/b.c)0
-rw-r--r--test cases/common/164 subproject dir name collision/custom_subproject_dir/B/meson.build (renamed from test cases/common/163 subproject dir name collision/custom_subproject_dir/B/meson.build)0
-rw-r--r--test cases/common/164 subproject dir name collision/custom_subproject_dir/C/c.c (renamed from test cases/common/163 subproject dir name collision/custom_subproject_dir/C/c.c)0
-rw-r--r--test cases/common/164 subproject dir name collision/custom_subproject_dir/C/meson.build (renamed from test cases/common/163 subproject dir name collision/custom_subproject_dir/C/meson.build)0
-rw-r--r--test cases/common/164 subproject dir name collision/meson.build (renamed from test cases/common/163 subproject dir name collision/meson.build)0
-rw-r--r--test cases/common/164 subproject dir name collision/other_subdir/custom_subproject_dir/other.c (renamed from test cases/common/163 subproject dir name collision/other_subdir/custom_subproject_dir/other.c)0
-rw-r--r--test cases/common/164 subproject dir name collision/other_subdir/meson.build (renamed from test cases/common/163 subproject dir name collision/other_subdir/meson.build)0
37 files changed, 310 insertions, 126 deletions
diff --git a/.appveyor.yml b/.appveyor.yml
index 22a5812..46edbd4 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -78,7 +78,14 @@ install:
- cmd: if %compiler%==msvc2010 ( call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" %arch% )
- cmd: if %compiler%==msvc2015 ( call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %arch% )
- cmd: if %compiler%==msvc2017 ( call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\VsDevCmd.bat" -arch=%arch% )
- - cmd: if %compiler%==msys2-mingw (if %arch%==x86 (set "PATH=C:\msys64\mingw32\bin;%PATH%") else (set "PATH=C:\msys64\mingw64\bin;%PATH%"))
+ - ps: |
+ If($Env:compiler -eq 'msys2-mingw') {
+ If($Env:arch -eq 'x86') {
+ $env:Path = 'C:\msys64\mingw32\bin;' + $env:Path
+ } Else {
+ $env:Path = 'C:\msys64\mingw64\bin;' + $env:Path
+ }
+ }
- cmd: if not %compiler%==cygwin ( set "PATH=%cd%;%MESON_PYTHON_PATH%;%PATH%;" )
- cmd: if %compiler%==cygwin ( set PYTHON=python3 ) else ( set PYTHON=python )
- cmd: if %compiler%==cygwin ( set WRAPPER=ci\run-in-cygwin.bat )
diff --git a/docs/markdown/Continuous-Integration.md b/docs/markdown/Continuous-Integration.md
index 96e8e5d..60e76d1 100644
--- a/docs/markdown/Continuous-Integration.md
+++ b/docs/markdown/Continuous-Integration.md
@@ -52,13 +52,14 @@ your best bet. Here's a sample `yml` file for use with that.
```yaml
os: Visual Studio 2015
-matrix:
- - arch: x86
- compiler: msvc2010
- - arch: x86
- compiler: msvc2015
- - arch: x64
- compiler: msvc2015
+environment:
+ matrix:
+ - arch: x86
+ compiler: msvc2010
+ - arch: x86
+ compiler: msvc2015
+ - arch: x64
+ compiler: msvc2015
platform:
- x64
@@ -66,10 +67,10 @@ platform:
install:
# Use the x86 python only when building for x86 for the cpython tests.
# For all other archs (including, say, arm), use the x64 python.
- - ps: (new-object net.webclient).DownloadFile('https://dl.dropboxusercontent.com/u/37517477/ninja.exe', 'C:\projects\meson\ninja.exe')
+ - ps: (new-object net.webclient).DownloadFile('https://www.dropbox.com/s/cyghxjrvgplu7sy/ninja.exe?dl=1', 'C:\projects\meson\ninja.exe')
- cmd: if %arch%==x86 (set MESON_PYTHON_PATH=C:\python34) else (set MESON_PYTHON_PATH=C:\python34-x64)
- cmd: echo Using Python at %MESON_PYTHON_PATH%
- - cmd: %MESON_PYTHON_PATH%\pip install meson
+ - cmd: "%MESON_PYTHON_PATH%\\pip install meson"
- cmd: if %compiler%==msvc2010 ( call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" %arch% )
- cmd: if %compiler%==msvc2015 ( call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %arch% )
diff --git a/docs/markdown/Reference-tables.md b/docs/markdown/Reference-tables.md
index b604fb6..ff28662 100644
--- a/docs/markdown/Reference-tables.md
+++ b/docs/markdown/Reference-tables.md
@@ -55,6 +55,7 @@ These are provided by the `.system()` method call.
| linux | |
| darwin | Either OSX or iOS |
| windows | Any version of Windows |
+| cygwin | The Cygwin environment for Windows |
Any string not listed above is not guaranteed to remain stable in
future releases. \ No newline at end of file
diff --git a/docs/markdown/Syntax.md b/docs/markdown/Syntax.md
index 88b9bbb..84403f4 100644
--- a/docs/markdown/Syntax.md
+++ b/docs/markdown/Syntax.md
@@ -84,7 +84,7 @@ single quote do it like this:
single quote = 'contains a \' character'
```
-Similarly `\n` gets converted to a newline and `\\\\` to a single
+Similarly `\n` gets converted to a newline and `\\` to a single
backslash.
#### String concatenation
diff --git a/docs/markdown/howtox.md b/docs/markdown/howtox.md
index c4aa9c5..4e7e220 100644
--- a/docs/markdown/howtox.md
+++ b/docs/markdown/howtox.md
@@ -125,6 +125,12 @@ Install scan-build and configure your project. Then do this:
$ ninja scan-build
```
+You can use the `SCAN_BUILD` environment variable to choose the scan-build executable.
+```console
+$ SCAN_BUILD=<your exe> ninja scan-build
+```
+
+
## Use profile guided optimization
Using profile guided optimization with GCC is a two phase operation. First we set up the project with profile measurements enabled and compile it.
diff --git a/docs/markdown/snippets/builtin-python.md b/docs/markdown/snippets/builtin-python.md
new file mode 100644
index 0000000..01bb6e0
--- /dev/null
+++ b/docs/markdown/snippets/builtin-python.md
@@ -0,0 +1,9 @@
+# Embedded Python in Windows MSI packages
+
+Meson now ships an internal version of Python in the MSI installer packages.
+This means that it can run Python scripts that are part of your build
+transparently. That is, if you do the following:
+
+ myprog = find_program('myscript.py')
+
+Then Meson will run the script with its internal Python version if necessary.
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index c633daf..cea1b08 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -2524,7 +2524,7 @@ rule FORTRAN_DEP_HACK
gcno_elem = NinjaBuildElement(self.all_outputs, 'meson-clean-gcno', 'CUSTOM_COMMAND', 'PHONY')
script_root = self.environment.get_script_dir()
clean_script = os.path.join(script_root, 'delwithsuffix.py')
- gcno_elem.add_item('COMMAND', [sys.executable, clean_script, '.', 'gcno'])
+ gcno_elem.add_item('COMMAND', mesonlib.python_command + [clean_script, '.', 'gcno'])
gcno_elem.add_item('description', 'Deleting gcno files.')
gcno_elem.write(outfile)
# Alias that runs the target defined above
@@ -2533,7 +2533,7 @@ rule FORTRAN_DEP_HACK
gcda_elem = NinjaBuildElement(self.all_outputs, 'meson-clean-gcda', 'CUSTOM_COMMAND', 'PHONY')
script_root = self.environment.get_script_dir()
clean_script = os.path.join(script_root, 'delwithsuffix.py')
- gcda_elem.add_item('COMMAND', [sys.executable, clean_script, '.', 'gcda'])
+ gcda_elem.add_item('COMMAND', mesonlib.python_command + [clean_script, '.', 'gcda'])
gcda_elem.add_item('description', 'Deleting gcda files.')
gcda_elem.write(outfile)
# Alias that runs the target defined above
diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
index e4e9696..69ee3e5 100644
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -23,7 +23,7 @@ from .. import dependencies
from .. import mlog
from .. import compilers
from ..compilers import CompilerArgs
-from ..mesonlib import MesonException, File
+from ..mesonlib import MesonException, File, python_command
from ..environment import Environment
def autodetect_vs_version(build):
@@ -396,10 +396,11 @@ class Vs2010Backend(backends.Backend):
action = ET.SubElement(root, 'ItemDefinitionGroup')
customstep = ET.SubElement(action, 'PostBuildEvent')
cmd_raw = [target.command] + target.args
- cmd = [sys.executable, os.path.join(self.environment.get_script_dir(), 'commandrunner.py'),
- self.environment.get_build_dir(),
- self.environment.get_source_dir(),
- self.get_target_dir(target)] + self.environment.get_build_command()
+ cmd = python_command + \
+ [os.path.join(self.environment.get_script_dir(), 'commandrunner.py'),
+ self.environment.get_build_dir(),
+ self.environment.get_source_dir(),
+ self.get_target_dir(target)] + self.environment.get_build_command()
for i in cmd_raw:
if isinstance(i, build.BuildTarget):
cmd.append(os.path.join(self.environment.get_build_dir(), self.get_target_filename(i)))
diff --git a/mesonbuild/backend/xcodebackend.py b/mesonbuild/backend/xcodebackend.py
index 199d7df..aca3aea 100644
--- a/mesonbuild/backend/xcodebackend.py
+++ b/mesonbuild/backend/xcodebackend.py
@@ -567,7 +567,7 @@ class XCodeBackend(backends.Backend):
self.write_line('shellPath = /bin/sh;')
script_root = self.environment.get_script_dir()
test_script = os.path.join(script_root, 'meson_test.py')
- cmd = [sys.executable, test_script, test_data, '--wd', self.environment.get_build_dir()]
+ cmd = mesonlib.python_command + [test_script, test_data, '--wd', self.environment.get_build_dir()]
cmdstr = ' '.join(["'%s'" % i for i in cmd])
self.write_line('shellScript = "%s";' % cmdstr)
self.write_line('showEnvVarsInLog = 0;')
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index e8b23fd..401211a 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -193,6 +193,10 @@ class CoreData:
# string is of type 'C:\' because 'C:' is not an absolute path.
if len(prefix) == 3 and prefix[1] == ':':
pass
+ # If prefix is a single character, preserve it since it is
+ # the root directory.
+ elif len(prefix) == 1:
+ pass
else:
prefix = prefix[:-1]
return prefix
diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py
index fcc74b5..15b47bc 100644
--- a/mesonbuild/dependencies/base.py
+++ b/mesonbuild/dependencies/base.py
@@ -434,7 +434,7 @@ class ExternalProgram:
commands = commands[1:]
# Windows does not ship python3.exe, but we know the path to it
if len(commands) > 0 and commands[0] == 'python3':
- commands[0] = sys.executable
+ commands = mesonlib.python_command + commands[1:]
return commands + [script]
except Exception:
pass
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index d9146eb..58cc9b9 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -325,14 +325,10 @@ class Environment:
return self.coredata
def get_build_command(self, unbuffered=False):
- # If running an executable created with cx_freeze,
- # Python might not be installed so don't prefix
- # the command with it.
- if sys.executable.endswith('meson.exe'):
- return [sys.executable]
- if unbuffered:
- [sys.executable, '-u', self.meson_script_launcher]
- return [sys.executable, self.meson_script_launcher]
+ cmd = mesonlib.meson_command[:]
+ if unbuffered and 'python' in cmd[0]:
+ cmd.insert(1, '-u')
+ return cmd
def is_header(self, fname):
return is_header(fname)
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index 6300f7f..fbf9a21 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -1358,6 +1358,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'},
'declare_dependency': {'include_directories', 'link_with', 'sources', 'dependencies', 'compile_args', 'link_args', 'version'},
'executable': exe_kwargs,
'find_program': {'required', 'native'},
@@ -2130,6 +2131,7 @@ to directly access options of other subprojects.''')
break
return identifier, cached_dep
+ @permittedKwargs(permitted_kwargs['dependency'])
def func_dependency(self, node, args, kwargs):
self.validate_arguments(args, 1, [str])
name = args[0]
diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py
index f74c6c1..b432bf3 100644
--- a/mesonbuild/mesonlib.py
+++ b/mesonbuild/mesonlib.py
@@ -22,6 +22,37 @@ import collections
from glob import glob
+def detect_meson_py_location():
+ c = sys.argv[0]
+ c_fname = os.path.split(c)[1]
+ if c_fname == 'meson' or c_fname == 'meson.py':
+ # $ /foo/meson.py <args>
+ if os.path.isabs(c):
+ return c
+ # $ meson <args> (gets run from /usr/bin/meson)
+ in_path_exe = shutil.which(c_fname)
+ if in_path_exe:
+ return in_path_exe
+ # $ python3 ./meson.py <args>
+ if os.path.exists(c):
+ return os.path.join(os.getcwd(), c)
+
+ # The only thing remaining is to try to find the bundled executable and
+ # pray distro packagers have not moved it.
+ fname = os.path.join(os.path.dirname(__file__), '..', 'meson.py')
+ if not os.path.exists(fname):
+ raise RuntimeError('Could not determine how to run Meson. Please file a bug with details.')
+ return fname
+
+if os.path.basename(sys.executable) == 'meson.exe':
+ # In Windows and using the MSI installed executable.
+ meson_command = [sys.executable]
+ python_command = [sys.executable, 'runpython']
+else:
+ python_command = [sys.executable]
+ meson_command = python_command + [detect_meson_py_location()]
+
+
# Put this in objects that should not get dumped to pickle files
# by accident.
import threading
@@ -394,24 +425,32 @@ def get_library_dirs():
def do_replacement(regex, line, confdata):
- match = re.search(regex, line)
missing_variables = set()
- while match:
- varname = match.group(1)
- if varname in confdata:
- (var, desc) = confdata.get(varname)
- if isinstance(var, str):
- pass
- elif isinstance(var, int):
- var = str(var)
- else:
- raise RuntimeError('Tried to replace a variable with something other than a string or int.')
+
+ def variable_replace(match):
+ # Pairs of escape characters before '@' or '\@'
+ if match.group(0).endswith('\\'):
+ num_escapes = match.end(0) - match.start(0)
+ return '\\' * (num_escapes // 2)
+ # Single escape character and '@'
+ elif match.group(0) == '\\@':
+ return '@'
+ # Template variable to be replaced
else:
- missing_variables.add(varname)
- var = ''
- line = line.replace('@' + varname + '@', var)
- match = re.search(regex, line)
- return line, missing_variables
+ varname = match.group(1)
+ if varname in confdata:
+ (var, desc) = confdata.get(varname)
+ if isinstance(var, str):
+ pass
+ elif isinstance(var, int):
+ var = str(var)
+ else:
+ raise RuntimeError('Tried to replace a variable with something other than a string or int.')
+ else:
+ missing_variables.add(varname)
+ var = ''
+ return var
+ return re.sub(regex, variable_replace, line), missing_variables
def do_mesondefine(line, confdata):
arr = line.split()
@@ -443,7 +482,7 @@ def do_conf_file(src, dst, confdata):
raise MesonException('Could not read input file %s: %s' % (src, str(e)))
# Only allow (a-z, A-Z, 0-9, _, -) as valid characters for a define
# Also allow escaping '@' with '\@'
- regex = re.compile(r'[^\\]?@([-a-zA-Z0-9_]+)@')
+ regex = re.compile(r'(?:\\\\)+(?=\\?@)|\\@|@([-a-zA-Z0-9_]+)@')
result = []
missing_variables = set()
for line in data:
diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py
index 8d5fb85..fa8c9e3 100644
--- a/mesonbuild/mesonmain.py
+++ b/mesonbuild/mesonmain.py
@@ -23,12 +23,9 @@ from . import mlog, coredata
from .mesonlib import MesonException
from .wrap import WrapMode, wraptool
-
-parser = argparse.ArgumentParser(prog='meson')
-
default_warning = '1'
-def add_builtin_argument(name, **kwargs):
+def add_builtin_argument(p, name, **kwargs):
k = kwargs.get('dest', name.replace('-', '_'))
c = coredata.get_builtin_option_choices(k)
b = True if kwargs.get('action', None) in ['store_true', 'store_false'] else False
@@ -42,31 +39,45 @@ def add_builtin_argument(name, **kwargs):
kwargs['default'] = default
else:
kwargs['default'] = argparse.SUPPRESS
- parser.add_argument('--' + name, help=h, **kwargs)
+ p.add_argument('--' + name, help=h, **kwargs)
-add_builtin_argument('prefix')
-add_builtin_argument('libdir')
-add_builtin_argument('libexecdir')
-add_builtin_argument('bindir')
-add_builtin_argument('sbindir')
-add_builtin_argument('includedir')
-add_builtin_argument('datadir')
-add_builtin_argument('mandir')
-add_builtin_argument('infodir')
-add_builtin_argument('localedir')
-add_builtin_argument('sysconfdir')
-add_builtin_argument('localstatedir')
-add_builtin_argument('sharedstatedir')
-add_builtin_argument('backend')
-add_builtin_argument('buildtype')
-add_builtin_argument('strip', action='store_true')
-add_builtin_argument('unity')
-add_builtin_argument('werror', action='store_true')
-add_builtin_argument('layout')
-add_builtin_argument('default-library')
-add_builtin_argument('warnlevel', dest='warning_level')
-add_builtin_argument('stdsplit', action='store_false')
-add_builtin_argument('errorlogs', action='store_false')
+def create_parser():
+ p = argparse.ArgumentParser(prog='meson')
+ add_builtin_argument(p, 'prefix')
+ add_builtin_argument(p, 'libdir')
+ add_builtin_argument(p, 'libexecdir')
+ add_builtin_argument(p, 'bindir')
+ add_builtin_argument(p, 'sbindir')
+ add_builtin_argument(p, 'includedir')
+ add_builtin_argument(p, 'datadir')
+ add_builtin_argument(p, 'mandir')
+ add_builtin_argument(p, 'infodir')
+ add_builtin_argument(p, 'localedir')
+ add_builtin_argument(p, 'sysconfdir')
+ add_builtin_argument(p, 'localstatedir')
+ add_builtin_argument(p, 'sharedstatedir')
+ add_builtin_argument(p, 'backend')
+ add_builtin_argument(p, 'buildtype')
+ add_builtin_argument(p, 'strip', action='store_true')
+ add_builtin_argument(p, 'unity')
+ add_builtin_argument(p, 'werror', action='store_true')
+ add_builtin_argument(p, 'layout')
+ add_builtin_argument(p, 'default-library')
+ add_builtin_argument(p, 'warnlevel', dest='warning_level')
+ add_builtin_argument(p, 'stdsplit', action='store_false')
+ add_builtin_argument(p, 'errorlogs', action='store_false')
+ p.add_argument('--cross-file', default=None,
+ help='File describing cross compilation environment.')
+ p.add_argument('-D', action='append', dest='projectoptions', default=[], metavar="option",
+ help='Set the value of an option, can be used several times to set multiple options.')
+ p.add_argument('-v', '--version', action='version',
+ version=coredata.version)
+ # See the mesonlib.WrapMode enum for documentation
+ p.add_argument('--wrap-mode', default=WrapMode.default,
+ type=wrapmodetype, choices=WrapMode,
+ help='Special wrap mode to use')
+ p.add_argument('directories', nargs='*')
+ return p
def wrapmodetype(string):
try:
@@ -76,18 +87,6 @@ def wrapmodetype(string):
msg = 'invalid argument {!r}, use one of {}'.format(string, msg)
raise argparse.ArgumentTypeError(msg)
-parser.add_argument('--cross-file', default=None,
- help='File describing cross compilation environment.')
-parser.add_argument('-D', action='append', dest='projectoptions', default=[], metavar="option",
- help='Set the value of an option, can be used several times to set multiple options.')
-parser.add_argument('-v', '--version', action='version',
- version=coredata.version)
-# See the mesonlib.WrapMode enum for documentation
-parser.add_argument('--wrap-mode', default=WrapMode.default,
- type=wrapmodetype, choices=WrapMode,
- help='Special wrap mode to use')
-parser.add_argument('directories', nargs='*')
-
class MesonApp:
def __init__(self, dir1, dir2, script_launcher, handshake, options, original_cmd_line_args):
@@ -155,7 +154,7 @@ class MesonApp:
def _generate(self, env):
mlog.debug('Build started at', datetime.datetime.now().isoformat())
- mlog.debug('Python binary:', sys.executable)
+ mlog.debug('Main binary:', sys.executable)
mlog.debug('Python system:', platform.system())
mlog.log(mlog.bold('The Meson build system'))
self.check_pkgconfig_envvar(env)
@@ -278,12 +277,13 @@ def run_script_command(args):
raise MesonException('Unknown internal command {}.'.format(cmdname))
return cmdfunc(cmdargs)
-def run(args, mainfile=None):
+def run(original_args, mainfile=None):
if sys.version_info < (3, 4):
print('Meson works correctly only with python 3.4+.')
print('You have python %s.' % sys.version)
print('Please update your environment')
return 1
+ args = original_args[:]
if len(args) > 0:
# First check if we want to run a subcommand.
cmd_name = args[0]
@@ -303,6 +303,12 @@ def run(args, mainfile=None):
return mconf.run(remaining_args)
elif cmd_name == 'wrap':
return wraptool.run(remaining_args)
+ elif cmd_name == 'runpython':
+ import runpy
+ script_file = remaining_args[0]
+ sys.argv[1:] = remaining_args[1:]
+ runpy.run_path(script_file, run_name='__main__')
+ sys.exit(0)
# No special command? Do the basic setup/reconf.
if len(args) >= 2 and args[0] == '--internal':
@@ -319,6 +325,8 @@ def run(args, mainfile=None):
else:
handshake = False
+ parser = create_parser()
+
args = mesonlib.expand_arguments(args)
options = parser.parse_args(args)
args = options.directories
@@ -342,7 +350,7 @@ def run(args, mainfile=None):
try:
if mainfile is None:
raise AssertionError('I iz broken. Sorry.')
- app = MesonApp(dir1, dir2, mainfile, handshake, options, sys.argv)
+ app = MesonApp(dir1, dir2, mainfile, handshake, options, original_args)
except Exception as e:
# Log directory does not exist, so just print
# to stdout.
diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py
index 52f3a50..f963323 100644
--- a/mesonbuild/modules/pkgconfig.py
+++ b/mesonbuild/modules/pkgconfig.py
@@ -55,6 +55,15 @@ class PkgConfigModule(ExtensionModule):
value = value.as_posix()
return value.replace(' ', '\ ')
+ def _make_relative(self, prefix, subdir):
+ if isinstance(prefix, PurePath):
+ prefix = prefix.as_posix()
+ if isinstance(subdir, PurePath):
+ subdir = subdir.as_posix()
+ if subdir.startswith(prefix):
+ subdir = subdir.replace(prefix, '')
+ return subdir
+
def generate_pkgconfig_file(self, state, libraries, subdirs, name, description,
url, version, pcfile, pub_reqs, priv_reqs,
conflicts, priv_libs, extra_cflags, variables):
@@ -98,7 +107,7 @@ class PkgConfigModule(ExtensionModule):
if install_dir is False:
continue
if isinstance(install_dir, str):
- yield '-L${prefix}/%s ' % self._escape(install_dir)
+ yield '-L${prefix}/%s ' % self._escape(self._make_relative(prefix, install_dir))
else: # install_dir is True
yield '-L${libdir}'
lname = self._get_lname(l, msg, pcfile)
diff --git a/mesonbuild/modules/python3.py b/mesonbuild/modules/python3.py
index 4fae88b..989e839 100644
--- a/mesonbuild/modules/python3.py
+++ b/mesonbuild/modules/python3.py
@@ -52,7 +52,7 @@ class Python3Module(ExtensionModule):
@noKwargs
def find_python(self, state, args, kwargs):
- py3 = dependencies.ExternalProgram('python3', sys.executable, silent=True)
+ py3 = dependencies.ExternalProgram('python3', mesonlib.python_command, silent=True)
return ModuleReturnValue(py3, [py3])
@noKwargs
diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py
index 267e130..30322aa 100644
--- a/mesonbuild/mtest.py
+++ b/mesonbuild/mtest.py
@@ -267,7 +267,13 @@ class TestHarness:
if is_windows():
subprocess.call(['taskkill', '/F', '/T', '/PID', str(p.pid)])
else:
- os.killpg(os.getpgid(p.pid), signal.SIGKILL)
+ try:
+ os.killpg(os.getpgid(p.pid), signal.SIGKILL)
+ except ProcessLookupError:
+ # Sometimes (e.g. with Wine) this happens.
+ # There's nothing we can do (maybe the process
+ # already died) so carry on.
+ pass
(stdo, stde) = p.communicate()
endtime = time.time()
duration = endtime - starttime
diff --git a/mesonbuild/scripts/meson_install.py b/mesonbuild/scripts/meson_install.py
index 9485967..fe1de1f 100644
--- a/mesonbuild/scripts/meson_install.py
+++ b/mesonbuild/scripts/meson_install.py
@@ -87,6 +87,8 @@ def set_mode(path, mode):
def restore_selinux_contexts():
'''
Restores the SELinux context for files in @selinux_updates
+
+ If $DESTDIR is set, do not warn if the call fails.
'''
try:
subprocess.check_call(['selinuxenabled'])
@@ -98,7 +100,7 @@ def restore_selinux_contexts():
with subprocess.Popen(['restorecon', '-F', '-f-', '-0'],
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as proc:
out, err = proc.communicate(input=b'\0'.join(os.fsencode(f) for f in selinux_updates) + b'\0')
- if proc.returncode != 0:
+ if proc.returncode != 0 and not os.environ.get('DESTDIR'):
print('Failed to restore SELinux context of installed files...',
'Standard output:', out.decode(),
'Standard error:', err.decode(), sep='\n')
diff --git a/mesonbuild/scripts/regen_checker.py b/mesonbuild/scripts/regen_checker.py
index 53c5428..a9b00c7 100644
--- a/mesonbuild/scripts/regen_checker.py
+++ b/mesonbuild/scripts/regen_checker.py
@@ -14,6 +14,7 @@
import sys, os
import pickle, subprocess
+from mesonbuild.mesonlib import meson_command
# This could also be used for XCode.
@@ -32,15 +33,11 @@ def need_regen(regeninfo, regen_timestamp):
return False
def regen(regeninfo, mesonscript, backend):
- if sys.executable.lower().endswith('meson.exe'):
- cmd_exe = [sys.executable]
- else:
- cmd_exe = [sys.executable, mesonscript]
- cmd = cmd_exe + ['--internal',
- 'regenerate',
- regeninfo.build_dir,
- regeninfo.source_dir,
- '--backend=' + backend]
+ cmd = meson_command + ['--internal',
+ 'regenerate',
+ regeninfo.build_dir,
+ regeninfo.source_dir,
+ '--backend=' + backend]
subprocess.check_call(cmd)
def run(args):
diff --git a/msi/createmsi.py b/msi/createmsi.py
index 7f165d8..3ea0958 100755
--- a/msi/createmsi.py
+++ b/msi/createmsi.py
@@ -82,9 +82,7 @@ class PackageGenerator:
modules = [os.path.splitext(os.path.split(x)[1])[0] for x in glob(os.path.join('mesonbuild/modules/*'))]
modules = ['mesonbuild.modules.' + x for x in modules if not x.startswith('_')]
modulestr = ','.join(modules)
- python = 'c:\\Python\python.exe'
- if sys.executable:
- python = sys.executable
+ python = shutil.which('python')
cxfreeze = os.path.join(os.path.dirname(python), "Scripts", "cxfreeze")
if not os.path.isfile(cxfreeze):
print("ERROR: This script requires cx_freeze module")
diff --git a/run_project_tests.py b/run_project_tests.py
index 17e095b..b94a976 100755
--- a/run_project_tests.py
+++ b/run_project_tests.py
@@ -33,7 +33,7 @@ import time
import multiprocessing
import concurrent.futures as conc
import re
-from run_unittests import get_fake_options, run_configure_inprocess
+from run_unittests import get_fake_options, run_configure
from run_tests import get_backend_commands, get_backend_args_for_dir, Backend
from run_tests import ensure_backend_detects_changes
@@ -322,14 +322,31 @@ def run_test(skipped, testdir, extra_args, compiler, backend, flags, commands, s
finally:
mlog.shutdown() # Close the log file because otherwise Windows wets itself.
+def pass_prefix_to_test(dirname):
+ if '40 prefix' in dirname:
+ return False
+ return True
+
+def pass_libdir_to_test(dirname):
+ if '8 install' in dirname:
+ return False
+ if '39 libdir' in dirname:
+ return False
+ return True
+
def _run_test(testdir, test_build_dir, install_dir, extra_args, compiler, backend, flags, commands, should_fail):
compile_commands, clean_commands, install_commands, uninstall_commands = commands
test_args = parse_test_args(testdir)
gen_start = time.time()
# Configure in-process
- gen_command = [meson_command, '--prefix', '/usr', '--libdir', 'lib', testdir, test_build_dir]\
- + flags + test_args + extra_args
- (returncode, stdo, stde) = run_configure_inprocess(gen_command)
+ if pass_prefix_to_test(testdir):
+ gen_args = ['--prefix', '/usr']
+ else:
+ gen_args = []
+ if pass_libdir_to_test(testdir):
+ gen_args += ['--libdir', 'lib']
+ gen_args += [testdir, test_build_dir] + flags + test_args + extra_args
+ (returncode, stdo, stde) = run_configure(meson_command, gen_args)
try:
logfile = os.path.join(test_build_dir, 'meson-logs/meson-log.txt')
with open(logfile, errors='ignore') as f:
@@ -603,7 +620,7 @@ def check_meson_commands_work():
testdir = 'test cases/common/1 trivial'
with AutoDeletedDir(tempfile.mkdtemp(prefix='b ', dir='.')) as build_dir:
print('Checking that configuring works...')
- gen_cmd = [sys.executable, meson_command, testdir, build_dir] + backend_flags
+ gen_cmd = mesonlib.meson_command + [testdir, build_dir] + backend_flags
pc, o, e = Popen_safe(gen_cmd)
if pc.returncode != 0:
raise RuntimeError('Failed to configure {!r}:\n{}\n{}'.format(testdir, e, o))
diff --git a/run_tests.py b/run_tests.py
index 79c9639..b287a1a 100755
--- a/run_tests.py
+++ b/run_tests.py
@@ -31,6 +31,12 @@ from glob import glob
Backend = Enum('Backend', 'ninja vs xcode')
+if 'MESON_EXE' in os.environ:
+ import shlex
+ meson_exe = shlex.split(os.environ['MESON_EXE'])
+else:
+ meson_exe = None
+
if mesonlib.is_windows() or mesonlib.is_cygwin():
exe_suffix = '.exe'
else:
@@ -127,18 +133,28 @@ def get_fake_options(prefix):
def should_run_linux_cross_tests():
return shutil.which('arm-linux-gnueabihf-gcc-7') and not platform.machine().lower().startswith('arm')
-def run_configure_inprocess(commandlist):
+def run_configure_inprocess(meson_command, commandlist):
old_stdout = sys.stdout
sys.stdout = mystdout = StringIO()
old_stderr = sys.stderr
sys.stderr = mystderr = StringIO()
try:
- returncode = mesonmain.run(commandlist[1:], commandlist[0])
+ returncode = mesonmain.run(commandlist, meson_command)
finally:
sys.stdout = old_stdout
sys.stderr = old_stderr
return returncode, mystdout.getvalue(), mystderr.getvalue()
+def run_configure_external(full_command):
+ pc, o, e = mesonlib.Popen_safe(full_command)
+ return pc.returncode, o, e
+
+def run_configure(meson_command, commandlist):
+ global meson_exe
+ if meson_exe:
+ return run_configure_external(meson_exe + commandlist)
+ return run_configure_inprocess(meson_command, commandlist)
+
class FakeEnvironment(object):
def __init__(self):
self.cross_info = None
@@ -207,11 +223,12 @@ if __name__ == '__main__':
'coverage.process_startup()\n')
env['COVERAGE_PROCESS_START'] = '.coveragerc'
env['PYTHONPATH'] = os.pathsep.join([td] + env.get('PYTHONPATH', []))
- returncode += subprocess.call([sys.executable, 'run_unittests.py', '-v'], env=env)
+ returncode += subprocess.call(mesonlib.python_command + ['run_unittests.py', '-v'], env=env)
# Ubuntu packages do not have a binary without -6 suffix.
if should_run_linux_cross_tests():
print(mlog.bold('Running cross compilation tests.').get_text(mlog.colorize_console))
print()
- returncode += subprocess.call([sys.executable, 'run_cross_test.py', 'cross/ubuntu-armhf.txt'], env=env)
- returncode += subprocess.call([sys.executable, 'run_project_tests.py'] + sys.argv[1:], env=env)
+ returncode += subprocess.call(mesonlib.python_command + ['run_cross_test.py', 'cross/ubuntu-armhf.txt'],
+ env=env)
+ returncode += subprocess.call(mesonlib.python_command + ['run_project_tests.py'] + sys.argv[1:], env=env)
sys.exit(returncode)
diff --git a/run_unittests.py b/run_unittests.py
index 80c58ea..fe75074 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -34,13 +34,14 @@ import mesonbuild.mesonlib
import mesonbuild.coredata
from mesonbuild.interpreter import ObjectHolder
from mesonbuild.mesonlib import is_linux, is_windows, is_osx, is_cygwin, windows_proof_rmtree
+from mesonbuild.mesonlib import python_command, meson_command
from mesonbuild.environment import Environment
from mesonbuild.dependencies import DependencyException
from mesonbuild.dependencies import PkgConfigDependency, ExternalProgram
from run_tests import exe_suffix, get_fake_options, FakeEnvironment
from run_tests import get_builddir_target_args, get_backend_commands, Backend
-from run_tests import ensure_backend_detects_changes, run_configure_inprocess
+from run_tests import ensure_backend_detects_changes, run_configure, meson_exe
from run_tests import should_run_linux_cross_tests
@@ -460,11 +461,12 @@ class BasePlatformTests(unittest.TestCase):
# Get the backend
# FIXME: Extract this from argv?
self.backend = getattr(Backend, os.environ.get('MESON_UNIT_TEST_BACKEND', 'ninja'))
- self.meson_args = [os.path.join(src_root, 'meson.py'), '--backend=' + self.backend.name]
- self.meson_command = [sys.executable] + self.meson_args
- self.mconf_command = [sys.executable, os.path.join(src_root, 'meson.py'), 'configure']
- self.mintro_command = [sys.executable, os.path.join(src_root, 'meson.py'), 'introspect']
- self.mtest_command = [sys.executable, os.path.join(src_root, 'meson.py'), 'test', '-C', self.builddir]
+ self.meson_mainfile = os.path.join(src_root, 'meson.py')
+ self.meson_args = ['--backend=' + self.backend.name]
+ self.meson_command = meson_command + self.meson_args
+ self.mconf_command = meson_command + ['configure']
+ self.mintro_command = meson_command + ['introspect']
+ self.mtest_command = meson_command + ['test', '-C', self.builddir]
# Backend-specific build commands
self.build_command, self.clean_command, self.test_command, self.install_command, \
self.uninstall_command = get_backend_commands(self.backend)
@@ -527,7 +529,7 @@ class BasePlatformTests(unittest.TestCase):
self.privatedir = os.path.join(self.builddir, 'meson-private')
if inprocess:
try:
- out = run_configure_inprocess(self.meson_args + args + extra_args)[1]
+ out = run_configure(self.meson_mainfile, self.meson_args + args + extra_args)[1]
except:
self._print_meson_log()
raise
@@ -1121,14 +1123,14 @@ class AllPlatformTests(BasePlatformTests):
# exelist + some argument. This is meant to test that setting
# something like `ccache gcc -pipe` or `distcc ccache gcc` works.
wrapper = os.path.join(testdir, 'compiler wrapper.py')
- wrappercc = [sys.executable, wrapper] + cc.get_exelist() + ['-DSOME_ARG']
+ wrappercc = python_command + [wrapper] + cc.get_exelist() + ['-DSOME_ARG']
wrappercc_s = ''
for w in wrappercc:
wrappercc_s += shlex.quote(w) + ' '
os.environ[evar] = wrappercc_s
wcc = getattr(env, 'detect_{}_compiler'.format(lang))(False)
# Check static linker too
- wrapperlinker = [sys.executable, wrapper] + linker.get_exelist() + linker.get_always_args()
+ wrapperlinker = python_command + [wrapper] + linker.get_exelist() + linker.get_always_args()
wrapperlinker_s = ''
for w in wrapperlinker:
wrapperlinker_s += shlex.quote(w) + ' '
@@ -1586,6 +1588,9 @@ class FailureTests(BasePlatformTests):
Assert that running meson configure on the specified @contents raises
a error message matching regex @match.
'''
+ if meson_exe is not None:
+ # Because the exception happens in a different process.
+ raise unittest.SkipTest('Can not test assert raise tests with an external Meson command.')
if langs is None:
langs = []
with open(self.mbuild, 'w') as f:
@@ -1717,12 +1722,12 @@ class WindowsTests(BasePlatformTests):
os.environ['PATH'] += os.pathsep + testdir
prog = ExternalProgram('test-script-ext')
self.assertTrue(prog.found(), msg='test-script-ext not found in PATH')
- self.assertPathEqual(prog.get_command()[0], sys.executable)
+ self.assertPathEqual(prog.get_command()[0], python_command[0])
self.assertPathBasenameEqual(prog.get_path(), 'test-script-ext.py')
# Finding a script in PATH with extension works and adds the interpreter
prog = ExternalProgram('test-script-ext.py')
self.assertTrue(prog.found(), msg='test-script-ext.py not found in PATH')
- self.assertPathEqual(prog.get_command()[0], sys.executable)
+ self.assertPathEqual(prog.get_command()[0], python_command[0])
self.assertPathBasenameEqual(prog.get_path(), 'test-script-ext.py')
def test_ignore_libs(self):
@@ -2246,7 +2251,7 @@ class RewriterTests(unittest.TestCase):
super().setUp()
src_root = os.path.dirname(__file__)
self.testroot = os.path.realpath(tempfile.mkdtemp())
- self.rewrite_command = [sys.executable, os.path.join(src_root, 'mesonrewriter.py')]
+ self.rewrite_command = python_command + [os.path.join(src_root, 'mesonrewriter.py')]
self.tmpdir = os.path.realpath(tempfile.mkdtemp())
self.workdir = os.path.join(self.tmpdir, 'foo')
self.test_dir = os.path.join(src_root, 'test cases/rewrite')
diff --git a/test cases/common/16 configure file/config5.h.in b/test cases/common/16 configure file/config5.h.in
new file mode 100644
index 0000000..323bec6
--- /dev/null
+++ b/test cases/common/16 configure file/config5.h.in
@@ -0,0 +1 @@
+#define MESSAGE "@var@"
diff --git a/test cases/common/16 configure file/config6.h.in b/test cases/common/16 configure file/config6.h.in
new file mode 100644
index 0000000..9719f87
--- /dev/null
+++ b/test cases/common/16 configure file/config6.h.in
@@ -0,0 +1,19 @@
+/* No escape */
+#define MESSAGE1 "@var1@"
+
+/* Single escape means no replace */
+#define MESSAGE2 "\@var1@"
+
+/* Replace pairs of escapes before '@' or '\@' with escape characters
+ * (note we have to double number of pairs due to C string escaping)
+ */
+#define MESSAGE3 "\\\\@var1@"
+
+/* Pairs of escapes and then single escape to avoid replace */
+#define MESSAGE4 "\\\\\@var1@"
+
+/* Check escaped variable does not overlap following variable */
+#define MESSAGE5 "\@var1@var2@"
+
+/* Check escape character outside variables */
+#define MESSAGE6 "\\ @ \@ \\\\@ \\\\\@"
diff --git a/test cases/common/16 configure file/meson.build b/test cases/common/16 configure file/meson.build
index 1e5a819..eda0a8f 100644
--- a/test cases/common/16 configure file/meson.build
+++ b/test cases/common/16 configure file/meson.build
@@ -109,3 +109,25 @@ configs = [
foreach c : configs
test('@0@'.format(c), file_contains_py, args: [ c, test_string ])
endforeach
+
+# Test variable is substituted only once
+conf5 = configuration_data()
+conf5.set('var', '@var2@')
+conf5.set('var2', 'error')
+configure_file(
+ input : 'config5.h.in',
+ output : '@BASENAME@',
+ configuration : conf5
+)
+test('test5', executable('prog5', 'prog5.c'))
+
+# Test escaping
+conf6 = configuration_data()
+conf6.set('var1', 'foo')
+conf6.set('var2', 'bar')
+configure_file(
+ input : 'config6.h.in',
+ output : '@BASENAME@',
+ configuration : conf6
+)
+test('test6', executable('prog6', 'prog6.c'))
diff --git a/test cases/common/16 configure file/prog5.c b/test cases/common/16 configure file/prog5.c
new file mode 100644
index 0000000..42c08f9
--- /dev/null
+++ b/test cases/common/16 configure file/prog5.c
@@ -0,0 +1,6 @@
+#include <string.h>
+#include <config5.h>
+
+int main(int argc, char **argv) {
+ return strcmp(MESSAGE, "@var2@");
+}
diff --git a/test cases/common/16 configure file/prog6.c b/test cases/common/16 configure file/prog6.c
new file mode 100644
index 0000000..7412404
--- /dev/null
+++ b/test cases/common/16 configure file/prog6.c
@@ -0,0 +1,11 @@
+#include <string.h>
+#include <config6.h>
+
+int main(int argc, char **argv) {
+ return strcmp(MESSAGE1, "foo")
+ || strcmp(MESSAGE2, "@var1@")
+ || strcmp(MESSAGE3, "\\foo")
+ || strcmp(MESSAGE4, "\\@var1@")
+ || strcmp(MESSAGE5, "@var1bar")
+ || strcmp(MESSAGE6, "\\ @ @ \\@ \\@");
+}
diff --git a/test cases/common/163 subproject dir name collision/a.c b/test cases/common/164 subproject dir name collision/a.c
index 6ed96fa..6ed96fa 100644
--- a/test cases/common/163 subproject dir name collision/a.c
+++ b/test cases/common/164 subproject dir name collision/a.c
diff --git a/test cases/common/163 subproject dir name collision/custom_subproject_dir/B/b.c b/test cases/common/164 subproject dir name collision/custom_subproject_dir/B/b.c
index 4c94ee9..4c94ee9 100644
--- a/test cases/common/163 subproject dir name collision/custom_subproject_dir/B/b.c
+++ b/test cases/common/164 subproject dir name collision/custom_subproject_dir/B/b.c
diff --git a/test cases/common/163 subproject dir name collision/custom_subproject_dir/B/meson.build b/test cases/common/164 subproject dir name collision/custom_subproject_dir/B/meson.build
index 280c60c..280c60c 100644
--- a/test cases/common/163 subproject dir name collision/custom_subproject_dir/B/meson.build
+++ b/test cases/common/164 subproject dir name collision/custom_subproject_dir/B/meson.build
diff --git a/test cases/common/163 subproject dir name collision/custom_subproject_dir/C/c.c b/test cases/common/164 subproject dir name collision/custom_subproject_dir/C/c.c
index eebfb9f..eebfb9f 100644
--- a/test cases/common/163 subproject dir name collision/custom_subproject_dir/C/c.c
+++ b/test cases/common/164 subproject dir name collision/custom_subproject_dir/C/c.c
diff --git a/test cases/common/163 subproject dir name collision/custom_subproject_dir/C/meson.build b/test cases/common/164 subproject dir name collision/custom_subproject_dir/C/meson.build
index abf0b1e..abf0b1e 100644
--- a/test cases/common/163 subproject dir name collision/custom_subproject_dir/C/meson.build
+++ b/test cases/common/164 subproject dir name collision/custom_subproject_dir/C/meson.build
diff --git a/test cases/common/163 subproject dir name collision/meson.build b/test cases/common/164 subproject dir name collision/meson.build
index 5531217..5531217 100644
--- a/test cases/common/163 subproject dir name collision/meson.build
+++ b/test cases/common/164 subproject dir name collision/meson.build
diff --git a/test cases/common/163 subproject dir name collision/other_subdir/custom_subproject_dir/other.c b/test cases/common/164 subproject dir name collision/other_subdir/custom_subproject_dir/other.c
index 0c27f84..0c27f84 100644
--- a/test cases/common/163 subproject dir name collision/other_subdir/custom_subproject_dir/other.c
+++ b/test cases/common/164 subproject dir name collision/other_subdir/custom_subproject_dir/other.c
diff --git a/test cases/common/163 subproject dir name collision/other_subdir/meson.build b/test cases/common/164 subproject dir name collision/other_subdir/meson.build
index 90cb67a..90cb67a 100644
--- a/test cases/common/163 subproject dir name collision/other_subdir/meson.build
+++ b/test cases/common/164 subproject dir name collision/other_subdir/meson.build