aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/markdown/Build-options.md57
-rw-r--r--docs/markdown/Reference-manual.md12
-rw-r--r--docs/markdown/Running-Meson.md102
-rw-r--r--docs/markdown/snippets/option-array-type.md5
-rw-r--r--mesonbuild/backend/backends.py4
-rw-r--r--mesonbuild/compilers/c.py4
-rw-r--r--mesonbuild/coredata.py7
-rw-r--r--mesonbuild/dependencies/base.py73
-rw-r--r--mesonbuild/dependencies/misc.py28
-rw-r--r--mesonbuild/dependencies/ui.py12
-rw-r--r--mesonbuild/interpreter.py21
-rw-r--r--mesonbuild/linkers.py4
-rw-r--r--mesonbuild/mesonlib.py9
-rw-r--r--mesonbuild/modules/gnome.py4
-rw-r--r--mesonbuild/optinterpreter.py20
-rwxr-xr-xrun_tests.py9
-rwxr-xr-xrun_unittests.py67
-rw-r--r--test cases/common/166 custom target subdir depend files/copyfile.py6
-rw-r--r--test cases/common/166 custom target subdir depend files/meson.build7
-rw-r--r--test cases/common/166 custom target subdir depend files/subdir/dep.dat1
-rw-r--r--test cases/common/166 custom target subdir depend files/subdir/foo.c.in6
-rw-r--r--test cases/common/166 custom target subdir depend files/subdir/meson.build6
-rw-r--r--test cases/common/169 array option/meson.build (renamed from test cases/common/166 array option/meson.build)0
-rw-r--r--test cases/common/169 array option/meson_options.txt (renamed from test cases/common/166 array option/meson_options.txt)0
-rw-r--r--test cases/common/170 custom target template substitution/checkcopy.py9
-rw-r--r--test cases/common/170 custom target template substitution/foo.c.in6
-rw-r--r--test cases/common/170 custom target template substitution/meson.build17
-rw-r--r--test cases/common/171 not-found dependency/meson.build8
-rw-r--r--test cases/common/42 string operations/meson.build2
-rw-r--r--test cases/common/47 options/meson_options.txt1
-rw-r--r--test cases/failing/67 dependency not-found and required/meson.build2
-rw-r--r--test cases/linuxlike/1 pkg-config/meson.build2
-rw-r--r--test cases/unit/17 pkgconfig static/meson.build16
33 files changed, 398 insertions, 129 deletions
diff --git a/docs/markdown/Build-options.md b/docs/markdown/Build-options.md
index f05eb7b..cd7f07d 100644
--- a/docs/markdown/Build-options.md
+++ b/docs/markdown/Build-options.md
@@ -16,32 +16,38 @@ Here is a simple option file.
option('someoption', type : 'string', value : 'optval', description : 'An option')
option('other_one', type : 'boolean', value : false)
option('combo_opt', type : 'combo', choices : ['one', 'two', 'three'], value : 'three')
+option('free_array_opt', type : 'array', value : ['one', 'two'])
option('array_opt', type : 'array', choices : ['one', 'two', 'three'], value : ['one', 'two'])
```
-All types allow a `description` value to be set describing the option, if no
-option is set then the name of the option will be used instead.
+All types allow a `description` value to be set describing the option,
+if no option is set then the name of the option will be used instead.
### Strings
-The string type is a free form string. If the default value is not set then an
-empty string will be used as the default.
+The string type is a free form string. If the default value is not set
+then an empty string will be used as the default.
### Booleans
-Booleans may have values of either `true` or `false`. If not default value is
-supplied then `true` will be used as the default.
+Booleans may have values of either `true` or `false`. If no default
+value is supplied then `true` will be used as the default.
### Combos
-A combo allows any one of the values in the `choices` parameter to be selected.
-If no default value is set then the first value will be the default.
+A combo allows any one of the values in the `choices` parameter to be
+selected. If no default value is set then the first value will be the
+default.
### Arrays
-Arrays allow one or more of the values in the `choices` parameter to be selected.
-If the `value` parameter is unset then the values of `choices` will be used as
-the default.
+Arrays represent an array of strings. By default the array can contain
+arbitrary strings. To limit the possible values that can used set the
+`choices` parameter. Meson will then only allow the value array to
+contain strings that are in the given list. The array may be
+empty. The `value` parameter specifies the default value of the option
+and if it is unset then the values of `choices` will be used as the
+default.
This type is new in version 0.44.0
@@ -61,9 +67,9 @@ 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 `meson configure` command
-line tool. Running `meson configure` without arguments in a build dir shows
-you all options you can set.
+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:
@@ -72,5 +78,26 @@ option:
$ meson configure -Doption=newvalue
```
+Setting the value of arrays is a bit special. If you only pass a
+single string, then it is considered to have all values separated by
+commas. Thus invoking the following command:
-**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
+```console
+$ meson configure -Darray_opt=foo,bar
+```
+
+would set the value to an array of two elements, `foo` and `bar`.
+
+If you need to have commas in your string values, then you need to
+pass the value with proper shell quoting like this:
+
+```console
+$ meson configure "-Doption=['a,b', 'c,d']"
+```
+
+The inner values must always be single quotes and the outer ones
+double quotes.
+
+**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/Reference-manual.md b/docs/markdown/Reference-manual.md
index ec5db03..ac83152 100644
--- a/docs/markdown/Reference-manual.md
+++ b/docs/markdown/Reference-manual.md
@@ -316,6 +316,13 @@ otherwise. This function supports the following keyword arguments:
You can also specify multiple restrictions by passing a list to this
keyword argument, such as: `['>=3.14.0', '<=4.1.0']`.
+If dependency_name is '', the dependency is always not found. So with
+`required: false`, this always returns a dependency object for which the
+`found()` method returns `false`, and which can be passed like any other
+dependency to the `dependencies:` keyword argument of a `build_target`. This
+can be used to implement a dependency which is sometimes not required e.g. in
+some branches of a conditional.
+
The returned object also has methods that are documented in the
[object methods section](#dependency-object) below.
@@ -440,10 +447,7 @@ be passed to [shared and static libraries](#library).
The list of `sources`, `objects`, and `dependencies` is always
flattened, which means you can freely nest and add lists while
-creating the final list. As a corollary, the best way to handle a
-'disabled dependency' is by assigning an empty list `[]` to it and
-passing it like any other dependency to the `dependencies:` keyword
-argument.
+creating the final list.
The returned object also has methods that are documented in the
[object methods section](#build-target-object) below.
diff --git a/docs/markdown/Running-Meson.md b/docs/markdown/Running-Meson.md
index 0e8da43..23d5e97 100644
--- a/docs/markdown/Running-Meson.md
+++ b/docs/markdown/Running-Meson.md
@@ -1,17 +1,26 @@
---
-short-description: Building a project with meson
+short-description: Building a project with Meson
...
-# Running meson
+# Running Meson
-There are two different ways of invoking Meson. First, you can run it directly from the source tree with the command `/path/to/source/meson.py`. Meson may also be installed in which case the command is simply `meson`. In this manual we only use the latter format for simplicity.
+There are two different ways of invoking Meson. First, you can run it
+directly from the source tree with the command
+`/path/to/source/meson.py`. Meson may also be installed in which case
+the command is simply `meson`. In this manual we only use the latter
+format for simplicity.
-At the time of writing only a command line version of Meson is available. This means that Meson must be invoked using the terminal. If you wish to use the MSVC compiler, you need to run Meson under "Visual Studio command prompt".
+At the time of writing only a command line version of Meson is
+available. This means that Meson must be invoked using the
+terminal. If you wish to use the MSVC compiler, you need to run Meson
+under "Visual Studio command prompt".
Configuring the source
==
-Let us assume that we have a source tree that has a Meson build system. This means that at the topmost directory has a file called `meson.build`. We run the following commands to get the build started.
+Let us assume that we have a source tree that has a Meson build
+system. This means that at the topmost directory has a file called
+`meson.build`. We run the following commands to get the build started.
cd /path/to/source/root
@@ -19,13 +28,22 @@ Let us assume that we have a source tree that has a Meson build system. This mea
cd builddir
meson ..
-First we create a directory to hold all files generated during the build. Then we go into it and invoke Meson, giving it the location of the source root.
+First we create a directory to hold all files generated during the
+build. Then we go into it and invoke Meson, giving it the location of
+the source root.
-Hint: The syntax of meson is `meson [options] [srcdir] [builddir]`, but you may omit either `srcdir` or `builddir`. Meson will deduce the `srcdir` by the location of `meson.build`. The other one will be your `pwd`.
+Hint: The syntax of meson is `meson [options] [srcdir] [builddir]`,
+but you may omit either `srcdir` or `builddir`. Meson will deduce the
+`srcdir` by the location of `meson.build`. The other one will be your
+`pwd`.
-Meson then loads the build configuration file and writes the corresponding build backend in the build directory. By default Meson generates a *debug build*, which turns on basic warnings and debug information and disables compiler optimizations.
+Meson then loads the build configuration file and writes the
+corresponding build backend in the build directory. By default Meson
+generates a *debug build*, which turns on basic warnings and debug
+information and disables compiler optimizations.
-You can specify a different type of build with the `--buildtype` command line argument. It can have one of the following values.
+You can specify a different type of build with the `--buildtype`
+command line argument. It can have one of the following values.
| value | meaning |
| ------ | -------- |
@@ -34,42 +52,78 @@ You can specify a different type of build with the `--buildtype` command line ar
| `debugoptimized` | debug info is generated and the code is optimized (on most compilers this means `-g -O2`) |
| `release` | full optimization, no debug info |
-The build directory is mandatory. The reason for this is that it simplifies the build process immensely. Meson will not under any circumstances write files inside the source directory (if it does, it is a bug and should be fixed). This means that the user does not need to add a bunch of files to their revision control's ignore list. It also means that you can create arbitrarily many build directories for any given source tree. If we wanted to test building the source code with the Clang compiler instead of the system default, we could just type the following commands.
+The build directory is mandatory. The reason for this is that it
+simplifies the build process immensely. Meson will not under any
+circumstances write files inside the source directory (if it does, it
+is a bug and should be fixed). This means that the user does not need
+to add a bunch of files to their revision control's ignore list. It
+also means that you can create arbitrarily many build directories for
+any given source tree. If we wanted to test building the source code
+with the Clang compiler instead of the system default, we could just
+type the following commands.
cd /path/to/source/root
mkdir buildclang
cd buildclang
CC=clang CXX=clang++ meson ..
-This separation is even more powerful if your code has multiple configuration options (such as multiple data backends). You can create a separate subdirectory for each of them. You can also have build directories for optimized builds, code coverage, static analysis and so on. They are all neatly separated and use the same source tree. Changing between different configurations is just a question of changing to the corresponding directory.
+This separation is even more powerful if your code has multiple
+configuration options (such as multiple data backends). You can create
+a separate subdirectory for each of them. You can also have build
+directories for optimized builds, code coverage, static analysis and
+so on. They are all neatly separated and use the same source
+tree. Changing between different configurations is just a question of
+changing to the corresponding directory.
-Unless otherwise mentioned, all following command line invocations are meant to be run in the build directory.
+Unless otherwise mentioned, all following command line invocations are
+meant to be run in the build directory.
-By default Meson will use the Ninja backend to build your project. If you wish to use any of the other backends, you need to pass the corresponding argument during configuration time. As an example, here is how you would use Meson to generate a Visual studio solution.
+By default Meson will use the Ninja backend to build your project. If
+you wish to use any of the other backends, you need to pass the
+corresponding argument during configuration time. As an example, here
+is how you would use Meson to generate a Visual studio solution.
meson <source dir> <build dir> --backend=vs2010
-You can then open the generated solution with Visual Studio and compile it in the usual way. A list of backends can be obtained with `meson --help`.
+You can then open the generated solution with Visual Studio and
+compile it in the usual way. A list of backends can be obtained with
+`meson --help`.
Building the source
==
-If you are not using an IDE, Meson uses the [Ninja build system](https://ninja-build.org/) to actually build the code. To start the build, simply type the following command.
+If you are not using an IDE, Meson uses the [Ninja build
+system](https://ninja-build.org/) to actually build the code. To start
+the build, simply type the following command.
ninja
-The main usability difference between Ninja and Make is that Ninja will automatically detect the number of CPUs in your computer and parallelize itself accordingly. You can override the amount of parallel processes used with the command line argument `-j <num processes>`.
-
-It should be noted that after the initial configure step `ninja` is the only command you ever need to type to compile. No matter how you alter your source tree (short of moving it to a completely new location), Meson will detect the changes and regenerate itself accordingly. This is especially handy if you have multiple build directories. Often one of them is used for development (the "debug" build) and others only every now and then (such as a "static analysis" build). Any configuration can be built just by `cd`'ing to the corresponding directory and running Ninja.
+The main usability difference between Ninja and Make is that Ninja
+will automatically detect the number of CPUs in your computer and
+parallelize itself accordingly. You can override the amount of
+parallel processes used with the command line argument `-j <num
+processes>`.
+
+It should be noted that after the initial configure step `ninja` is
+the only command you ever need to type to compile. No matter how you
+alter your source tree (short of moving it to a completely new
+location), Meson will detect the changes and regenerate itself
+accordingly. This is especially handy if you have multiple build
+directories. Often one of them is used for development (the "debug"
+build) and others only every now and then (such as a "static analysis"
+build). Any configuration can be built just by `cd`'ing to the
+corresponding directory and running Ninja.
Running tests
==
-Meson provides native support for running tests. The command to do that is simple.
+Meson provides native support for running tests. The command to do
+that is simple.
ninja test
-Meson does not force the use of any particular testing framework. You are free to use GTest, Boost Test, Check or even custom executables.
+Meson does not force the use of any particular testing framework. You
+are free to use GTest, Boost Test, Check or even custom executables.
Installing
==
@@ -78,13 +132,17 @@ Installing the built software is just as simple.
ninja install
-By default Meson installs to `/usr/local`. This can be changed by passing the command line argument `--prefix /your/prefix` to Meson during configure time. Meson also supports the `DESTDIR` variable used in e.g. building packages. It is used like this:
+By default Meson installs to `/usr/local`. This can be changed by
+passing the command line argument `--prefix /your/prefix` to Meson
+during configure time. Meson also supports the `DESTDIR` variable used
+in e.g. building packages. It is used like this:
DESTDIR=/path/to/staging ninja install
Command line help
==
-Meson has a standard command line help feature. It can be accessed with the following command.
+Meson has a standard command line help feature. It can be accessed
+with the following command.
meson --help
diff --git a/docs/markdown/snippets/option-array-type.md b/docs/markdown/snippets/option-array-type.md
index f073dc1..9eb1312 100644
--- a/docs/markdown/snippets/option-array-type.md
+++ b/docs/markdown/snippets/option-array-type.md
@@ -3,8 +3,9 @@
Previously to have an option that took more than one value a string value would
have to be created and split, but validating this was difficult. A new array type
has been added to the meson_options.txt for this case. It works like a 'combo', but
-allows more than one option to be passed. When used on the command line (with -D),
-values are passed as a comma separated list.
+allows more than one option to be passed. The values can optionally be validated
+against a list of valid values. When used on the command line (with -D), values
+are passed as a comma separated list.
```meson
option('array_opt', type : 'array', choices : ['one', 'two', 'three'], value : ['one'])
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index df58271..067b719 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -740,9 +740,9 @@ class Backend:
deps.append(i.rel_to_builddir(self.build_to_src))
else:
if absolute_paths:
- deps.append(os.path.join(self.environment.get_build_dir(), i))
+ deps.append(os.path.join(self.environment.get_source_dir(), target.subdir, i))
else:
- deps.append(os.path.join(self.build_to_src, i))
+ deps.append(os.path.join(self.build_to_src, target.subdir, i))
return deps
def eval_custom_target_command(self, target, absolute_outputs=False):
diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py
index 317a4d7..2d12314 100644
--- a/mesonbuild/compilers/c.py
+++ b/mesonbuild/compilers/c.py
@@ -727,10 +727,12 @@ class CCompiler(Compiler):
if for_darwin(env.is_cross_build(), env):
shlibext = ['dylib']
elif for_windows(env.is_cross_build(), env):
+ # FIXME: .lib files can be import or static so we should read the
+ # file, figure out which one it is, and reject the wrong kind.
if self.id == 'msvc':
shlibext = ['lib']
else:
- shlibext = ['dll', 'dll.a', 'lib']
+ shlibext = ['dll.a', 'lib', 'dll']
# Yep, static libraries can also be foo.lib
stlibext += ['lib']
elif for_cygwin(env.is_cross_build(), env):
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index ecb2492..302c286 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -133,7 +133,7 @@ class UserStringArrayOption(UserOption):
def validate(self, value, user_input):
# User input is for options defined on the command line (via -D
- # options). Users should put their input in as a comma separated
+ # options). Users can put their input in as a comma separated
# string, but for defining options in meson_options.txt the format
# should match that of a combo
if not user_input:
@@ -145,7 +145,10 @@ class UserStringArrayOption(UserOption):
newvalue = value
else:
assert isinstance(value, str)
- newvalue = [v.strip() for v in value.split(',')]
+ if value.startswith('['):
+ newvalue = ast.literal_eval(value)
+ else:
+ newvalue = [v.strip() for v in value.split(',')]
if not isinstance(newvalue, list):
raise MesonException('"{0}" should be a string array, but it is not'.format(str(newvalue)))
for i in newvalue:
diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py
index a720232..f8469c5 100644
--- a/mesonbuild/dependencies/base.py
+++ b/mesonbuild/dependencies/base.py
@@ -22,6 +22,7 @@ import shlex
import shutil
import textwrap
from enum import Enum
+from pathlib import PurePath
from .. import mlog
from .. import mesonlib
@@ -129,7 +130,7 @@ class Dependency:
def need_threads(self):
return False
- def get_pkgconfig_variable(self, variable_name):
+ def get_pkgconfig_variable(self, variable_name, kwargs):
raise NotImplementedError('{!r} is not a pkgconfig dependency'.format(self.name))
def get_configtool_variable(self, variable_name):
@@ -156,9 +157,6 @@ class ExternalDependency(Dependency):
self.name = type_name # default
self.is_found = False
self.language = language
- if language and language not in self.env.coredata.compilers:
- m = self.name.capitalize() + ' requires a {} compiler'
- raise DependencyException(m.format(language.capitalize()))
self.version_reqs = kwargs.get('version', None)
self.required = kwargs.get('required', True)
self.silent = kwargs.get('silent', False)
@@ -176,7 +174,20 @@ class ExternalDependency(Dependency):
compilers = self.env.coredata.cross_compilers
else:
compilers = self.env.coredata.compilers
- self.compiler = compilers.get(self.language or 'c', None)
+ # Set the compiler for this dependency if a language is specified,
+ # else try to pick something that looks usable.
+ if self.language:
+ if self.language not in compilers:
+ m = self.name.capitalize() + ' requires a {} compiler'
+ raise DependencyException(m.format(self.language.capitalize()))
+ self.compiler = compilers[self.language]
+ else:
+ # Try to find a compiler that this dependency can use for compiler
+ # checks. It's ok if we don't find one.
+ for lang in ('c', 'cpp', 'objc', 'objcpp', 'fortran', 'd'):
+ self.compiler = compilers.get(lang, None)
+ if self.compiler:
+ break
def get_compiler(self):
return self.compiler
@@ -308,8 +319,8 @@ class PkgConfigDependency(ExternalDependency):
# multiple times in the same Meson invocation.
class_pkgbin = None
- def __init__(self, name, environment, kwargs):
- super().__init__('pkgconfig', environment, None, kwargs)
+ def __init__(self, name, environment, kwargs, language=None):
+ super().__init__('pkgconfig', environment, language, kwargs)
self.name = name
self.is_libtool = False
# Store a copy of the pkg-config path on the object itself so it is
@@ -401,12 +412,40 @@ class PkgConfigDependency(ExternalDependency):
p, out = Popen_safe([self.pkgbin] + args, env=env)[0:2]
return p.returncode, out.strip()
+ def _convert_mingw_paths(self, args):
+ '''
+ Both MSVC and native Python on Windows cannot handle MinGW-esque /c/foo
+ paths so convert them to C:/foo. We cannot resolve other paths starting
+ with / like /home/foo so leave them as-is so that the user gets an
+ error/warning from the compiler/linker.
+ '''
+ if not mesonlib.is_windows():
+ return args
+ converted = []
+ for arg in args:
+ pargs = []
+ # Library search path
+ if arg.startswith('-L/'):
+ pargs = PurePath(arg[2:]).parts
+ tmpl = '-L{}:/{}'
+ elif arg.startswith('-I/'):
+ pargs = PurePath(arg[2:]).parts
+ tmpl = '-I{}:/{}'
+ # Full path to library or .la file
+ elif arg.startswith('/'):
+ pargs = PurePath(arg).parts
+ tmpl = '{}:/{}'
+ if len(pargs) > 1 and len(pargs[1]) == 1:
+ arg = tmpl.format(pargs[1], '/'.join(pargs[2:]))
+ converted.append(arg)
+ return converted
+
def _set_cargs(self):
ret, out = self._call_pkgbin(['--cflags', self.name])
if ret != 0:
raise DependencyException('Could not generate cargs for %s:\n\n%s' %
(self.name, out))
- self.compile_args = shlex.split(out)
+ self.compile_args = self._convert_mingw_paths(shlex.split(out))
def _set_libs(self):
env = None
@@ -423,7 +462,7 @@ class PkgConfigDependency(ExternalDependency):
(self.name, out))
self.link_args = []
libpaths = []
- for lib in shlex.split(out):
+ for lib in self._convert_mingw_paths(shlex.split(out)):
# If we want to use only static libraries, we have to look for the
# file ourselves instead of depending on the compiler to find it
# with -lfoo or foo.lib. However, we can only do this if we already
@@ -452,8 +491,20 @@ class PkgConfigDependency(ExternalDependency):
self.is_libtool = True
self.link_args.append(lib)
- def get_pkgconfig_variable(self, variable_name):
- ret, out = self._call_pkgbin(['--variable=' + variable_name, self.name])
+ def get_pkgconfig_variable(self, variable_name, kwargs):
+ options = ['--variable=' + variable_name, self.name]
+
+ if 'define_variable' in kwargs:
+ definition = kwargs.get('define_variable', [])
+ if not isinstance(definition, list):
+ raise MesonException('define_variable takes a list')
+
+ if len(definition) != 2 or not all(isinstance(i, str) for i in definition):
+ raise MesonException('define_variable must be made up of 2 strings for VARIABLENAME and VARIABLEVALUE')
+
+ options = ['--define-variable=' + '='.join(definition)] + options
+
+ ret, out = self._call_pkgbin(options)
variable = ''
if ret != 0:
if self.required:
diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py
index 41666a3..61dd953 100644
--- a/mesonbuild/dependencies/misc.py
+++ b/mesonbuild/dependencies/misc.py
@@ -237,17 +237,18 @@ class BoostDependency(ExternalDependency):
def detect_lib_modules_win(self):
arch = detect_cpu_family(self.env.coredata.compilers)
- compiler_ts = self.env.detect_cpp_compiler(self.want_cross).get_toolset_version().split('.')
+ comp_ts_version = self.env.detect_cpp_compiler(self.want_cross).get_toolset_version()
+ compiler_ts = comp_ts_version.split('.')
compiler = 'vc{}{}'.format(compiler_ts[0], compiler_ts[1])
if not self.libdir:
- # The libdirs in the distributed binaries
+ # The libdirs in the distributed binaries (from sf)
if arch == 'x86':
- gl = 'lib32*'
+ lib_sf = 'lib32-msvc-{}'.format(comp_ts_version)
elif arch == 'x86_64':
- gl = 'lib64*'
+ lib_sf = 'lib64-msvc-{}'.format(comp_ts_version)
else:
# Does anyone do Boost cross-compiling to other archs on Windows?
- gl = None
+ lib_sf = None
if self.boost_root:
roots = [self.boost_root]
else:
@@ -258,11 +259,10 @@ class BoostDependency(ExternalDependency):
if os.path.isdir(libdir):
self.libdir = libdir
break
- if gl:
- tmp = glob.glob(os.path.join(root, gl))
- if len(tmp) > 0:
- # FIXME: Should pick the correct version
- self.libdir = tmp[0]
+ if lib_sf:
+ full_path = os.path.join(root, lib_sf)
+ if os.path.isdir(full_path):
+ self.libdir = full_path
break
if not self.libdir:
@@ -408,7 +408,7 @@ class MPIDependency(ExternalDependency):
for pkg in pkgconfig_files:
try:
- pkgdep = PkgConfigDependency(pkg, environment, kwargs)
+ pkgdep = PkgConfigDependency(pkg, environment, kwargs, language=self.language)
if pkgdep.found():
self.compile_args = pkgdep.get_compile_args()
self.link_args = pkgdep.get_link_args()
@@ -682,11 +682,11 @@ class Python3Dependency(ExternalDependency):
else:
return [DependencyMethods.PKGCONFIG]
- def get_pkgconfig_variable(self, variable_name):
+ def get_pkgconfig_variable(self, variable_name, kwargs):
if self.pkgdep:
- return self.pkgdep.get_pkgconfig_variable(variable_name)
+ return self.pkgdep.get_pkgconfig_variable(variable_name, kwargs)
else:
- return super().get_pkgconfig_variable(variable_name)
+ return super().get_pkgconfig_variable(variable_name, kwargs)
class PcapDependency(ExternalDependency):
diff --git a/mesonbuild/dependencies/ui.py b/mesonbuild/dependencies/ui.py
index dd04580..1db518c 100644
--- a/mesonbuild/dependencies/ui.py
+++ b/mesonbuild/dependencies/ui.py
@@ -218,7 +218,8 @@ class QtBaseDependency(ExternalDependency):
kwargs['required'] = False
modules = OrderedDict()
for module in mods:
- modules[module] = PkgConfigDependency(self.qtpkgname + module, self.env, kwargs)
+ modules[module] = PkgConfigDependency(self.qtpkgname + module, self.env,
+ kwargs, language=self.language)
for m in modules.values():
if not m.found():
self.is_found = False
@@ -232,12 +233,13 @@ class QtBaseDependency(ExternalDependency):
core = modules['Core']
else:
corekwargs = {'required': 'false', 'silent': 'true'}
- core = PkgConfigDependency(self.qtpkgname + 'Core', self.env, corekwargs)
+ core = PkgConfigDependency(self.qtpkgname + 'Core', self.env, corekwargs,
+ language=self.language)
# Used by self.compilers_detect()
self.bindir = self.get_pkgconfig_host_bins(core)
if not self.bindir:
# If exec_prefix is not defined, the pkg-config file is broken
- prefix = core.get_pkgconfig_variable('exec_prefix')
+ prefix = core.get_pkgconfig_variable('exec_prefix', {})
if prefix:
self.bindir = os.path.join(prefix, 'bin')
@@ -357,7 +359,7 @@ class Qt4Dependency(QtBaseDependency):
applications = ['moc', 'uic', 'rcc', 'lupdate', 'lrelease']
for application in applications:
try:
- return os.path.dirname(core.get_pkgconfig_variable('%s_location' % application))
+ return os.path.dirname(core.get_pkgconfig_variable('%s_location' % application, {}))
except MesonException:
pass
@@ -367,7 +369,7 @@ class Qt5Dependency(QtBaseDependency):
QtBaseDependency.__init__(self, 'qt5', env, kwargs)
def get_pkgconfig_host_bins(self, core):
- return core.get_pkgconfig_variable('host_bins')
+ return core.get_pkgconfig_variable('host_bins', {})
# There are three different ways of depending on SDL2:
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index a9ced7d..f33d437 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -295,7 +295,7 @@ class DependencyHolder(InterpreterObject, ObjectHolder):
varname = args[0]
if not isinstance(varname, str):
raise InterpreterException('Variable name must be a string.')
- return self.held_object.get_pkgconfig_variable(varname)
+ return self.held_object.get_pkgconfig_variable(varname, kwargs)
def configtool_method(self, args, kwargs):
args = listify(args)
@@ -2147,6 +2147,12 @@ to directly access options of other subprojects.''')
def func_dependency(self, node, args, kwargs):
self.validate_arguments(args, 1, [str])
name = args[0]
+
+ if name == '':
+ if kwargs.get('required', True):
+ raise InvalidArguments('Dependency is both required and not-found')
+ return DependencyHolder(Dependency('not-found', {}))
+
if '<' in name or '>' in name or '=' in name:
raise InvalidArguments('Characters <, > and = are forbidden in dependency names. To specify'
'version\n requirements use the \'version\' keyword argument instead.')
@@ -3005,12 +3011,19 @@ different subdirectory.
def format_string(self, templ, args):
if isinstance(args, mparser.ArgumentNode):
args = args.arguments
- for (i, arg) in enumerate(args):
+ arg_strings = []
+ for arg in args:
arg = self.evaluate_statement(arg)
if isinstance(arg, bool): # Python boolean is upper case.
arg = str(arg).lower()
- templ = templ.replace('@{}@'.format(i), str(arg))
- return templ
+ arg_strings.append(str(arg))
+
+ def arg_replace(match):
+ idx = int(match.group(1))
+ if idx >= len(arg_strings):
+ raise InterpreterException('Format placeholder @{}@ out of range.'.format(idx))
+ return arg_strings[idx]
+ return re.sub(r'@(\d+)@', arg_replace, templ)
# Only permit object extraction from the same subproject
def validate_extraction(self, buildtarget):
diff --git a/mesonbuild/linkers.py b/mesonbuild/linkers.py
index e0554e0..de788b7 100644
--- a/mesonbuild/linkers.py
+++ b/mesonbuild/linkers.py
@@ -40,10 +40,10 @@ class VisualStudioLinker(StaticLinker):
return []
def get_always_args(self):
- return VisualStudioLinker.always_args
+ return VisualStudioLinker.always_args[:]
def get_linker_always_args(self):
- return VisualStudioLinker.always_args
+ return VisualStudioLinker.always_args[:]
def build_rpath_args(self, build_dir, from_dir, rpath_paths, build_rpath, install_rpath):
return []
diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py
index a35345b..09b5d92 100644
--- a/mesonbuild/mesonlib.py
+++ b/mesonbuild/mesonlib.py
@@ -744,6 +744,8 @@ def substitute_values(command, values):
_substitute_values_check_errors(command, values)
# Substitution
outcmd = []
+ rx_keys = [re.escape(key) for key in values if key not in ('@INPUT@', '@OUTPUT@')]
+ value_rx = re.compile('|'.join(rx_keys)) if rx_keys else None
for vv in command:
if not isinstance(vv, str):
outcmd.append(vv)
@@ -770,12 +772,9 @@ def substitute_values(command, values):
elif vv in values:
outcmd.append(values[vv])
# Substitute everything else with replacement
+ elif value_rx:
+ outcmd.append(value_rx.sub(lambda m: values[m.group(0)], vv))
else:
- for key, value in values.items():
- if key in ('@INPUT@', '@OUTPUT@'):
- # Already done above
- continue
- vv = vv.replace(key, value)
outcmd.append(vv)
return outcmd
diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py
index f916c2c..56765a5 100644
--- a/mesonbuild/modules/gnome.py
+++ b/mesonbuild/modules/gnome.py
@@ -362,7 +362,7 @@ class GnomeModule(ExtensionModule):
ldflags.update([lib])
if isinstance(dep, PkgConfigDependency):
- girdir = dep.get_pkgconfig_variable("girdir")
+ girdir = dep.get_pkgconfig_variable("girdir", {})
if girdir:
gi_includes.update([girdir])
elif isinstance(dep, (build.StaticLibrary, build.SharedLibrary)):
@@ -553,7 +553,7 @@ class GnomeModule(ExtensionModule):
if subdir not in typelib_includes:
typelib_includes.append(subdir)
elif isinstance(dep, PkgConfigDependency):
- girdir = dep.get_pkgconfig_variable("girdir")
+ girdir = dep.get_pkgconfig_variable("girdir", {})
if girdir and girdir not in typelib_includes:
typelib_includes.append(girdir)
# ldflags will be misinterpreted by gir scanner (showing
diff --git a/mesonbuild/optinterpreter.py b/mesonbuild/optinterpreter.py
index 22a263e..3cca239 100644
--- a/mesonbuild/optinterpreter.py
+++ b/mesonbuild/optinterpreter.py
@@ -86,15 +86,17 @@ def ComboParser(name, description, kwargs):
@permitted_kwargs({'value', 'choices'})
def string_array_parser(name, description, kwargs):
- if 'choices' not in kwargs:
- raise OptionException('Array option missing "choices" keyword.')
- choices = kwargs['choices']
- if not isinstance(choices, list):
- raise OptionException('Array choices must be an array.')
- for i in choices:
- if not isinstance(i, str):
- raise OptionException('Array choice elements must be strings.')
- value = kwargs.get('value', choices)
+ if 'choices' in kwargs:
+ choices = kwargs['choices']
+ if not isinstance(choices, list):
+ raise OptionException('Array choices must be an array.')
+ for i in choices:
+ if not isinstance(i, str):
+ raise OptionException('Array choice elements must be strings.')
+ value = kwargs.get('value', choices)
+ else:
+ choices = None
+ value = kwargs.get('value', [])
if not isinstance(value, list):
raise OptionException('Array choices must be passed as an array.')
return coredata.UserStringArrayOption(name, description, value, choices=choices)
diff --git a/run_tests.py b/run_tests.py
index b287a1a..1cc3983 100755
--- a/run_tests.py
+++ b/run_tests.py
@@ -155,15 +155,6 @@ def run_configure(meson_command, commandlist):
return run_configure_external(meson_exe + commandlist)
return run_configure_inprocess(meson_command, commandlist)
-class FakeEnvironment(object):
- def __init__(self):
- self.cross_info = None
- self.coredata = lambda: None
- self.coredata.compilers = {}
-
- def is_cross_build(self):
- return False
-
def print_system_info():
print(mlog.bold('System information.').get_text(mlog.colorize_console))
print('Architecture:', platform.architecture())
diff --git a/run_unittests.py b/run_unittests.py
index 79805b2..0002f6c 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -40,7 +40,7 @@ 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 exe_suffix, get_fake_options
from run_tests import get_builddir_target_args, get_backend_commands, Backend
from run_tests import ensure_backend_detects_changes, run_configure, meson_exe
from run_tests import should_run_linux_cross_tests
@@ -1061,16 +1061,17 @@ class AllPlatformTests(BasePlatformTests):
evalue = os.environ.pop(evar)
# Very rough/strict heuristics. Would never work for actual
# compiler detection, but should be ok for the tests.
- if os.path.basename(evalue).startswith('g'):
+ ebase = os.path.basename(evalue)
+ if ebase.startswith('g') or ebase.endswith(('-gcc', '-g++')):
self.assertIsInstance(ecc, gnu)
self.assertIsInstance(elinker, ar)
- elif 'clang' in os.path.basename(evalue):
+ elif 'clang' in ebase:
self.assertIsInstance(ecc, clang)
self.assertIsInstance(elinker, ar)
- elif os.path.basename(evalue).startswith('ic'):
+ elif ebase.startswith('ic'):
self.assertIsInstance(ecc, intel)
self.assertIsInstance(elinker, ar)
- elif os.path.basename(evalue).startswith('cl'):
+ elif ebase.startswith('cl'):
self.assertIsInstance(ecc, msvc)
self.assertIsInstance(elinker, lib)
else:
@@ -1398,6 +1399,7 @@ int main(int argc, char **argv) {
env = Environment('', self.builddir, self.meson_command,
get_fake_options(self.prefix), [])
cc = env.detect_c_compiler(False)
+ stlinker = env.detect_static_linker(cc)
if mesonbuild.mesonlib.is_windows():
object_suffix = 'obj'
shared_suffix = 'dll'
@@ -1410,7 +1412,7 @@ int main(int argc, char **argv) {
else:
object_suffix = 'o'
shared_suffix = 'so'
- return (cc, object_suffix, shared_suffix)
+ return (cc, stlinker, object_suffix, shared_suffix)
def pbcompile(self, compiler, source, objectfile, extra_args=[]):
cmd = compiler.get_exelist()
@@ -1422,7 +1424,7 @@ int main(int argc, char **argv) {
def test_prebuilt_object(self):
- (compiler, object_suffix, _) = self.detect_prebuild_env()
+ (compiler, _, object_suffix, _) = self.detect_prebuild_env()
tdir = os.path.join(self.unit_test_dir, '14 prebuilt object')
source = os.path.join(tdir, 'source.c')
objectfile = os.path.join(tdir, 'prebuilt.' + object_suffix)
@@ -1434,13 +1436,18 @@ int main(int argc, char **argv) {
finally:
os.unlink(objectfile)
- def build_static_lib(self, compiler, source, objectfile, outfile, extra_args=None):
+ def build_static_lib(self, compiler, linker, source, objectfile, outfile, extra_args=None):
if extra_args is None:
extra_args = []
if compiler.id == 'msvc':
link_cmd = ['lib', '/NOLOGO', '/OUT:' + outfile, objectfile]
else:
link_cmd = ['ar', 'csr', outfile, objectfile]
+ link_cmd = linker.get_exelist()
+ link_cmd += linker.get_always_args()
+ link_cmd += linker.get_std_link_args()
+ link_cmd += linker.get_output_args(outfile)
+ link_cmd += [objectfile]
self.pbcompile(compiler, source, objectfile, extra_args=extra_args)
try:
subprocess.check_call(link_cmd)
@@ -1448,12 +1455,12 @@ int main(int argc, char **argv) {
os.unlink(objectfile)
def test_prebuilt_static_lib(self):
- (cc, object_suffix, _) = self.detect_prebuild_env()
+ (cc, stlinker, object_suffix, _) = self.detect_prebuild_env()
tdir = os.path.join(self.unit_test_dir, '15 prebuilt static')
source = os.path.join(tdir, 'libdir/best.c')
objectfile = os.path.join(tdir, 'libdir/best.' + object_suffix)
stlibfile = os.path.join(tdir, 'libdir/libbest.a')
- self.build_static_lib(cc, source, objectfile, stlibfile)
+ self.build_static_lib(cc, stlinker, source, objectfile, stlibfile)
# Run the test
try:
self.init(tdir)
@@ -1480,7 +1487,7 @@ int main(int argc, char **argv) {
os.unlink(objectfile)
def test_prebuilt_shared_lib(self):
- (cc, object_suffix, shared_suffix) = self.detect_prebuild_env()
+ (cc, _, object_suffix, shared_suffix) = self.detect_prebuild_env()
tdir = os.path.join(self.unit_test_dir, '16 prebuilt shared')
source = os.path.join(tdir, 'alexandria.c')
objectfile = os.path.join(tdir, 'alexandria.' + object_suffix)
@@ -1514,7 +1521,7 @@ int main(int argc, char **argv) {
'''
if not shutil.which('pkg-config'):
raise unittest.SkipTest('pkg-config not found')
- (cc, objext, shext) = self.detect_prebuild_env()
+ (cc, stlinker, objext, shext) = self.detect_prebuild_env()
testdir = os.path.join(self.unit_test_dir, '17 pkgconfig static')
source = os.path.join(testdir, 'foo.c')
objectfile = os.path.join(testdir, 'foo.' + objext)
@@ -1527,7 +1534,7 @@ int main(int argc, char **argv) {
else:
shlibfile = os.path.join(testdir, 'libfoo.' + shext)
# Build libs
- self.build_static_lib(cc, source, objectfile, stlibfile, extra_args=['-DFOO_STATIC'])
+ self.build_static_lib(cc, stlinker, source, objectfile, stlibfile, extra_args=['-DFOO_STATIC'])
self.build_shared_lib(cc, source, objectfile, shlibfile, impfile)
# Run test
os.environ['PKG_CONFIG_LIBDIR'] = self.builddir
@@ -1555,7 +1562,8 @@ int main(int argc, char **argv) {
'--libdir=' + libdir])
# Find foo dependency
os.environ['PKG_CONFIG_LIBDIR'] = self.privatedir
- env = FakeEnvironment()
+ env = Environment(testdir, self.builddir, self.meson_command,
+ get_fake_options(self.prefix), [])
kwargs = {'required': True, 'silent': True}
foo_dep = PkgConfigDependency('libfoo', env, kwargs)
# Ensure link_args are properly quoted
@@ -1614,6 +1622,25 @@ int main(int argc, char **argv) {
changed = get_opt()
self.assertDictEqual(changed, expected)
+ def opt_has(self, name, value):
+ res = self.introspect('--buildoptions')
+ found = False
+ for i in res:
+ if i['name'] == name:
+ self.assertEqual(i['value'], value)
+ found = True
+ break
+ self.assertTrue(found, "Array option not found in introspect data.")
+
+ def test_free_stringarray_setting(self):
+ testdir = os.path.join(self.common_test_dir, '47 options')
+ self.init(testdir)
+ self.opt_has('free_array_opt', [])
+ self.setconf('-Dfree_array_opt=foo,bar', will_build=False)
+ self.opt_has('free_array_opt', ['foo', 'bar'])
+ self.setconf("-Dfree_array_opt=['a,b', 'c,d']", will_build=False)
+ self.opt_has('free_array_opt', ['a,b', 'c,d'])
+
class FailureTests(BasePlatformTests):
'''
@@ -1856,15 +1883,16 @@ class LinuxlikeTests(BasePlatformTests):
'''
testdir = os.path.join(self.common_test_dir, '51 pkgconfig-gen')
self.init(testdir)
- env = FakeEnvironment()
+ env = Environment(testdir, self.builddir, self.meson_command,
+ get_fake_options(self.prefix), [])
kwargs = {'required': True, 'silent': True}
os.environ['PKG_CONFIG_LIBDIR'] = self.privatedir
foo_dep = PkgConfigDependency('libfoo', env, kwargs)
self.assertTrue(foo_dep.found())
self.assertEqual(foo_dep.get_version(), '1.0')
self.assertIn('-lfoo', foo_dep.get_link_args())
- self.assertEqual(foo_dep.get_pkgconfig_variable('foo'), 'bar')
- self.assertPathEqual(foo_dep.get_pkgconfig_variable('datadir'), '/usr/data')
+ self.assertEqual(foo_dep.get_pkgconfig_variable('foo', {}), 'bar')
+ self.assertPathEqual(foo_dep.get_pkgconfig_variable('datadir', {}), '/usr/data')
def test_vala_c_warnings(self):
'''
@@ -2240,8 +2268,9 @@ class LinuxlikeTests(BasePlatformTests):
raise unittest.SkipTest('gcovr not found')
if not shutil.which('genhtml'):
raise unittest.SkipTest('genhtml not found')
- if 'clang' in os.environ.get('CC', '') and os.environ.get('TRAVIS_OS_NAME', '') == 'linux':
- raise unittest.SkipTest('Gcovr has a bug and does not work with Clang in the CI environment.')
+ if 'clang' in os.environ.get('CC', ''):
+ # We need to use llvm-cov instead of gcovr with clang
+ raise unittest.SkipTest('Coverage does not work with clang right now, help wanted!')
testdir = os.path.join(self.common_test_dir, '1 trivial')
self.init(testdir, ['-Db_coverage=true'])
self.build()
diff --git a/test cases/common/166 custom target subdir depend files/copyfile.py b/test cases/common/166 custom target subdir depend files/copyfile.py
new file mode 100644
index 0000000..ff42ac3
--- /dev/null
+++ b/test cases/common/166 custom target subdir depend files/copyfile.py
@@ -0,0 +1,6 @@
+#!/usr/bin/env python3
+
+import sys
+import shutil
+
+shutil.copyfile(sys.argv[1], sys.argv[2])
diff --git a/test cases/common/166 custom target subdir depend files/meson.build b/test cases/common/166 custom target subdir depend files/meson.build
new file mode 100644
index 0000000..44f5c71
--- /dev/null
+++ b/test cases/common/166 custom target subdir depend files/meson.build
@@ -0,0 +1,7 @@
+project('custom target subdir depend files', 'c')
+
+copy = find_program('copyfile.py')
+
+subdir('subdir')
+
+executable('foo', foo_src)
diff --git a/test cases/common/166 custom target subdir depend files/subdir/dep.dat b/test cases/common/166 custom target subdir depend files/subdir/dep.dat
new file mode 100644
index 0000000..5daee49
--- /dev/null
+++ b/test cases/common/166 custom target subdir depend files/subdir/dep.dat
@@ -0,0 +1 @@
+You can depend on this file. \ No newline at end of file
diff --git a/test cases/common/166 custom target subdir depend files/subdir/foo.c.in b/test cases/common/166 custom target subdir depend files/subdir/foo.c.in
new file mode 100644
index 0000000..d53846f
--- /dev/null
+++ b/test cases/common/166 custom target subdir depend files/subdir/foo.c.in
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+int main() {
+ printf("foo is working.\n");
+ return 0;
+}
diff --git a/test cases/common/166 custom target subdir depend files/subdir/meson.build b/test cases/common/166 custom target subdir depend files/subdir/meson.build
new file mode 100644
index 0000000..f9d31c4
--- /dev/null
+++ b/test cases/common/166 custom target subdir depend files/subdir/meson.build
@@ -0,0 +1,6 @@
+foo_src = custom_target('foo_src',
+ depend_files : 'dep.dat',
+ input : 'foo.c.in',
+ output : 'foo.c',
+ command : [copy, '@INPUT@', '@OUTPUT@']
+)
diff --git a/test cases/common/166 array option/meson.build b/test cases/common/169 array option/meson.build
index bfcde7c..bfcde7c 100644
--- a/test cases/common/166 array option/meson.build
+++ b/test cases/common/169 array option/meson.build
diff --git a/test cases/common/166 array option/meson_options.txt b/test cases/common/169 array option/meson_options.txt
index 7ed0ac1..7ed0ac1 100644
--- a/test cases/common/166 array option/meson_options.txt
+++ b/test cases/common/169 array option/meson_options.txt
diff --git a/test cases/common/170 custom target template substitution/checkcopy.py b/test cases/common/170 custom target template substitution/checkcopy.py
new file mode 100644
index 0000000..ab9f436
--- /dev/null
+++ b/test cases/common/170 custom target template substitution/checkcopy.py
@@ -0,0 +1,9 @@
+#!/usr/bin/env python3
+
+import sys
+import shutil
+
+if '@INPUT1@' in sys.argv[1]:
+ shutil.copyfile(sys.argv[2], sys.argv[3])
+else:
+ sys.exit('String @INPUT1@ not found in "{}"'.format(sys.argv[1]))
diff --git a/test cases/common/170 custom target template substitution/foo.c.in b/test cases/common/170 custom target template substitution/foo.c.in
new file mode 100644
index 0000000..d53846f
--- /dev/null
+++ b/test cases/common/170 custom target template substitution/foo.c.in
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+int main() {
+ printf("foo is working.\n");
+ return 0;
+}
diff --git a/test cases/common/170 custom target template substitution/meson.build b/test cases/common/170 custom target template substitution/meson.build
new file mode 100644
index 0000000..3f6a159
--- /dev/null
+++ b/test cases/common/170 custom target template substitution/meson.build
@@ -0,0 +1,17 @@
+project('custom target template substitution', 'c')
+
+check = find_program('checkcopy.py')
+
+config = configuration_data()
+
+in = configure_file(configuration : config, output : 'x@IN')
+
+# Check that substitution does not find @FOO@ and then misses @INPUT0@.
+# Check the resulting x@INPUT1@ is not replaced.
+foo = custom_target('runcheck',
+ input : [in, 'foo.c.in'],
+ output : 'foo.c',
+ command : [check, '-D@FOO@INPUT0@PUT1@', '@INPUT1@', '@OUTPUT@']
+)
+
+executable('foo', foo)
diff --git a/test cases/common/171 not-found dependency/meson.build b/test cases/common/171 not-found dependency/meson.build
new file mode 100644
index 0000000..7d92f5a
--- /dev/null
+++ b/test cases/common/171 not-found dependency/meson.build
@@ -0,0 +1,8 @@
+project('dep-test')
+
+dep = dependency('', required:false)
+if dep.found()
+ error('not-found dependency was found')
+endif
+
+assert(dep.type_name() == 'not-found', 'dependency should be of type "not-found" not ' + dep.type_name())
diff --git a/test cases/common/42 string operations/meson.build b/test cases/common/42 string operations/meson.build
index e60006a..a43de70 100644
--- a/test cases/common/42 string operations/meson.build
+++ b/test cases/common/42 string operations/meson.build
@@ -13,6 +13,8 @@ subs2 = '42'
assert(templ2.format(subs2) == '42', 'String formatting with variables is broken.')
+assert('@@0@@ @@1@@'.format(1, 2) == '@1@ @2@', 'String format is recursive.')
+
long = 'abcde'
prefix = 'abc'
suffix = 'cde'
diff --git a/test cases/common/47 options/meson_options.txt b/test cases/common/47 options/meson_options.txt
index 8978d44..6bd0346 100644
--- a/test cases/common/47 options/meson_options.txt
+++ b/test cases/common/47 options/meson_options.txt
@@ -2,3 +2,4 @@ option('testoption', type : 'string', value : 'optval', description : 'An option
option('other_one', type : 'boolean', value : false)
option('combo_opt', type : 'combo', choices : ['one', 'two', 'combo'], value : 'combo')
option('array_opt', type : 'array', choices : ['one', 'two', 'three'], value : ['one', 'two'])
+option('free_array_opt', type : 'array')
diff --git a/test cases/failing/67 dependency not-found and required/meson.build b/test cases/failing/67 dependency not-found and required/meson.build
new file mode 100644
index 0000000..1ce5747
--- /dev/null
+++ b/test cases/failing/67 dependency not-found and required/meson.build
@@ -0,0 +1,2 @@
+project('dep-test')
+dep = dependency('', required:true)
diff --git a/test cases/linuxlike/1 pkg-config/meson.build b/test cases/linuxlike/1 pkg-config/meson.build
index 17feb21..30e5d25 100644
--- a/test cases/linuxlike/1 pkg-config/meson.build
+++ b/test cases/linuxlike/1 pkg-config/meson.build
@@ -17,6 +17,8 @@ test('zlibtest', exe)
zprefix = dep.get_pkgconfig_variable('prefix') # Always set but we can't be sure what the value is.
# pkg-config returns empty string for not defined variables
assert(dep.get_pkgconfig_variable('nonexisting') == '', 'Value of unknown variable is not empty.')
+# pkg-config is able to replace variables
+assert(dep.get_pkgconfig_variable('prefix', define_variable: ['prefix', '/tmp']) == '/tmp', 'prefix variable has not been replaced.')
# Test that dependencies of dependencies work.
dep2 = declare_dependency(dependencies : dep)
diff --git a/test cases/unit/17 pkgconfig static/meson.build b/test cases/unit/17 pkgconfig static/meson.build
index caeb4aa..d1b0fd5 100644
--- a/test cases/unit/17 pkgconfig static/meson.build
+++ b/test cases/unit/17 pkgconfig static/meson.build
@@ -5,8 +5,22 @@ if build_machine.system() != 'windows'
else
# pkg-config files should not use paths with \
prefix_parts = meson.source_root().split('\\')
- prefix = '/'.join(prefix_parts)
+ # If the path is C:/foo/bar, convert it to /c/foo/bar so we can test if our
+ # automatic conversion to C:/foo/bar inside PkgConfigDependency is working.
+ if prefix_parts[0][1] == ':'
+ drive = prefix_parts[0][0]
+ else
+ drive = prefix_parts[0]
+ endif
+ new_parts = []
+ foreach part : prefix_parts
+ if part != prefix_parts[0]
+ new_parts += part
+ endif
+ endforeach
+ prefix = '/@0@/@1@'.format(drive, '/'.join(new_parts))
endif
+message(prefix)
# Escape spaces
prefix_parts = prefix.split(' ')