aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ci/appveyor-install.bat4
-rw-r--r--docs/markdown/Build-options.md13
-rw-r--r--docs/markdown/Generating-sources.md2
-rw-r--r--docs/markdown/Reference-manual.md18
-rw-r--r--docs/markdown/Release-notes-for-0.43.0/001-generator-capture.md4
-rw-r--r--docs/markdown/Unit-tests.md18
-rw-r--r--docs/markdown/i18n-module.md2
-rw-r--r--docs/markdown/snippets/custom-target-index.md21
-rw-r--r--mesonbuild/backend/backends.py2
-rw-r--r--mesonbuild/backend/ninjabackend.py59
-rw-r--r--mesonbuild/backend/vs2010backend.py21
-rw-r--r--mesonbuild/build.py40
-rw-r--r--mesonbuild/compilers/c.py33
-rw-r--r--mesonbuild/compilers/compilers.py2
-rw-r--r--mesonbuild/dependencies/dev.py84
-rw-r--r--mesonbuild/dependencies/misc.py19
-rw-r--r--mesonbuild/interpreter.py127
-rw-r--r--mesonbuild/interpreterbase.py37
-rw-r--r--mesonbuild/mesonmain.py10
-rw-r--r--mesonbuild/modules/__init__.py1
-rw-r--r--mesonbuild/modules/gnome.py34
-rw-r--r--mesonbuild/modules/i18n.py36
-rw-r--r--mesonbuild/modules/modtest.py2
-rw-r--r--mesonbuild/modules/pkgconfig.py2
-rw-r--r--mesonbuild/modules/python3.py3
-rw-r--r--mesonbuild/modules/qt4.py2
-rw-r--r--mesonbuild/modules/qt5.py2
-rw-r--r--mesonbuild/modules/rpm.py2
-rw-r--r--mesonbuild/modules/windows.py2
-rw-r--r--mesonbuild/scripts/meson_install.py4
-rw-r--r--mesonbuild/wrap/wrap.py90
-rwxr-xr-xmesonrewriter.py3
-rwxr-xr-xmsi/createmsi.py34
-rwxr-xr-xrun_project_tests.py2
-rwxr-xr-xrun_unittests.py2
-rw-r--r--setup.cfg8
-rw-r--r--test cases/common/114 multiple dir configure file/meson.build4
-rw-r--r--test cases/common/114 multiple dir configure file/subdir/foo.txt0
-rw-r--r--test cases/common/114 multiple dir configure file/subdir/meson.build7
-rw-r--r--test cases/common/147 mesonintrospect from scripts/check_env.py4
-rw-r--r--test cases/common/161 index customtarget/gen_sources.py49
-rw-r--r--test cases/common/161 index customtarget/lib.c20
-rw-r--r--test cases/common/161 index customtarget/meson.build32
-rw-r--r--test cases/common/161 index customtarget/subdir/foo.c22
-rw-r--r--test cases/common/161 index customtarget/subdir/meson.build19
-rw-r--r--test cases/common/42 string operations/meson.build7
-rw-r--r--test cases/common/98 gen extra/meson.build10
-rw-r--r--test cases/common/98 gen extra/srcgen3.py16
-rw-r--r--test cases/failing/60 assign custom target index/meson.build24
-rw-r--r--test cases/frameworks/15 llvm/meson.build5
-rw-r--r--test cases/frameworks/19 pcap/meson.build3
51 files changed, 693 insertions, 274 deletions
diff --git a/ci/appveyor-install.bat b/ci/appveyor-install.bat
index 9eddeac..becc80a 100644
--- a/ci/appveyor-install.bat
+++ b/ci/appveyor-install.bat
@@ -1,7 +1,5 @@
set CACHE=C:\cache
set CYGWIN_MIRROR="http://cygwin.mirror.constant.com"
-set CYGWIN_ADDITIONAL_REPO="http://www.dronecode.org.uk/cygwin/"
-set CYGWIN_ADDITIONAL_REPO_KEY="http://www.dronecode.org.uk/cygwin/dronecode.gpg"
if _%arch%_ == _x64_ set SETUP=setup-x86_64.exe && set CYGWIN_ROOT=C:\cygwin64
if _%arch%_ == _x86_ set SETUP=setup-x86.exe && set CYGWIN_ROOT=C:\cygwin
@@ -9,5 +7,5 @@ if _%arch%_ == _x86_ set SETUP=setup-x86.exe && set CYGWIN_ROOT=C:\cygwin
if not exist %CACHE% mkdir %CACHE%
echo Updating Cygwin and installing ninja and test prerequisites
-%CYGWIN_ROOT%\%SETUP% -qnNdO -R "%CYGWIN_ROOT%" -s "%CYGWIN_MIRROR%" -s "%CYGWIN_ADDITIONAL_REPO%" -K "%CYGWIN_ADDITIONAL_REPO_KEY%" -l "%CACHE%" -g -P "ninja,gcc-objc,gcc-objc++,libglib2.0-devel,zlib-devel,python3-pip"
+%CYGWIN_ROOT%\%SETUP% -qnNdO -R "%CYGWIN_ROOT%" -s "%CYGWIN_MIRROR%" -l "%CACHE%" -g -P "ninja,gcc-objc,gcc-objc++,libglib2.0-devel,zlib-devel,python3-pip"
echo Install done
diff --git a/docs/markdown/Build-options.md b/docs/markdown/Build-options.md
index 54905d5..cb7b19e 100644
--- a/docs/markdown/Build-options.md
+++ b/docs/markdown/Build-options.md
@@ -42,11 +42,16 @@ prefix = get_option('prefix')
```
It should be noted that you can not set option values in your Meson
-scripts. They have to be set externally with the `mesonconf` command
-line tool. Running `mesonconf` without arguments in a build dir shows
-you all options you can set. To change their values use the `-D`
+scripts. They have to be set externally with the `meson configure` command
+line tool. Running `meson configure` without arguments in a build dir shows
+you all options you can set.
+
+To change their values use the `-D`
option:
```console
-$ mesonconf -Doption=newvalue
+$ meson configure -Doption=newvalue
```
+
+
+**NOTE:** If you cannot call `meson configure` you likely have a old version of Meson. In that case you can call `mesonconf` instead, but that is deprecated in newer versions
diff --git a/docs/markdown/Generating-sources.md b/docs/markdown/Generating-sources.md
index c251805..c5e338d 100644
--- a/docs/markdown/Generating-sources.md
+++ b/docs/markdown/Generating-sources.md
@@ -31,7 +31,7 @@ gen_src = custom_target('gen-output',
'--h-out', '@OUTPUT1@'])
```
-The `@INPUT@` there will be transformed to `'out.c' 'out.h'`. Just like the output, you can also refer to each input file individually by index.
+The `@INPUT@` there will be transformed to `'somefile1.c' 'file2.c'`. Just like the output, you can also refer to each input file individually by index.
Then you just put that in your program and you're done.
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md
index de51479..f37fb34 100644
--- a/docs/markdown/Reference-manual.md
+++ b/docs/markdown/Reference-manual.md
@@ -554,6 +554,9 @@ following:
- `output` a template string (or list of template strings) defining
how an output file name is (or multiple output names are) generated
from a single source file name
+- `capture` when this argument is set to true, Meson captures `stdout`
+ of the `executable` and writes it to the target file specified as
+ `output`. Available since v0.43.0.
The returned object also has methods that are documented in the
[object methods section](#generator-object) below.
@@ -1309,9 +1312,9 @@ the following methods:
- `get_id()` returns a string identifying the compiler. For example,
`gcc`, `msvc`, [and more](Compiler-properties.md#compiler-id).
-- `get_supported_arguments(list_of_string)` returns an array
- containing only the arguments supported by the compiler, as if
- `has_argument` were called on them individually.
+- `get_supported_arguments(list_of_string)` *(added 0.43.0)* returns
+ an array containing only the arguments supported by the compiler,
+ as if `has_argument` were called on them individually.
- `has_argument(argument_name)` returns true if the compiler accepts
the specified command line argument, that is, can compile code
@@ -1440,7 +1443,9 @@ are immutable, all operations return their results as a new string.
- `startswith(string)` returns true if string starts with the string
specified as the argument
-- `strip()` removes whitespace at the beginning and end of the string
+- `strip()` removes whitespace at the beginning and end of the string
+ *(added 0.43.0)* optionally can take one positional string argument,
+ and all characters in that string will be stripped
- `to_int` returns the string converted to an integer (error if string
is not a number)
@@ -1565,6 +1570,11 @@ contains a target with the following methods:
this and will also allow Meson to setup inter-target dependencies
correctly. Please file a bug if that doesn't work for you.
+- `[index]` returns an opaque object that references this target, and can be
+ used as a source in other targets. When it is used as such it will make that
+ target depend on this custom target, but the only source added will be the
+ one that corresponds to the index of the custom target's output argument.
+
### `dependency` object
This object is returned by [`dependency()`](#dependency) and contains
diff --git a/docs/markdown/Release-notes-for-0.43.0/001-generator-capture.md b/docs/markdown/Release-notes-for-0.43.0/001-generator-capture.md
new file mode 100644
index 0000000..4eb7fc0
--- /dev/null
+++ b/docs/markdown/Release-notes-for-0.43.0/001-generator-capture.md
@@ -0,0 +1,4 @@
+## Generator learned capture
+
+Generators can now be configured to capture the standard output. See
+`test cases/common/98 gen extra/meson.build` for an example.
diff --git a/docs/markdown/Unit-tests.md b/docs/markdown/Unit-tests.md
index 7949522..6ded714 100644
--- a/docs/markdown/Unit-tests.md
+++ b/docs/markdown/Unit-tests.md
@@ -57,42 +57,42 @@ Sometimes a test can only determine at runtime that it can not be run. The GNU s
## Testing tool
-In version 0.37.0 a new tool called `mesontest` was added. The goal of this tool is to provide a simple way to run tests in a variety of different ways. The tool is designed to be run in the build directory.
+The goal of the meson test tool is to provide a simple way to run tests in a variety of different ways. The tool is designed to be run in the build directory.
The simplest thing to do is just to run all tests, which is equivalent to running `ninja test`.
```console
-$ mesontest
+$ meson test
```
You can also run only a single test by giving its name:
```console
-$ mesontest testname
+$ meson test testname
```
Sometimes you need to run the tests multiple times, which is done like this:
```console
-$ mesontest --repeat=10
+$ meson test --repeat=10
```
Invoking tests via a helper executable such as Valgrind can be done with the `--wrap` argument
```console
-$ mesontest --wrap=valgrind testname
+$ meson test --wrap=valgrind testname
```
Arguments to the wrapper binary can be given like this:
```console
-$ mesontest --wrap='valgrind --tool=helgrind' testname
+$ meson test --wrap='valgrind --tool=helgrind' testname
```
Meson also supports running the tests under GDB. Just doing this:
```console
-$ mesontest --gdb testname
+$ meson test --gdb testname
```
Mesontest will launch `gdb` all set up to run the test. Just type `run` in the GDB command prompt to start the program.
@@ -100,9 +100,11 @@ Mesontest will launch `gdb` all set up to run the test. Just type `run` in the G
The second use case is a test that segfaults only rarely. In this case you can invoke the following command:
```console
-$ mesontest --gdb --repeat=10000 testname
+$ meson test --gdb --repeat=10000 testname
```
This runs the test up to 10 000 times under GDB automatically. If the program crashes, GDB will halt and the user can debug the application. Note that testing timeouts are disabled in this case so mesontest will not kill `gdb` while the developer is still debugging it. The downside is that if the test binary freezes, the test runner will wait forever.
For further information see the command line help of Mesontest by running `mesontest -h`.
+
+**NOTE:** If `meson test` does not work for you, you likely have a old version of Meson. In that case you should call `mesontest` instead. If `mesontest` doesn't work either you have a very old version prior to 0.37.0 and should upgrade.
diff --git a/docs/markdown/i18n-module.md b/docs/markdown/i18n-module.md
index 5e6004a..1144e29 100644
--- a/docs/markdown/i18n-module.md
+++ b/docs/markdown/i18n-module.md
@@ -32,6 +32,8 @@ argument which is the name of the gettext module.
[source](https://github.com/mesonbuild/meson/blob/master/mesonbuild/modules/i18n.py)
for for their value
+* `install`: (*Added 0.43.0*) if false, do not install the built translations.
+
This function also defines targets for maintainers to use:
**Note**: These output to the source directory
diff --git a/docs/markdown/snippets/custom-target-index.md b/docs/markdown/snippets/custom-target-index.md
new file mode 100644
index 0000000..10d7cf1
--- /dev/null
+++ b/docs/markdown/snippets/custom-target-index.md
@@ -0,0 +1,21 @@
+# Can index CustomTaget objects
+
+The `CustomTarget` object can now be indexed like an array. The resulting
+object can be used as a source file for other Targets, this will create a
+dependency on the original `CustomTarget`, but will only insert the generated
+file corresponding to the index value of the `CustomTarget`'s `output` keyword.
+
+ c = CustomTarget(
+ ...
+ output : ['out.h', 'out.c'],
+ )
+ lib1 = static_library(
+ 'lib1',
+ [lib1_sources, c[0]],
+ ...
+ )
+ exec = executable(
+ 'executable',
+ c[1],
+ link_with : lib1,
+ )
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index 9f2092b..960f2e2 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -180,7 +180,7 @@ class Backend:
Returns the full path of the generated source relative to the build root
"""
# CustomTarget generators output to the build dir of the CustomTarget
- if isinstance(gensrc, build.CustomTarget):
+ if isinstance(gensrc, (build.CustomTarget, build.CustomTargetIndex)):
return os.path.join(self.get_target_dir(gensrc), src)
# GeneratedList generators output to the private build directory of the
# target that the GeneratedList is used in
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index f67e412..2e6e351 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import os, pickle, re, shlex, shutil, subprocess, sys
+import os, pickle, re, shlex, subprocess, sys
from collections import OrderedDict
from . import backends
@@ -83,10 +83,9 @@ class NinjaBuildElement:
def write(self, outfile):
self.check_outputs()
- line = 'build %s: %s %s' % (
- ' '.join([ninja_quote(i) for i in self.outfilenames]),
- self.rule,
- ' '.join([ninja_quote(i) for i in self.infilenames]))
+ line = 'build %s: %s %s' % (' '.join([ninja_quote(i) for i in self.outfilenames]),
+ self.rule,
+ ' '.join([ninja_quote(i) for i in self.infilenames]))
if len(self.deps) > 0:
line += ' | ' + ' '.join([ninja_quote(x) for x in self.deps])
if len(self.orderdeps) > 0:
@@ -246,7 +245,7 @@ int dummy;
header_deps = []
# XXX: Why don't we add deps to CustomTarget headers here?
for genlist in target.get_generated_sources():
- if isinstance(genlist, build.CustomTarget):
+ if isinstance(genlist, (build.CustomTarget, build.CustomTargetIndex)):
continue
for src in genlist.get_outputs():
if self.environment.is_header(src):
@@ -721,8 +720,7 @@ int dummy;
# On toolchains/platforms that use an import library for
# linking (separate from the shared library with all the
# code), we need to install that too (dll.a/.lib).
- if (isinstance(t, build.SharedLibrary) or
- isinstance(t, build.Executable)) and t.get_import_filename():
+ if (isinstance(t, build.SharedLibrary) or isinstance(t, build.Executable)) and t.get_import_filename():
if custom_install_dir:
# If the DLL is installed into a custom directory,
# install the import library into the same place so
@@ -856,8 +854,9 @@ int dummy;
self.create_target_alias('meson-test', outfile)
# And then benchmarks.
- cmd = self.environment.get_build_command(True) + ['test', '--benchmark', '--logbase',
- 'benchmarklog', '--num-processes=1', '--no-rebuild']
+ cmd = self.environment.get_build_command(True) + [
+ 'test', '--benchmark', '--logbase',
+ 'benchmarklog', '--num-processes=1', '--no-rebuild']
elem = NinjaBuildElement(self.all_outputs, 'meson-benchmark', 'CUSTOM_COMMAND', ['all', 'PHONY'])
elem.add_item('COMMAND', cmd)
elem.add_item('DESC', 'Running benchmark suite.')
@@ -1576,9 +1575,10 @@ int dummy;
def generate_swift_compile_rules(self, compiler, outfile):
rule = 'rule %s_COMPILER\n' % compiler.get_language()
full_exe = [ninja_quote(x) for x in self.environment.get_build_command()] + [
- '--internal',
- 'dirchanger',
- '$RUNDIR']
+ '--internal',
+ 'dirchanger',
+ '$RUNDIR',
+ ]
invoc = (' '.join(full_exe) + ' ' +
' '.join(ninja_quote(i) for i in compiler.get_exelist()))
command = ' command = %s $ARGS $in\n' % invoc
@@ -1761,10 +1761,11 @@ rule FORTRAN_DEP_HACK
outfile.write('\n')
def generate_generator_list_rules(self, target, outfile):
- # CustomTargets have already written their rules,
- # so write rules for GeneratedLists here
+ # CustomTargets have already written their rules and
+ # CustomTargetIndexes don't actually get generated, so write rules for
+ # GeneratedLists here
for genlist in target.get_generated_sources():
- if isinstance(genlist, build.CustomTarget):
+ if isinstance(genlist, (build.CustomTarget, build.CustomTargetIndex)):
continue
self.generate_genlist_for_target(genlist, target, outfile)
@@ -1813,6 +1814,19 @@ rule FORTRAN_DEP_HACK
relout = self.get_target_private_dir(target)
args = self.replace_paths(target, args)
cmdlist = exe_arr + self.replace_extra_args(args, genlist)
+ if generator.capture:
+ exe_data = self.serialize_executable(
+ cmdlist[0],
+ cmdlist[1:],
+ self.environment.get_build_dir(),
+ capture=outfiles[0]
+ )
+ cmd = self.environment.get_build_command() + ['--internal', 'exe', exe_data]
+ abs_pdir = os.path.join(self.environment.get_build_dir(), self.get_target_dir(target))
+ os.makedirs(abs_pdir, exist_ok=True)
+ else:
+ cmd = cmdlist
+
elem = NinjaBuildElement(self.all_outputs, outfiles, rulename, infilename)
if generator.depfile is not None:
elem.add_item('DEPFILE', depfile)
@@ -1821,7 +1835,7 @@ rule FORTRAN_DEP_HACK
elem.add_item('DESC', 'Generating {!r}.'.format(sole_output))
if isinstance(exe, build.BuildTarget):
elem.add_dep(self.get_target_filename(exe))
- elem.add_item('COMMAND', cmdlist)
+ elem.add_item('COMMAND', cmd)
elem.write(outfile)
def scan_fortran_module_outputs(self, target):
@@ -2013,7 +2027,7 @@ rule FORTRAN_DEP_HACK
# Generator output goes into the target private dir which is
# already in the include paths list. Only custom targets have their
# own target build dir.
- if not isinstance(i, build.CustomTarget):
+ if not isinstance(i, (build.CustomTarget, build.CustomTargetIndex)):
continue
idir = self.get_target_dir(i)
if idir not in custom_target_include_dirs:
@@ -2527,10 +2541,11 @@ rule FORTRAN_DEP_HACK
def generate_dist(self, outfile):
elem = NinjaBuildElement(self.all_outputs, 'meson-dist', 'CUSTOM_COMMAND', 'PHONY')
elem.add_item('DESC', 'Creating source packages')
- elem.add_item('COMMAND', self.environment.get_build_command() +
- ['--internal', 'dist',
- self.environment.source_dir,
- self.environment.build_dir] + self.environment.get_build_command())
+ elem.add_item('COMMAND', self.environment.get_build_command() + [
+ '--internal', 'dist',
+ self.environment.source_dir,
+ self.environment.build_dir,
+ ] + self.environment.get_build_command())
elem.add_item('pool', 'console')
elem.write(outfile)
# Alias that runs the target defined above
diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
index 758be79..e4e9696 100644
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -22,7 +22,6 @@ from .. import build
from .. import dependencies
from .. import mlog
from .. import compilers
-from ..build import BuildTarget
from ..compilers import CompilerArgs
from ..mesonlib import MesonException, File
from ..environment import Environment
@@ -92,7 +91,7 @@ class Vs2010Backend(backends.Backend):
source_target_dir = self.get_target_source_dir(target)
down = self.target_to_build_root(target)
for genlist in target.get_generated_sources():
- if isinstance(genlist, build.CustomTarget):
+ if isinstance(genlist, (build.CustomTarget, build.CustomTargetIndex)):
for i in genlist.get_outputs():
# Path to the generated source from the current vcxproj dir via the build root
ipath = os.path.join(down, self.get_target_dir(genlist), i)
@@ -129,6 +128,16 @@ class Vs2010Backend(backends.Backend):
.replace("@BUILD_ROOT@", self.environment.get_build_dir())
for x in args]
cmd = exe_arr + self.replace_extra_args(args, genlist)
+ if generator.capture:
+ exe_data = self.serialize_executable(
+ cmd[0],
+ cmd[1:],
+ self.environment.get_build_dir(),
+ capture=outfiles[0]
+ )
+ cmd = self.environment.get_build_command() + ['--internal', 'exe', exe_data]
+ abs_pdir = os.path.join(self.environment.get_build_dir(), self.get_target_dir(target))
+ os.makedirs(abs_pdir, exist_ok=True)
cbs = ET.SubElement(idgroup, 'CustomBuild', Include=infilename)
ET.SubElement(cbs, 'Command').text = ' '.join(self.quote_arguments(cmd))
ET.SubElement(cbs, 'Outputs').text = ';'.join(outfiles)
@@ -202,6 +211,8 @@ class Vs2010Backend(backends.Backend):
for gendep in target.get_generated_sources():
if isinstance(gendep, build.CustomTarget):
all_deps[gendep.get_id()] = gendep
+ elif isinstance(gendep, build.CustomTargetIndex):
+ all_deps[gendep.target.get_id()] = gendep.target
else:
gen_exe = gendep.generator.get_exe()
if isinstance(gen_exe, build.Executable):
@@ -388,8 +399,7 @@ class Vs2010Backend(backends.Backend):
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()
+ 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)))
@@ -946,8 +956,7 @@ class Vs2010Backend(backends.Backend):
ofile.text = '$(OutDir)%s' % target.get_filename()
subsys = ET.SubElement(link, 'SubSystem')
subsys.text = subsystem
- if (isinstance(target, build.SharedLibrary) or
- isinstance(target, build.Executable)) and target.get_import_filename():
+ if (isinstance(target, build.SharedLibrary) or isinstance(target, build.Executable)) and target.get_import_filename():
# DLLs built with MSVC always have an import library except when
# they're data-only DLLs, but we don't support those yet.
ET.SubElement(link, 'ImportLibrary').text = target.get_import_filename()
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index 5740fbb..5f5dd6b 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -425,7 +425,7 @@ class BuildTarget(Target):
if s not in added_sources:
self.sources.append(s)
added_sources[s] = True
- elif isinstance(s, (GeneratedList, CustomTarget)):
+ elif isinstance(s, (GeneratedList, CustomTarget, CustomTargetIndex)):
self.generated.append(s)
else:
msg = 'Bad source of type {!r} in target {!r}.'.format(type(s).__name__, self.name)
@@ -1019,6 +1019,7 @@ class Generator:
raise InvalidArguments('First generator argument must be an executable.')
self.exe = exe
self.depfile = None
+ self.capture = False
self.process_kwargs(kwargs)
def __repr__(self):
@@ -1062,6 +1063,11 @@ class Generator:
if os.path.split(depfile)[1] != depfile:
raise InvalidArguments('Depfile must be a plain filename without a subdirectory.')
self.depfile = depfile
+ if 'capture' in kwargs:
+ capture = kwargs['capture']
+ if not isinstance(capture, bool):
+ raise InvalidArguments('Capture must be boolean.')
+ self.capture = capture
def get_base_outnames(self, inname):
plainname = os.path.split(inname)[1]
@@ -1676,6 +1682,15 @@ class CustomTarget(Target):
def type_suffix(self):
return "@cus"
+ def __getitem__(self, index):
+ return CustomTargetIndex(self, self.outputs[index])
+
+ def __setitem__(self, index, value):
+ raise NotImplementedError
+
+ def __delitem__(self, index):
+ raise NotImplementedError
+
class RunTarget(Target):
def __init__(self, name, command, args, dependencies, subdir):
super().__init__(name, subdir, False)
@@ -1735,6 +1750,29 @@ class Jar(BuildTarget):
pass
+class CustomTargetIndex:
+
+ """A special opaque object returned by indexing a CustomTaget. This object
+ exists in meson, but acts as a proxy in the backends, making targets depend
+ on the CustomTarget it's derived from, but only adding one source file to
+ the sources.
+ """
+
+ def __init__(self, target, output):
+ self.target = target
+ self.output = output
+
+ def __repr__(self):
+ return '<CustomTargetIndex: {!r}[{}]>'.format(
+ self.target, self.target.output.index(self.output))
+
+ def get_outputs(self):
+ return [self.output]
+
+ def get_subdir(self):
+ return self.target.get_subdir()
+
+
class ConfigureFile:
def __init__(self, subdir, sourcename, targetname, configuration_data):
diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py
index 255a506..82b1ef0 100644
--- a/mesonbuild/compilers/c.py
+++ b/mesonbuild/compilers/c.py
@@ -482,6 +482,34 @@ class CCompiler(Compiler):
# minus the extra newline at the end
return p.stdo.split(delim + '\n')[-1][:-1]
+ def get_return_value(self, fname, rtype, prefix, env, extra_args, dependencies):
+ if rtype == 'string':
+ fmt = '%s'
+ cast = '(char*)'
+ elif rtype == 'int':
+ fmt = '%lli'
+ cast = '(long long int)'
+ else:
+ raise AssertionError('BUG: Unknown return type {!r}'.format(rtype))
+ fargs = {'prefix': prefix, 'f': fname, 'cast': cast, 'fmt': fmt}
+ code = '''{prefix}
+ #include <stdio.h>
+ int main(int argc, char *argv[]) {{
+ printf ("{fmt}", {cast} {f}());
+ }}'''.format(**fargs)
+ res = self.run(code, env, extra_args, dependencies)
+ if not res.compiled:
+ m = 'Could not get return value of {}()'
+ raise EnvironmentException(m.format(fname))
+ if rtype == 'string':
+ return res.stdout
+ elif rtype == 'int':
+ try:
+ return int(res.stdout.strip())
+ except:
+ m = 'Return value of {}() is not an int'
+ raise EnvironmentException(m.format(fname))
+
@staticmethod
def _no_prototype_templ():
"""
@@ -896,6 +924,9 @@ class VisualStudioCCompiler(CCompiler):
def get_linker_search_args(self, dirname):
return ['/LIBPATH:' + dirname]
+ def get_gui_app_args(self):
+ return ['/SUBSYSTEM:WINDOWS']
+
def get_pic_args(self):
return [] # PIC is handled by the loader on Windows
@@ -1025,5 +1056,3 @@ class VisualStudioCCompiler(CCompiler):
# and the can not be called.
return None
return vs32_instruction_set_args.get(instruction_set, None)
-
-
diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py
index c431194..89208e0 100644
--- a/mesonbuild/compilers/compilers.py
+++ b/mesonbuild/compilers/compilers.py
@@ -252,7 +252,7 @@ vs32_instruction_set_args = {'mmx': ['/arch:SSE'], # There does not seem to be a
'avx': ['/arch:AVX'],
'avx2': ['/arch:AVX2'],
'neon': None,
-}
+ }
# The 64 bit compiler defaults to /arch:avx.
vs64_instruction_set_args = {'mmx': ['/arch:AVX'],
diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py
index f991d3c..d2dd107 100644
--- a/mesonbuild/dependencies/dev.py
+++ b/mesonbuild/dependencies/dev.py
@@ -129,9 +129,6 @@ class LLVMDependency(ExternalDependency):
'llvm-config-3.5', 'llvm-config35',
'llvm-config-5.0', 'llvm-config-devel', # development snapshot
]
- llvmconfig = None
- _llvmconfig_found = False
- __best_found = None
__cpp_blacklist = {'-DNDEBUG'}
def __init__(self, environment, kwargs):
@@ -139,11 +136,12 @@ class LLVMDependency(ExternalDependency):
# the C linker works fine if only using the C API.
super().__init__('llvm-config', environment, 'cpp', kwargs)
self.modules = []
+ self.llvmconfig = None
+ self.__best_found = None
# FIXME: Support multiple version requirements ala PkgConfigDependency
req_version = kwargs.get('version', None)
+ self.check_llvmconfig(req_version)
if self.llvmconfig is None:
- self.check_llvmconfig(req_version)
- if not self._llvmconfig_found:
if self.__best_found is not None:
mlog.log('found {!r} but need:'.format(self.__best_found),
req_version)
@@ -159,31 +157,36 @@ class LLVMDependency(ExternalDependency):
mlog.debug('stdout: {}\nstderr: {}'.format(out, err))
if self.required:
raise DependencyException('Dependency LLVM not found')
+ mlog.log('Dependency LLVM found:', mlog.red('NO'))
return
- else:
- self.version = out.strip()
- mlog.log('Dependency LLVM found:', mlog.green('YES'))
- self.is_found = True
- p, out = Popen_safe(
- [self.llvmconfig, '--libs', '--ldflags', '--system-libs'])[:2]
- if p.returncode != 0:
- raise DependencyException('Could not generate libs for LLVM.')
- self.link_args = shlex.split(out)
-
- p, out = Popen_safe([self.llvmconfig, '--cppflags'])[:2]
- if p.returncode != 0:
- raise DependencyException('Could not generate includedir for LLVM.')
- cargs = mesonlib.OrderedSet(shlex.split(out))
- self.compile_args = list(cargs.difference(self.__cpp_blacklist))
-
- p, out = Popen_safe([self.llvmconfig, '--components'])[:2]
- if p.returncode != 0:
- raise DependencyException('Could not generate modules for LLVM.')
- self.modules = shlex.split(out)
-
- modules = mesonlib.stringlistify(kwargs.get('modules', []))
- for mod in modules:
+ mlog.log('Dependency LLVM found:', mlog.green('YES'))
+ self.is_found = True
+
+ # Currently meson doesn't really atempt to handle pre-release versions,
+ # so strip the 'svn' off the end, since it will probably cuase problems
+ # for users who want the patch version.
+ self.version = out.strip().rstrip('svn')
+
+ p, out = Popen_safe(
+ [self.llvmconfig, '--libs', '--ldflags', '--system-libs'])[:2]
+ if p.returncode != 0:
+ raise DependencyException('Could not generate libs for LLVM.')
+ self.link_args = shlex.split(out)
+
+ p, out = Popen_safe([self.llvmconfig, '--cppflags'])[:2]
+ if p.returncode != 0:
+ raise DependencyException('Could not generate includedir for LLVM.')
+ cargs = mesonlib.OrderedSet(shlex.split(out))
+ self.compile_args = list(cargs.difference(self.__cpp_blacklist))
+
+ p, out = Popen_safe([self.llvmconfig, '--components'])[:2]
+ if p.returncode != 0:
+ raise DependencyException('Could not generate modules for LLVM.')
+ self.modules = shlex.split(out)
+
+ modules = mesonlib.stringlistify(mesonlib.flatten(kwargs.get('modules', [])))
+ for mod in sorted(set(modules)):
if mod not in self.modules:
mlog.log('LLVM module', mod, 'found:', mlog.red('NO'))
self.is_found = False
@@ -193,38 +196,33 @@ class LLVMDependency(ExternalDependency):
else:
mlog.log('LLVM module', mod, 'found:', mlog.green('YES'))
- @classmethod
- def check_llvmconfig(cls, version_req):
+ def check_llvmconfig(self, version_req):
"""Try to find the highest version of llvm-config."""
- for llvmconfig in cls.llvm_config_bins:
+ for llvmconfig in self.llvm_config_bins:
try:
p, out = Popen_safe([llvmconfig, '--version'])[0:2]
out = out.strip()
if p.returncode != 0:
continue
- # FIXME: As soon as some llvm-config is found, version checks
- # in further dependnecy() calls will be ignored
if version_req:
if version_compare(out, version_req, strict=True):
- if cls.__best_found and version_compare(out, '<={}'.format(cls.__best_found), strict=True):
+ if self.__best_found and version_compare(
+ out, '<={}'.format(self.__best_found), strict=True):
continue
- cls.__best_found = out
- cls.llvmconfig = llvmconfig
+ self.__best_found = out
+ self.llvmconfig = llvmconfig
else:
# If no specific version is requested use the first version
# found, since that should be the best.
- cls.__best_found = out
- cls.llvmconfig = llvmconfig
+ self.__best_found = out
+ self.llvmconfig = llvmconfig
break
except (FileNotFoundError, PermissionError):
pass
- if cls.__best_found:
+ if self.__best_found:
mlog.log('Found llvm-config:',
- mlog.bold(shutil.which(cls.llvmconfig)),
+ mlog.bold(shutil.which(self.llvmconfig)),
'({})'.format(out.strip()))
- cls._llvmconfig_found = True
- else:
- cls.llvmconfig = False
def need_threads(self):
return True
diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py
index c0ac5a8..c2b6dbd 100644
--- a/mesonbuild/dependencies/misc.py
+++ b/mesonbuild/dependencies/misc.py
@@ -575,6 +575,7 @@ class Python3Dependency(ExternalDependency):
else:
return [DependencyMethods.PKGCONFIG]
+
class PcapDependency(ExternalDependency):
def __init__(self, environment, kwargs):
super().__init__('pcap', environment, None, kwargs)
@@ -598,23 +599,12 @@ class PcapDependency(ExternalDependency):
self.compile_args = stdo.strip().split()
stdo = Popen_safe(['pcap-config', '--libs'])[1]
self.link_args = stdo.strip().split()
- self.version = '0'
+ self.version = self.get_pcap_lib_version()
self.is_found = True
mlog.log('Dependency', mlog.bold('pcap'), 'found:',
mlog.green('YES'), '(%s)' % pcapconf)
return
mlog.debug('Could not find pcap-config binary, trying next.')
- if DependencyMethods.EXTRAFRAMEWORK in self.methods:
- if mesonlib.is_osx():
- fwdep = ExtraFrameworkDependency('pcap', False, None, self.env,
- self.language, kwargs)
- if fwdep.found():
- self.is_found = True
- self.compile_args = fwdep.get_compile_args()
- self.link_args = fwdep.get_link_args()
- self.version = '2' # FIXME
- return
- mlog.log('Dependency', mlog.bold('pcap'), 'found:', mlog.red('NO'))
def get_methods(self):
if mesonlib.is_osx():
@@ -622,6 +612,11 @@ class PcapDependency(ExternalDependency):
else:
return [DependencyMethods.PKGCONFIG, DependencyMethods.PCAPCONFIG]
+ def get_pcap_lib_version(self):
+ return self.compiler.get_return_value('pcap_lib_version', 'string',
+ '#include <pcap.h>', self.env, [], [self])
+
+
class CupsDependency(ExternalDependency):
def __init__(self, environment, kwargs):
super().__init__('cups', environment, None, kwargs)
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index 6658c26..8197b5e 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -566,6 +566,11 @@ class JarHolder(BuildTargetHolder):
def __init__(self, target, interp):
super().__init__(target, interp)
+class CustomTargetIndexHolder(InterpreterObject):
+ def __init__(self, object_to_hold):
+ super().__init__()
+ self.held_object = object_to_hold
+
class CustomTargetHolder(TargetHolder):
def __init__(self, object_to_hold, interp):
super().__init__()
@@ -582,6 +587,15 @@ class CustomTargetHolder(TargetHolder):
def full_path_method(self, args, kwargs):
return self.interpreter.backend.get_target_filename_abs(self.held_object)
+ def __getitem__(self, index):
+ return CustomTargetIndexHolder(self.held_object[index])
+
+ def __setitem__(self, index, value):
+ raise InterpreterException('Cannot set a member of a CustomTarget')
+
+ def __delitem__(self, index):
+ raise InterpreterException('Cannot delete a member of a CustomTarget')
+
class RunTargetHolder(InterpreterObject):
def __init__(self, name, command, args, dependencies, subdir):
super().__init__()
@@ -881,7 +895,7 @@ class CompilerHolder(InterpreterObject):
extra_args = self.determine_args(kwargs)
deps = self.determine_dependencies(kwargs)
value = self.compiler.get_define(element, prefix, self.environment, extra_args, deps)
- mlog.log('Checking for value of define "%s": %s' % (element, value))
+ mlog.log('Fetching value of define "%s": %s' % (element, value))
return value
def compiles_method(self, args, kwargs):
@@ -1028,7 +1042,6 @@ class CompilerHolder(InterpreterObject):
h)
return result
-
def first_supported_argument_method(self, args, kwargs):
for i in mesonlib.stringlistify(args):
if self.compiler.has_argument(i, self.environment):
@@ -1245,48 +1258,50 @@ class MesonMain(InterpreterObject):
pch_kwargs = set(['c_pch', 'cpp_pch'])
-lang_arg_kwargs = set(['c_args',
- 'cpp_args',
- 'd_args',
- 'd_import_dirs',
- 'd_unittest',
- 'd_module_versions',
- 'fortran_args',
- 'java_args',
- 'objc_args',
- 'objcpp_args',
- 'rust_args',
- 'vala_args',
- 'cs_args',
- ])
+lang_arg_kwargs = set([
+ 'c_args',
+ 'cpp_args',
+ 'd_args',
+ 'd_import_dirs',
+ 'd_unittest',
+ 'd_module_versions',
+ 'fortran_args',
+ 'java_args',
+ 'objc_args',
+ 'objcpp_args',
+ 'rust_args',
+ 'vala_args',
+ 'cs_args',
+])
vala_kwargs = set(['vala_header', 'vala_gir', 'vala_vapi'])
rust_kwargs = set(['rust_crate_type'])
cs_kwargs = set(['resources', 'cs_args'])
-buildtarget_kwargs = set(['build_by_default',
- 'build_rpath',
- 'dependencies',
- 'extra_files',
- 'gui_app',
- 'link_with',
- 'link_whole',
- 'link_args',
- 'link_depends',
- 'implicit_include_directories',
- 'include_directories',
- 'install',
- 'install_rpath',
- 'install_dir',
- 'name_prefix',
- 'name_suffix',
- 'native',
- 'objects',
- 'override_options',
- 'pic',
- 'sources',
- 'vs_module_defs',
- ])
+buildtarget_kwargs = set([
+ 'build_by_default',
+ 'build_rpath',
+ 'dependencies',
+ 'extra_files',
+ 'gui_app',
+ 'link_with',
+ 'link_whole',
+ 'link_args',
+ 'link_depends',
+ 'implicit_include_directories',
+ 'include_directories',
+ 'install',
+ 'install_rpath',
+ 'install_dir',
+ 'name_prefix',
+ 'name_suffix',
+ 'native',
+ 'objects',
+ 'override_options',
+ 'pic',
+ 'sources',
+ 'vs_module_defs',
+])
build_target_common_kwargs = (
buildtarget_kwargs |
@@ -1320,7 +1335,7 @@ permitted_kwargs = {'add_global_arguments': {'language'},
'declare_dependency': {'include_directories', 'link_with', 'sources', 'dependencies', 'compile_args', 'link_args', 'version'},
'executable': exe_kwargs,
'find_program': {'required', 'native'},
- 'generator': {'arguments', 'output', 'depfile'},
+ 'generator': {'arguments', 'output', 'depfile', 'capture'},
'include_directories': {'is_system'},
'install_data': {'install_dir', 'install_mode', 'sources'},
'install_headers': {'install_dir', 'subdir'},
@@ -2013,7 +2028,7 @@ class Interpreter(InterpreterBase):
if not isinstance(use_native, bool):
raise InvalidArguments('Argument to "native" must be a boolean.')
if not use_native:
- progobj = self.program_from_cross_file(args)
+ progobj = self.program_from_cross_file(args)
if progobj is None:
progobj = self.program_from_system(args)
if required and (progobj is None or not progobj.found()):
@@ -2549,12 +2564,10 @@ class Interpreter(InterpreterBase):
if not isinstance(inputfile, (str, mesonlib.File)):
raise InterpreterException('Input must be a string or a file')
if isinstance(inputfile, str):
- inputfile = os.path.join(self.subdir, inputfile)
- ifile_abs = os.path.join(self.environment.source_dir, inputfile)
- else:
- ifile_abs = inputfile.absolute_path(self.environment.source_dir,
- self.environment.build_dir)
- inputfile = inputfile.relative_name()
+ inputfile = mesonlib.File.from_source_file(self.environment.source_dir,
+ self.subdir, inputfile)
+ ifile_abs = inputfile.absolute_path(self.environment.source_dir,
+ self.environment.build_dir)
elif 'command' in kwargs and '@INPUT@' in kwargs['command']:
raise InterpreterException('@INPUT@ used as command argument, but no input file specified.')
# Validate output
@@ -2575,18 +2588,13 @@ class Interpreter(InterpreterBase):
raise InterpreterException('Argument "configuration" is not of type configuration_data')
mlog.log('Configuring', mlog.bold(output), 'using configuration')
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(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)
missing_variables = mesonlib.do_conf_file(ifile_abs, ofile_abs,
conf.held_object)
if missing_variables:
var_list = ", ".join(map(repr, sorted(missing_variables)))
mlog.warning(
- "The variable(s) %s in the input file %r are not "
+ "The variable(s) %s in the input file %s are not "
"present in the given configuration data" % (
var_list, inputfile))
else:
@@ -2616,6 +2624,17 @@ class Interpreter(InterpreterBase):
mesonlib.replace_if_different(ofile_abs, dst_tmp)
else:
raise InterpreterException('Configure_file must have either "configuration" or "command".')
+ # If the input is a source file, add it to the list of files that we
+ # need to reconfigure on when they change. FIXME: Do the same for
+ # files() objects in the command: kwarg.
+ if inputfile and not inputfile.is_built:
+ # Normalize the path of the conffile (relative to the
+ # source root) to avoid duplicates. This is especially
+ # important to convert '/' to '\' on Windows
+ conffile = os.path.normpath(inputfile.relative_name())
+ if conffile not in self.build_def_files:
+ self.build_def_files.append(conffile)
+ # Install file if requested
idir = kwargs.get('install_dir', None)
if isinstance(idir, str):
cfile = mesonlib.File.from_built_file(ofile_path, ofile_fname)
@@ -2769,7 +2788,7 @@ different subdirectory.
results = []
for s in sources:
if isinstance(s, (mesonlib.File, GeneratedListHolder,
- CustomTargetHolder)):
+ CustomTargetHolder, CustomTargetIndexHolder)):
pass
elif isinstance(s, str):
s = mesonlib.File.from_source_file(self.environment.source_dir, self.subdir, s)
diff --git a/mesonbuild/interpreterbase.py b/mesonbuild/interpreterbase.py
index d2e2ab3..cb82e56 100644
--- a/mesonbuild/interpreterbase.py
+++ b/mesonbuild/interpreterbase.py
@@ -369,14 +369,16 @@ class InterpreterBase:
def evaluate_indexing(self, node):
assert(isinstance(node, mparser.IndexNode))
iobject = self.evaluate_statement(node.iobject)
- if not isinstance(iobject, list):
- raise InterpreterException('Tried to index a non-array object.')
+ if not hasattr(iobject, '__getitem__'):
+ raise InterpreterException(
+ 'Tried to index an object that doesn\'t support indexing.')
index = self.evaluate_statement(node.index)
if not isinstance(index, int):
raise InterpreterException('Index value is not an integer.')
- if index < -len(iobject) or index >= len(iobject):
+ try:
+ return iobject[index]
+ except IndexError:
raise InterpreterException('Index %d out of bounds of array of size %d.' % (index, len(iobject)))
- return iobject[index]
def function_call(self, node):
func_name = node.func_name
@@ -450,9 +452,25 @@ class InterpreterBase:
else:
raise InterpreterException('Unknown method "%s" for an integer.' % method_name)
+ @staticmethod
+ def _get_one_string_posarg(posargs, method_name):
+ if len(posargs) > 1:
+ m = '{}() must have zero or one arguments'
+ raise InterpreterException(m.format(method_name))
+ elif len(posargs) == 1:
+ s = posargs[0]
+ if not isinstance(s, str):
+ m = '{}() argument must be a string'
+ raise InterpreterException(m.format(method_name))
+ return s
+ return None
+
def string_method_call(self, obj, method_name, args):
(posargs, _) = self.reduce_arguments(args)
if method_name == 'strip':
+ s = self._get_one_string_posarg(posargs, 'strip')
+ if s is not None:
+ return obj.strip(s)
return obj.strip()
elif method_name == 'format':
return self.format_string(obj, args)
@@ -463,15 +481,10 @@ class InterpreterBase:
elif method_name == 'underscorify':
return re.sub(r'[^a-zA-Z0-9]', '_', obj)
elif method_name == 'split':
- if len(posargs) > 1:
- raise InterpreterException('Split() must have at most one argument.')
- elif len(posargs) == 1:
- s = posargs[0]
- if not isinstance(s, str):
- raise InterpreterException('Split() argument must be a string')
+ s = self._get_one_string_posarg(posargs, 'split')
+ if s is not None:
return obj.split(s)
- else:
- return obj.split()
+ return obj.split()
elif method_name == 'startswith' or method_name == 'contains' or method_name == 'endswith':
s = posargs[0]
if not isinstance(s, str):
diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py
index 1657ddd..45e6026 100644
--- a/mesonbuild/mesonmain.py
+++ b/mesonbuild/mesonmain.py
@@ -122,11 +122,11 @@ class MesonApp:
if os.path.exists(priv_dir):
if not handshake:
print('Directory already configured, exiting Meson. Just run your build command\n'
- '(e.g. ninja) and Meson will regenerate as necessary. If ninja fails, run ninja\n'
- 'reconfigure to force Meson to regenerate.\n'
- '\nIf build failures persist, manually wipe your build directory to clear any\n'
- 'stored system data.\n'
- '\nTo change option values, run meson configure instead.')
+ '(e.g. ninja) and Meson will regenerate as necessary. If ninja fails, run ninja\n'
+ 'reconfigure to force Meson to regenerate.\n'
+ '\nIf build failures persist, manually wipe your build directory to clear any\n'
+ 'stored system data.\n'
+ '\nTo change option values, run meson configure instead.')
sys.exit(0)
else:
if handshake:
diff --git a/mesonbuild/modules/__init__.py b/mesonbuild/modules/__init__.py
index 8b5b210..364bc45 100644
--- a/mesonbuild/modules/__init__.py
+++ b/mesonbuild/modules/__init__.py
@@ -4,7 +4,6 @@ from .. import build
from .. import dependencies
from .. import mlog
from ..mesonlib import MesonException
-from ..interpreterbase import permittedKwargs, noKwargs
class permittedSnippetKwargs:
diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py
index 137d380..d1d7013 100644
--- a/mesonbuild/modules/gnome.py
+++ b/mesonbuild/modules/gnome.py
@@ -17,7 +17,6 @@ functionality such as gobject-introspection, gresources and gtk-doc'''
from .. import build
import os
-import sys
import copy
import subprocess
from . import ModuleReturnValue
@@ -30,7 +29,7 @@ from .. import interpreter
from . import GResourceTarget, GResourceHeaderTarget, GirTarget, TypelibTarget, VapiTarget
from . import find_program, get_include_args
from . import ExtensionModule
-from . import noKwargs, permittedKwargs
+from ..interpreterbase import noKwargs, permittedKwargs
# gresource compilation is broken due to the way
# the resource compiler and Ninja clash about it
@@ -108,12 +107,12 @@ class GnomeModule(ExtensionModule):
for (ii, dep) in enumerate(dependencies):
if hasattr(dep, 'held_object'):
dependencies[ii] = dep = dep.held_object
- if not isinstance(dep, (mesonlib.File, build.CustomTarget)):
+ if not isinstance(dep, (mesonlib.File, build.CustomTarget, build.CustomTargetIndex)):
m = 'Unexpected dependency type {!r} for gnome.compile_resources() ' \
'"dependencies" argument.\nPlease pass the return value of ' \
'custom_target() or configure_file()'
raise MesonException(m.format(dep))
- if isinstance(dep, build.CustomTarget):
+ if isinstance(dep, (build.CustomTarget, build.CustomTargetIndex)):
if not mesonlib.version_compare(glib_version, gresource_dep_needed_version):
m = 'The "dependencies" argument of gnome.compile_resources() can not\n' \
'be used with the current version of glib-compile-resources due to\n' \
@@ -132,6 +131,7 @@ class GnomeModule(ExtensionModule):
elif isinstance(ifile, str):
ifile = os.path.join(state.subdir, ifile)
elif isinstance(ifile, (interpreter.CustomTargetHolder,
+ interpreter.CustomTargetIndexHolder,
interpreter.GeneratedObjectsHolder)):
m = 'Resource xml files generated at build-time cannot be used ' \
'with gnome.compile_resources() because we need to scan ' \
@@ -262,7 +262,7 @@ class GnomeModule(ExtensionModule):
dep_files.append(dep)
subdirs.append(dep.subdir)
break
- elif isinstance(dep, build.CustomTarget):
+ elif isinstance(dep, (build.CustomTarget, build.CustomTargetIndex)):
fname = None
outputs = {(o, os.path.basename(o)) for o in dep.get_outputs()}
for o, baseo in outputs:
@@ -444,7 +444,7 @@ class GnomeModule(ExtensionModule):
for s in libsources:
if hasattr(s, 'held_object'):
s = s.held_object
- if isinstance(s, build.CustomTarget):
+ if isinstance(s, (build.CustomTarget, build.CustomTargetIndex)):
gir_filelist.write(os.path.join(state.environment.get_build_dir(),
state.backend.get_target_dir(s),
s.get_outputs()[0]) + '\n')
@@ -697,18 +697,22 @@ This will become a hard error in the future.''')
args.append('--langs=' + '@@'.join(langs))
inscript = build.RunScript(script, args)
- potargs = state.environment.get_build_command() + ['--internal', 'yelphelper', 'pot',
- '--subdir=' + state.subdir,
- '--id=' + project_id,
- '--sources=' + source_str]
+ potargs = state.environment.get_build_command() + [
+ '--internal', 'yelphelper', 'pot',
+ '--subdir=' + state.subdir,
+ '--id=' + project_id,
+ '--sources=' + source_str,
+ ]
pottarget = build.RunTarget('help-' + project_id + '-pot', potargs[0],
potargs[1:], [], state.subdir)
- poargs = state.environment.get_build_command() + ['--internal', 'yelphelper', 'update-po',
- '--subdir=' + state.subdir,
- '--id=' + project_id,
- '--sources=' + source_str,
- '--langs=' + '@@'.join(langs)]
+ poargs = state.environment.get_build_command() + [
+ '--internal', 'yelphelper', 'update-po',
+ '--subdir=' + state.subdir,
+ '--id=' + project_id,
+ '--sources=' + source_str,
+ '--langs=' + '@@'.join(langs),
+ ]
potarget = build.RunTarget('help-' + project_id + '-update-po', poargs[0],
poargs[1:], [], state.subdir)
diff --git a/mesonbuild/modules/i18n.py b/mesonbuild/modules/i18n.py
index 2af09de..c1dd837 100644
--- a/mesonbuild/modules/i18n.py
+++ b/mesonbuild/modules/i18n.py
@@ -12,7 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import sys
import shutil
from os import path
@@ -20,7 +19,7 @@ from .. import coredata, mesonlib, build
from ..mesonlib import MesonException
from . import ModuleReturnValue
from . import ExtensionModule
-from . import permittedKwargs
+from ..interpreterbase import permittedKwargs
PRESET_ARGS = {
'glib': [
@@ -72,8 +71,10 @@ class I18nModule(ExtensionModule):
datadirs = self._get_data_dirs(state, mesonlib.stringlistify(kwargs.pop('data_dirs', [])))
datadirs = '--datadirs=' + ':'.join(datadirs) if datadirs else None
- command = state.environment.get_build_command() + ['--internal', 'msgfmthelper',
- '@INPUT@', '@OUTPUT@', file_type, podir]
+ command = state.environment.get_build_command() + [
+ '--internal', 'msgfmthelper',
+ '@INPUT@', '@OUTPUT@', file_type, podir
+ ]
if datadirs:
command.append(datadirs)
@@ -81,7 +82,7 @@ class I18nModule(ExtensionModule):
ct = build.CustomTarget(kwargs['output'] + '_merge', state.subdir, kwargs)
return ModuleReturnValue(ct, [ct])
- @permittedKwargs({'po_dir', 'data_dirs', 'type', 'languages', 'args', 'preset'})
+ @permittedKwargs({'po_dir', 'data_dirs', 'type', 'languages', 'args', 'preset', 'install'})
def gettext(self, state, args, kwargs):
if len(args) != 1:
raise coredata.MesonException('Gettext requires one positional argument (package name).')
@@ -126,16 +127,21 @@ class I18nModule(ExtensionModule):
updatepoargs.append(extra_args)
updatepotarget = build.RunTarget(packagename + '-update-po', updatepoargs[0], updatepoargs[1:], [], state.subdir)
- script = state.environment.get_build_command()
- args = ['--internal', 'gettext', 'install',
- '--subdir=' + state.subdir,
- '--localedir=' + state.environment.coredata.get_builtin_option('localedir'),
- pkg_arg]
- if lang_arg:
- args.append(lang_arg)
- iscript = build.RunScript(script, args)
-
- return ModuleReturnValue(None, [pottarget, gmotarget, iscript, updatepotarget])
+ targets = [pottarget, gmotarget, updatepotarget]
+
+ install = kwargs.get('install', True)
+ if install:
+ script = state.environment.get_build_command()
+ args = ['--internal', 'gettext', 'install',
+ '--subdir=' + state.subdir,
+ '--localedir=' + state.environment.coredata.get_builtin_option('localedir'),
+ pkg_arg]
+ if lang_arg:
+ args.append(lang_arg)
+ iscript = build.RunScript(script, args)
+ targets.append(iscript)
+
+ return ModuleReturnValue(None, targets)
def initialize():
return I18nModule()
diff --git a/mesonbuild/modules/modtest.py b/mesonbuild/modules/modtest.py
index dd2f215..758eeae 100644
--- a/mesonbuild/modules/modtest.py
+++ b/mesonbuild/modules/modtest.py
@@ -14,7 +14,7 @@
from . import ModuleReturnValue
from . import ExtensionModule
-from . import noKwargs
+from ..interpreterbase import noKwargs
class TestModule(ExtensionModule):
diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py
index 824ba78..aaed820 100644
--- a/mesonbuild/modules/pkgconfig.py
+++ b/mesonbuild/modules/pkgconfig.py
@@ -19,7 +19,7 @@ from .. import mesonlib
from .. import mlog
from . import ModuleReturnValue
from . import ExtensionModule
-from . import permittedKwargs
+from ..interpreterbase import permittedKwargs
class PkgConfigModule(ExtensionModule):
diff --git a/mesonbuild/modules/python3.py b/mesonbuild/modules/python3.py
index 94db75c..4fae88b 100644
--- a/mesonbuild/modules/python3.py
+++ b/mesonbuild/modules/python3.py
@@ -18,7 +18,8 @@ from .. import mesonlib, dependencies
from . import ExtensionModule
from mesonbuild.modules import ModuleReturnValue
-from . import noKwargs, permittedSnippetKwargs
+from . import permittedSnippetKwargs
+from ..interpreterbase import noKwargs
from ..interpreter import shlib_kwargs
mod_kwargs = set()
diff --git a/mesonbuild/modules/qt4.py b/mesonbuild/modules/qt4.py
index 37e630b..a63aff8 100644
--- a/mesonbuild/modules/qt4.py
+++ b/mesonbuild/modules/qt4.py
@@ -20,7 +20,7 @@ from ..dependencies import Qt4Dependency
from . import ExtensionModule
import xml.etree.ElementTree as ET
from . import ModuleReturnValue
-from . import permittedKwargs
+from ..interpreterbase import permittedKwargs
class Qt4Module(ExtensionModule):
tools_detected = False
diff --git a/mesonbuild/modules/qt5.py b/mesonbuild/modules/qt5.py
index ef3d52f..08ce662 100644
--- a/mesonbuild/modules/qt5.py
+++ b/mesonbuild/modules/qt5.py
@@ -20,7 +20,7 @@ from ..dependencies import Qt5Dependency
from . import ExtensionModule
import xml.etree.ElementTree as ET
from . import ModuleReturnValue
-from . import permittedKwargs
+from ..interpreterbase import permittedKwargs
class Qt5Module(ExtensionModule):
tools_detected = False
diff --git a/mesonbuild/modules/rpm.py b/mesonbuild/modules/rpm.py
index b0a8db9..dbb01f7 100644
--- a/mesonbuild/modules/rpm.py
+++ b/mesonbuild/modules/rpm.py
@@ -22,7 +22,7 @@ from .. import mlog
from . import GirTarget, TypelibTarget
from . import ModuleReturnValue
from . import ExtensionModule
-from . import noKwargs
+from ..interpreterbase import noKwargs
import os
diff --git a/mesonbuild/modules/windows.py b/mesonbuild/modules/windows.py
index ab215dc..c16d7a8 100644
--- a/mesonbuild/modules/windows.py
+++ b/mesonbuild/modules/windows.py
@@ -20,7 +20,7 @@ from ..mesonlib import MesonException, extract_as_list
from . import get_include_args
from . import ModuleReturnValue
from . import ExtensionModule
-from . import permittedKwargs
+from ..interpreterbase import permittedKwargs
class WindowsModule(ExtensionModule):
diff --git a/mesonbuild/scripts/meson_install.py b/mesonbuild/scripts/meson_install.py
index f978be4..985b0e9 100644
--- a/mesonbuild/scripts/meson_install.py
+++ b/mesonbuild/scripts/meson_install.py
@@ -227,7 +227,9 @@ def install_man(d):
if outfilename.endswith('.gz') and not full_source_filename.endswith('.gz'):
with open(outfilename, 'wb') as of:
with open(full_source_filename, 'rb') as sf:
- of.write(gzip.compress(sf.read()))
+ # Set mtime and filename for reproducibility.
+ with gzip.GzipFile(fileobj=of, mode='wb', filename='', mtime=0) as gz:
+ gz.write(sf.read())
shutil.copystat(full_source_filename, outfilename)
append_to_log(outfilename)
else:
diff --git a/mesonbuild/wrap/wrap.py b/mesonbuild/wrap/wrap.py
index ac84d0e..81a2f88 100644
--- a/mesonbuild/wrap/wrap.py
+++ b/mesonbuild/wrap/wrap.py
@@ -14,7 +14,7 @@
from .. import mlog
import contextlib
-import urllib.request, os, hashlib, shutil
+import urllib.request, os, hashlib, shutil, tempfile, stat
import subprocess
import sys
from pathlib import Path
@@ -230,6 +230,8 @@ class Resolver:
def get_data(self, url):
blocksize = 10 * 1024
+ h = hashlib.sha256()
+ tmpfile = tempfile.NamedTemporaryFile(mode='wb', dir=self.cachedir, delete=False)
if url.startswith('https://wrapdb.mesonbuild.com'):
resp = open_wrapdburl(url)
else:
@@ -241,26 +243,34 @@ class Resolver:
dlsize = None
if dlsize is None:
print('Downloading file of unknown size.')
- return resp.read()
+ while True:
+ block = resp.read(blocksize)
+ if block == b'':
+ break
+ h.update(block)
+ tmpfile.write(block)
+ hashvalue = h.hexdigest()
+ return hashvalue, tmpfile.name
print('Download size:', dlsize)
print('Downloading: ', end='')
sys.stdout.flush()
printed_dots = 0
- blocks = []
downloaded = 0
while True:
block = resp.read(blocksize)
if block == b'':
break
downloaded += len(block)
- blocks.append(block)
+ h.update(block)
+ tmpfile.write(block)
ratio = int(downloaded / dlsize * 10)
while printed_dots < ratio:
print('.', end='')
sys.stdout.flush()
printed_dots += 1
print('')
- return b''.join(blocks)
+ hashvalue = h.hexdigest()
+ return hashvalue, tmpfile.name
def get_hash(self, data):
h = hashlib.sha256()
@@ -272,34 +282,55 @@ class Resolver:
ofname = os.path.join(self.cachedir, p.get('source_filename'))
if os.path.exists(ofname):
mlog.log('Using', mlog.bold(packagename), 'from cache.')
- return
- srcurl = p.get('source_url')
- mlog.log('Downloading', mlog.bold(packagename), 'from', mlog.bold(srcurl))
- srcdata = self.get_data(srcurl)
- dhash = self.get_hash(srcdata)
- expected = p.get('source_hash')
- if dhash != expected:
- raise RuntimeError('Incorrect hash for source %s:\n %s expected\n %s actual.' % (packagename, expected, dhash))
- with open(ofname, 'wb') as f:
- f.write(srcdata)
+ else:
+ srcurl = p.get('source_url')
+ mlog.log('Downloading', mlog.bold(packagename), 'from', mlog.bold(srcurl))
+ dhash, tmpfile = self.get_data(srcurl)
+ expected = p.get('source_hash')
+ if dhash != expected:
+ os.remove(tmpfile)
+ raise RuntimeError('Incorrect hash for source %s:\n %s expected\n %s actual.' % (packagename, expected, dhash))
+ os.rename(tmpfile, ofname)
if p.has_patch():
- purl = p.get('patch_url')
- mlog.log('Downloading patch from', mlog.bold(purl))
- pdata = self.get_data(purl)
- phash = self.get_hash(pdata)
- expected = p.get('patch_hash')
- if phash != expected:
- raise RuntimeError('Incorrect hash for patch %s:\n %s expected\n %s actual' % (packagename, expected, phash))
- filename = os.path.join(self.cachedir, p.get('patch_filename'))
- with open(filename, 'wb') as f:
- f.write(pdata)
+ patch_filename = p.get('patch_filename')
+ filename = os.path.join(self.cachedir, patch_filename)
+ if os.path.exists(filename):
+ mlog.log('Using', mlog.bold(patch_filename), 'from cache.')
+ else:
+ purl = p.get('patch_url')
+ mlog.log('Downloading patch from', mlog.bold(purl))
+ phash, tmpfile = self.get_data(purl)
+ expected = p.get('patch_hash')
+ if phash != expected:
+ os.remove(tmpfile)
+ raise RuntimeError('Incorrect hash for patch %s:\n %s expected\n %s actual' % (packagename, expected, phash))
+ os.rename(tmpfile, filename)
else:
mlog.log('Package does not require patch.')
+ def copy_tree(self, root_src_dir, root_dst_dir):
+ """
+ Copy directory tree. Overwrites also read only files.
+ """
+ for src_dir, dirs, files in os.walk(root_src_dir):
+ dst_dir = src_dir.replace(root_src_dir, root_dst_dir, 1)
+ if not os.path.exists(dst_dir):
+ os.makedirs(dst_dir)
+ for file_ in files:
+ src_file = os.path.join(src_dir, file_)
+ dst_file = os.path.join(dst_dir, file_)
+ if os.path.exists(dst_file):
+ try:
+ os.remove(dst_file)
+ except PermissionError as exc:
+ os.chmod(dst_file, stat.S_IWUSR)
+ os.remove(dst_file)
+ shutil.copy2(src_file, dst_dir)
+
def extract_package(self, package):
if sys.version_info < (3, 5):
try:
- import lzma
+ import lzma # noqa: F401
del lzma
except ImportError:
pass
@@ -322,4 +353,9 @@ class Resolver:
pass
shutil.unpack_archive(os.path.join(self.cachedir, package.get('source_filename')), extract_dir)
if package.has_patch():
- shutil.unpack_archive(os.path.join(self.cachedir, package.get('patch_filename')), self.subdir_root)
+ try:
+ shutil.unpack_archive(os.path.join(self.cachedir, package.get('patch_filename')), self.subdir_root)
+ except Exception:
+ with tempfile.TemporaryDirectory() as workdir:
+ shutil.unpack_archive(os.path.join(self.cachedir, package.get('patch_filename')), workdir)
+ self.copy_tree(workdir, self.subdir_root)
diff --git a/mesonrewriter.py b/mesonrewriter.py
index 426d878..e6f2637 100755
--- a/mesonrewriter.py
+++ b/mesonrewriter.py
@@ -23,11 +23,10 @@
# - move targets
# - reindent?
-from mesonbuild import mesonmain, mlog
+from mesonbuild import mesonmain
import sys
if __name__ == '__main__':
print('Warning: This executable is deprecated. Use "meson rewrite" instead.',
file=sys.stderr)
sys.exit(mesonmain.run(['rewrite'] + sys.argv[1:]))
-
diff --git a/msi/createmsi.py b/msi/createmsi.py
index 13b4081..dd92e50 100755
--- a/msi/createmsi.py
+++ b/msi/createmsi.py
@@ -56,7 +56,7 @@ class PackageGenerator:
'Title': 'Meson',
'Description': 'Meson executables',
'Level': '1',
- 'Absent': 'disallow',
+ 'Absent': 'disallow',
},
self.staging_dirs[1]: {
'Id': 'NinjaProgram',
@@ -109,7 +109,7 @@ class PackageGenerator:
'Language': '1033',
'Codepage': '1252',
'Version': self.version,
- })
+ })
package = ET.SubElement(product, 'Package', {
'Id': '*',
@@ -121,7 +121,7 @@ class PackageGenerator:
'Languages': '1033',
'Compressed': 'yes',
'SummaryCodepage': '1252',
- })
+ })
if self.bytesize == 64:
package.set('Platform', 'x64')
@@ -129,25 +129,26 @@ class PackageGenerator:
'Id': '1',
'Cabinet': 'meson.cab',
'EmbedCab': 'yes',
- })
+ })
targetdir = ET.SubElement(product, 'Directory', {
'Id': 'TARGETDIR',
'Name': 'SourceDir',
- })
+ })
progfiledir = ET.SubElement(targetdir, 'Directory', {
- 'Id' : self.progfile_dir,
- })
+ 'Id': self.progfile_dir,
+ })
installdir = ET.SubElement(progfiledir, 'Directory', {
'Id': 'INSTALLDIR',
- 'Name': 'Meson'})
+ 'Name': 'Meson',
+ })
ET.SubElement(product, 'Property', {
'Id': 'WIXUI_INSTALLDIR',
'Value': 'INSTALLDIR',
- })
+ })
ET.SubElement(product, 'UIRef', {
'Id': 'WixUI_FeatureTree',
- })
+ })
for sd in self.staging_dirs:
assert(os.path.isdir(sd))
top_feature = ET.SubElement(product, 'Feature', {
@@ -157,7 +158,7 @@ class PackageGenerator:
'Display': 'expand',
'Level': '1',
'ConfigurableDirectory': 'INSTALLDIR',
- })
+ })
for sd in self.staging_dirs:
nodes = {}
for root, dirs, files in os.walk(sd):
@@ -165,7 +166,7 @@ class PackageGenerator:
nodes[root] = cur_node
self.create_xml(nodes, sd, installdir, sd)
self.build_features(nodes, top_feature, sd)
- ET.ElementTree(self.root).write(self.main_xml, encoding='utf-8',xml_declaration=True)
+ ET.ElementTree(self.root).write(self.main_xml, encoding='utf-8', xml_declaration=True)
# ElementTree can not do prettyprinting so do it manually
import xml.dom.minidom
doc = xml.dom.minidom.parse(self.main_xml)
@@ -177,8 +178,7 @@ class PackageGenerator:
for component_id in self.feature_components[staging_dir]:
ET.SubElement(feature, 'ComponentRef', {
'Id': component_id,
- })
-
+ })
def create_xml(self, nodes, current_dir, parent_xml_node, staging_dir):
cur_node = nodes[current_dir]
@@ -187,7 +187,7 @@ class PackageGenerator:
comp_xml_node = ET.SubElement(parent_xml_node, 'Component', {
'Id': component_id,
'Guid': gen_guid(),
- })
+ })
self.feature_components[staging_dir].append(component_id)
if self.bytesize == 64:
comp_xml_node.set('Win64', 'yes')
@@ -208,14 +208,14 @@ class PackageGenerator:
'Id': file_id,
'Name': f,
'Source': os.path.join(current_dir, f),
- })
+ })
for dirname in cur_node.dirs:
dir_id = os.path.join(current_dir, dirname).replace('\\', '_').replace('/', '_')
dir_node = ET.SubElement(parent_xml_node, 'Directory', {
'Id': dir_id,
'Name': dirname,
- })
+ })
self.create_xml(nodes, os.path.join(current_dir, dirname), dir_node, staging_dir)
def build_package(self):
diff --git a/run_project_tests.py b/run_project_tests.py
index 71770f3..426e2c7 100755
--- a/run_project_tests.py
+++ b/run_project_tests.py
@@ -585,7 +585,7 @@ def check_file(fname):
with open(fname, 'rb') as f:
lines = f.readlines()
for line in lines:
- if b'\t' in line:
+ if line.startswith(b'\t'):
print("File %s contains a literal tab on line %d. Only spaces are permitted." % (fname, linenum))
sys.exit(1)
if b'\r' in line:
diff --git a/run_unittests.py b/run_unittests.py
index 2626931..b217714 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -1946,7 +1946,7 @@ cpu = 'armv7' # Not sure if correct.
endian = 'little'
''' % os.path.join(testdir, 'some_cross_tool.py'))
crossfile.flush()
- self.init(testdir, ['--cross-file='+crossfile.name])
+ self.init(testdir, ['--cross-file=' + crossfile.name])
def test_reconfigure(self):
testdir = os.path.join(self.unit_test_dir, '13 reconfigure')
diff --git a/setup.cfg b/setup.cfg
index b3adc59..edcf3c5 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -14,8 +14,10 @@ ignore =
E305,
# E401: multiple imports on one line
E401,
- # too many leading '#' for block comment
+ # E266: too many leading '#' for block comment
E266,
- # module level import not at top of file
- E402
+ # E402: module level import not at top of file
+ E402,
+ # E731: do not assign a lambda expression, use a def (too many false positives)
+ E731
max-line-length = 120
diff --git a/test cases/common/114 multiple dir configure file/meson.build b/test cases/common/114 multiple dir configure file/meson.build
index 180227c..c76c6b4 100644
--- a/test cases/common/114 multiple dir configure file/meson.build
+++ b/test cases/common/114 multiple dir configure file/meson.build
@@ -5,3 +5,7 @@ subdir('subdir')
configure_file(input : 'subdir/someinput.in',
output : 'outputhere',
configuration : configuration_data())
+
+configure_file(input : cfile1,
+ output : '@BASENAME@',
+ configuration : configuration_data())
diff --git a/test cases/common/114 multiple dir configure file/subdir/foo.txt b/test cases/common/114 multiple dir configure file/subdir/foo.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test cases/common/114 multiple dir configure file/subdir/foo.txt
diff --git a/test cases/common/114 multiple dir configure file/subdir/meson.build b/test cases/common/114 multiple dir configure file/subdir/meson.build
index a8f731d..9c72bf9 100644
--- a/test cases/common/114 multiple dir configure file/subdir/meson.build
+++ b/test cases/common/114 multiple dir configure file/subdir/meson.build
@@ -2,3 +2,10 @@ configure_file(input : 'someinput.in',
output : 'outputsubdir',
install : false,
configuration : configuration_data())
+
+py3 = import('python3').find_python()
+
+cfile1 = configure_file(input : 'foo.txt',
+ output : 'foo.h.in',
+ capture : true,
+ command : [py3, '-c', 'print("#mesondefine FOO_BAR")'])
diff --git a/test cases/common/147 mesonintrospect from scripts/check_env.py b/test cases/common/147 mesonintrospect from scripts/check_env.py
index 9bd64d7..2d46d88 100644
--- a/test cases/common/147 mesonintrospect from scripts/check_env.py
+++ b/test cases/common/147 mesonintrospect from scripts/check_env.py
@@ -16,8 +16,8 @@ mesonintrospect = os.environ['MESONINTROSPECT']
introspect_arr = shlex.split(mesonintrospect)
-#print(mesonintrospect)
-#print(introspect_arr)
+# print(mesonintrospect)
+# print(introspect_arr)
some_executable = introspect_arr[0]
diff --git a/test cases/common/161 index customtarget/gen_sources.py b/test cases/common/161 index customtarget/gen_sources.py
new file mode 100644
index 0000000..0bdb529
--- /dev/null
+++ b/test cases/common/161 index customtarget/gen_sources.py
@@ -0,0 +1,49 @@
+# Copyright © 2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import argparse
+import textwrap
+
+HEADER = textwrap.dedent('''\
+ void stringify(int foo, char * buffer);
+ ''')
+
+CODE = textwrap.dedent('''\
+ #include <stdio.h>
+
+ #ifndef WORKS
+ # error "This shouldn't have been included"
+ #endif
+
+ void stringify(int foo, char * buffer) {
+ sprintf(buffer, "%i", foo);
+ }
+ ''')
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--header')
+ parser.add_argument('--code')
+ args = parser.parse_args()
+
+ with open(args.header, 'w') as f:
+ f.write(HEADER)
+
+ with open(args.code, 'w') as f:
+ f.write(CODE)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test cases/common/161 index customtarget/lib.c b/test cases/common/161 index customtarget/lib.c
new file mode 100644
index 0000000..17117d5
--- /dev/null
+++ b/test cases/common/161 index customtarget/lib.c
@@ -0,0 +1,20 @@
+/* Copyright © 2017 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gen.h"
+
+void func(char * buffer) {
+ stringify(1, buffer);
+}
diff --git a/test cases/common/161 index customtarget/meson.build b/test cases/common/161 index customtarget/meson.build
new file mode 100644
index 0000000..11cb214
--- /dev/null
+++ b/test cases/common/161 index customtarget/meson.build
@@ -0,0 +1,32 @@
+# Copyright © 2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+project('custom_target_index', 'c', default_options : 'c_std=c89')
+
+py_mod = import('python3')
+prog_python = py_mod.find_python()
+
+gen = custom_target(
+ 'gen.[ch]',
+ input : 'gen_sources.py',
+ output : ['gen.c', 'gen.h'],
+ command : [prog_python, '@INPUT@', '--header', '@OUTPUT1@', '--code', '@OUTPUT0@'],
+)
+
+lib = static_library(
+ 'libfoo',
+ ['lib.c', gen[1]],
+)
+
+subdir('subdir')
diff --git a/test cases/common/161 index customtarget/subdir/foo.c b/test cases/common/161 index customtarget/subdir/foo.c
new file mode 100644
index 0000000..c620a11
--- /dev/null
+++ b/test cases/common/161 index customtarget/subdir/foo.c
@@ -0,0 +1,22 @@
+/* Copyright © 2017 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gen.h"
+
+int main(void) {
+ char buf[50];
+ stringify(10, buf);
+ return 0;
+}
diff --git a/test cases/common/161 index customtarget/subdir/meson.build b/test cases/common/161 index customtarget/subdir/meson.build
new file mode 100644
index 0000000..47bcd32
--- /dev/null
+++ b/test cases/common/161 index customtarget/subdir/meson.build
@@ -0,0 +1,19 @@
+# Copyright © 2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+foo = executable(
+ 'foo',
+ ['foo.c', gen[0], gen[1]],
+ c_args : '-DWORKS',
+)
diff --git a/test cases/common/42 string operations/meson.build b/test cases/common/42 string operations/meson.build
index 5d7a73d..d9f8130 100644
--- a/test cases/common/42 string operations/meson.build
+++ b/test cases/common/42 string operations/meson.build
@@ -67,3 +67,10 @@ assert(not version_number.version_compare('!=1.2.8'), 'Version_compare neq broke
assert(version_number.version_compare('<2.0'), 'Version_compare major less broken')
assert(version_number.version_compare('>0.9'), 'Version_compare major greater broken')
+
+assert(' spaces tabs '.strip() == 'spaces tabs', 'Spaces and tabs badly stripped')
+assert('''
+multiline string '''.strip() == '''multiline string''', 'Newlines badly stripped')
+assert('"1.1.20"'.strip('"') == '1.1.20', '" badly stripped')
+assert('"1.1.20"'.strip('".') == '1.1.20', '". badly stripped')
+assert('"1.1.20" '.strip('" ') == '1.1.20', '". badly stripped')
diff --git a/test cases/common/98 gen extra/meson.build b/test cases/common/98 gen extra/meson.build
index 772f52e..cbbdceb 100644
--- a/test cases/common/98 gen extra/meson.build
+++ b/test cases/common/98 gen extra/meson.build
@@ -28,3 +28,13 @@ plainname_gen = generator(prog2,
plainname_src = plainname_gen.process('name.l')
test('plainname', executable('plainname', plainname_src))
+
+prog3 = find_program('srcgen3.py')
+capture_gen = generator(prog3,
+ output : ['@BASENAME@.yy.c'],
+ arguments : ['@INPUT@'],
+ capture : true)
+
+capture_src = capture_gen.process('name.l')
+
+test('capture', executable('capture', capture_src))
diff --git a/test cases/common/98 gen extra/srcgen3.py b/test cases/common/98 gen extra/srcgen3.py
new file mode 100644
index 0000000..ad0a5cb
--- /dev/null
+++ b/test cases/common/98 gen extra/srcgen3.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python3
+
+import os
+import sys
+import argparse
+
+parser = argparse.ArgumentParser()
+parser.add_argument('input',
+ help='the input file')
+
+options = parser.parse_args(sys.argv[1:])
+
+with open(options.input) as f:
+ content = f.read().strip()
+
+print(content)
diff --git a/test cases/failing/60 assign custom target index/meson.build b/test cases/failing/60 assign custom target index/meson.build
new file mode 100644
index 0000000..7f2a820
--- /dev/null
+++ b/test cases/failing/60 assign custom target index/meson.build
@@ -0,0 +1,24 @@
+# Copyright © 2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+prog_python = import('python3').find_python()
+
+target = custom_target(
+ 'target',
+ output : ['1', '2'],
+ command : [prog_python, '-c',
+ 'with open("1", "w") as f: f.write("foo"); with open("2", "w") as f: f.write("foo")'],
+)
+
+target[0] = 'foo'
diff --git a/test cases/frameworks/15 llvm/meson.build b/test cases/frameworks/15 llvm/meson.build
index af7f8c6..e1d97cb 100644
--- a/test cases/frameworks/15 llvm/meson.build
+++ b/test cases/frameworks/15 llvm/meson.build
@@ -10,8 +10,7 @@ llvm_dep = dependency(
d = dependency('llvm', modules : 'not-found', required : false)
assert(d.found() == false, 'not-found llvm module found')
-# XXX: Version checks are broken, see FIXME in LLVMDependency
-#d = dependency('llvm', version : '<0.1', required : false)
-#assert(d.found() == false, 'ancient llvm module found')
+d = dependency('llvm', version : '<0.1', required : false)
+assert(d.found() == false, 'ancient llvm module found')
executable('sum', 'sum.c', dependencies : llvm_dep)
diff --git a/test cases/frameworks/19 pcap/meson.build b/test cases/frameworks/19 pcap/meson.build
index 909d7cd..c505960 100644
--- a/test cases/frameworks/19 pcap/meson.build
+++ b/test cases/frameworks/19 pcap/meson.build
@@ -2,6 +2,9 @@ project('pcap test', 'c')
pcap_dep = dependency('pcap', version : '>=1.0')
+pcap_ver = pcap_dep.version()
+assert(pcap_ver.split('.').length() > 1, 'pcap version is "@0@"'.format(pcap_ver))
+
e = executable('pcap_prog', 'pcap_prog.c', dependencies : pcap_dep)
test('pcaptest', e)