aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--docs/.editorconfig2
-rw-r--r--docs/markdown/Native-environments.md76
-rw-r--r--docs/markdown/Pkg-config-files.md2
-rw-r--r--docs/markdown/Pkgconfig-module.md7
-rw-r--r--docs/markdown/Reference-manual.md3
-rw-r--r--docs/markdown/index.md4
-rw-r--r--docs/markdown/snippets/native_files.md15
-rw-r--r--docs/markdown/snippets/test_setup_is_default.md14
-rw-r--r--docs/sitemap.txt1
-rw-r--r--mesonbuild/backend/ninjabackend.py4
-rw-r--r--mesonbuild/backend/vs2010backend.py15
-rw-r--r--mesonbuild/build.py13
-rw-r--r--mesonbuild/compilers/c.py106
-rw-r--r--mesonbuild/compilers/compilers.py9
-rw-r--r--mesonbuild/compilers/cpp.py15
-rw-r--r--mesonbuild/compilers/d.py2
-rw-r--r--mesonbuild/compilers/fortran.py12
-rw-r--r--mesonbuild/coredata.py88
-rw-r--r--mesonbuild/dependencies/base.py15
-rw-r--r--mesonbuild/dependencies/misc.py1
-rw-r--r--mesonbuild/dependencies/ui.py66
-rw-r--r--mesonbuild/environment.py39
-rw-r--r--mesonbuild/interpreter.py81
-rw-r--r--mesonbuild/modules/python.py4
-rw-r--r--mesonbuild/modules/python3.py5
-rw-r--r--mesonbuild/modules/qt.py9
-rw-r--r--mesonbuild/modules/qt4.py7
-rw-r--r--mesonbuild/modules/qt5.py7
-rw-r--r--mesonbuild/modules/windows.py11
-rw-r--r--mesonbuild/msetup.py4
-rw-r--r--mesonbuild/mtest.py36
-rwxr-xr-xrun_meson_command_tests.py7
-rwxr-xr-xrun_project_tests.py57
-rwxr-xr-xrun_tests.py1
-rwxr-xr-xrun_unittests.py347
-rw-r--r--test cases/common/122 shared module/installed_files.txt5
-rw-r--r--test cases/common/122 shared module/meson.build8
-rw-r--r--test cases/common/152 simd/simd_sse2.c2
-rw-r--r--test cases/common/152 simd/simd_sse3.c2
-rw-r--r--test cases/common/152 simd/simd_sse41.c2
-rw-r--r--test cases/common/152 simd/simd_sse42.c2
-rw-r--r--test cases/common/152 simd/simd_ssse3.c2
-rw-r--r--test cases/common/152 simd/simdchecker.c158
-rw-r--r--test cases/common/152 simd/simdfuncs.h8
-rw-r--r--test cases/common/207 install name_prefix name_suffix/installed_files.txt15
-rw-r--r--test cases/common/207 install name_prefix name_suffix/libfile.c14
-rw-r--r--test cases/common/207 install name_prefix name_suffix/meson.build10
-rw-r--r--test cases/common/25 library versions/installed_files.txt1
-rw-r--r--test cases/common/25 library versions/lib.c13
-rw-r--r--test cases/java/8 codegen custom target/com/mesonbuild/meson.build2
-rw-r--r--test cases/unit/46 native file binary/meson.build21
-rw-r--r--test cases/unit/46 native file binary/meson_options.txt5
-rw-r--r--test cases/unit/47 testsetup default/envcheck.py11
-rw-r--r--test cases/unit/47 testsetup default/meson.build23
-rw-r--r--test cases/windows/7 dll versioning/installed_files.txt10
-rw-r--r--test cases/windows/7 dll versioning/meson.build4
57 files changed, 1158 insertions, 247 deletions
diff --git a/README.md b/README.md
index 5620e57..ad2ca1b 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@ build system.
[![PyPI](https://img.shields.io/pypi/v/meson.svg)](https://pypi.python.org/pypi/meson)
[![Travis](https://travis-ci.org/mesonbuild/meson.svg?branch=master)](https://travis-ci.org/mesonbuild/meson)
[![Appveyor](https://ci.appveyor.com/api/projects/status/7jfaotriu8d8ncov?svg=true)](https://ci.appveyor.com/project/mesonbuild/meson)
-[![Build Status](https://dev.azure.com/jussi0947/jussi/_apis/build/status/mesonbuild.meson%20(1))](https://dev.azure.com/jussi0947/jussi/_build/latest?definitionId=2)
+[![Build Status](https://dev.azure.com/jussi0947/jussi/_apis/build/status/mesonbuild.meson)](https://dev.azure.com/jussi0947/jussi/_build/latest?definitionId=1)
[![Codecov](https://codecov.io/gh/mesonbuild/meson/coverage.svg?branch=master)](https://codecov.io/gh/mesonbuild/meson/branch/master)
[![Code Quality: Python](https://img.shields.io/lgtm/grade/python/g/mesonbuild/meson.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/mesonbuild/meson/context:python)
[![Total Alerts](https://img.shields.io/lgtm/alerts/g/mesonbuild/meson.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/mesonbuild/meson/alerts)
diff --git a/docs/.editorconfig b/docs/.editorconfig
new file mode 100644
index 0000000..b5276f1
--- /dev/null
+++ b/docs/.editorconfig
@@ -0,0 +1,2 @@
+[sitemap.txt]
+indent_style = tab
diff --git a/docs/markdown/Native-environments.md b/docs/markdown/Native-environments.md
new file mode 100644
index 0000000..af7edd2
--- /dev/null
+++ b/docs/markdown/Native-environments.md
@@ -0,0 +1,76 @@
+---
+short-description: Setting up native compilation
+...
+
+# Persistent native environments
+
+New in 0.49.0
+
+Meson has [cross files for describing cross compilation environments](Cross-compilation.md),
+for describing native environments it has equivalent "native files".
+
+Natives describe the *build machine*, and can be used to override properties of
+non-cross builds, as well as properties that are marked as "native" in a cross
+build.
+
+There are a couple of reasons you might want to use a native file to keep a
+persistent environment:
+
+* To build with a non-default native tool chain (such as clang instead of gcc)
+* To use a non-default version of another binary, such as yacc, or llvm-config
+
+
+## Changing native file settings
+
+All of the rules about cross files and changed settings apply to native files
+as well, see [here](Cross-compilation.md#Changing-cross-file-settings)
+
+
+## Defining the environment
+
+### Binaries
+
+Currently the only use of native files is to override native binaries. This
+includes the compilers and binaries collected with `find_program`, and those
+used by dependencies that use a config-tool instead of pkgconfig for detection,
+like `llvm-config`
+
+```ini
+[binaries]
+c = '/usr/local/bin/clang'
+cpp = '/usr/local/bin/clang++'
+rust = '/usr/local/bin/rust'
+llvm-conifg = '/usr/local/llvm-svn/bin/llvm-config'
+```
+
+## Loading multiple native files
+
+Unlike cross file, native files allow layering. More than one native file can be
+loaded, with values from a previous file being overridden by the next. The
+intention of this is not overriding, but to allow composing native files.
+
+For example, if there is a project using C and C++, python 3.4-3.7, and LLVM
+5-7, and it needs to build with clang 5, 6, and 7, and gcc 5.x, 6.x, and 7.x;
+expressing all of these configurations in monolithic configurations would
+result in 81 different native files. By layering them, it can be expressed by
+just 12 native files.
+
+
+## Native file locations
+
+Like cross files, native files may be installed to user or system wide
+locations, defined as:
+ - $XDG_DATA_DIRS/meson/native
+ (/usr/local/share/meson/native:/usr/share/meson/native if $XDG_DATA_DIRS is
+ undefined)
+ - $XDG_DATA_HOME/meson/native ($HOME/.local/share/meson/native if
+ $XDG_DATA_HOME is undefined)
+
+The order of locations tried is as follows:
+ - A file relative to the local dir
+ - The user local location
+ - The system wide locations in order
+
+These files are not intended to be shipped by distributions, unless they are
+specifically for distribution packaging, they are mainly intended for
+developers.
diff --git a/docs/markdown/Pkg-config-files.md b/docs/markdown/Pkg-config-files.md
index 0427b0e..305a6d8 100644
--- a/docs/markdown/Pkg-config-files.md
+++ b/docs/markdown/Pkg-config-files.md
@@ -18,4 +18,4 @@ pkg.generate(libraries : libs,
This causes a file called `simple.pc` to be created and placed into the install directory during the install phase.
-More infromation on the pkg-config module and the parameters can be found on the [pkgconfig-module](http://mesonbuild.com/Pkgconfig-module.html) page.
+More infromation on the pkg-config module and the parameters can be found on the [pkgconfig-module](Pkgconfig-module.md) page.
diff --git a/docs/markdown/Pkgconfig-module.md b/docs/markdown/Pkgconfig-module.md
index b727f1a..9a34e14 100644
--- a/docs/markdown/Pkgconfig-module.md
+++ b/docs/markdown/Pkgconfig-module.md
@@ -14,7 +14,7 @@ can, of course, replace the name `pkg` with anything else.
The generated file's properties are specified with the following
keyword arguments.
-- `description` a string describing the library
+- `description` a string describing the library, used to set the `Description:` field
- `extra_cflags` a list of extra compiler flags to be added to the
`Cflags` field after the header search path
- `filebase` the base name to use for the pkg-config file; as an
@@ -33,7 +33,7 @@ keyword arguments.
- `libraries_private` list of built libraries or strings to put in the
`Libs.private` field. Since 0.45.0 it can also contain dependency objects,
their `link_args` will be added to `Libs.private`.
-- `name` the name of this library
+- `name` the name of this library, used to set the `Name:` field
- `subdirs` which subdirs of `include` should be added to the header
search path, for example if you install headers into
`${PREFIX}/include/foobar-1`, the correct value for this argument
@@ -48,7 +48,8 @@ keyword arguments.
reference other pkgconfig variables,
e.g. `datadir=${prefix}/share`. The names `prefix`, `libdir` and
`installdir` are reserved and may not be used.
-- `version` a string describing the version of this library
+- `version` a string describing the version of this library, used to set the
+ `Version:` field. Defaults to the project version if unspecified.
- `d_module_versions` a list of module version flags used when compiling
D sources referred to by this pkg-config file
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md
index 72e9609..7df0717 100644
--- a/docs/markdown/Reference-manual.md
+++ b/docs/markdown/Reference-manual.md
@@ -105,6 +105,9 @@ the following:
- `exe_wrapper` a list containing the wrapper command or script followed by the arguments to it
- `gdb` if `true`, the tests are also run under `gdb`
- `timeout_multiplier` a number to multiply the test timeout with
+- `is_default` a bool to set whether this is the default test setup.
+ If `true`, the setup will be used whenever `meson test` is run
+ without the `--setup` option. Since 0.49.0
To use the test setup, run `meson test --setup=*name*` inside the build dir.
diff --git a/docs/markdown/index.md b/docs/markdown/index.md
index cffd488..e57cd69 100644
--- a/docs/markdown/index.md
+++ b/docs/markdown/index.md
@@ -33,13 +33,13 @@ developers. The first one is the mailing list, which is hosted at
The second way is via IRC. The channel to use is `#mesonbuild` at
[Freenode](https://freenode.net/).
-### [Projects using Meson](http://mesonbuild.com/Users.html)
+### [Projects using Meson](Users.md)
Many projects out there are using Meson and their communities are also
a great resource for learning about what (and what not too!) do when
trying to convert to using Meson.
-[A short list of Meson users can be found here](http://mesonbuild.com/Users.html)
+[A short list of Meson users can be found here](Users.md)
but there are many more. We would love to hear about your success
stories too and how things could be improved too!
diff --git a/docs/markdown/snippets/native_files.md b/docs/markdown/snippets/native_files.md
new file mode 100644
index 0000000..7bc3644
--- /dev/null
+++ b/docs/markdown/snippets/native_files.md
@@ -0,0 +1,15 @@
+## Native config files
+
+Native files are the counterpart to cross files, and allow specifying
+information about the build machine, both when cross compiling and when not.
+
+Currently the native files only allow specifying the names of binaries, similar
+to the cross file, for example:
+
+```ini
+[binaries]
+llvm-config = "/opt/llvm-custom/bin/llvm-config"
+```
+
+Will override the llvm-config used for *native* binaries. Targets for the host
+machine will continue to use the cross file.
diff --git a/docs/markdown/snippets/test_setup_is_default.md b/docs/markdown/snippets/test_setup_is_default.md
new file mode 100644
index 0000000..2274dc9
--- /dev/null
+++ b/docs/markdown/snippets/test_setup_is_default.md
@@ -0,0 +1,14 @@
+## New keyword argument `is_default` to `add_test_setup()`
+
+The keyword argument `is_default` may be used to set whether the test
+setup should be used by default whenever `meson test` is run without
+the `--setup` option.
+
+```meson
+add_test_setup('default', is_default: true, env: 'G_SLICE=debug-blocks')
+add_test_setup('valgrind', env: 'G_SLICE=always-malloc', ...)
+test('mytest', exe)
+```
+
+For the example above, running `meson test` and `meson test
+--setup=default` is now equivalent.
diff --git a/docs/sitemap.txt b/docs/sitemap.txt
index bfed027..f79eb05 100644
--- a/docs/sitemap.txt
+++ b/docs/sitemap.txt
@@ -9,6 +9,7 @@ index.md
Using-with-Visual-Studio.md
Meson-sample.md
Syntax.md
+ Native-environments.md
Build-targets.md
Include-directories.md
Installing.md
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index 9e76c5b..5606c41 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -877,6 +877,10 @@ int dummy;
def generate_single_java_compile(self, src, target, compiler, outfile):
deps = [os.path.join(self.get_target_dir(l), l.get_filename()) for l in target.link_targets]
+ generated_sources = self.get_target_generated_sources(target)
+ for rel_src, gensrc in generated_sources.items():
+ if rel_src.endswith('.java'):
+ deps.append(rel_src)
args = []
args += compiler.get_buildtype_args(self.get_option_for_target('buildtype', target))
args += self.build.get_global_args(compiler, target.is_cross)
diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
index 2e86ca9..05bcd3a 100644
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -26,7 +26,7 @@ from .. import mlog
from .. import compilers
from ..compilers import CompilerArgs
from ..mesonlib import MesonException, File, python_command
-from ..environment import Environment
+from ..environment import Environment, build_filename
def autodetect_vs_version(build):
vs_version = os.getenv('VisualStudioVersion', None)
@@ -417,7 +417,7 @@ class Vs2010Backend(backends.Backend):
pref = ET.SubElement(ig, 'ProjectReference', Include=include)
ET.SubElement(pref, 'Project').text = '{%s}' % projid
- def create_basic_crap(self, target):
+ def create_basic_crap(self, target, guid):
project_name = target.name
root = ET.Element('Project', {'DefaultTargets': "Build",
'ToolsVersion': '4.0',
@@ -431,7 +431,7 @@ class Vs2010Backend(backends.Backend):
pl.text = self.platform
globalgroup = ET.SubElement(root, 'PropertyGroup', Label='Globals')
guidelem = ET.SubElement(globalgroup, 'ProjectGuid')
- guidelem.text = '{%s}' % self.environment.coredata.test_guid
+ guidelem.text = '{%s}' % guid
kw = ET.SubElement(globalgroup, 'Keyword')
kw.text = self.platform + 'Proj'
p = ET.SubElement(globalgroup, 'Platform')
@@ -460,7 +460,7 @@ class Vs2010Backend(backends.Backend):
return root
def gen_run_target_vcxproj(self, target, ofname, guid):
- root = self.create_basic_crap(target)
+ root = self.create_basic_crap(target, guid)
action = ET.SubElement(root, 'ItemDefinitionGroup')
customstep = ET.SubElement(action, 'PostBuildEvent')
cmd_raw = [target.command] + target.args
@@ -486,7 +486,7 @@ class Vs2010Backend(backends.Backend):
self._prettyprint_vcxproj_xml(ET.ElementTree(root), ofname)
def gen_custom_target_vcxproj(self, target, ofname, guid):
- root = self.create_basic_crap(target)
+ root = self.create_basic_crap(target, guid)
action = ET.SubElement(root, 'ItemDefinitionGroup')
customstep = ET.SubElement(action, 'CustomBuildStep')
# We need to always use absolute paths because our invocation is always
@@ -1098,6 +1098,9 @@ class Vs2010Backend(backends.Backend):
else:
raise MesonException('Unsupported Visual Studio target machine: ' + targetmachine)
+ meson_file_group = ET.SubElement(root, 'ItemGroup')
+ ET.SubElement(meson_file_group, 'None', Include=os.path.join(proj_to_src_dir, build_filename))
+
extra_files = target.extra_files
if len(headers) + len(gen_hdrs) + len(extra_files) > 0:
inc_hdrs = ET.SubElement(root, 'ItemGroup')
@@ -1173,7 +1176,7 @@ class Vs2010Backend(backends.Backend):
pl.text = self.platform
globalgroup = ET.SubElement(root, 'PropertyGroup', Label='Globals')
guidelem = ET.SubElement(globalgroup, 'ProjectGuid')
- guidelem.text = '{%s}' % self.environment.coredata.test_guid
+ guidelem.text = '{%s}' % self.environment.coredata.regen_guid
kw = ET.SubElement(globalgroup, 'Keyword')
kw.text = self.platform + 'Proj'
p = ET.SubElement(globalgroup, 'Platform')
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index 814b6bb..c0f4564 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -135,6 +135,7 @@ class Build:
self.dep_manifest = {}
self.cross_stdlibs = {}
self.test_setups = {}
+ self.test_setup_default_name = None
self.find_overrides = {}
self.searched_programs = set() # The list of all programs that have been searched for.
@@ -1549,13 +1550,9 @@ class SharedLibrary(BuildTarget):
prefix = ''
suffix = ''
self.filename_tpl = self.basic_filename_tpl
- # If the user already provided the prefix and suffix to us, we don't
- # need to do any filename suffix/prefix detection.
# NOTE: manual prefix/suffix override is currently only tested for C/C++
- if self.prefix is not None and self.suffix is not None:
- pass
# C# and Mono
- elif 'cs' in self.compilers:
+ if 'cs' in self.compilers:
prefix = ''
suffix = 'dll'
self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
@@ -1564,8 +1561,8 @@ class SharedLibrary(BuildTarget):
# For all other targets/platforms import_filename stays None
elif for_windows(is_cross, env):
suffix = 'dll'
- self.vs_import_filename = '{0}.lib'.format(self.name)
- self.gcc_import_filename = 'lib{0}.dll.a'.format(self.name)
+ self.vs_import_filename = '{0}{1}.lib'.format(self.prefix if self.prefix is not None else '', self.name)
+ self.gcc_import_filename = '{0}{1}.dll.a'.format(self.prefix if self.prefix is not None else 'lib', self.name)
if self.get_using_msvc():
# Shared library is of the form foo.dll
prefix = ''
@@ -1584,7 +1581,7 @@ class SharedLibrary(BuildTarget):
self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
elif for_cygwin(is_cross, env):
suffix = 'dll'
- self.gcc_import_filename = 'lib{0}.dll.a'.format(self.name)
+ self.gcc_import_filename = '{0}{1}.dll.a'.format(self.prefix if self.prefix is not None else 'lib', self.name)
# Shared library is of the form cygfoo.dll
# (ld --dll-search-prefix=cyg is the default)
prefix = 'cyg'
diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py
index b57001a..1b198b6 100644
--- a/mesonbuild/compilers/c.py
+++ b/mesonbuild/compilers/c.py
@@ -209,7 +209,9 @@ class CCompiler(Compiler):
def _get_search_dirs(self, env):
extra_args = ['--print-search-dirs']
stdo = None
- with self._build_wrapper('', env, extra_args, None, 'compile', True) as p:
+ with self._build_wrapper('', env, extra_args=extra_args,
+ dependencies=None, mode='compile',
+ want_output=True) as p:
stdo = p.stdo
return stdo
@@ -217,9 +219,22 @@ class CCompiler(Compiler):
def _split_fetch_real_dirs(pathstr, sep=':'):
paths = []
for p in pathstr.split(sep):
- p = Path(p)
- if p.exists() and p.resolve().as_posix() not in paths:
- paths.append(p.resolve().as_posix())
+ # GCC returns paths like this:
+ # /usr/lib/gcc/x86_64-linux-gnu/8/../../../../x86_64-linux-gnu/lib
+ # It would make sense to normalize them to get rid of the .. parts
+ # Sadly when you are on a merged /usr fs it also kills these:
+ # /lib/x86_64-linux-gnu
+ # since /lib is a symlink to /usr/lib. This would mean
+ # paths under /lib would be considered not a "system path",
+ # which is wrong and breaks things. Store everything, just to be sure.
+ pobj = Path(p)
+ unresolved = pobj.as_posix()
+ resolved = Path(p).resolve().as_posix()
+ if pobj.exists():
+ if unresolved not in paths:
+ paths.append(unresolved)
+ if resolved not in paths:
+ paths.append(resolved)
return tuple(paths)
def get_compiler_dirs(self, env, name):
@@ -361,13 +376,14 @@ class CCompiler(Compiler):
code = 'int main(int argc, char **argv) { int class=0; return class; }\n'
return self.sanity_check_impl(work_dir, environment, 'sanitycheckc.c', code)
- def check_header(self, hname, prefix, env, extra_args=None, dependencies=None):
+ def check_header(self, hname, prefix, env, *, extra_args=None, dependencies=None):
fargs = {'prefix': prefix, 'header': hname}
code = '''{prefix}
#include <{header}>'''
- return self.compiles(code.format(**fargs), env, extra_args, dependencies)
+ return self.compiles(code.format(**fargs), env, extra_args=extra_args,
+ dependencies=dependencies)
- def has_header(self, hname, prefix, env, extra_args=None, dependencies=None):
+ def has_header(self, hname, prefix, env, *, extra_args=None, dependencies=None):
fargs = {'prefix': prefix, 'header': hname}
code = '''{prefix}
#ifdef __has_include
@@ -377,10 +393,10 @@ class CCompiler(Compiler):
#else
#include <{header}>
#endif'''
- return self.compiles(code.format(**fargs), env, extra_args,
- dependencies, 'preprocess')
+ return self.compiles(code.format(**fargs), env, extra_args=extra_args,
+ dependencies=dependencies, mode='preprocess')
- def has_header_symbol(self, hname, symbol, prefix, env, extra_args=None, dependencies=None):
+ def has_header_symbol(self, hname, symbol, prefix, env, *, extra_args=None, dependencies=None):
fargs = {'prefix': prefix, 'header': hname, 'symbol': symbol}
t = '''{prefix}
#include <{header}>
@@ -390,7 +406,8 @@ class CCompiler(Compiler):
{symbol};
#endif
}}'''
- return self.compiles(t.format(**fargs), env, extra_args, dependencies)
+ return self.compiles(t.format(**fargs), env, extra_args=extra_args,
+ dependencies=dependencies)
def _get_compiler_check_args(self, env, extra_args, dependencies, mode='compile'):
if callable(extra_args):
@@ -437,7 +454,7 @@ class CCompiler(Compiler):
args += extra_args
return args
- def compiles(self, code, env, extra_args=None, dependencies=None, mode='compile'):
+ def compiles(self, code, env, *, extra_args=None, dependencies=None, mode='compile'):
with self._build_wrapper(code, env, extra_args, dependencies, mode) as p:
return p.returncode == 0
@@ -445,10 +462,11 @@ class CCompiler(Compiler):
args = self._get_compiler_check_args(env, extra_args, dependencies, mode)
return self.compile(code, args, mode, want_output=want_output)
- def links(self, code, env, extra_args=None, dependencies=None):
- return self.compiles(code, env, extra_args, dependencies, mode='link')
+ def links(self, code, env, *, extra_args=None, dependencies=None):
+ return self.compiles(code, env, extra_args=extra_args,
+ dependencies=dependencies, mode='link')
- def run(self, code, env, extra_args=None, dependencies=None):
+ def run(self, code, env, *, extra_args=None, dependencies=None):
if self.is_cross and self.exe_wrapper is None:
raise CrossNoRunException('Can not run test applications in this cross environment.')
with self._build_wrapper(code, env, extra_args, dependencies, mode='link', want_output=True) as p:
@@ -478,7 +496,8 @@ class CCompiler(Compiler):
t = '''#include <stdio.h>
{prefix}
int main() {{ static int a[1-2*!({expression})]; a[0]=0; return 0; }}'''
- return self.compiles(t.format(**fargs), env, extra_args, dependencies)
+ return self.compiles(t.format(**fargs), env, extra_args=extra_args,
+ dependencies=dependencies)
def cross_compute_int(self, expression, low, high, guess, prefix, env, extra_args, dependencies):
# Try user's guess first
@@ -528,7 +547,7 @@ class CCompiler(Compiler):
return low
- def compute_int(self, expression, low, high, guess, prefix, env, extra_args=None, dependencies=None):
+ def compute_int(self, expression, low, high, guess, prefix, env, *, extra_args=None, dependencies=None):
if extra_args is None:
extra_args = []
if self.is_cross:
@@ -540,14 +559,15 @@ class CCompiler(Compiler):
printf("%ld\\n", (long)({expression}));
return 0;
}};'''
- res = self.run(t.format(**fargs), env, extra_args, dependencies)
+ res = self.run(t.format(**fargs), env, extra_args=extra_args,
+ dependencies=dependencies)
if not res.compiled:
return -1
if res.returncode != 0:
raise EnvironmentException('Could not run compute_int test binary.')
return int(res.stdout)
- def cross_sizeof(self, typename, prefix, env, extra_args=None, dependencies=None):
+ def cross_sizeof(self, typename, prefix, env, *, extra_args=None, dependencies=None):
if extra_args is None:
extra_args = []
fargs = {'prefix': prefix, 'type': typename}
@@ -556,30 +576,33 @@ class CCompiler(Compiler):
int main(int argc, char **argv) {{
{type} something;
}}'''
- if not self.compiles(t.format(**fargs), env, extra_args, dependencies):
+ if not self.compiles(t.format(**fargs), env, extra_args=extra_args,
+ dependencies=dependencies):
return -1
return self.cross_compute_int('sizeof(%s)' % typename, None, None, None, prefix, env, extra_args, dependencies)
- def sizeof(self, typename, prefix, env, extra_args=None, dependencies=None):
+ def sizeof(self, typename, prefix, env, *, extra_args=None, dependencies=None):
if extra_args is None:
extra_args = []
fargs = {'prefix': prefix, 'type': typename}
if self.is_cross:
- return self.cross_sizeof(typename, prefix, env, extra_args, dependencies)
+ return self.cross_sizeof(typename, prefix, env, extra_args=extra_args,
+ dependencies=dependencies)
t = '''#include<stdio.h>
{prefix}
int main(int argc, char **argv) {{
printf("%ld\\n", (long)(sizeof({type})));
return 0;
}};'''
- res = self.run(t.format(**fargs), env, extra_args, dependencies)
+ res = self.run(t.format(**fargs), env, extra_args=extra_args,
+ dependencies=dependencies)
if not res.compiled:
return -1
if res.returncode != 0:
raise EnvironmentException('Could not run sizeof test binary.')
return int(res.stdout)
- def cross_alignment(self, typename, prefix, env, extra_args=None, dependencies=None):
+ def cross_alignment(self, typename, prefix, env, *, extra_args=None, dependencies=None):
if extra_args is None:
extra_args = []
fargs = {'prefix': prefix, 'type': typename}
@@ -588,7 +611,8 @@ class CCompiler(Compiler):
int main(int argc, char **argv) {{
{type} something;
}}'''
- if not self.compiles(t.format(**fargs), env, extra_args, dependencies):
+ if not self.compiles(t.format(**fargs), env, extra_args=extra_args,
+ dependencies=dependencies):
return -1
t = '''#include <stddef.h>
{prefix}
@@ -598,11 +622,12 @@ class CCompiler(Compiler):
}};'''
return self.cross_compute_int('offsetof(struct tmp, target)', None, None, None, t.format(**fargs), env, extra_args, dependencies)
- def alignment(self, typename, prefix, env, extra_args=None, dependencies=None):
+ def alignment(self, typename, prefix, env, *, extra_args=None, dependencies=None):
if extra_args is None:
extra_args = []
if self.is_cross:
- return self.cross_alignment(typename, prefix, env, extra_args, dependencies)
+ return self.cross_alignment(typename, prefix, env, extra_args=extra_args,
+ dependencies=dependencies)
fargs = {'prefix': prefix, 'type': typename}
t = '''#include <stdio.h>
#include <stddef.h>
@@ -615,7 +640,8 @@ class CCompiler(Compiler):
printf("%d", (int)offsetof(struct tmp, target));
return 0;
}}'''
- res = self.run(t.format(**fargs), env, extra_args, dependencies)
+ res = self.run(t.format(**fargs), env, extra_args=extra_args,
+ dependencies=dependencies)
if not res.compiled:
raise EnvironmentException('Could not compile alignment test.')
if res.returncode != 0:
@@ -659,7 +685,7 @@ class CCompiler(Compiler):
int main(int argc, char *argv[]) {{
printf ("{fmt}", {cast} {f}());
}}'''.format(**fargs)
- res = self.run(code, env, extra_args, dependencies)
+ res = self.run(code, env, extra_args=extra_args, dependencies=dependencies)
if not res.compiled:
m = 'Could not get return value of {}()'
raise EnvironmentException(m.format(fname))
@@ -728,7 +754,7 @@ class CCompiler(Compiler):
}}'''
return head, main
- def has_function(self, funcname, prefix, env, extra_args=None, dependencies=None):
+ def has_function(self, funcname, prefix, env, *, extra_args=None, dependencies=None):
"""
First, this function looks for the symbol in the default libraries
provided by the compiler (stdlib + a few others usually). If that
@@ -776,7 +802,8 @@ class CCompiler(Compiler):
head, main = self._no_prototype_templ()
templ = head + stubs_fail + main
- if self.links(templ.format(**fargs), env, extra_args, dependencies):
+ if self.links(templ.format(**fargs), env, extra_args=extra_args,
+ dependencies=dependencies):
return True
# MSVC does not have compiler __builtin_-s.
@@ -809,9 +836,10 @@ class CCompiler(Compiler):
#endif
#endif
}}'''
- return self.links(t.format(**fargs), env, extra_args, dependencies)
+ return self.links(t.format(**fargs), env, extra_args=extra_args,
+ dependencies=dependencies)
- def has_members(self, typename, membernames, prefix, env, extra_args=None, dependencies=None):
+ def has_members(self, typename, membernames, prefix, env, *, extra_args=None, dependencies=None):
if extra_args is None:
extra_args = []
fargs = {'prefix': prefix, 'type': typename, 'name': 'foo'}
@@ -825,7 +853,8 @@ class CCompiler(Compiler):
{type} {name};
{members}
}};'''
- return self.compiles(t.format(**fargs), env, extra_args, dependencies)
+ return self.compiles(t.format(**fargs), env, extra_args=extra_args,
+ dependencies=dependencies)
def has_type(self, typename, prefix, env, extra_args, dependencies=None):
fargs = {'prefix': prefix, 'type': typename}
@@ -833,7 +862,8 @@ class CCompiler(Compiler):
void bar() {{
sizeof({type});
}};'''
- return self.compiles(t.format(**fargs), env, extra_args, dependencies)
+ return self.compiles(t.format(**fargs), env, extra_args=extra_args,
+ dependencies=dependencies)
def symbols_have_underscore_prefix(self, env):
'''
@@ -1221,11 +1251,13 @@ class ElbrusCCompiler(GnuCCompiler, ElbrusCompiler):
# Elbrus C compiler does not have lchmod, but there is only linker warning, not compiler error.
# So we should explicitly fail at this case.
- def has_function(self, funcname, prefix, env, extra_args=None, dependencies=None):
+ def has_function(self, funcname, prefix, env, *, extra_args=None, dependencies=None):
if funcname == 'lchmod':
return False
else:
- return super().has_function(funcname, prefix, env, extra_args, dependencies)
+ return super().has_function(funcname, prefix, env,
+ extra_args=extra_args,
+ dependencies=dependencies)
class IntelCCompiler(IntelCompiler, CCompiler):
diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py
index 495663e..85a8480 100644
--- a/mesonbuild/compilers/compilers.py
+++ b/mesonbuild/compilers/compilers.py
@@ -868,10 +868,10 @@ class Compiler:
def compute_int(self, expression, low, high, guess, prefix, env, extra_args, dependencies):
raise EnvironmentException('%s does not support compute_int ' % self.get_id())
- def has_members(self, typename, membernames, prefix, env, extra_args=None, dependencies=None):
+ def has_members(self, typename, membernames, prefix, env, *, extra_args=None, dependencies=None):
raise EnvironmentException('%s does not support has_member(s) ' % self.get_id())
- def has_type(self, typename, prefix, env, extra_args, dependencies=None):
+ def has_type(self, typename, prefix, env, extra_args, *, dependencies=None):
raise EnvironmentException('%s does not support has_type ' % self.get_id())
def symbols_have_underscore_prefix(self, env):
@@ -1614,7 +1614,7 @@ class ClangCompiler(GnuLikeCompiler):
myargs + args,
env)
- def has_function(self, funcname, prefix, env, extra_args=None, dependencies=None):
+ def has_function(self, funcname, prefix, env, *, extra_args=None, dependencies=None):
if extra_args is None:
extra_args = []
# Starting with XCode 8, we need to pass this to force linker
@@ -1623,7 +1623,8 @@ class ClangCompiler(GnuLikeCompiler):
# https://github.com/Homebrew/homebrew-core/issues/3727
if self.compiler_type.is_osx_compiler and version_compare(self.version, '>=8.0'):
extra_args.append('-Wl,-no_weak_imports')
- return super().has_function(funcname, prefix, env, extra_args, dependencies)
+ return super().has_function(funcname, prefix, env, extra_args=extra_args,
+ dependencies=dependencies)
def openmp_flags(self):
if version_compare(self.version, '>=3.8.0'):
diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py
index e6f5803..7d2000e 100644
--- a/mesonbuild/compilers/cpp.py
+++ b/mesonbuild/compilers/cpp.py
@@ -62,9 +62,11 @@ class CPPCompiler(CCompiler):
# too strict without this and always fails.
return super().get_compiler_check_args() + ['-fpermissive']
- def has_header_symbol(self, hname, symbol, prefix, env, extra_args=None, dependencies=None):
+ def has_header_symbol(self, hname, symbol, prefix, env, *, extra_args=None, dependencies=None):
# Check if it's a C-like symbol
- if super().has_header_symbol(hname, symbol, prefix, env, extra_args, dependencies):
+ if super().has_header_symbol(hname, symbol, prefix, env,
+ extra_args=extra_args,
+ dependencies=dependencies):
return True
# Check if it's a class or a template
if extra_args is None:
@@ -74,7 +76,8 @@ class CPPCompiler(CCompiler):
#include <{header}>
using {symbol};
int main () {{ return 0; }}'''
- return self.compiles(t.format(**fargs), env, extra_args, dependencies)
+ return self.compiles(t.format(**fargs), env, extra_args=extra_args,
+ dependencies=dependencies)
def _test_cpp_std_arg(self, cpp_std_value):
# Test whether the compiler understands a -std=XY argument
@@ -246,11 +249,13 @@ class ElbrusCPPCompiler(GnuCPPCompiler, ElbrusCompiler):
# Elbrus C++ compiler does not have lchmod, but there is only linker warning, not compiler error.
# So we should explicitly fail at this case.
- def has_function(self, funcname, prefix, env, extra_args=None, dependencies=None):
+ def has_function(self, funcname, prefix, env, *, extra_args=None, dependencies=None):
if funcname == 'lchmod':
return False
else:
- return super().has_function(funcname, prefix, env, extra_args, dependencies)
+ return super().has_function(funcname, prefix, env,
+ extra_args=extra_args,
+ dependencies=dependencies)
class IntelCPPCompiler(IntelCompiler, CPPCompiler):
diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py
index 0a59e7f..2cf0fbd 100644
--- a/mesonbuild/compilers/d.py
+++ b/mesonbuild/compilers/d.py
@@ -303,7 +303,7 @@ class DCompiler(Compiler):
args += extra_args
return args
- def compiles(self, code, env, extra_args=None, dependencies=None, mode='compile'):
+ def compiles(self, code, env, *, extra_args=None, dependencies=None, mode='compile'):
args = self._get_compiler_check_args(env, extra_args, dependencies, mode)
with self.compile(code, args, mode) as p:
diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py
index b58c4e0..23c4892 100644
--- a/mesonbuild/compilers/fortran.py
+++ b/mesonbuild/compilers/fortran.py
@@ -210,16 +210,18 @@ end program prog
def _get_compiler_check_args(self, env, extra_args, dependencies, mode='compile'):
return CCompiler._get_compiler_check_args(self, env, extra_args, dependencies, mode='compile')
- def compiles(self, code, env, extra_args=None, dependencies=None, mode='compile'):
- return CCompiler.compiles(self, code, env, extra_args, dependencies, mode)
+ def compiles(self, code, env, *, extra_args=None, dependencies=None, mode='compile'):
+ return CCompiler.compiles(self, code, env, extra_args=extra_args,
+ dependencies=dependencies, mode=mode)
def _build_wrapper(self, code, env, extra_args, dependencies=None, mode='compile', want_output=False):
return CCompiler._build_wrapper(self, code, env, extra_args, dependencies, mode, want_output)
- def links(self, code, env, extra_args=None, dependencies=None):
- return CCompiler.links(self, code, env, extra_args, dependencies)
+ def links(self, code, env, *, extra_args=None, dependencies=None):
+ return CCompiler.links(self, code, env, extra_args=extra_args,
+ dependencies=dependencies)
- def run(self, code, env, extra_args=None, dependencies=None):
+ def run(self, code, env, *, extra_args=None, dependencies=None):
return CCompiler.run(self, code, env, extra_args, dependencies)
def _get_patterns(self, *args, **kwargs):
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index cdfed7c..ae37576 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -183,6 +183,7 @@ class UserArrayOption(UserOption):
', '.join(bad), ', '.join(self.choices)))
return newvalue
+
class UserFeatureOption(UserComboOption):
static_choices = ['enabled', 'disabled', 'auto']
@@ -198,6 +199,72 @@ class UserFeatureOption(UserComboOption):
def is_auto(self):
return self.value == 'auto'
+
+def load_configs(filenames):
+ """Load native files."""
+ def gen():
+ for f in filenames:
+ f = os.path.expanduser(os.path.expandvars(f))
+ if os.path.exists(f):
+ yield f
+ continue
+ elif sys.platform != 'win32':
+ f = os.path.basename(f)
+ paths = [
+ os.environ.get('XDG_DATA_HOME', os.path.expanduser('~/.local/share')),
+ ] + os.environ.get('XDG_DATA_DIRS', '/usr/local/share:/usr/share').split(':')
+ for path in paths:
+ path_to_try = os.path.join(path, 'meson', 'native', f)
+ if os.path.isfile(path_to_try):
+ yield path_to_try
+ break
+ else:
+ raise MesonException('Cannot find specified native file: ' + f)
+ continue
+
+ raise MesonException('Cannot find specified native file: ' + f)
+
+ config = configparser.SafeConfigParser()
+ config.read(gen())
+ return config
+
+
+def _get_section(config, section):
+ if config.has_section(section):
+ final = {}
+ for k, v in config.items(section):
+ # Windows paths...
+ v = v.replace('\\', '\\\\')
+ try:
+ final[k] = ast.literal_eval(v)
+ except SyntaxError:
+ raise MesonException(
+ 'Malformed value in native file variable: {}'.format(v))
+ return final
+ return {}
+
+
+class ConfigData:
+
+ """Contains configuration information provided by the user for the build."""
+
+ def __init__(self, config=None):
+ if config:
+ self.binaries = _get_section(config, 'binaries')
+ # global is a keyword and globals is a builtin, rather than mangle it,
+ # use a similar word
+ self.universal = _get_section(config, 'globals')
+ self.subprojects = {s: _get_section(config, s) for s in config.sections()
+ if s not in {'binaries', 'globals'}}
+ else:
+ self.binaries = {}
+ self.universal = {}
+ self.subprojects = {}
+
+ def get_binaries(self, name):
+ return self.binaries.get(name, None)
+
+
# This class contains all data that must persist over multiple
# invocations of Meson. It is roughly the same thing as
# cmakecache.
@@ -229,6 +296,15 @@ class CoreData:
self.deps = OrderedDict()
# Only to print a warning if it changes between Meson invocations.
self.pkgconf_envvar = os.environ.get('PKG_CONFIG_PATH', '')
+ self.config_files = self.__load_config_files(options.native_file)
+
+ @staticmethod
+ def __load_config_files(filenames):
+ if not filenames:
+ return []
+ filenames = [os.path.abspath(os.path.expanduser(os.path.expanduser(f)))
+ for f in filenames]
+ return filenames
@staticmethod
def __load_cross_file(filename):
@@ -460,12 +536,18 @@ class CoreData:
sub = 'In subproject {}: '.format(subproject) if subproject else ''
mlog.warning('{}Unknown options: "{}"'.format(sub, unknown_options))
+class CmdLineFileParser(configparser.ConfigParser):
+ def __init__(self):
+ # We don't want ':' as key delimiter, otherwise it would break when
+ # storing subproject options like "subproject:option=value"
+ super().__init__(delimiters=['='])
+
def get_cmd_line_file(build_dir):
return os.path.join(build_dir, 'meson-private', 'cmd_line.txt')
def read_cmd_line_file(build_dir, options):
filename = get_cmd_line_file(build_dir)
- config = configparser.ConfigParser()
+ config = CmdLineFileParser()
config.read(filename)
# Do a copy because config is not really a dict. options.cmd_line_options
@@ -480,7 +562,7 @@ def read_cmd_line_file(build_dir, options):
def write_cmd_line_file(build_dir, options):
filename = get_cmd_line_file(build_dir)
- config = configparser.ConfigParser()
+ config = CmdLineFileParser()
properties = {}
if options.cross_file is not None:
@@ -493,7 +575,7 @@ def write_cmd_line_file(build_dir, options):
def update_cmd_line_file(build_dir, options):
filename = get_cmd_line_file(build_dir)
- config = configparser.ConfigParser()
+ config = CmdLineFileParser()
config.read(filename)
config['options'].update(options.cmd_line_options)
with open(filename, 'w') as f:
diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py
index e67f4c0..b1d79bb 100644
--- a/mesonbuild/dependencies/base.py
+++ b/mesonbuild/dependencies/base.py
@@ -399,6 +399,8 @@ class ConfigToolDependency(ExternalDependency):
'Falling back to searching PATH. This may find a '
'native version of {0}!'.format(self.tool_name))
tools = self.tools
+ elif self.tool_name in self.env.config_info.binaries:
+ tools = [self.env.config_info.binaries[self.tool_name]]
else:
tools = self.tools
@@ -500,7 +502,8 @@ class PkgConfigDependency(ExternalDependency):
if self.required:
raise DependencyException('Pkg-config binary missing from cross file')
else:
- potential_pkgbin = ExternalProgram.from_cross_info(environment.cross_info, 'pkgconfig')
+ potential_pkgbin = ExternalProgram.from_bin_list(
+ environment.cross_info.config['binaries'], 'pkgconfig')
if potential_pkgbin.found():
self.pkgbin = potential_pkgbin
else:
@@ -1076,10 +1079,10 @@ class ExternalProgram:
return ' '.join(self.command)
@staticmethod
- def from_cross_info(cross_info, name):
- if name not in cross_info.config['binaries']:
+ def from_bin_list(bins, name):
+ if name not in bins:
return NonExistingExternalProgram()
- command = cross_info.config['binaries'][name]
+ command = bins[name]
if not isinstance(command, (list, str)):
raise MesonException('Invalid type {!r} for binary {!r} in cross file'
''.format(command, name))
@@ -1238,8 +1241,8 @@ class ExternalProgram:
class NonExistingExternalProgram(ExternalProgram):
"A program that will never exist"
- def __init__(self):
- self.name = 'nonexistingprogram'
+ def __init__(self, name='nonexistingprogram'):
+ self.name = name
self.command = [None]
self.path = None
diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py
index cc012ac..f220a8e 100644
--- a/mesonbuild/dependencies/misc.py
+++ b/mesonbuild/dependencies/misc.py
@@ -234,6 +234,7 @@ class MPIDependency(ExternalDependency):
class OpenMPDependency(ExternalDependency):
# Map date of specification release (which is the macro value) to a version.
VERSIONS = {
+ '201811': '5.0',
'201511': '4.5',
'201307': '4.0',
'201107': '3.1',
diff --git a/mesonbuild/dependencies/ui.py b/mesonbuild/dependencies/ui.py
index e3b371d..b589889 100644
--- a/mesonbuild/dependencies/ui.py
+++ b/mesonbuild/dependencies/ui.py
@@ -30,7 +30,7 @@ from ..mesonlib import (
from ..environment import detect_cpu
from .base import DependencyException, DependencyMethods
-from .base import ExternalDependency, ExternalProgram
+from .base import ExternalDependency, ExternalProgram, NonExistingExternalProgram
from .base import ExtraFrameworkDependency, PkgConfigDependency
from .base import ConfigToolDependency
@@ -230,21 +230,46 @@ class QtBaseDependency(ExternalDependency):
self.from_text = mlog.format_list(methods)
self.version = None
- def compilers_detect(self):
+ def compilers_detect(self, interp_obj):
"Detect Qt (4 or 5) moc, uic, rcc in the specified bindir or in PATH"
- if self.bindir or for_windows(self.env.is_cross_build(), self.env):
- moc = ExternalProgram(os.path.join(self.bindir, 'moc'), silent=True)
- uic = ExternalProgram(os.path.join(self.bindir, 'uic'), silent=True)
- rcc = ExternalProgram(os.path.join(self.bindir, 'rcc'), silent=True)
- lrelease = ExternalProgram(os.path.join(self.bindir, 'lrelease'), silent=True)
- else:
- # We don't accept unsuffixed 'moc', 'uic', and 'rcc' because they
- # are sometimes older, or newer versions.
- moc = ExternalProgram('moc-' + self.name, silent=True)
- uic = ExternalProgram('uic-' + self.name, silent=True)
- rcc = ExternalProgram('rcc-' + self.name, silent=True)
- lrelease = ExternalProgram('lrelease-' + self.name, silent=True)
- return moc, uic, rcc, lrelease
+ # It is important that this list does not change order as the order of
+ # the returned ExternalPrograms will change as well
+ bins = ['moc', 'uic', 'rcc', 'lrelease']
+ found = {b: NonExistingExternalProgram(name='{}-{}'.format(b, self.name))
+ for b in bins}
+
+ def gen_bins():
+ for b in bins:
+ yield '{}-{}'.format(b, self.name), b, False
+ yield b, b, self.required
+
+ for b, name, required in gen_bins():
+ if found[name].found():
+ continue
+
+ # prefer the <tool>-qt<version> of the tool to the plain one, as we
+ # don't know what the unsuffixed one points to without calling it.
+ p = interp_obj.find_program_impl([b], silent=True, required=required).held_object
+ if not p.found():
+ continue
+
+ if b.startswith('lrelease'):
+ arg = ['-version']
+ elif mesonlib.version_compare(self.version, '>= 5'):
+ arg = ['--version']
+ else:
+ arg = ['-v']
+
+ # Ensure that the version of qt and each tool are the same
+ _, out, err = mesonlib.Popen_safe(p.get_command() + arg)
+ if b.startswith('lrelease') or not self.version.startswith('4'):
+ care = out
+ else:
+ care = err
+ if mesonlib.version_compare(self.version, '== {}'.format(care.split(' ')[-1])):
+ found[name] = p
+
+ return tuple([found[b] for b in bins])
def _pkgconfig_detect(self, mods, kwargs):
# We set the value of required to False so that we can try the
@@ -302,8 +327,15 @@ class QtBaseDependency(ExternalDependency):
def _find_qmake(self, qmake):
# Even when cross-compiling, if a cross-info qmake is not specified, we
# fallback to using the qmake in PATH because that's what we used to do
- if self.env.is_cross_build() and 'qmake' in self.env.cross_info.config['binaries']:
- return ExternalProgram.from_cross_info(self.env.cross_info, 'qmake')
+ if self.env.is_cross_build():
+ if 'qmake' in self.env.cross_info.config['binaries']:
+ return ExternalProgram.from_bin_list(self.env.cross_info.config['binaries'], 'qmake')
+ elif self.env.config_info:
+ # Prefer suffixed to unsuffixed version
+ p = ExternalProgram.from_bin_list(self.env.config_info.binaries, 'qmake-' + self.name)
+ if p.found():
+ return p
+ return ExternalProgram.from_bin_list(self.env.config_info.binaries, 'qmake')
return ExternalProgram(qmake, silent=True)
def _qmake_detect(self, mods, kwargs):
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index f45f91b..01a7c51 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -120,7 +120,7 @@ def find_coverage_tools():
return gcovr_exe, gcovr_new_rootdir, lcov_exe, genhtml_exe
def detect_ninja(version='1.5', log=False):
- for n in ['ninja', 'ninja-build']:
+ for n in ['ninja', 'ninja-build', 'samu']:
try:
p, found = Popen_safe([n, '--version'])[0:2]
except (FileNotFoundError, PermissionError):
@@ -340,7 +340,8 @@ class Environment:
self.cross_info = CrossBuildInfo(self.coredata.cross_file)
if 'exe_wrapper' in self.cross_info.config['binaries']:
from .dependencies import ExternalProgram
- self.exe_wrapper = ExternalProgram.from_cross_info(self.cross_info, 'exe_wrapper')
+ self.exe_wrapper = ExternalProgram.from_bin_list(
+ self.cross_info.config['binaries'], 'exe_wrapper')
if 'host_machine' in self.cross_info.config:
self.machines.host = MachineInfo.from_literal(
self.cross_info.config['host_machine'])
@@ -351,6 +352,12 @@ class Environment:
self.cross_info = None
self.machines.default_missing()
+ if self.coredata.config_files:
+ self.config_info = coredata.ConfigData(
+ coredata.load_configs(self.coredata.config_files))
+ else:
+ self.config_info = coredata.ConfigData()
+
self.cmd_line_options = options.cmd_line_options.copy()
# List of potential compilers.
@@ -505,7 +512,10 @@ class Environment:
The list of compilers is detected in the exact same way for
C, C++, ObjC, ObjC++, Fortran, CS so consolidate it here.
'''
+ is_cross = False
+ exe_wrap = None
evar = BinaryTable.evarMap[lang]
+
if self.is_cross_build() and want_cross:
if lang not in self.cross_info.config['binaries']:
raise EnvironmentException('{!r} compiler binary not defined in cross file'.format(lang))
@@ -521,13 +531,13 @@ class Environment:
shlex.split(os.environ[evar]))
# Return value has to be a list of compiler 'choices'
compilers = [compilers]
- is_cross = False
- exe_wrap = None
+ elif lang in self.config_info.binaries:
+ compilers, ccache = BinaryTable.parse_entry(
+ mesonlib.stringlistify(self.config_info.binaries[lang]))
+ compilers = [compilers]
else:
compilers = getattr(self, 'default_' + lang)
ccache = BinaryTable.detect_ccache()
- is_cross = False
- exe_wrap = None
return compilers, ccache, is_cross, exe_wrap
def _handle_exceptions(self, exceptions, binaries, bintype='compiler'):
@@ -798,13 +808,17 @@ class Environment:
self._handle_exceptions(popen_exceptions, compilers)
def detect_java_compiler(self):
- exelist = ['javac']
+ if 'java' in self.config_info.binaries:
+ exelist = mesonlib.stringlistify(self.config_info.binaries['java'])
+ else:
+ exelist = ['javac']
+
try:
p, out, err = Popen_safe(exelist + ['-version'])
except OSError:
raise EnvironmentException('Could not execute Java compiler "%s"' % ' '.join(exelist))
- version = search_version(err)
if 'javac' in out or 'javac' in err:
+ version = search_version(err if 'javac' in err else out)
return JavaCompiler(exelist, version)
raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"')
@@ -831,6 +845,8 @@ class Environment:
def detect_vala_compiler(self):
if 'VALAC' in os.environ:
exelist = shlex.split(os.environ['VALAC'])
+ elif 'vala' in self.config_info.binaries:
+ exelist = mesonlib.stringlistify(self.config_info.binaries['vala'])
else:
exelist = ['valac']
try:
@@ -875,6 +891,8 @@ class Environment:
elif self.is_cross_build() and want_cross:
exelist = mesonlib.stringlistify(self.cross_info.config['binaries']['d'])
is_cross = True
+ elif 'd' in self.config_info.binaries:
+ exelist = mesonlib.stringlistify(self.config_info.binaries['d'])
elif shutil.which("ldc2"):
exelist = ['ldc2']
elif shutil.which("ldc"):
@@ -912,7 +930,10 @@ class Environment:
raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"')
def detect_swift_compiler(self):
- exelist = ['swiftc']
+ if 'swift' in self.config_info.binaries:
+ exelist = mesonlib.stringlistify(self.config_info.binaries['swift'])
+ else:
+ exelist = ['swiftc']
try:
p, _, err = Popen_safe(exelist + ['-v'])
except OSError:
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index 86b761e..e820afb 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -1018,7 +1018,9 @@ class CompilerHolder(InterpreterObject):
raise InterpreterException('Prefix argument of sizeof must be a string.')
extra_args = mesonlib.stringlistify(kwargs.get('args', []))
deps, msg = self.determine_dependencies(kwargs)
- result = self.compiler.alignment(typename, prefix, self.environment, extra_args, deps)
+ result = self.compiler.alignment(typename, prefix, self.environment,
+ extra_args=extra_args,
+ dependencies=deps)
mlog.log('Checking for alignment of', mlog.bold(typename, True), msg, result)
return result
@@ -1043,7 +1045,8 @@ class CompilerHolder(InterpreterObject):
raise InterpreterException('Testname argument must be a string.')
extra_args = functools.partial(self.determine_args, kwargs)
deps, msg = self.determine_dependencies(kwargs, endl=None)
- result = self.compiler.run(code, self.environment, extra_args, deps)
+ result = self.compiler.run(code, self.environment, extra_args=extra_args,
+ dependencies=deps)
if len(testname) > 0:
if not result.compiled:
h = mlog.red('DID NOT COMPILE')
@@ -1099,7 +1102,9 @@ class CompilerHolder(InterpreterObject):
extra_args = functools.partial(self.determine_args, kwargs)
deps, msg = self.determine_dependencies(kwargs)
had = self.compiler.has_members(typename, [membername], prefix,
- self.environment, extra_args, deps)
+ self.environment,
+ extra_args=extra_args,
+ dependencies=deps)
if had:
hadtxt = mlog.green('YES')
else:
@@ -1127,7 +1132,9 @@ class CompilerHolder(InterpreterObject):
extra_args = functools.partial(self.determine_args, kwargs)
deps, msg = self.determine_dependencies(kwargs)
had = self.compiler.has_members(typename, membernames, prefix,
- self.environment, extra_args, deps)
+ self.environment,
+ extra_args=extra_args,
+ dependencies=deps)
if had:
hadtxt = mlog.green('YES')
else:
@@ -1154,7 +1161,9 @@ class CompilerHolder(InterpreterObject):
raise InterpreterException('Prefix argument of has_function must be a string.')
extra_args = self.determine_args(kwargs)
deps, msg = self.determine_dependencies(kwargs)
- had = self.compiler.has_function(funcname, prefix, self.environment, extra_args, deps)
+ had = self.compiler.has_function(funcname, prefix, self.environment,
+ extra_args=extra_args,
+ dependencies=deps)
if had:
hadtxt = mlog.green('YES')
else:
@@ -1179,7 +1188,8 @@ class CompilerHolder(InterpreterObject):
raise InterpreterException('Prefix argument of has_type must be a string.')
extra_args = functools.partial(self.determine_args, kwargs)
deps, msg = self.determine_dependencies(kwargs)
- had = self.compiler.has_type(typename, prefix, self.environment, extra_args, deps)
+ had = self.compiler.has_type(typename, prefix, self.environment,
+ extra_args=extra_args, dependencies=deps)
if had:
hadtxt = mlog.green('YES')
else:
@@ -1217,7 +1227,9 @@ class CompilerHolder(InterpreterObject):
raise InterpreterException('Guess argument of compute_int must be an int.')
extra_args = functools.partial(self.determine_args, kwargs)
deps, msg = self.determine_dependencies(kwargs)
- res = self.compiler.compute_int(expression, low, high, guess, prefix, self.environment, extra_args, deps)
+ res = self.compiler.compute_int(expression, low, high, guess, prefix,
+ self.environment, extra_args=extra_args,
+ dependencies=deps)
mlog.log('Computing int of', mlog.bold(expression, True), msg, res)
return res
@@ -1238,7 +1250,8 @@ class CompilerHolder(InterpreterObject):
raise InterpreterException('Prefix argument of sizeof must be a string.')
extra_args = functools.partial(self.determine_args, kwargs)
deps, msg = self.determine_dependencies(kwargs)
- esize = self.compiler.sizeof(element, prefix, self.environment, extra_args, deps)
+ esize = self.compiler.sizeof(element, prefix, self.environment,
+ extra_args=extra_args, dependencies=deps)
mlog.log('Checking for size of', mlog.bold(element, True), msg, esize)
return esize
@@ -1260,7 +1273,9 @@ class CompilerHolder(InterpreterObject):
raise InterpreterException('Prefix argument of get_define() must be a string.')
extra_args = functools.partial(self.determine_args, kwargs)
deps, msg = self.determine_dependencies(kwargs)
- value = self.compiler.get_define(element, prefix, self.environment, extra_args, deps)
+ value = self.compiler.get_define(element, prefix, self.environment,
+ extra_args=extra_args,
+ dependencies=deps)
mlog.log('Fetching value of define', mlog.bold(element, True), msg, value)
return value
@@ -1285,7 +1300,9 @@ class CompilerHolder(InterpreterObject):
raise InterpreterException('Testname argument must be a string.')
extra_args = functools.partial(self.determine_args, kwargs)
deps, msg = self.determine_dependencies(kwargs, endl=None)
- result = self.compiler.compiles(code, self.environment, extra_args, deps)
+ result = self.compiler.compiles(code, self.environment,
+ extra_args=extra_args,
+ dependencies=deps)
if len(testname) > 0:
if result:
h = mlog.green('YES')
@@ -1315,7 +1332,9 @@ class CompilerHolder(InterpreterObject):
raise InterpreterException('Testname argument must be a string.')
extra_args = functools.partial(self.determine_args, kwargs)
deps, msg = self.determine_dependencies(kwargs, endl=None)
- result = self.compiler.links(code, self.environment, extra_args, deps)
+ result = self.compiler.links(code, self.environment,
+ extra_args=extra_args,
+ dependencies=deps)
if len(testname) > 0:
if result:
h = mlog.green('YES')
@@ -1342,7 +1361,9 @@ class CompilerHolder(InterpreterObject):
raise InterpreterException('Prefix argument of has_header must be a string.')
extra_args = functools.partial(self.determine_args, kwargs)
deps, msg = self.determine_dependencies(kwargs)
- haz = self.compiler.check_header(hname, prefix, self.environment, extra_args, deps)
+ haz = self.compiler.check_header(hname, prefix, self.environment,
+ extra_args=extra_args,
+ dependencies=deps)
if haz:
h = mlog.green('YES')
else:
@@ -1367,7 +1388,8 @@ class CompilerHolder(InterpreterObject):
raise InterpreterException('Prefix argument of has_header must be a string.')
extra_args = functools.partial(self.determine_args, kwargs)
deps, msg = self.determine_dependencies(kwargs)
- haz = self.compiler.has_header(hname, prefix, self.environment, extra_args, deps)
+ haz = self.compiler.has_header(hname, prefix, self.environment,
+ extra_args=extra_args, dependencies=deps)
if haz:
h = mlog.green('YES')
else:
@@ -1393,7 +1415,9 @@ class CompilerHolder(InterpreterObject):
raise InterpreterException('Prefix argument of has_header_symbol must be a string.')
extra_args = functools.partial(self.determine_args, kwargs)
deps, msg = self.determine_dependencies(kwargs)
- haz = self.compiler.has_header_symbol(hname, symbol, prefix, self.environment, extra_args, deps)
+ haz = self.compiler.has_header_symbol(hname, symbol, prefix, self.environment,
+ extra_args=extra_args,
+ dependencies=deps)
if haz:
h = mlog.green('YES')
else:
@@ -2724,8 +2748,7 @@ external dependencies (including libraries) must go to "dependencies".''')
self.coredata. base_options[optname] = oobj
self.emit_base_options_warnings(enabled_opts)
- def program_from_cross_file(self, prognames, silent=False):
- cross_info = self.environment.cross_info
+ def _program_from_file(self, prognames, bins, silent):
for p in prognames:
if hasattr(p, 'held_object'):
p = p.held_object
@@ -2733,11 +2756,19 @@ external dependencies (including libraries) must go to "dependencies".''')
continue # Always points to a local (i.e. self generated) file.
if not isinstance(p, str):
raise InterpreterException('Executable name must be a string')
- prog = ExternalProgram.from_cross_info(cross_info, p)
+ prog = ExternalProgram.from_bin_list(bins, p)
if prog.found():
return ExternalProgramHolder(prog)
return None
+ def program_from_cross_file(self, prognames, silent=False):
+ bins = self.environment.cross_info.config['binaries']
+ return self._program_from_file(prognames, bins, silent)
+
+ def program_from_config_file(self, prognames, silent=False):
+ bins = self.environment.config_info.binaries
+ return self._program_from_file(prognames, bins, silent)
+
def program_from_system(self, args, silent=False):
# Search for scripts relative to current subdir.
# Do not cache found programs because find_program('foobar')
@@ -2792,10 +2823,14 @@ external dependencies (including libraries) must go to "dependencies".''')
def find_program_impl(self, args, native=False, required=True, silent=True):
if not isinstance(args, list):
args = [args]
+
progobj = self.program_from_overrides(args, silent=silent)
- if progobj is None and self.build.environment.is_cross_build():
- if not native:
+ if progobj is None:
+ if self.build.environment.is_cross_build() and not native:
progobj = self.program_from_cross_file(args, silent=silent)
+ else:
+ progobj = self.program_from_config_file(args, silent=silent)
+
if progobj is None:
progobj = self.program_from_system(args, silent=silent)
if required and (progobj is None or not progobj.found()):
@@ -3733,6 +3768,14 @@ different subdirectory.
timeout_multiplier = kwargs.get('timeout_multiplier', 1)
if not isinstance(timeout_multiplier, int):
raise InterpreterException('Timeout multiplier must be a number.')
+ is_default = kwargs.get('is_default', False)
+ if not isinstance(is_default, bool):
+ raise InterpreterException('is_default option must be a boolean')
+ if is_default:
+ if self.build.test_setup_default_name is not None:
+ raise InterpreterException('\'%s\' is already set as default. '
+ 'is_default can be set to true only once' % self.build.test_setup_default_name)
+ self.build.test_setup_default_name = setup_name
env = self.unpack_env_kwarg(kwargs)
self.build.test_setups[setup_name] = build.TestSetup(exe_wrapper=exe_wrapper,
gdb=gdb,
diff --git a/mesonbuild/modules/python.py b/mesonbuild/modules/python.py
index 954220b..3b2bf07 100644
--- a/mesonbuild/modules/python.py
+++ b/mesonbuild/modules/python.py
@@ -480,7 +480,9 @@ class PythonModule(ExtensionModule):
if len(args) > 1:
raise InvalidArguments('find_installation takes zero or one positional argument.')
- if args:
+ if 'python' in state.environment.config_info.binaries:
+ name_or_path = state.environment.config_info.binaries['python']
+ elif args:
name_or_path = args[0]
if not isinstance(name_or_path, str):
raise InvalidArguments('find_installation argument must be a string.')
diff --git a/mesonbuild/modules/python3.py b/mesonbuild/modules/python3.py
index 5bda5ab..f664632 100644
--- a/mesonbuild/modules/python3.py
+++ b/mesonbuild/modules/python3.py
@@ -48,7 +48,10 @@ class Python3Module(ExtensionModule):
@noKwargs
def find_python(self, state, args, kwargs):
- py3 = dependencies.ExternalProgram('python3', mesonlib.python_command, silent=True)
+ options = [state.environment.config_info.binaries.get('python3')]
+ if not options[0]: # because this would be [None]
+ options = ['python3', mesonlib.python_command]
+ py3 = dependencies.ExternalProgram(*options, silent=True)
return ModuleReturnValue(py3, [py3])
@noKwargs
diff --git a/mesonbuild/modules/qt.py b/mesonbuild/modules/qt.py
index 7a2c338..367b15b 100644
--- a/mesonbuild/modules/qt.py
+++ b/mesonbuild/modules/qt.py
@@ -18,7 +18,7 @@ from .. import build
from ..mesonlib import MesonException, Popen_safe, extract_as_list, File
from ..dependencies import Dependency, Qt4Dependency, Qt5Dependency
import xml.etree.ElementTree as ET
-from . import ModuleReturnValue, get_include_args
+from . import ModuleReturnValue, get_include_args, ExtensionModule
from ..interpreterbase import permittedKwargs, FeatureNewKwargs
_QT_DEPS_LUT = {
@@ -27,10 +27,11 @@ _QT_DEPS_LUT = {
}
-class QtBaseModule:
+class QtBaseModule(ExtensionModule):
tools_detected = False
- def __init__(self, qt_version=5):
+ def __init__(self, interpreter, qt_version=5):
+ ExtensionModule.__init__(self, interpreter)
self.qt_version = qt_version
def _detect_tools(self, env, method):
@@ -43,7 +44,7 @@ class QtBaseModule:
kwargs = {'required': 'true', 'modules': 'Core', 'silent': 'true', 'method': method}
qt = _QT_DEPS_LUT[self.qt_version](env, kwargs)
# Get all tools and then make sure that they are the right version
- self.moc, self.uic, self.rcc, self.lrelease = qt.compilers_detect()
+ self.moc, self.uic, self.rcc, self.lrelease = qt.compilers_detect(self.interpreter)
# Moc, uic and rcc write their version strings to stderr.
# Moc and rcc return a non-zero result when doing so.
# What kind of an idiot thought that was a good idea?
diff --git a/mesonbuild/modules/qt4.py b/mesonbuild/modules/qt4.py
index 29992d5..112e3e4 100644
--- a/mesonbuild/modules/qt4.py
+++ b/mesonbuild/modules/qt4.py
@@ -14,14 +14,13 @@
from .. import mlog
from .qt import QtBaseModule
-from . import ExtensionModule
-class Qt4Module(ExtensionModule, QtBaseModule):
+class Qt4Module(QtBaseModule):
def __init__(self, interpreter):
- QtBaseModule.__init__(self, qt_version=4)
- ExtensionModule.__init__(self, interpreter)
+ QtBaseModule.__init__(self, interpreter, qt_version=4)
+
def initialize(*args, **kwargs):
mlog.warning('rcc dependencies will not work properly until this upstream issue is fixed:',
diff --git a/mesonbuild/modules/qt5.py b/mesonbuild/modules/qt5.py
index 19623ac..96a7964 100644
--- a/mesonbuild/modules/qt5.py
+++ b/mesonbuild/modules/qt5.py
@@ -14,14 +14,13 @@
from .. import mlog
from .qt import QtBaseModule
-from . import ExtensionModule
-class Qt5Module(ExtensionModule, QtBaseModule):
+class Qt5Module(QtBaseModule):
def __init__(self, interpreter):
- QtBaseModule.__init__(self, qt_version=5)
- ExtensionModule.__init__(self, interpreter)
+ QtBaseModule.__init__(self, interpreter, qt_version=5)
+
def initialize(*args, **kwargs):
mlog.warning('rcc dependencies will not work reliably until this upstream issue is fixed:',
diff --git a/mesonbuild/modules/windows.py b/mesonbuild/modules/windows.py
index 4d0f244..d185d89 100644
--- a/mesonbuild/modules/windows.py
+++ b/mesonbuild/modules/windows.py
@@ -49,8 +49,8 @@ class WindowsModule(ExtensionModule):
if state.environment.is_cross_build():
# If cross compiling see if windres has been specified in the
# cross file before trying to find it another way.
- cross_info = state.environment.cross_info
- rescomp = ExternalProgram.from_cross_info(cross_info, 'windres')
+ bins = state.environment.cross_info.config['binaries']
+ rescomp = ExternalProgram.from_bin_list(bins, 'windres')
if not rescomp or not rescomp.found():
if 'WINDRES' in os.environ:
@@ -59,6 +59,13 @@ class WindowsModule(ExtensionModule):
rescomp = ExternalProgram('windres', command=os.environ.get('WINDRES'), silent=True)
if not rescomp or not rescomp.found():
+ # Take windres from the config file after the environment, which is
+ # in keeping with the expectations on unix-like OSes that
+ # environment variables trump config files.
+ bins = state.environment.config_info.binaries
+ rescomp = ExternalProgram.from_bin_list(bins, 'windres')
+
+ if not rescomp or not rescomp.found():
comp = self.detect_compiler(state.compilers)
if comp.id == 'msvc' or comp.id == 'clang-cl':
rescomp = ExternalProgram('rc', silent=True)
diff --git a/mesonbuild/msetup.py b/mesonbuild/msetup.py
index ce03f43..f9a5e1c 100644
--- a/mesonbuild/msetup.py
+++ b/mesonbuild/msetup.py
@@ -29,6 +29,10 @@ def add_arguments(parser):
coredata.register_builtin_arguments(parser)
parser.add_argument('--cross-file', default=None,
help='File describing cross compilation environment.')
+ parser.add_argument('--native-file',
+ default=[],
+ action='append',
+ help='File containing overrides for native compilation environment.')
parser.add_argument('-v', '--version', action='version',
version=coredata.version)
parser.add_argument('--profile-self', action='store_true', dest='profile',
diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py
index cee4c5a..a5a3626 100644
--- a/mesonbuild/mtest.py
+++ b/mesonbuild/mtest.py
@@ -144,6 +144,8 @@ class TestResult(enum.Enum):
TIMEOUT = 'TIMEOUT'
SKIP = 'SKIP'
FAIL = 'FAIL'
+ EXPECTEDFAIL = 'EXPECTEDFAIL'
+ UNEXPECTEDPASS = 'UNEXPECTEDPASS'
class TestRun:
@@ -389,10 +391,10 @@ class SingleTestRunner:
res = TestResult.TIMEOUT
elif p.returncode == GNU_SKIP_RETURNCODE:
res = TestResult.SKIP
- elif self.test.should_fail == bool(p.returncode):
- res = TestResult.OK
+ elif self.test.should_fail:
+ res = TestResult.EXPECTEDFAIL if bool(p.returncode) else TestResult.UNEXPECTEDPASS
else:
- res = TestResult.FAIL
+ res = TestResult.FAIL if bool(p.returncode) else TestResult.OK
return TestRun(res, p.returncode, self.test.should_fail, duration, stdo, stde, cmd, self.test.env)
@@ -401,6 +403,8 @@ class TestHarness:
self.options = options
self.collected_logs = []
self.fail_count = 0
+ self.expectedfail_count = 0
+ self.unexpectedpass_count = 0
self.success_count = 0
self.skip_count = 0
self.timeout_count = 0
@@ -446,6 +450,8 @@ class TestHarness:
def get_test_runner(self, test):
options = deepcopy(self.options)
+ if not options.setup:
+ options.setup = self.build_data.test_setup_default_name
if options.setup:
env = self.merge_suite_options(options, test)
else:
@@ -465,6 +471,10 @@ class TestHarness:
self.success_count += 1
elif result.res is TestResult.FAIL:
self.fail_count += 1
+ elif result.res is TestResult.EXPECTEDFAIL:
+ self.expectedfail_count += 1
+ elif result.res is TestResult.UNEXPECTEDPASS:
+ self.unexpectedpass_count += 1
else:
sys.exit('Unknown test result encountered: {}'.format(result.res))
@@ -480,9 +490,10 @@ class TestHarness:
result_str = '%s %s %s%s%s%5.2f s %s' % \
(num, name, padding1, result.res.value, padding2, result.duration,
status)
- if not self.options.quiet or result.res is not TestResult.OK:
- if result.res is not TestResult.OK and mlog.colorize_console:
- if result.res in (TestResult.FAIL, TestResult.TIMEOUT):
+ ok_statuses = (TestResult.OK, TestResult.EXPECTEDFAIL)
+ if not self.options.quiet or result.res not in ok_statuses:
+ if result.res not in ok_statuses and mlog.colorize_console:
+ if result.res in (TestResult.FAIL, TestResult.TIMEOUT, TestResult.UNEXPECTEDPASS):
decorator = mlog.red
elif result.res is TestResult.SKIP:
decorator = mlog.yellow
@@ -503,11 +514,14 @@ class TestHarness:
def print_summary(self):
msg = '''
-OK: %4d
-FAIL: %4d
-SKIP: %4d
-TIMEOUT: %4d
-''' % (self.success_count, self.fail_count, self.skip_count, self.timeout_count)
+Ok: %4d
+Expected Fail: %4d
+Fail: %4d
+Unexpected Pass: %4d
+Skipped: %4d
+Timeout: %4d
+''' % (self.success_count, self.expectedfail_count, self.fail_count,
+ self.unexpectedpass_count, self.skip_count, self.timeout_count)
print(msg)
if self.logfile:
self.logfile.write(msg)
diff --git a/run_meson_command_tests.py b/run_meson_command_tests.py
index 6dc7964..e7eab72 100755
--- a/run_meson_command_tests.py
+++ b/run_meson_command_tests.py
@@ -63,15 +63,14 @@ class CommandTests(unittest.TestCase):
def _run(self, command, workdir=None):
'''
- Run a command while printing the stdout and stderr to stdout,
- and also return a copy of it
+ Run a command while printing the stdout, and also return a copy of it
'''
# If this call hangs CI will just abort. It is very hard to distinguish
# between CI issue and test bug in that case. Set timeout and fail loud
# instead.
p = subprocess.run(command, stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT, env=os.environ.copy(),
- universal_newlines=True, cwd=workdir, timeout=60 * 5)
+ env=os.environ.copy(), universal_newlines=True,
+ cwd=workdir, timeout=60 * 5)
print(p.stdout)
if p.returncode != 0:
raise subprocess.CalledProcessError(p.returncode, command)
diff --git a/run_project_tests.py b/run_project_tests.py
index c73567e..0d64f47 100755
--- a/run_project_tests.py
+++ b/run_project_tests.py
@@ -118,10 +118,25 @@ def get_relative_files_list_from_dir(fromdir):
return paths
def platform_fix_name(fname, compiler, env):
+ # canonicalize compiler
+ if compiler == 'clang-cl':
+ canonical_compiler = 'msvc'
+ else:
+ canonical_compiler = compiler
+
if '?lib' in fname:
- if mesonlib.for_cygwin(env.is_cross_build(), env):
+ if mesonlib.for_windows(env.is_cross_build(), env) and canonical_compiler == 'msvc':
+ fname = re.sub(r'lib/\?lib(.*)\.', r'bin/\1.', fname)
+ fname = re.sub(r'/\?lib/', r'/bin/', fname)
+ elif mesonlib.for_windows(env.is_cross_build(), env):
+ fname = re.sub(r'lib/\?lib(.*)\.', r'bin/lib\1.', fname)
+ fname = re.sub(r'\?lib(.*)\.dll$', r'lib\1.dll', fname)
+ fname = re.sub(r'/\?lib/', r'/bin/', fname)
+ elif mesonlib.for_cygwin(env.is_cross_build(), env):
fname = re.sub(r'lib/\?lib(.*)\.so$', r'bin/cyg\1.dll', fname)
+ fname = re.sub(r'lib/\?lib(.*)\.', r'bin/cyg\1.', fname)
fname = re.sub(r'\?lib(.*)\.dll$', r'cyg\1.dll', fname)
+ fname = re.sub(r'/\?lib/', r'/bin/', fname)
else:
fname = re.sub(r'\?lib', 'lib', fname)
@@ -132,17 +147,47 @@ def platform_fix_name(fname, compiler, env):
if fname.startswith('?msvc:'):
fname = fname[6:]
- if compiler != 'msvc':
+ if canonical_compiler != 'msvc':
return None
if fname.startswith('?gcc:'):
fname = fname[5:]
- if compiler == 'msvc':
+ if canonical_compiler == 'msvc':
return None
if fname.startswith('?cygwin:'):
fname = fname[8:]
- if compiler == 'msvc' or not mesonlib.for_cygwin(env.is_cross_build(), env):
+ if not mesonlib.for_cygwin(env.is_cross_build(), env):
+ return None
+
+ if fname.endswith('?so'):
+ if mesonlib.for_windows(env.is_cross_build(), env) and canonical_compiler == 'msvc':
+ fname = re.sub(r'lib/([^/]*)\?so$', r'bin/\1.dll', fname)
+ fname = re.sub(r'/(?:lib|)([^/]*?)\?so$', r'/\1.dll', fname)
+ return fname
+ elif mesonlib.for_windows(env.is_cross_build(), env):
+ fname = re.sub(r'lib/([^/]*)\?so$', r'bin/\1.dll', fname)
+ fname = re.sub(r'/([^/]*?)\?so$', r'/\1.dll', fname)
+ return fname
+ elif mesonlib.for_cygwin(env.is_cross_build(), env):
+ fname = re.sub(r'lib/([^/]*)\?so$', r'bin/\1.dll', fname)
+ fname = re.sub(r'/lib([^/]*?)\?so$', r'/cyg\1.dll', fname)
+ fname = re.sub(r'/([^/]*?)\?so$', r'/\1.dll', fname)
+ return fname
+ elif mesonlib.for_darwin(env.is_cross_build(), env):
+ return fname[:-3] + '.dylib'
+ else:
+ return fname[:-3] + '.so'
+
+ if fname.endswith('?implib') or fname.endswith('?implibempty'):
+ if mesonlib.for_windows(env.is_cross_build(), env) and canonical_compiler == 'msvc':
+ # only MSVC doesn't generate empty implibs
+ if fname.endswith('?implibempty') and compiler == 'msvc':
+ return None
+ return re.sub(r'/(?:lib|)([^/]*?)\?implib(?:empty|)$', r'/\1.lib', fname)
+ elif mesonlib.for_windows(env.is_cross_build(), env) or mesonlib.for_cygwin(env.is_cross_build(), env):
+ return re.sub(r'\?implib(?:empty|)$', r'.dll.a', fname)
+ else:
return None
return fname
@@ -696,10 +741,6 @@ def detect_system_compiler():
raise RuntimeError("Could not find C compiler.")
system_compiler = comp.get_id()
- # canonicalize for platform_fix_name()
- if system_compiler == 'clang-cl':
- system_compiler = 'msvc'
-
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Run the test suite of Meson.")
parser.add_argument('extra_args', nargs='*',
diff --git a/run_tests.py b/run_tests.py
index 3445e30..ebee602 100755
--- a/run_tests.py
+++ b/run_tests.py
@@ -73,6 +73,7 @@ def get_fake_options(prefix):
opts.wrap_mode = None
opts.prefix = prefix
opts.cmd_line_options = {}
+ opts.native_file = []
return opts
def get_fake_env(sdir, bdir, prefix):
diff --git a/run_unittests.py b/run_unittests.py
index d63a961..bc11732 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -26,6 +26,7 @@ import sys
import unittest
import platform
import pickle
+import functools
from itertools import chain
from unittest import mock
from configparser import ConfigParser
@@ -41,7 +42,7 @@ import mesonbuild.modules.gnome
from mesonbuild.interpreter import Interpreter, ObjectHolder
from mesonbuild.mesonlib import (
is_windows, is_osx, is_cygwin, is_dragonflybsd, is_openbsd, is_haiku,
- windows_proof_rmtree, python_command, version_compare,
+ is_linux, windows_proof_rmtree, python_command, version_compare,
BuildDirLock, Version
)
from mesonbuild.environment import detect_ninja
@@ -108,12 +109,41 @@ def skipIfNoPkgconfig(f):
Note: Yes, we provide pkg-config even while running Windows CI
'''
+ @functools.wraps(f)
def wrapped(*args, **kwargs):
if not is_ci() and shutil.which('pkg-config') is None:
raise unittest.SkipTest('pkg-config not found')
return f(*args, **kwargs)
return wrapped
+def skip_if_not_language(lang):
+ def wrapper(func):
+ @functools.wraps(func)
+ def wrapped(*args, **kwargs):
+ try:
+ env = get_fake_env('', '', '')
+ f = getattr(env, 'detect_{}_compiler'.format(lang))
+ if lang in ['cs', 'vala', 'java', 'swift']:
+ f()
+ else:
+ f(False)
+ except EnvironmentException:
+ raise unittest.SkipTest('No {} compiler found.'.format(lang))
+ return func(*args, **kwargs)
+ return wrapped
+ return wrapper
+
+def skip_if_env_value(value):
+ def wrapper(func):
+ @functools.wraps(func)
+ def wrapped(*args, **kwargs):
+ if value in os.environ:
+ raise unittest.SkipTest(
+ 'Environment variable "{}" set, skipping.'.format(value))
+ return func(*args, **kwargs)
+ return wrapped
+ return wrapper
+
class PatchModule:
'''
Fancy monkey-patching! Whee! Can't use mock.patch because it only
@@ -921,11 +951,11 @@ class BasePlatformTests(unittest.TestCase):
# Misc stuff
self.orig_env = os.environ.copy()
if self.backend is Backend.ninja:
- self.no_rebuild_stdout = 'ninja: no work to do.'
+ self.no_rebuild_stdout = ['ninja: no work to do.', 'samu: nothing to do']
else:
# VS doesn't have a stable output when no changes are done
# XCode backend is untested with unit tests, help welcome!
- self.no_rebuild_stdout = 'UNKNOWN BACKEND {!r}'.format(self.backend.name)
+ self.no_rebuild_stdout = ['UNKNOWN BACKEND {!r}'.format(self.backend.name)]
self.builddirs = []
self.new_builddir()
@@ -1076,8 +1106,11 @@ class BasePlatformTests(unittest.TestCase):
def get_compdb(self):
if self.backend is not Backend.ninja:
raise unittest.SkipTest('Compiler db not available with {} backend'.format(self.backend.name))
- with open(os.path.join(self.builddir, 'compile_commands.json')) as ifile:
- contents = json.load(ifile)
+ try:
+ with open(os.path.join(self.builddir, 'compile_commands.json')) as ifile:
+ contents = json.load(ifile)
+ except FileNotFoundError:
+ raise unittest.SkipTest('Compiler db not found')
# If Ninja is using .rsp files, generate them, read their contents, and
# replace it as the command for all compile commands in the parsed json.
if len(contents) > 0 and contents[0]['command'].endswith('.rsp'):
@@ -1131,7 +1164,7 @@ class BasePlatformTests(unittest.TestCase):
def assertBuildIsNoop(self):
ret = self.build()
if self.backend is Backend.ninja:
- self.assertEqual(ret.split('\n')[-2], self.no_rebuild_stdout)
+ self.assertIn(ret.split('\n')[-2], self.no_rebuild_stdout)
elif self.backend is Backend.vs:
# Ensure that some target said that no rebuild was done
self.assertIn('CustomBuild:\n All outputs are up-to-date.', ret)
@@ -1461,6 +1494,38 @@ class AllPlatformTests(BasePlatformTests):
self.assertRaises(subprocess.CalledProcessError, self._run,
self.mtest_command + ['--setup=main:onlyinbar'])
+ def test_testsetup_default(self):
+ testdir = os.path.join(self.unit_test_dir, '47 testsetup default')
+ self.init(testdir)
+ self.build()
+
+ # Run tests without --setup will cause the default setup to be used
+ self.run_tests()
+ with open(os.path.join(self.logdir, 'testlog.txt')) as f:
+ default_log = f.read()
+
+ # Run tests with explicitly using the same setup that is set as default
+ self._run(self.mtest_command + ['--setup=mydefault'])
+ with open(os.path.join(self.logdir, 'testlog-mydefault.txt')) as f:
+ mydefault_log = f.read()
+
+ # Run tests with another setup
+ self._run(self.mtest_command + ['--setup=other'])
+ with open(os.path.join(self.logdir, 'testlog-other.txt')) as f:
+ other_log = f.read()
+
+ self.assertTrue('ENV_A is 1' in default_log)
+ self.assertTrue('ENV_B is 2' in default_log)
+ self.assertTrue('ENV_C is 2' in default_log)
+
+ self.assertTrue('ENV_A is 1' in mydefault_log)
+ self.assertTrue('ENV_B is 2' in mydefault_log)
+ self.assertTrue('ENV_C is 2' in mydefault_log)
+
+ self.assertTrue('ENV_A is 1' in other_log)
+ self.assertTrue('ENV_B is 3' in other_log)
+ self.assertTrue('ENV_C is 2' in other_log)
+
def assertFailedTestCount(self, failure_count, command):
try:
self._run(command)
@@ -4411,6 +4476,273 @@ class RewriterTests(unittest.TestCase):
self.assertEqual(s2, self.read_contents('sub2/meson.build'))
+class NativeFileTests(BasePlatformTests):
+
+ def setUp(self):
+ super().setUp()
+ self.testcase = os.path.join(self.unit_test_dir, '46 native file binary')
+ self.current_config = 0
+ self.current_wrapper = 0
+
+ def helper_create_native_file(self, values):
+ """Create a config file as a temporary file.
+
+ values should be a nested dictionary structure of {section: {key:
+ value}}
+ """
+ filename = os.path.join(self.builddir, 'generated{}.config'.format(self.current_config))
+ self.current_config += 1
+ with open(filename, 'wt') as f:
+ for section, entries in values.items():
+ f.write('[{}]\n'.format(section))
+ for k, v in entries.items():
+ f.write("{}='{}'\n".format(k, v))
+ return filename
+
+ def helper_create_binary_wrapper(self, binary, **kwargs):
+ """Creates a wrapper around a binary that overrides specific values."""
+ filename = os.path.join(self.builddir, 'binary_wrapper{}.py'.format(self.current_wrapper))
+ self.current_wrapper += 1
+ if is_haiku():
+ chbang = '#!/bin/env python3'
+ else:
+ chbang = '#!/usr/bin/env python3'
+
+ with open(filename, 'wt') as f:
+ f.write(textwrap.dedent('''\
+ {}
+ import argparse
+ import subprocess
+ import sys
+
+ def main():
+ parser = argparse.ArgumentParser()
+ '''.format(chbang)))
+ for name in kwargs:
+ f.write(' parser.add_argument("-{0}", "--{0}", action="store_true")\n'.format(name))
+ f.write(' args, extra_args = parser.parse_known_args()\n')
+ for name, value in kwargs.items():
+ f.write(' if args.{}:\n'.format(name))
+ f.write(' print("{}", file=sys.{})\n'.format(value, kwargs.get('outfile', 'stdout')))
+ f.write(' sys.exit(0)\n')
+ f.write(textwrap.dedent('''
+ ret = subprocess.run(
+ ["{}"] + extra_args,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ encoding='utf-8')
+ print(ret.stdout)
+ print(ret.stderr, file=sys.stderr)
+ sys.exit(ret.returncode)
+
+ if __name__ == '__main__':
+ main()
+ '''.format(binary)))
+
+ if not is_windows():
+ os.chmod(filename, 0o755)
+ return filename
+
+ # On windows we need yet another level of indirection, as cmd cannot
+ # invoke python files itself, so instead we generate a .bat file, which
+ # invokes our python wrapper
+ batfile = os.path.join(self.builddir, 'binary_wrapper{}.bat'.format(self.current_wrapper))
+ with open(batfile, 'wt') as f:
+ f.write('py -3 {} %*'.format(filename))
+ return batfile
+
+ def helper_for_compiler(self, lang, cb):
+ """Helper for generating tests for overriding compilers for langaugages
+ with more than one implementation, such as C, C++, ObjC, ObjC++, and D.
+ """
+ env = get_fake_env('', '', '')
+ getter = getattr(env, 'detect_{}_compiler'.format(lang))
+ if lang not in ['cs']:
+ getter = functools.partial(getter, False)
+ cc = getter()
+ binary, newid = cb(cc)
+ env.config_info.binaries = {lang: binary}
+ compiler = getter()
+ self.assertEqual(compiler.id, newid)
+
+ def test_multiple_native_files_override(self):
+ wrapper = self.helper_create_binary_wrapper('bash', version='foo')
+ config = self.helper_create_native_file({'binaries': {'bash': wrapper}})
+ wrapper = self.helper_create_binary_wrapper('bash', version='12345')
+ config2 = self.helper_create_native_file({'binaries': {'bash': wrapper}})
+ self.init(self.testcase, extra_args=[
+ '--native-file', config, '--native-file', config2,
+ '-Dcase=find_program'])
+
+ def test_multiple_native_files(self):
+ wrapper = self.helper_create_binary_wrapper('bash', version='12345')
+ config = self.helper_create_native_file({'binaries': {'bash': wrapper}})
+ wrapper = self.helper_create_binary_wrapper('python')
+ config2 = self.helper_create_native_file({'binaries': {'python': wrapper}})
+ self.init(self.testcase, extra_args=[
+ '--native-file', config, '--native-file', config2,
+ '-Dcase=find_program'])
+
+ def _simple_test(self, case, binary):
+ wrapper = self.helper_create_binary_wrapper(binary, version='12345')
+ config = self.helper_create_native_file({'binaries': {binary: wrapper}})
+ self.init(self.testcase, extra_args=['--native-file', config, '-Dcase={}'.format(case)])
+
+ def test_find_program(self):
+ self._simple_test('find_program', 'bash')
+
+ def test_config_tool_dep(self):
+ # Do the skip at this level to avoid screwing up the cache
+ if not shutil.which('llvm-config'):
+ raise unittest.SkipTest('No llvm-installed, cannot test')
+ self._simple_test('config_dep', 'llvm-config')
+
+ def test_python3_module(self):
+ self._simple_test('python3', 'python3')
+
+ def test_python_module(self):
+ if is_windows():
+ # Bat adds extra crap to stdout, so the version check logic in the
+ # python module breaks. This is fine on other OSes because they
+ # don't need the extra indirection.
+ raise unittest.SkipTest('bat indirection breaks internal sanity checks.')
+ self._simple_test('python', 'python')
+
+ @unittest.skipIf(is_windows(), 'Setting up multiple compilers on windows is hard')
+ @skip_if_env_value('CC')
+ def test_c_compiler(self):
+ def cb(comp):
+ if comp.id == 'gcc':
+ if not shutil.which('clang'):
+ raise unittest.SkipTest('Only one compiler found, cannot test.')
+ return 'clang', 'clang'
+ if not shutil.which('gcc'):
+ raise unittest.SkipTest('Only one compiler found, cannot test.')
+ return 'gcc', 'gcc'
+ self.helper_for_compiler('c', cb)
+
+ @unittest.skipIf(is_windows(), 'Setting up multiple compilers on windows is hard')
+ @skip_if_env_value('CXX')
+ def test_cpp_compiler(self):
+ def cb(comp):
+ if comp.id == 'gcc':
+ if not shutil.which('clang++'):
+ raise unittest.SkipTest('Only one compiler found, cannot test.')
+ return 'clang++', 'clang'
+ if not shutil.which('g++'):
+ raise unittest.SkipTest('Only one compiler found, cannot test.')
+ return 'g++', 'gcc'
+ self.helper_for_compiler('cpp', cb)
+
+ @skip_if_not_language('objc')
+ @skip_if_env_value('OBJC')
+ def test_objc_compiler(self):
+ def cb(comp):
+ if comp.id == 'gcc':
+ if not shutil.which('clang'):
+ raise unittest.SkipTest('Only one compiler found, cannot test.')
+ return 'clang', 'clang'
+ if not shutil.which('gcc'):
+ raise unittest.SkipTest('Only one compiler found, cannot test.')
+ return 'gcc', 'gcc'
+ self.helper_for_compiler('objc', cb)
+
+ @skip_if_not_language('objcpp')
+ @skip_if_env_value('OBJCXX')
+ def test_objcpp_compiler(self):
+ def cb(comp):
+ if comp.id == 'gcc':
+ if not shutil.which('clang++'):
+ raise unittest.SkipTest('Only one compiler found, cannot test.')
+ return 'clang++', 'clang'
+ if not shutil.which('g++'):
+ raise unittest.SkipTest('Only one compiler found, cannot test.')
+ return 'g++', 'gcc'
+ self.helper_for_compiler('objcpp', cb)
+
+ @skip_if_not_language('d')
+ @skip_if_env_value('DC')
+ def test_d_compiler(self):
+ def cb(comp):
+ if comp.id == 'dmd':
+ if shutil.which('ldc'):
+ return 'ldc', 'ldc'
+ elif shutil.which('gdc'):
+ return 'gdc', 'gdc'
+ else:
+ raise unittest.SkipTest('No alternative dlang compiler found.')
+ return 'dmd', 'dmd'
+ self.helper_for_compiler('d', cb)
+
+ @skip_if_not_language('cs')
+ @skip_if_env_value('CSC')
+ def test_cs_compiler(self):
+ def cb(comp):
+ if comp.id == 'csc':
+ if not shutil.which('mcs'):
+ raise unittest.SkipTest('No alternate C# implementation.')
+ return 'mcs', 'mcs'
+ if not shutil.which('csc'):
+ raise unittest.SkipTest('No alternate C# implementation.')
+ return 'csc', 'csc'
+ self.helper_for_compiler('cs', cb)
+
+ @skip_if_not_language('fortran')
+ @skip_if_env_value('FC')
+ def test_fortran_compiler(self):
+ def cb(comp):
+ if comp.id == 'gcc':
+ if shutil.which('ifort'):
+ return 'ifort', 'intel'
+ # XXX: there are several other fortran compilers meson
+ # supports, but I don't have any of them to test with
+ raise unittest.SkipTest('No alternate Fortran implementation.')
+ if not shutil.which('gfortran'):
+ raise unittest.SkipTest('No alternate C# implementation.')
+ return 'gfortran', 'gcc'
+ self.helper_for_compiler('fortran', cb)
+
+ def _single_implementation_compiler(self, lang, binary, version_str, version):
+ """Helper for languages with a single (supported) implementation.
+
+ Builds a wrapper around the compiler to override the version.
+ """
+ wrapper = self.helper_create_binary_wrapper(binary, version=version_str)
+ env = get_fake_env('', '', '')
+ getter = getattr(env, 'detect_{}_compiler'.format(lang))
+ if lang in ['rust']:
+ getter = functools.partial(getter, False)
+ env.config_info.binaries = {lang: wrapper}
+ compiler = getter()
+ self.assertEqual(compiler.version, version)
+
+ @skip_if_not_language('vala')
+ @skip_if_env_value('VALAC')
+ def test_vala_compiler(self):
+ self._single_implementation_compiler(
+ 'vala', 'valac', 'Vala 1.2345', '1.2345')
+
+ @skip_if_not_language('rust')
+ @skip_if_env_value('RUSTC')
+ def test_rust_compiler(self):
+ self._single_implementation_compiler(
+ 'rust', 'rustc', 'rustc 1.2345', '1.2345')
+
+ @skip_if_not_language('java')
+ def test_java_compiler(self):
+ self._single_implementation_compiler(
+ 'java', 'javac', 'javac 9.99.77', '9.99.77')
+
+ @skip_if_not_language('swift')
+ def test_swift_compiler(self):
+ wrapper = self.helper_create_binary_wrapper(
+ 'swiftc', version='Swift 1.2345', outfile='stderr')
+ env = get_fake_env('', '', '')
+ env.config_info.binaries = {'swift': wrapper}
+ compiler = env.detect_swift_compiler()
+ self.assertEqual(compiler.version, '1.2345')
+
+
def unset_envs():
# For unit tests we must fully control all command lines
# so that there are no unexpected changes coming from the
@@ -4428,7 +4760,8 @@ def should_run_cross_mingw_tests():
def main():
unset_envs()
- cases = ['InternalTests', 'DataTests', 'AllPlatformTests', 'FailureTests', 'PythonTests']
+ cases = ['InternalTests', 'DataTests', 'AllPlatformTests', 'FailureTests',
+ 'PythonTests', 'NativeFileTests']
if not is_windows():
cases += ['LinuxlikeTests']
if should_run_cross_arm_tests():
diff --git a/test cases/common/122 shared module/installed_files.txt b/test cases/common/122 shared module/installed_files.txt
index 4542a55..d46527c 100644
--- a/test cases/common/122 shared module/installed_files.txt
+++ b/test cases/common/122 shared module/installed_files.txt
@@ -1,2 +1,3 @@
-usr/lib/libnosyms.so
-?msvc:usr/lib/libnosyms.pdb
+usr/lib/modules/libnosyms?so
+usr/lib/modules/libnosyms?implibempty
+?msvc:usr/lib/modules/nosyms.pdb
diff --git a/test cases/common/122 shared module/meson.build b/test cases/common/122 shared module/meson.build
index 9f9ad63..3d52300 100644
--- a/test cases/common/122 shared module/meson.build
+++ b/test cases/common/122 shared module/meson.build
@@ -13,8 +13,6 @@ e = executable('prog', 'prog.c',
test('import test', e, args : m)
# Shared module that does not export any symbols
-shared_module('nosyms', 'nosyms.c', install : true,
- # Because we don't have cross-platform library support in
- # installed_files.txt
- name_suffix : 'so',
- name_prefix : 'lib')
+shared_module('nosyms', 'nosyms.c',
+ install : true,
+ install_dir : join_paths(get_option('libdir'), 'modules'))
diff --git a/test cases/common/152 simd/simd_sse2.c b/test cases/common/152 simd/simd_sse2.c
index 0274533..271022e 100644
--- a/test cases/common/152 simd/simd_sse2.c
+++ b/test cases/common/152 simd/simd_sse2.c
@@ -21,7 +21,7 @@ int sse2_available() {
#endif
void increment_sse2(float arr[4]) {
- double darr[4];
+ ALIGN_16 double darr[4];
__m128d val1 = _mm_set_pd(arr[0], arr[1]);
__m128d val2 = _mm_set_pd(arr[2], arr[3]);
__m128d one = _mm_set_pd(1.0, 1.0);
diff --git a/test cases/common/152 simd/simd_sse3.c b/test cases/common/152 simd/simd_sse3.c
index e97d102..89c2f8b 100644
--- a/test cases/common/152 simd/simd_sse3.c
+++ b/test cases/common/152 simd/simd_sse3.c
@@ -22,7 +22,7 @@ int sse3_available() {
#endif
void increment_sse3(float arr[4]) {
- double darr[4];
+ ALIGN_16 double darr[4];
__m128d val1 = _mm_set_pd(arr[0], arr[1]);
__m128d val2 = _mm_set_pd(arr[2], arr[3]);
__m128d one = _mm_set_pd(1.0, 1.0);
diff --git a/test cases/common/152 simd/simd_sse41.c b/test cases/common/152 simd/simd_sse41.c
index 0308c7e..859fb43 100644
--- a/test cases/common/152 simd/simd_sse41.c
+++ b/test cases/common/152 simd/simd_sse41.c
@@ -24,7 +24,7 @@ int sse41_available() {
#endif
void increment_sse41(float arr[4]) {
- double darr[4];
+ ALIGN_16 double darr[4];
__m128d val1 = _mm_set_pd(arr[0], arr[1]);
__m128d val2 = _mm_set_pd(arr[2], arr[3]);
__m128d one = _mm_set_pd(1.0, 1.0);
diff --git a/test cases/common/152 simd/simd_sse42.c b/test cases/common/152 simd/simd_sse42.c
index 137ffc4..edd6e5b 100644
--- a/test cases/common/152 simd/simd_sse42.c
+++ b/test cases/common/152 simd/simd_sse42.c
@@ -27,7 +27,7 @@ int sse42_available() {
#endif
void increment_sse42(float arr[4]) {
- double darr[4];
+ ALIGN_16 double darr[4];
__m128d val1 = _mm_set_pd(arr[0], arr[1]);
__m128d val2 = _mm_set_pd(arr[2], arr[3]);
__m128d one = _mm_set_pd(1.0, 1.0);
diff --git a/test cases/common/152 simd/simd_ssse3.c b/test cases/common/152 simd/simd_ssse3.c
index ab4dff4..0156f77 100644
--- a/test cases/common/152 simd/simd_ssse3.c
+++ b/test cases/common/152 simd/simd_ssse3.c
@@ -30,7 +30,7 @@ int ssse3_available() {
#endif
void increment_ssse3(float arr[4]) {
- double darr[4];
+ ALIGN_16 double darr[4];
__m128d val1 = _mm_set_pd(arr[0], arr[1]);
__m128d val2 = _mm_set_pd(arr[2], arr[3]);
__m128d one = _mm_set_pd(1.0, 1.0);
diff --git a/test cases/common/152 simd/simdchecker.c b/test cases/common/152 simd/simdchecker.c
index 222fbf3..cd6fe4f 100644
--- a/test cases/common/152 simd/simdchecker.c
+++ b/test cases/common/152 simd/simdchecker.c
@@ -1,93 +1,143 @@
#include<simdfuncs.h>
#include<stdio.h>
+#include<string.h>
-/*
- * A function that checks at runtime which simd accelerations are
- * available and calls the best one. Falls
- * back to plain C implementation if SIMD is not available.
- */
+typedef void (*simd_func)(float*);
+
+int check_simd_implementation(float *four,
+ const float *four_initial,
+ const char *simd_type,
+ const float *expected,
+ simd_func fptr,
+ const int blocksize) {
+ int rv = 0;
+ memcpy(four, four_initial, blocksize*sizeof(float));
+ printf("Using %s.\n", simd_type);
+ fptr(four);
+ for(int i=0; i<blocksize; i++) {
+ if(four[i] != expected[i]) {
+ printf("Increment function failed, got %f expected %f.\n", four[i], expected[i]);
+ rv = 1;
+ }
+ }
+ return rv;
+}
int main(int argc, char **argv) {
- float four[4] = {2.0, 3.0, 4.0, 5.0};
+ static const float four_initial[4] = {2.0, 3.0, 4.0, 5.0};
+ ALIGN_16 float four[4];
const float expected[4] = {3.0, 4.0, 5.0, 6.0};
- void (*fptr)(float[4]) = NULL;
- const char *type;
- int i;
+ int r=0;
+ const int blocksize = 4;
-/* Add here. The first matched one is used so put "better" instruction
- * sets at the top.
+/*
+ * Test all implementations that the current CPU supports.
*/
#if HAVE_NEON
- if(fptr == NULL && neon_available()) {
- fptr = increment_neon;
- type = "NEON";
+ if(neon_available()) {
+ r += check_simd_implementation(four,
+ four_initial,
+ "NEON",
+ expected,
+ increment_neon,
+ blocksize);
}
#endif
#if HAVE_AVX2
- if(fptr == NULL && avx2_available()) {
- fptr = increment_avx2;
- type = "AVX2";
+ if(avx2_available()) {
+ r += check_simd_implementation(four,
+ four_initial,
+ "AVX2",
+ expected,
+ increment_avx2,
+ blocksize);
}
#endif
#if HAVE_AVX
- if(fptr == NULL && avx_available()) {
- fptr = increment_avx;
- type = "AVX";
+ if(avx_available()) {
+ r += check_simd_implementation(four,
+ four_initial,
+ "AVC",
+ expected,
+ increment_avx,
+ blocksize);
}
#endif
#if HAVE_SSE42
- if(fptr == NULL && sse42_available()) {
- fptr = increment_sse42;
- type = "SSE42";
+ if(sse42_available()) {
+ r += check_simd_implementation(four,
+ four_initial,
+ "SSR42",
+ expected,
+ increment_sse42,
+ blocksize);
}
#endif
#if HAVE_SSE41
- if(fptr == NULL && sse41_available()) {
- fptr = increment_sse41;
- type = "SSE41";
+ if(sse41_available()) {
+ r += check_simd_implementation(four,
+ four_initial,
+ "SSE41",
+ expected,
+ increment_sse41,
+ blocksize);
}
#endif
#if HAVE_SSSE3
- if(fptr == NULL && ssse3_available()) {
- fptr = increment_ssse3;
- type = "SSSE3";
+ if(ssse3_available()) {
+ r += check_simd_implementation(four,
+ four_initial,
+ "SSSE3",
+ expected,
+ increment_ssse3,
+ blocksize);
}
#endif
#if HAVE_SSE3
- if(fptr == NULL && sse3_available()) {
- fptr = increment_sse3;
- type = "SSE3";
+ if(sse3_available()) {
+ r += check_simd_implementation(four,
+ four_initial,
+ "SSE3",
+ expected,
+ increment_sse3,
+ blocksize);
}
#endif
#if HAVE_SSE2
- if(fptr == NULL && sse2_available()) {
- fptr = increment_sse2;
- type = "SSE2";
+ if(sse2_available()) {
+ r += check_simd_implementation(four,
+ four_initial,
+ "SSE2",
+ expected,
+ increment_sse2,
+ blocksize);
}
#endif
#if HAVE_SSE
- if(fptr == NULL && sse_available()) {
- fptr = increment_sse;
- type = "SSE";
+ if(sse_available()) {
+ r += check_simd_implementation(four,
+ four_initial,
+ "SSE",
+ expected,
+ increment_sse,
+ blocksize);
}
#endif
#if HAVE_MMX
- if(fptr == NULL && mmx_available()) {
- fptr = increment_mmx;
- type = "MMX";
+ if(mmx_available()) {
+ r += check_simd_implementation(four,
+ four_initial,
+ "MMX",
+ expected,
+ increment_mmx,
+ blocksize);
}
#endif
- if(fptr == NULL) {
- fptr = increment_fallback;
- type = "fallback";
- }
- printf("Using %s.\n", type);
- fptr(four);
- for(i=0; i<4; i++) {
- if(four[i] != expected[i]) {
- printf("Increment function failed, got %f expected %f.\n", four[i], expected[i]);
- return 1;
- }
- }
- return 0;
+ r += check_simd_implementation(four,
+ four_initial,
+ "fallback",
+ expected,
+ increment_fallback,
+ blocksize);
+ return r;
}
diff --git a/test cases/common/152 simd/simdfuncs.h b/test cases/common/152 simd/simdfuncs.h
index dfb0560..c5e1658 100644
--- a/test cases/common/152 simd/simdfuncs.h
+++ b/test cases/common/152 simd/simdfuncs.h
@@ -2,6 +2,14 @@
#include<simdconfig.h>
+#ifdef _MSC_VER
+#define ALIGN_16 __declspec(align(16))
+#else
+#include<stdalign.h>
+#define ALIGN_16 alignas(16)
+#endif
+
+
/* Yes, I do know that arr[4] decays into a pointer
* as a function argument. Don't do this in real code
* but for this test it is ok.
diff --git a/test cases/common/207 install name_prefix name_suffix/installed_files.txt b/test cases/common/207 install name_prefix name_suffix/installed_files.txt
new file mode 100644
index 0000000..240a8be
--- /dev/null
+++ b/test cases/common/207 install name_prefix name_suffix/installed_files.txt
@@ -0,0 +1,15 @@
+?msvc:usr/bin/baz.pdb
+?msvc:usr/bin/bowcorge.pdb
+?msvc:usr/bin/foo.pdb
+?msvc:usr/lib/baz.pdb
+?msvc:usr/lib/bowcorge.pdb
+?msvc:usr/lib/foo.pdb
+usr/?lib/bowcorge.stern
+usr/lib/?libbaz.cheese
+usr/lib/bar.a
+usr/lib/bowcorge?implib
+usr/lib/bowgrault.stern
+usr/lib/foo?implib
+usr/lib/foo?so
+usr/lib/libbaz?implib
+usr/lib/libqux.cheese
diff --git a/test cases/common/207 install name_prefix name_suffix/libfile.c b/test cases/common/207 install name_prefix name_suffix/libfile.c
new file mode 100644
index 0000000..44f7667
--- /dev/null
+++ b/test cases/common/207 install name_prefix name_suffix/libfile.c
@@ -0,0 +1,14 @@
+#if defined _WIN32 || defined __CYGWIN__
+ #define DLL_PUBLIC __declspec(dllexport)
+#else
+ #if defined __GNUC__
+ #define DLL_PUBLIC __attribute__ ((visibility("default")))
+ #else
+ #pragma message ("Compiler does not support symbol visibility.")
+ #define DLL_PUBLIC
+ #endif
+#endif
+
+int DLL_PUBLIC func() {
+ return 0;
+}
diff --git a/test cases/common/207 install name_prefix name_suffix/meson.build b/test cases/common/207 install name_prefix name_suffix/meson.build
new file mode 100644
index 0000000..4539999
--- /dev/null
+++ b/test cases/common/207 install name_prefix name_suffix/meson.build
@@ -0,0 +1,10 @@
+project('library with name_prefix name_suffix test', 'c')
+
+shared_library('foo', 'libfile.c', name_prefix: '', install : true)
+static_library('bar', 'libfile.c', name_prefix: '', install : true)
+
+shared_library('baz', 'libfile.c', name_suffix: 'cheese', install : true)
+static_library('qux', 'libfile.c', name_suffix: 'cheese', install : true)
+
+shared_library('corge', 'libfile.c', name_prefix: 'bow', name_suffix: 'stern', install : true)
+static_library('grault', 'libfile.c', name_prefix: 'bow', name_suffix: 'stern', install : true)
diff --git a/test cases/common/25 library versions/installed_files.txt b/test cases/common/25 library versions/installed_files.txt
index c842ed8..938e063 100644
--- a/test cases/common/25 library versions/installed_files.txt
+++ b/test cases/common/25 library versions/installed_files.txt
@@ -1,2 +1,3 @@
usr/lib/prefixsomelib.suffix
+usr/lib/prefixsomelib?implib
?msvc:usr/lib/prefixsomelib.pdb
diff --git a/test cases/common/25 library versions/lib.c b/test cases/common/25 library versions/lib.c
index 67b6f4d..10019dc 100644
--- a/test cases/common/25 library versions/lib.c
+++ b/test cases/common/25 library versions/lib.c
@@ -1,3 +1,14 @@
-int myFunc() {
+#if defined _WIN32 || defined __CYGWIN__
+ #define DLL_PUBLIC __declspec(dllexport)
+#else
+ #if defined __GNUC__
+ #define DLL_PUBLIC __attribute__ ((visibility("default")))
+ #else
+ #pragma message ("Compiler does not support symbol visibility.")
+ #define DLL_PUBLIC
+ #endif
+#endif
+
+int DLL_PUBLIC myFunc() {
return 55;
}
diff --git a/test cases/java/8 codegen custom target/com/mesonbuild/meson.build b/test cases/java/8 codegen custom target/com/mesonbuild/meson.build
index 67b98a4..0309941 100644
--- a/test cases/java/8 codegen custom target/com/mesonbuild/meson.build
+++ b/test cases/java/8 codegen custom target/com/mesonbuild/meson.build
@@ -4,5 +4,5 @@ config_file = custom_target('confgen',
input : 'Config.java.in',
output : 'Config.java',
command : [python, '-c',
- 'import shutil; import sys; shutil.copy(sys.argv[1], sys.argv[2])',
+ 'import shutil, sys, time; time.sleep(1); shutil.copy(sys.argv[1], sys.argv[2])',
'@INPUT@', '@OUTPUT@'])
diff --git a/test cases/unit/46 native file binary/meson.build b/test cases/unit/46 native file binary/meson.build
new file mode 100644
index 0000000..4489ac1
--- /dev/null
+++ b/test cases/unit/46 native file binary/meson.build
@@ -0,0 +1,21 @@
+project('test project')
+
+case = get_option('case')
+
+if case == 'find_program'
+ prog = find_program('bash')
+ result = run_command(prog, ['--version'])
+ assert(result.stdout().strip().endswith('12345'), 'Didn\'t load bash from config file')
+elif case == 'config_dep'
+ add_languages('cpp')
+ dep = dependency('llvm')
+ assert(dep.get_configtool_variable('version').endswith('12345'), 'Didn\'t load llvm from config file')
+elif case == 'python3'
+ prog = import('python3').find_python()
+ result = run_command(prog, ['--version'])
+ assert(result.stdout().strip().endswith('12345'), 'Didn\'t load python3 from config file')
+elif case == 'python'
+ prog = import('python').find_installation()
+ result = run_command(prog, ['--version'])
+ assert(result.stdout().strip().endswith('12345'), 'Didn\'t load python from config file')
+endif
diff --git a/test cases/unit/46 native file binary/meson_options.txt b/test cases/unit/46 native file binary/meson_options.txt
new file mode 100644
index 0000000..651da0e
--- /dev/null
+++ b/test cases/unit/46 native file binary/meson_options.txt
@@ -0,0 +1,5 @@
+option(
+ 'case',
+ type : 'combo',
+ choices : ['find_program', 'config_dep', 'python3', 'python']
+)
diff --git a/test cases/unit/47 testsetup default/envcheck.py b/test cases/unit/47 testsetup default/envcheck.py
new file mode 100644
index 0000000..6ba3093
--- /dev/null
+++ b/test cases/unit/47 testsetup default/envcheck.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python3
+
+import os
+
+assert('ENV_A' in os.environ)
+assert('ENV_B' in os.environ)
+assert('ENV_C' in os.environ)
+
+print('ENV_A is', os.environ['ENV_A'])
+print('ENV_B is', os.environ['ENV_B'])
+print('ENV_C is', os.environ['ENV_C'])
diff --git a/test cases/unit/47 testsetup default/meson.build b/test cases/unit/47 testsetup default/meson.build
new file mode 100644
index 0000000..bdd35b8
--- /dev/null
+++ b/test cases/unit/47 testsetup default/meson.build
@@ -0,0 +1,23 @@
+project('testsetup default', 'c')
+
+envcheck = find_program('envcheck.py')
+
+# Defining ENV_A in test-env should overwrite ENV_A from test setup
+env_1 = environment()
+env_1.set('ENV_A', '1')
+test('test-env', envcheck, env: env_1)
+
+# Defining default env which is used unless --setup is given or the
+# env variable is defined in the test.
+env_2 = environment()
+env_2.set('ENV_A', '2')
+env_2.set('ENV_B', '2')
+env_2.set('ENV_C', '2')
+add_test_setup('mydefault', env: env_2, is_default: true)
+
+# Defining a test setup that will update some of the env variables
+# from the default test setup.
+env_3 = env_2
+env_3.set('ENV_A', '3')
+env_3.set('ENV_B', '3')
+add_test_setup('other', env: env_3)
diff --git a/test cases/windows/7 dll versioning/installed_files.txt b/test cases/windows/7 dll versioning/installed_files.txt
index 517620e..62b5c9a 100644
--- a/test cases/windows/7 dll versioning/installed_files.txt
+++ b/test cases/windows/7 dll versioning/installed_files.txt
@@ -14,9 +14,9 @@
?msvc:usr/libexec/customdir.dll
?msvc:usr/libexec/customdir.lib
?msvc:usr/libexec/customdir.pdb
-?msvc:usr/lib/module.dll
-?msvc:usr/lib/module.lib
-?msvc:usr/lib/module.pdb
+?msvc:usr/lib/modules/module.dll
+?msvc:usr/lib/modules/module.lib
+?msvc:usr/lib/modules/module.pdb
?gcc:usr/bin/?libsome-0.dll
?gcc:usr/lib/libsome.dll.a
?gcc:usr/bin/?libnoversion.dll
@@ -27,5 +27,5 @@
?gcc:usr/lib/libonlysoversion.dll.a
?gcc:usr/libexec/?libcustomdir.dll
?gcc:usr/libexec/libcustomdir.dll.a
-?gcc:usr/lib/?libmodule.dll
-?gcc:usr/lib/libmodule.dll.a
+?gcc:usr/lib/modules/?libmodule.dll
+?gcc:usr/lib/modules/libmodule.dll.a
diff --git a/test cases/windows/7 dll versioning/meson.build b/test cases/windows/7 dll versioning/meson.build
index 80acf88..983c2c4 100644
--- a/test cases/windows/7 dll versioning/meson.build
+++ b/test cases/windows/7 dll versioning/meson.build
@@ -49,4 +49,6 @@ shared_library('customdir', 'lib.c',
install : true,
install_dir : get_option('libexecdir'))
-shared_module('module', 'lib.c', install : true)
+shared_module('module', 'lib.c',
+ install : true,
+ install_dir: join_paths(get_option('libdir'), 'modules'))