aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cross/armcc.txt20
-rw-r--r--data/shell-completions/zsh/_meson2
-rw-r--r--data/syntax-highlighting/vim/syntax/meson.vim1
-rw-r--r--docs/markdown/Adding-new-projects-to-wrapdb.md5
-rw-r--r--docs/markdown/Compiler-properties.md21
-rw-r--r--docs/markdown/FAQ.md43
-rw-r--r--docs/markdown/Gnome-module.md16
-rw-r--r--docs/markdown/Reference-manual.md20
-rw-r--r--docs/markdown/Reference-tables.md3
-rw-r--r--docs/markdown/Release-notes-for-0.45.0.md26
-rw-r--r--docs/markdown/Syntax.md20
-rw-r--r--docs/markdown/Unit-tests.md8
-rw-r--r--docs/markdown/snippets/armcc-cross.md15
-rw-r--r--docs/markdown/snippets/del-old-names.md2
-rw-r--r--docs/markdown/snippets/find-override.md37
-rw-r--r--docs/markdown/snippets/lcc.md23
-rw-r--r--docs/markdown/snippets/more-escape-sequences.md17
-rw-r--r--docs/markdown/snippets/new-wrap-mode.md3
-rw-r--r--docs/markdown/snippets/non-unique-target-names.md9
-rw-r--r--docs/markdown/snippets/openmp-dependency.md6
-rw-r--r--docs/markdown/snippets/pkg-config-fix-static-only.md12
-rw-r--r--manual tests/2 multiwrap/meson.build2
-rw-r--r--mesonbuild/backend/backends.py2
-rw-r--r--mesonbuild/backend/ninjabackend.py107
-rw-r--r--mesonbuild/backend/vs2010backend.py24
-rw-r--r--mesonbuild/build.py46
-rw-r--r--mesonbuild/compilers/__init__.py8
-rw-r--r--mesonbuild/compilers/c.py129
-rw-r--r--mesonbuild/compilers/compilers.py210
-rw-r--r--mesonbuild/compilers/cpp.py52
-rw-r--r--mesonbuild/compilers/cs.py2
-rw-r--r--mesonbuild/compilers/d.py4
-rw-r--r--mesonbuild/compilers/fortran.py30
-rw-r--r--mesonbuild/compilers/java.py2
-rw-r--r--mesonbuild/compilers/vala.py4
-rw-r--r--mesonbuild/coredata.py74
-rw-r--r--mesonbuild/dependencies/__init__.py4
-rw-r--r--mesonbuild/dependencies/base.py21
-rw-r--r--mesonbuild/dependencies/misc.py32
-rw-r--r--mesonbuild/environment.py57
-rw-r--r--mesonbuild/interpreter.py165
-rw-r--r--mesonbuild/linkers.py19
-rw-r--r--mesonbuild/mesonlib.py33
-rw-r--r--mesonbuild/mesonmain.py3
-rw-r--r--mesonbuild/mintro.py2
-rw-r--r--mesonbuild/mlog.py29
-rw-r--r--mesonbuild/modules/__init__.py15
-rw-r--r--mesonbuild/modules/gnome.py122
-rw-r--r--mesonbuild/modules/i18n.py4
-rw-r--r--mesonbuild/modules/modtest.py4
-rw-r--r--mesonbuild/modules/pkgconfig.py25
-rw-r--r--mesonbuild/modules/python3.py8
-rw-r--r--mesonbuild/modules/qt.py52
-rw-r--r--mesonbuild/modules/qt4.py8
-rw-r--r--mesonbuild/modules/qt5.py8
-rw-r--r--mesonbuild/modules/rpm.py11
-rw-r--r--mesonbuild/modules/unstable_icestorm.py18
-rw-r--r--mesonbuild/modules/unstable_simd.py8
-rw-r--r--mesonbuild/modules/windows.py4
-rw-r--r--mesonbuild/mparser.py48
-rw-r--r--mesonbuild/mtest.py19
-rw-r--r--mesonbuild/scripts/depfixer.py67
-rw-r--r--mesonbuild/scripts/meson_install.py11
-rw-r--r--mesonbuild/wrap/__init__.py7
-rwxr-xr-xrun_unittests.py139
-rw-r--r--test cases/common/112 has arg/meson.build8
-rw-r--r--test cases/common/13 pch/meson.build6
-rw-r--r--test cases/common/132 dependency file generation/meson.build10
-rw-r--r--test cases/common/142 compute int/config.h.in2
-rw-r--r--test cases/common/142 compute int/meson.build8
-rw-r--r--test cases/common/142 compute int/prog.c.in9
-rw-r--r--test cases/common/16 configure file/config7.h.in16
-rw-r--r--test cases/common/16 configure file/meson.build12
-rw-r--r--test cases/common/16 configure file/prog7.c10
-rw-r--r--test cases/common/168 disabler/meson.build4
-rw-r--r--test cases/common/183 same target name/file.c (renamed from test cases/failing/17 same name/file.c)0
-rw-r--r--test cases/common/183 same target name/meson.build (renamed from test cases/failing/17 same name/meson.build)0
-rw-r--r--test cases/common/183 same target name/sub/file2.c (renamed from test cases/failing/17 same name/sub/file2.c)0
-rw-r--r--test cases/common/183 same target name/sub/meson.build (renamed from test cases/failing/17 same name/sub/meson.build)0
-rw-r--r--test cases/common/189 same target name flat layout/foo.c1
-rw-r--r--test cases/common/189 same target name flat layout/main.c16
-rw-r--r--test cases/common/189 same target name flat layout/meson.build11
-rw-r--r--test cases/common/189 same target name flat layout/subdir/foo.c1
-rw-r--r--test cases/common/189 same target name flat layout/subdir/meson.build1
-rw-r--r--test cases/common/190 escape and unicode/file.c.in5
-rw-r--r--test cases/common/190 escape and unicode/file.py10
-rw-r--r--test cases/common/190 escape and unicode/find.py9
-rw-r--r--test cases/common/190 escape and unicode/fun.c3
-rw-r--r--test cases/common/190 escape and unicode/main.c12
-rw-r--r--test cases/common/190 escape and unicode/meson.build24
-rw-r--r--test cases/common/190 find override/meson.build12
-rw-r--r--test cases/common/190 find override/otherdir/main.c5
-rw-r--r--test cases/common/190 find override/otherdir/main2.c5
-rw-r--r--test cases/common/190 find override/otherdir/meson.build26
-rw-r--r--test cases/common/190 find override/otherdir/source.desc1
-rw-r--r--test cases/common/190 find override/otherdir/source2.desc1
-rwxr-xr-xtest cases/common/190 find override/subdir/converter.py15
-rwxr-xr-xtest cases/common/190 find override/subdir/gencodegen.py.in15
-rw-r--r--test cases/common/190 find override/subdir/meson.build14
-rw-r--r--test cases/common/190 openmp/main.c16
-rw-r--r--test cases/common/190 openmp/main.cpp16
-rw-r--r--test cases/common/190 openmp/main.f908
-rw-r--r--test cases/common/190 openmp/meson.build40
-rw-r--r--test cases/common/22 header in file list/meson.build10
-rw-r--r--test cases/common/33 try compile/meson.build4
-rw-r--r--test cases/common/39 tryrun/meson.build4
-rw-r--r--test cases/common/42 string operations/meson.build18
-rw-r--r--test cases/common/51 pkgconfig-gen/dependencies/meson.build6
-rw-r--r--test cases/common/64 custom header generator/meson.build10
-rw-r--r--test cases/failing/17 same target/file.c1
-rw-r--r--test cases/failing/17 same target/meson.build4
-rw-r--r--test cases/failing/72 invalid escape char/meson.build4
-rw-r--r--test cases/failing/72 override used/meson.build5
-rwxr-xr-xtest cases/failing/72 override used/other.py3
-rwxr-xr-xtest cases/failing/72 override used/something.py3
-rw-r--r--test cases/failing/73 dual override/meson.build5
-rw-r--r--test cases/failing/73 dual override/overrides.py4
-rw-r--r--test cases/frameworks/4 qt/meson.build2
-rw-r--r--test cases/frameworks/4 qt/subfolder/generator.py6
-rw-r--r--test cases/frameworks/4 qt/subfolder/main.cpp23
-rw-r--r--test cases/frameworks/4 qt/subfolder/meson.build32
-rw-r--r--test cases/frameworks/4 qt/subfolder/resources/stuff4.qrc.in8
-rw-r--r--test cases/frameworks/7 gnome/gdbus/meson.build10
-rw-r--r--test cases/frameworks/7 gnome/installed_files.txt1
-rw-r--r--test cases/frameworks/7 gnome/mkenums/meson.build1
-rw-r--r--test cases/unit/13 reconfigure/meson.build4
-rw-r--r--test cases/unit/26 guessed linker dependencies/exe/app.c6
-rw-r--r--test cases/unit/26 guessed linker dependencies/exe/meson.build7
-rw-r--r--test cases/unit/26 guessed linker dependencies/lib/lib.c20
-rw-r--r--test cases/unit/26 guessed linker dependencies/lib/meson.build11
-rw-r--r--test cases/unit/26 guessed linker dependencies/lib/meson_options.txt1
-rw-r--r--test cases/unit/27 forcefallback/meson.build8
-rw-r--r--test cases/unit/27 forcefallback/subprojects/notzlib/meson.build7
-rw-r--r--test cases/unit/27 forcefallback/subprojects/notzlib/notzlib.c6
-rw-r--r--test cases/unit/27 forcefallback/subprojects/notzlib/notzlib.h18
-rw-r--r--test cases/unit/27 forcefallback/test_not_zlib.c8
-rw-r--r--test cases/unit/28 pkgconfig use libraries/app/app.c6
-rw-r--r--test cases/unit/28 pkgconfig use libraries/app/meson.build5
-rw-r--r--test cases/unit/28 pkgconfig use libraries/lib/liba.c2
-rw-r--r--test cases/unit/28 pkgconfig use libraries/lib/libb.c5
-rw-r--r--test cases/unit/28 pkgconfig use libraries/lib/meson.build16
-rw-r--r--test cases/unit/29 cross file overrides always args/meson.build3
-rw-r--r--test cases/unit/29 cross file overrides always args/test.c8
-rw-r--r--test cases/unit/29 cross file overrides always args/ubuntu-armhf-overrides.txt19
144 files changed, 2236 insertions, 388 deletions
diff --git a/cross/armcc.txt b/cross/armcc.txt
new file mode 100644
index 0000000..c884ffa
--- /dev/null
+++ b/cross/armcc.txt
@@ -0,0 +1,20 @@
+# This file assumes that path to the arm compiler toolchain is added
+# to the environment(PATH) variable, so that Meson can find
+# the armcc, armlink and armar while building.
+[binaries]
+c = 'armcc'
+cpp = 'armcc'
+ar = 'armar'
+strip = 'armar'
+
+[properties]
+# The '--cpu' option with the appropriate target type should be mentioned
+# to cross compile c/c++ code with armcc,.
+c_args = ['--cpu=Cortex-M0plus']
+cpp_args = ['--cpu=Cortex-M0plus']
+
+[host_machine]
+system = 'bare metal' # Update with your system name - bare metal/OS.
+cpu_family = 'arm'
+cpu = 'Cortex-M0+'
+endian = 'little'
diff --git a/data/shell-completions/zsh/_meson b/data/shell-completions/zsh/_meson
index 877d700..481d04c 100644
--- a/data/shell-completions/zsh/_meson
+++ b/data/shell-completions/zsh/_meson
@@ -31,7 +31,7 @@ local -i ret
local __meson_backends="(ninja xcode ${(j. .)${:-vs{,2010,2015,2017}}})"
local __meson_build_types="(plain debug debugoptimized minsize release)"
-local __meson_wrap_modes="(WrapMode.{default,nofallback,nodownload})"
+local __meson_wrap_modes="(WrapMode.{default,nofallback,nodownload,forcefallback})"
local -a meson_commands=(
'setup:set up a build directory'
diff --git a/data/syntax-highlighting/vim/syntax/meson.vim b/data/syntax-highlighting/vim/syntax/meson.vim
index 83dd66a..d58903e 100644
--- a/data/syntax-highlighting/vim/syntax/meson.vim
+++ b/data/syntax-highlighting/vim/syntax/meson.vim
@@ -70,6 +70,7 @@ syn keyword mesonBuiltin
\ add_project_link_arguments
\ add_test_setup
\ benchmark
+ \ both_libraries
\ build_machine
\ build_target
\ configuration_data
diff --git a/docs/markdown/Adding-new-projects-to-wrapdb.md b/docs/markdown/Adding-new-projects-to-wrapdb.md
index 4420de5..58b27ba 100644
--- a/docs/markdown/Adding-new-projects-to-wrapdb.md
+++ b/docs/markdown/Adding-new-projects-to-wrapdb.md
@@ -37,11 +37,10 @@ Each project gets its own repo. It is initialized like this:
git init
git add readme.txt
- git commit -a -m 'Start of project foobar.'
- git tag commit_zero -a -m 'A tag that helps get revision ids for releases.'
+ git add LICENSE.build
+ git commit -a -m 'Create project foobar'
git remote add origin <repo url>
git push -u origin master
- git push --tags
Note that this is the *only* commit that will ever be made to master branch. All other commits are done to branches.
diff --git a/docs/markdown/Compiler-properties.md b/docs/markdown/Compiler-properties.md
index 579417a..1228f42 100644
--- a/docs/markdown/Compiler-properties.md
+++ b/docs/markdown/Compiler-properties.md
@@ -160,15 +160,30 @@ Does a function exist?
Just having a header doesn't say anything about its
contents. Sometimes you need to explicitly check if some function
-exists. This is how we would check whether the function `somefunc`
-exists in header `someheader.h`
+exists. This is how we would check whether the function `open_memstream`
+exists in header `stdio.h`
```meson
-if compiler.has_function('somefunc', prefix : '#include<someheader.h>')
+if compiler.has_function('open_memstream', prefix : '#include <stdio.h>')
# function exists, do whatever is required.
endif
```
+Note that, on macOS programs can be compiled targeting older macOS
+versions than the one that the program is compiled on. It can't be
+assumed that the OS version that is compiled on matches the OS
+version that the binary will run on.
+
+Therefore when detecting function availability with `has_function`, it
+is important to specify the correct header in the prefix argument.
+
+In the example above, the function `open_memstream` is detected, which
+was introduced in macOS 10.13. When the user builds on macOS 10.13, but
+targeting macOS 10.11 (`-mmacosx-version-min=10.11`), this will correctly
+report the function as missing. Without the header however, it would lack
+the necessary availability information and incorrectly report the function
+as available.
+
Does a structure contain a member?
==
diff --git a/docs/markdown/FAQ.md b/docs/markdown/FAQ.md
index f4cf89b..ff93216 100644
--- a/docs/markdown/FAQ.md
+++ b/docs/markdown/FAQ.md
@@ -288,3 +288,46 @@ has a option called `wrap-mode` which can be used to disable wrap
downloads altogether with `--wrap-mode=nodownload`. You can also
disable dependency fallbacks altogether with `--wrap-mode=nofallback`,
which also implies the `nodownload` option.
+
+If on the other hand, you want meson to always use the fallback
+for dependencies, even when an external dependency exists and could
+satisfy the version requirements, for example in order to make
+sure your project builds when fallbacks are used, you can use
+`--wrap-mode=forcefallback` since 0.46.0.
+
+## Why is Meson implemented in Python rather than [programming language X]?
+
+Because build systems are special in ways normal applications aren't.
+
+Perhaps the biggest limitation is that because Meson is used to build
+software at the very lowest levels of the OS, it is part of the core
+bootstrap for new systems. Whenever support for a new CPU architecture
+is added, Meson must run on the system before software using it can be
+compiled natively. This requirement adds two hard limitations.
+
+The first one is that Meson must have the minimal amount of
+dependencies, because they must all be built during the bootstrap to
+get Meson to work.
+
+The second is that Meson must support all CPU architectures, both
+existing and future ones. As an example many new programming languages
+have only an LLVM based compiler available. LLVM has limited CPU
+support compared to, say, GCC, and thus bootstrapping Meson on such
+platforms would first require adding new processor support to
+LLVM. This is in most cases unfeasible.
+
+A further limitation is that we want developers on as many platforms
+as possible to submit to Meson development using the default tools
+provided by their operating system. In practice what this means is
+that Windows developers should be able to contribute using nothing but
+Visual Studio.
+
+At the time of writing (April 2018) there are only three languages
+that could fullfill these requirements:
+
+ - C
+ - C++
+ - Python
+
+Out of these we have chosen Python because it is the best fit for our
+needs.
diff --git a/docs/markdown/Gnome-module.md b/docs/markdown/Gnome-module.md
index ad3715e..3db6cc0 100644
--- a/docs/markdown/Gnome-module.md
+++ b/docs/markdown/Gnome-module.md
@@ -235,9 +235,21 @@ files and the second specifies the XML file name.
* `object_manager`: *(Added 0.40.0)* if true generates object manager code
* `annotations`: *(Added 0.43.0)* list of lists of 3 strings for the annotation for `'ELEMENT', 'KEY', 'VALUE'`
* `docbook`: *(Added 0.43.0)* prefix to generate `'PREFIX'-NAME.xml` docbooks
+* `build_by_default`: causes, when set to true, to have this target be
+ built by default, that is, when invoking plain `ninja`, the default
+ value is true for all built target types
+* `install_dir`: (*Added 0.46.0*) location to install the header or
+ bundle depending on previous options
+* `install_header`: (*Added 0.46.0*) if true, install the header file
+
+Starting *0.46.0*, this function returns a list of at least two custom targets
+(in order): one for the source code and one for the header. The list will
+contain a third custom target for the generated docbook files if that keyword
+argument is passed.
-Returns an opaque object containing the source files. Add it to a top
-level target's source list.
+Earlier versions return a single custom target representing all the outputs.
+Generally, you should just add this list of targets to a top level target's
+source list.
Example:
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md
index d98fc19..fad6a3c 100644
--- a/docs/markdown/Reference-manual.md
+++ b/docs/markdown/Reference-manual.md
@@ -186,7 +186,12 @@ These are all the supported keyword arguments:
`output`. Available since v0.41.0.
- `command` as explained above, if specified, Meson does not create
the file itself but rather runs the specified command, which allows
- you to do fully custom file generation
+ you to do fully custom file generation.
+- `format` *(added 0.46.0)* the format of defines. It defaults to `meson`, and so substitutes
+`#mesondefine` statements and variables surrounded by `@` characters, you can also use `cmake`
+to replace `#cmakedefine` statements and variables with the `${variable}` syntax. Finally you can use
+`cmake@` in which case substitutions will apply on `#cmakedefine` statements and variables with
+the `@variable@` syntax.
- `input` the input file name. If it's not specified in configuration
mode, all the variables in the `configuration:` object (see above)
are written to the `output:` file.
@@ -1238,6 +1243,12 @@ Keyword arguments are the following:
- `should_fail` when true the test is considered passed if the
executable returns a non-zero return value (i.e. reports an error)
+- `suite` `'label'` (or list of labels `['label1', 'label2']`)
+ attached to this test. The suite name is qualified by a (sub)project
+ name resulting in `(sub)project_name:label`. In the case of a list
+ of strings, the suite names will be `(sub)project_name:label1`,
+ `(sub)project_name:label2`, etc.
+
- `timeout` the amount of seconds the test is allowed to run, a test
that exceeds its time limit is always considered failed, defaults to
30 seconds
@@ -1385,6 +1396,13 @@ the following methods.
/path/to/meson.py introspect`. The user is responsible for splitting
the string to an array if needed.
+- `override_find_program(progname, program)` [*(Added
+ 0.46.0)*](Release-notes-for-0-46-0.html#Can-override-find_program)
+ specifies that whenever `find_program` is used to find a program
+ named `progname`, Meson should not not look it up on the system but
+ instead return `program`, which may either be the result of
+ `find_program` or `configure_file`.
+
- `project_version()` returns the version string specified in `project` function call.
- `project_license()` returns the array of licenses specified in `project` function call.
diff --git a/docs/markdown/Reference-tables.md b/docs/markdown/Reference-tables.md
index 7611232..2157e72 100644
--- a/docs/markdown/Reference-tables.md
+++ b/docs/markdown/Reference-tables.md
@@ -21,6 +21,8 @@ These are return values of the `get_id` method in a compiler object.
| g95 | The G95 Fortran compiler |
| open64 | The Open64 Fortran Compiler |
| nagfor | The NAG Fortran compiler |
+| lcc | Elbrus C/C++/Fortran Compiler |
+| arm | ARM compiler |
## Script environment variables
@@ -42,6 +44,7 @@ set in the cross file.
| x86 | 32 bit x86 processor |
| x86_64 | 64 bit x86 processor |
| arm | 32 bit ARM processor |
+| e2k | MCST Elbrus processor |
Any cpu family not listed in the above list is not guaranteed to
remain stable in future releases.
diff --git a/docs/markdown/Release-notes-for-0.45.0.md b/docs/markdown/Release-notes-for-0.45.0.md
index 6b24183..19d65b8 100644
--- a/docs/markdown/Release-notes-for-0.45.0.md
+++ b/docs/markdown/Release-notes-for-0.45.0.md
@@ -18,7 +18,7 @@ ldflags, etc) from.
These binaries may now be specified in the `binaries` section of a
cross file.
-```dosini
+```ini
[binaries]
cc = ...
llvm-config = '/usr/bin/llvm-config32'
@@ -37,12 +37,16 @@ time. Starting with this version it becomes a hard error.
There used to be a keywordless version of `run_target` which looked
like this:
- run_target('targetname', 'command', 'arg1', 'arg2')
+```meson
+run_target('targetname', 'command', 'arg1', 'arg2')
+```
This is now an error. The correct format for this is now:
- run_target('targetname',
- command : ['command', 'arg1', 'arg2'])
+```meson
+run_target('targetname',
+ command : ['command', 'arg1', 'arg2'])
+```
## Experimental FPGA support
@@ -84,7 +88,9 @@ private directory:
Hexadecimal integer literals can now be used in build and option files.
- int_255 = 0xFF
+```meson
+int_255 = 0xFF
+```
## b_ndebug : if-release
@@ -110,7 +116,9 @@ instead of directory itself, stripping basename of the source directory.
There is a new integer option type with optional minimum and maximum
values. It can be specified like this in the `meson_options.txt` file:
- option('integer_option', type : 'integer', min : 0, max : 5, value : 3)
+```meson
+option('integer_option', type : 'integer', min : 0, max : 5, value : 3)
+```
## New method meson.project_license()
@@ -124,7 +132,7 @@ cross-compilers, the Rust binary must be specified in your cross
file. It should specify a `--target` (as installed by `rustup target`)
and a custom linker pointing to your C cross-compiler. For example:
-```
+```ini
[binaries]
c = '/usr/bin/arm-linux-gnueabihf-gcc-7'
rust = [
@@ -146,9 +154,7 @@ private sysroot.
Meson ships with predefined project templates. To start a new project from
scratch, simply go to an empty directory and type:
-```meson
-meson init --name=myproject --type=executable --language=c
-```
+ meson init --name=myproject --type=executable --language=c
## Improve test setup selection
diff --git a/docs/markdown/Syntax.md b/docs/markdown/Syntax.md
index 1005100..01c8c6e 100644
--- a/docs/markdown/Syntax.md
+++ b/docs/markdown/Syntax.md
@@ -90,8 +90,24 @@ single quote do it like this:
single quote = 'contains a \' character'
```
-Similarly `\n` gets converted to a newline and `\\` to a single
-backslash.
+The full list of escape sequences is:
+
+* `\\` Backslash
+* `\'` Single quote
+* `\a` Bell
+* `\b` Backspace
+* `\f` Formfeed
+* `\n` Newline
+* `\r` Carriage Return
+* `\t` Horizontal Tab
+* `\v` Vertical Tab
+* `\ooo` Character with octal value ooo
+* `\xhh` Character with hex value hh
+* `\uxxxx` Character with 16-bit hex value xxxx
+* `\Uxxxxxxxx` Character with 32-bit hex value xxxxxxxx
+* `\N{name}` Character named name in Unicode database
+
+As in python and C, up to three octal digits are accepted in `\ooo`.
#### String concatenation
diff --git a/docs/markdown/Unit-tests.md b/docs/markdown/Unit-tests.md
index 53ce9ec..e5e4107 100644
--- a/docs/markdown/Unit-tests.md
+++ b/docs/markdown/Unit-tests.md
@@ -71,6 +71,14 @@ You can also run only a single test by giving its name:
$ meson test testname
```
+Tests belonging to a suite `suite` can be run as follows
+
+```console
+$ meson test --suite (sub)project_name:suite
+```
+
+Since version *0.46*, `(sub)project_name` can be omitted if it is the top-level project.
+
Sometimes you need to run the tests multiple times, which is done like this:
```console
diff --git a/docs/markdown/snippets/armcc-cross.md b/docs/markdown/snippets/armcc-cross.md
new file mode 100644
index 0000000..668f0ab
--- /dev/null
+++ b/docs/markdown/snippets/armcc-cross.md
@@ -0,0 +1,15 @@
+## ARM compiler for C and CPP
+
+Cross-compilation is now supported for ARM targets using ARM compiler - ARMCC.
+The current implementation does not support shareable libraries.
+The default extension of the output is .axf.
+The environment path should be set properly for the ARM compiler executables.
+The '--cpu' option with the appropriate target type should be mentioned
+in the cross file as shown in the snippet below.
+
+```
+[properties]
+c_args = ['--cpu=Cortex-M0plus']
+cpp_args = ['--cpu=Cortex-M0plus']
+
+```
diff --git a/docs/markdown/snippets/del-old-names.md b/docs/markdown/snippets/del-old-names.md
index c4abc9a..5ac5873 100644
--- a/docs/markdown/snippets/del-old-names.md
+++ b/docs/markdown/snippets/del-old-names.md
@@ -2,6 +2,6 @@
Old executable names `mesonintrospect`, `mesonconf`, `mesonrewriter`
and `mesontest` have been deprecated for a long time. Starting from
-this versino they no longer do anything but instead always error
+this version they no longer do anything but instead always error
out. All functionality is available as subcommands in the main `meson`
binary.
diff --git a/docs/markdown/snippets/find-override.md b/docs/markdown/snippets/find-override.md
new file mode 100644
index 0000000..ef3a4a2
--- /dev/null
+++ b/docs/markdown/snippets/find-override.md
@@ -0,0 +1,37 @@
+## Can override find_program
+
+It is now possible to override the result of `find_program` to point
+to a custom program you want. The overriding is global and applies to
+every subproject from there on. Here is how you would use it.
+
+In master project
+
+```meson
+subproject('mydep')
+```
+
+In the called subproject:
+
+```meson
+prog = find_program('my_custom_script')
+meson.override_find_program('mycodegen', prog)
+```
+
+In master project (or, in fact, any subproject):
+
+```meson
+genprog = find_program('mycodegen')
+```
+
+Now `genprog` points to the custom script. If the dependency had come
+from the system, then it would point to the system version.
+
+You can also use the return value of `configure_file()` to override
+a program in the same way as above:
+
+```meson
+prog_script = configure_file(input : 'script.sh.in',
+ output : 'script.sh',
+ configuration : cdata)
+meson.override_find_program('mycodegen', prog_script)
+```
diff --git a/docs/markdown/snippets/lcc.md b/docs/markdown/snippets/lcc.md
new file mode 100644
index 0000000..2ce300d
--- /dev/null
+++ b/docs/markdown/snippets/lcc.md
@@ -0,0 +1,23 @@
+## Support for lcc compiler for e2k (Elbrus) architecture
+
+In this version, a support for lcc compiler for Elbrus processors
+based on [e2k microarchitecture](https://en.wikipedia.org/wiki/Elbrus_2000)
+has been added.
+
+Examples of such CPUs:
+* [Elbrus-8S](https://en.wikipedia.org/wiki/Elbrus-8S);
+* Elbrus-4S;
+* [Elbrus-2S+](https://en.wikipedia.org/wiki/Elbrus-2S%2B).
+
+Such compiler have a similar behavior as gcc (basic option compatibility),
+but, in is not strictly compatible with gcc as of current version.
+
+Major differences as of version 1.21.22:
+* it does not support LTO and PCH;
+* it suffers from the same dependency file creation error as icc;
+* it has minor differences in output, especially version output;
+* it differently reacts to lchmod() detection;
+* some backend messages are produced in ru_RU.KOI8-R even if LANG=C;
+* its preprocessor treats some characters differently.
+
+So every noted difference is properly handled now in meson. \ No newline at end of file
diff --git a/docs/markdown/snippets/more-escape-sequences.md b/docs/markdown/snippets/more-escape-sequences.md
new file mode 100644
index 0000000..2894079
--- /dev/null
+++ b/docs/markdown/snippets/more-escape-sequences.md
@@ -0,0 +1,17 @@
+## String escape character update
+
+The strings (both single-quoted and triple-quoted) in meson has been taught the
+same set of escape sequences as in Python. It is therefore now possible to use
+arbitrary bytes in strings, like for example NUL (`\0`) and other ASCII control
+characters. See the chapter about *Strings* in *Syntax* for more details.
+
+Potential backwards compatibility issue: Any valid escape sequence according to
+the new rules will be interpreted as an escape sequence instead of the literal
+characters. Previously only single-quote strings supported escape sequences and
+the supported sequences were `\'`, `\\` and `\n`.
+
+The most likely breakage is usage of backslash-n in triple-quoted strings. It
+is now written in the same way as in single-quoted strings: `\\n` instead of
+`\n`. In general it is now recommended to escape any usage of backslash.
+However, backslash-c (`\c`), for example, is still backslash-c because it isn't
+a valid escape sequence.
diff --git a/docs/markdown/snippets/new-wrap-mode.md b/docs/markdown/snippets/new-wrap-mode.md
new file mode 100644
index 0000000..e33dd83
--- /dev/null
+++ b/docs/markdown/snippets/new-wrap-mode.md
@@ -0,0 +1,3 @@
+A new wrap mode was added, `--wrap-mode=forcefallback`. When this is set,
+dependencies for which a fallback was provided will always use it, even
+if an external dependency exists and satisfies the version requirements.
diff --git a/docs/markdown/snippets/non-unique-target-names.md b/docs/markdown/snippets/non-unique-target-names.md
new file mode 100644
index 0000000..9b3f917
--- /dev/null
+++ b/docs/markdown/snippets/non-unique-target-names.md
@@ -0,0 +1,9 @@
+## Relaxing of target name requirements
+
+In earlier versions of Meson you could only have one target of a given name for each type.
+For example you could not have two executables named `foo`. This requirement is now
+relaxed so that you can have multiple targets with the same name, as long as they are in
+different subdirectories.
+
+Note that projects that have multiple targets with the same name can not be built with
+the `flat` layout or any backend that writes outputs in the same directory.
diff --git a/docs/markdown/snippets/openmp-dependency.md b/docs/markdown/snippets/openmp-dependency.md
new file mode 100644
index 0000000..ad70011
--- /dev/null
+++ b/docs/markdown/snippets/openmp-dependency.md
@@ -0,0 +1,6 @@
+## Addition of OpenMP dependency
+
+An OpenMP dependency (`openmp`) has been added that encapsulates the various
+flags used by compilers to enable OpenMP and checks for the existence of the
+`omp.h` header. The `language` keyword may be passed to force the use of a
+specific compiler for the checks.
diff --git a/docs/markdown/snippets/pkg-config-fix-static-only.md b/docs/markdown/snippets/pkg-config-fix-static-only.md
new file mode 100644
index 0000000..31cd389
--- /dev/null
+++ b/docs/markdown/snippets/pkg-config-fix-static-only.md
@@ -0,0 +1,12 @@
+## Improved generation of pkg-config files for static only libraries.
+
+Previously pkg-config files generated by the pkgconfig modules for static libraries
+with dependencies could only be used in a dependencies with `static: true`.
+
+Now the generated file contains the needed dependencies libraries directly within
+`Requires` and `Libs` for build static libraries passed via the `libraries` keyword
+argument.
+
+Projects that install both a static and a shared version of a library should use
+the result of `both_libraries` to the pkg config file generator or use
+configure_file for more complicated setups.
diff --git a/manual tests/2 multiwrap/meson.build b/manual tests/2 multiwrap/meson.build
index 741a899..a4c42f4 100644
--- a/manual tests/2 multiwrap/meson.build
+++ b/manual tests/2 multiwrap/meson.build
@@ -6,7 +6,7 @@ project('multiwrap', 'c',
cc = meson.get_compiler('c')
luadep = dependency('lua', fallback : ['lua', 'lua_dep'])
-pngdep = dependency('libpng', fallback : ['libpng', 'pngdep'])
+pngdep = dependency('libpng', fallback : ['libpng', 'png_dep'])
executable('prog', 'prog.c',
dependencies : [pngdep, luadep])
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index 916f680..694700e 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -540,6 +540,8 @@ class Backend:
# pkg-config puts the thread flags itself via `Cflags:`
if dep.need_threads():
commands += compiler.thread_flags(self.environment)
+ elif dep.need_openmp():
+ commands += compiler.openmp_flags()
# Fortran requires extra include directives.
if compiler.language == 'fortran':
for lt in target.link_targets:
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index cee1434..bc3a8ef 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -169,7 +169,7 @@ class NinjaBackend(backends.Backend):
break
else:
# None of our compilers are MSVC, we're done.
- return open(tempfilename, 'a')
+ return open(tempfilename, 'a', encoding='utf-8')
filename = os.path.join(self.environment.get_scratch_dir(),
'incdetect.c')
with open(filename, 'w') as f:
@@ -196,7 +196,7 @@ int dummy;
if match:
with open(tempfilename, 'ab') as binfile:
binfile.write(b'msvc_deps_prefix = ' + match.group(1) + b'\n')
- return open(tempfilename, 'a')
+ return open(tempfilename, 'a', encoding='utf-8')
raise MesonException('Could not determine vs dep dependency prefix string.')
def generate(self, interp):
@@ -206,7 +206,7 @@ int dummy;
raise MesonException('Could not detect Ninja v1.5 or newer')
outfilename = os.path.join(self.environment.get_build_dir(), self.ninja_filename)
tempfilename = outfilename + '~'
- with open(tempfilename, 'w') as outfile:
+ with open(tempfilename, 'w', encoding='utf-8') as outfile:
outfile.write('# This is the build file for project "%s"\n' %
self.build.get_project())
outfile.write('# It is autogenerated by the Meson build system.\n')
@@ -1156,7 +1156,7 @@ int dummy;
abs_vala_file = os.path.join(self.environment.get_build_dir(), vala_file)
if PurePath(os.path.commonpath((abs_srcbasedir, abs_vala_file))) == PurePath(abs_srcbasedir):
vala_c_subdir = PurePath(abs_vala_file).parent.relative_to(abs_srcbasedir)
- vala_c_file = os.path.join(vala_c_subdir, vala_c_file)
+ vala_c_file = os.path.join(str(vala_c_subdir), vala_c_file)
else:
path_to_target = os.path.join(self.build_to_src, target.get_subdir())
if vala_file.startswith(path_to_target):
@@ -1473,7 +1473,7 @@ int dummy;
# gcc-ar blindly pass the --plugin argument to `ar` and you cannot pass
# options as arguments while using the @file.rsp syntax.
# See: https://github.com/mesonbuild/meson/issues/1646
- if mesonlib.is_windows() and not isinstance(static_linker, ArLinker):
+ if static_linker.can_linker_accept_rsp():
command_template = ''' command = {executable} @$out.rsp
rspfile = $out.rsp
rspfile_content = $LINK_ARGS {output_args} $in
@@ -1528,7 +1528,7 @@ int dummy;
except KeyError:
pass
rule = 'rule %s%s_LINKER\n' % (langname, crstr)
- if mesonlib.is_windows():
+ if compiler.can_linker_accept_rsp():
command_template = ''' command = {executable} @$out.rsp
rspfile = $out.rsp
rspfile_content = $ARGS {output_args} $in $LINK_ARGS {cross_args} $aliasing
@@ -1657,12 +1657,12 @@ rule FORTRAN_DEP_HACK
if getattr(self, 'created_llvm_ir_rule', False):
return
rule = 'rule llvm_ir{}_COMPILER\n'.format('_CROSS' if is_cross else '')
- if mesonlib.is_windows():
+ if compiler.can_linker_accept_rsp():
command_template = ' command = {executable} @$out.rsp\n' \
' rspfile = $out.rsp\n' \
- ' rspfile_content = {cross_args} $ARGS {output_args} {compile_only_args} $in\n'
+ ' rspfile_content = $ARGS{cross_args} {output_args} {compile_only_args} $in\n'
else:
- command_template = ' command = {executable} {cross_args} $ARGS {output_args} {compile_only_args} $in\n'
+ command_template = ' command = {executable} $ARGS {cross_args} {output_args} {compile_only_args} $in\n'
command = command_template.format(
executable=' '.join([ninja_quote(i) for i in compiler.get_exelist()]),
cross_args=' '.join(self.get_cross_info_lang_args(compiler.language, is_cross)),
@@ -1718,13 +1718,13 @@ rule FORTRAN_DEP_HACK
d = quote_func(d)
quoted_depargs.append(d)
cross_args = self.get_cross_info_lang_args(langname, is_cross)
- if mesonlib.is_windows():
+ if compiler.can_linker_accept_rsp():
command_template = ''' command = {executable} @$out.rsp
rspfile = $out.rsp
- rspfile_content = {cross_args} $ARGS {dep_args} {output_args} {compile_only_args} $in
+ rspfile_content = $ARGS {cross_args} {dep_args} {output_args} {compile_only_args} $in
'''
else:
- command_template = ' command = {executable} {cross_args} $ARGS {dep_args} {output_args} {compile_only_args} $in\n'
+ command_template = ' command = {executable} $ARGS {cross_args} {dep_args} {output_args} {compile_only_args} $in\n'
command = command_template.format(
executable=' '.join([ninja_quote(i) for i in compiler.get_exelist()]),
cross_args=' '.join(cross_args),
@@ -1769,7 +1769,7 @@ rule FORTRAN_DEP_HACK
output = ''
else:
output = ' '.join(compiler.get_output_args('$out'))
- command = " command = {executable} {cross_args} $ARGS {dep_args} {output_args} {compile_only_args} $in\n".format(
+ command = " command = {executable} $ARGS {cross_args} {dep_args} {output_args} {compile_only_args} $in\n".format(
executable=' '.join(compiler.get_exelist()),
cross_args=' '.join(cross_args),
dep_args=' '.join(quoted_depargs),
@@ -2392,7 +2392,7 @@ rule FORTRAN_DEP_HACK
commands += linker.get_pic_args()
# Add -Wl,-soname arguments on Linux, -install_name on OS X
commands += linker.get_soname_args(target.prefix, target.name, target.suffix,
- abspath, target.soversion,
+ abspath, target.soversion, target.ltversion,
isinstance(target, build.SharedModule))
# This is only visited when building for Windows using either GCC or Visual Studio
if target.vs_module_defs and hasattr(linker, 'gen_vs_module_defs_args'):
@@ -2410,6 +2410,74 @@ rule FORTRAN_DEP_HACK
target_args = self.build_target_link_arguments(linker, target.link_whole_targets)
return linker.get_link_whole_for(target_args) if len(target_args) else []
+ def guess_library_absolute_path(self, libname, search_dirs, prefixes, suffixes):
+ for directory in search_dirs:
+ for suffix in suffixes:
+ for prefix in prefixes:
+ trial = os.path.join(directory, prefix + libname + '.' + suffix)
+ if os.path.isfile(trial):
+ return trial
+
+ def guess_external_link_dependencies(self, linker, target, commands, internal):
+ # Ideally the linker would generate dependency information that could be used.
+ # But that has 2 problems:
+ # * currently ld can not create dependency information in a way that ninja can use:
+ # https://sourceware.org/bugzilla/show_bug.cgi?id=22843
+ # * Meson optimizes libraries from the same build using the symbol extractor.
+ # Just letting ninja use ld generated dependencies would undo this optimization.
+ search_dirs = []
+ libs = []
+ absolute_libs = []
+
+ build_dir = self.environment.get_build_dir()
+ # the following loop sometimes consumes two items from command in one pass
+ it = iter(commands)
+ for item in it:
+ if item in internal and not item.startswith('-'):
+ continue
+
+ if item.startswith('-L'):
+ if len(item) > 2:
+ path = item[2:]
+ else:
+ try:
+ path = next(it)
+ except StopIteration:
+ mlog.warning("Generated linker command has -L argument without following path")
+ break
+ if not os.path.isabs(path):
+ path = os.path.join(build_dir, path)
+ search_dirs.append(path)
+ elif item.startswith('-l'):
+ if len(item) > 2:
+ libs.append(item[2:])
+ else:
+ try:
+ libs.append(next(it))
+ except StopIteration:
+ mlog.warning("Generated linker command has '-l' argument without following library name")
+ break
+ elif os.path.isabs(item) and self.environment.is_library(item) and os.path.isfile(item):
+ absolute_libs.append(item)
+
+ guessed_dependencies = []
+ # TODO The get_library_naming requirement currently excludes link targets that use d or fortran as their main linker
+ if hasattr(linker, 'get_library_naming'):
+ search_dirs += linker.get_library_dirs()
+ prefixes_static, suffixes_static = linker.get_library_naming(self.environment, 'static', strict=True)
+ prefixes_shared, suffixes_shared = linker.get_library_naming(self.environment, 'shared', strict=True)
+ for libname in libs:
+ # be conservative and record most likely shared and static resolution, because we don't know exactly
+ # which one the linker will prefer
+ static_resolution = self.guess_library_absolute_path(libname, search_dirs, prefixes_static, suffixes_static)
+ shared_resolution = self.guess_library_absolute_path(libname, search_dirs, prefixes_shared, suffixes_shared)
+ if static_resolution:
+ guessed_dependencies.append(os.path.realpath(static_resolution))
+ if shared_resolution:
+ guessed_dependencies.append(os.path.realpath(shared_resolution))
+
+ return guessed_dependencies + absolute_libs
+
def generate_link(self, target, outfile, outname, obj_list, linker, extra_args=[]):
if isinstance(target, build.StaticLibrary):
linker_base = 'STATIC'
@@ -2476,12 +2544,15 @@ rule FORTRAN_DEP_HACK
dependencies = []
else:
dependencies = target.get_dependencies()
- commands += self.build_target_link_arguments(linker, dependencies)
+ internal = self.build_target_link_arguments(linker, dependencies)
+ commands += internal
# For 'automagic' deps: Boost and GTest. Also dependency('threads').
# pkg-config puts the thread flags itself via `Cflags:`
for d in target.external_deps:
if d.need_threads():
commands += linker.thread_link_flags(self.environment)
+ elif d.need_openmp():
+ commands += linker.openmp_flags()
# Only non-static built targets need link args and link dependencies
if not isinstance(target, build.StaticLibrary):
commands += target.link_args
@@ -2500,6 +2571,10 @@ rule FORTRAN_DEP_HACK
# symbols from those can be found here. This is needed when the
# *_winlibs that we want to link to are static mingw64 libraries.
commands += linker.get_option_link_args(self.environment.coredata.compiler_options)
+
+ dep_targets = []
+ dep_targets.extend(self.guess_external_link_dependencies(linker, target, commands, internal))
+
# Set runtime-paths so we can run executables without needing to set
# LD_LIBRARY_PATH, etc in the environment. Doesn't work on Windows.
if has_path_sep(target.name):
@@ -2523,7 +2598,7 @@ rule FORTRAN_DEP_HACK
# Convert from GCC-style link argument naming to the naming used by the
# current compiler.
commands = commands.to_native()
- dep_targets = [self.get_dependency_filename(t) for t in dependencies]
+ dep_targets.extend([self.get_dependency_filename(t) for t in dependencies])
dep_targets.extend([self.get_dependency_filename(t)
for t in target.link_depends])
elem = NinjaBuildElement(self.all_outputs, outname, linker_rule, obj_list)
diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
index 5e972f2..22383dc 100644
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -227,7 +227,7 @@ class Vs2010Backend(backends.Backend):
def generate_solution(self, sln_filename, projlist):
default_projlist = self.get_build_by_default_targets()
- with open(sln_filename, 'w') as ofile:
+ with open(sln_filename, 'w', encoding='utf-8') as ofile:
ofile.write('Microsoft Visual Studio Solution File, Format '
'Version 11.00\n')
ofile.write('# Visual Studio ' + self.vs_version + '\n')
@@ -575,7 +575,7 @@ class Vs2010Backend(backends.Backend):
tree.write(ofname, encoding='utf-8', xml_declaration=True)
# ElementTree can not do prettyprinting so do it manually
doc = xml.dom.minidom.parse(ofname)
- with open(ofname, 'w') as of:
+ with open(ofname, 'w', encoding='utf-8') as of:
of.write(doc.toprettyxml())
def gen_vcxproj(self, target, ofname, guid):
@@ -824,7 +824,10 @@ class Vs2010Backend(backends.Backend):
for d in reversed(target.get_external_deps()):
# Cflags required by external deps might have UNIX-specific flags,
# so filter them out if needed
- d_compile_args = compiler.unix_args_to_native(d.get_compile_args())
+ if isinstance(d, dependencies.OpenMPDependency):
+ d_compile_args = compiler.openmp_flags()
+ else:
+ d_compile_args = compiler.unix_args_to_native(d.get_compile_args())
for arg in d_compile_args:
if arg.startswith(('-D', '/D')):
define = arg[2:]
@@ -915,11 +918,17 @@ class Vs2010Backend(backends.Backend):
for dep in target.get_external_deps():
# Extend without reordering or de-dup to preserve `-L -l` sets
# https://github.com/mesonbuild/meson/issues/1718
- extra_link_args.extend_direct(dep.get_link_args())
+ if isinstance(dep, dependencies.OpenMPDependency):
+ extra_link_args.extend_direct(compiler.openmp_flags())
+ else:
+ extra_link_args.extend_direct(dep.get_link_args())
for d in target.get_dependencies():
if isinstance(d, build.StaticLibrary):
for dep in d.get_external_deps():
- extra_link_args.extend_direct(dep.get_link_args())
+ if isinstance(dep, dependencies.OpenMPDependency):
+ extra_link_args.extend_direct(compiler.openmp_flags())
+ else:
+ extra_link_args.extend_direct(dep.get_link_args())
# Add link args for c_* or cpp_* build options. Currently this only
# adds c_winlibs and cpp_winlibs when building for Windows. This needs
# to be after all internal and external libraries so that unresolved
@@ -946,7 +955,8 @@ class Vs2010Backend(backends.Backend):
self.add_project_reference(root, tvcxproj, tid)
else:
# Other libraries go into AdditionalDependencies
- additional_links.append(linkname)
+ if linkname not in additional_links:
+ additional_links.append(linkname)
for lib in self.get_custom_target_provided_libraries(target):
additional_links.append(self.relpath(lib, self.get_target_dir(target)))
additional_objects = []
@@ -1118,7 +1128,7 @@ if %%errorlevel%% neq 0 goto :VCEnd'''
igroup = ET.SubElement(root, 'ItemGroup')
rulefile = os.path.join(self.environment.get_scratch_dir(), 'regen.rule')
if not os.path.exists(rulefile):
- with open(rulefile, 'w') as f:
+ with open(rulefile, 'w', encoding='utf-8') as f:
f.write("# Meson regen file.")
custombuild = ET.SubElement(igroup, 'CustomBuild', Include=rulefile)
message = ET.SubElement(custombuild, 'Message')
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index 08e0c9d..e707053 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -121,6 +121,8 @@ class Build:
self.dep_manifest = {}
self.cross_stdlibs = {}
self.test_setups = {}
+ self.find_overrides = {}
+ self.searched_programs = set() # The list of all programs that have been searched for.
def add_compiler(self, compiler):
if self.static_linker is None and compiler.needs_static_linker():
@@ -308,11 +310,16 @@ a hard error in the future.''' % name)
def get_id(self):
# This ID must also be a valid file name on all OSs.
# It should also avoid shell metacharacters for obvious
- # reasons.
- base = self.name + self.type_suffix()
- if self.subproject == '':
- return base
- return self.subproject + '@@' + base
+ # reasons. '@' is not used as often as '_' in source code names.
+ # In case of collisions consider using checksums.
+ # FIXME replace with assert when slash in names is prohibited
+ name_part = self.name.replace('/', '@').replace('\\', '@')
+ assert not has_path_sep(self.type_suffix())
+ myid = name_part + self.type_suffix()
+ if self.subdir:
+ subdir_part = self.subdir.replace('/', '@').replace('\\', '@')
+ myid = subdir_part + '@@' + myid
+ return myid
def process_kwargs(self, kwargs):
if 'build_by_default' in kwargs:
@@ -803,12 +810,16 @@ This will become a hard error in a future Meson release.''')
def get_extra_args(self, language):
return self.extra_args.get(language, [])
- def get_dependencies(self):
+ def get_dependencies(self, exclude=None):
transitive_deps = []
+ if exclude is None:
+ exclude = []
for t in itertools.chain(self.link_targets, self.link_whole_targets):
+ if t in transitive_deps or t in exclude:
+ continue
transitive_deps.append(t)
if isinstance(t, StaticLibrary):
- transitive_deps += t.get_dependencies()
+ transitive_deps += t.get_dependencies(transitive_deps + exclude)
return transitive_deps
def get_source_subdir(self):
@@ -851,13 +862,14 @@ This will become a hard error in a future Meson release.''')
self.link(l)
for l in dep.whole_libraries:
self.link_whole(l)
- # Those parts that are external.
- extpart = dependencies.InternalDependency('undefined',
- [],
- dep.compile_args,
- dep.link_args,
- [], [], [], [])
- self.external_deps.append(extpart)
+ if dep.compile_args or dep.link_args:
+ # Those parts that are external.
+ extpart = dependencies.InternalDependency('undefined',
+ [],
+ dep.compile_args,
+ dep.link_args,
+ [], [], [], [])
+ self.external_deps.append(extpart)
# Deps of deps.
self.add_deps(dep.ext_deps)
elif isinstance(dep, dependencies.Dependency):
@@ -1202,7 +1214,11 @@ class Executable(BuildTarget):
for_cygwin(is_cross, environment) or 'cs' in self.compilers):
self.suffix = 'exe'
else:
- self.suffix = ''
+ if ('c' in self.compilers and self.compilers['c'].get_id().startswith('arm') or
+ 'cpp' in self.compilers and self.compilers['cpp'].get_id().startswith('arm')):
+ self.suffix = 'axf'
+ else:
+ self.suffix = ''
self.filename = self.name
if self.suffix:
self.filename += '.' + self.suffix
diff --git a/mesonbuild/compilers/__init__.py b/mesonbuild/compilers/__init__.py
index 84c87fb..288b3f5 100644
--- a/mesonbuild/compilers/__init__.py
+++ b/mesonbuild/compilers/__init__.py
@@ -54,10 +54,13 @@ __all__ = [
'FortranCompiler',
'G95FortranCompiler',
'GnuCCompiler',
+ 'ElbrusCCompiler',
'GnuCompiler',
'GnuCPPCompiler',
+ 'ElbrusCPPCompiler',
'GnuDCompiler',
'GnuFortranCompiler',
+ 'ElbrusFortranCompiler',
'GnuObjCCompiler',
'GnuObjCPPCompiler',
'IntelCompiler',
@@ -115,16 +118,20 @@ from .compilers import (
IntelCompiler,
)
from .c import (
+ ArmCCompiler,
CCompiler,
ClangCCompiler,
GnuCCompiler,
+ ElbrusCCompiler,
IntelCCompiler,
VisualStudioCCompiler,
)
from .cpp import (
+ ArmCPPCompiler,
CPPCompiler,
ClangCPPCompiler,
GnuCPPCompiler,
+ ElbrusCPPCompiler,
IntelCPPCompiler,
VisualStudioCPPCompiler,
)
@@ -139,6 +146,7 @@ from .fortran import (
FortranCompiler,
G95FortranCompiler,
GnuFortranCompiler,
+ ElbrusFortranCompiler,
IntelFortranCompiler,
NAGFortranCompiler,
Open64FortranCompiler,
diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py
index 56b46b4..0e474e7 100644
--- a/mesonbuild/compilers/c.py
+++ b/mesonbuild/compilers/c.py
@@ -31,11 +31,13 @@ from .compilers import (
msvc_winlibs,
vs32_instruction_set_args,
vs64_instruction_set_args,
+ ArmCompiler,
ClangCompiler,
Compiler,
CompilerArgs,
CrossNoRunException,
GnuCompiler,
+ ElbrusCompiler,
IntelCompiler,
RunResult,
)
@@ -84,7 +86,7 @@ class CCompiler(Compiler):
# Almost every compiler uses this for disabling warnings
return ['-w']
- def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, is_shared_module):
+ def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, version, is_shared_module):
return []
def split_shlib_to_parts(self, fname):
@@ -294,6 +296,8 @@ class CCompiler(Compiler):
args += d.get_compile_args()
if d.need_threads():
args += self.thread_flags(env)
+ elif d.need_openmp():
+ args += self.openmp_flags()
if mode == 'link':
# Add link flags needed to find dependencies
args += d.get_link_args()
@@ -319,16 +323,16 @@ 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', want_output=False):
args = self._get_compiler_check_args(env, extra_args, dependencies, mode)
# We only want to compile; not link
with self.compile(code, args.to_native(), mode) as p:
return p.returncode == 0
- def _links_wrapper(self, code, env, extra_args, dependencies):
+ def _links_wrapper(self, code, env, extra_args, dependencies, want_output=False):
"Shares common code between self.links and self.run"
args = self._get_compiler_check_args(env, extra_args, dependencies, mode='link')
- return self.compile(code, args)
+ return self.compile(code, args, want_output=want_output)
def links(self, code, env, extra_args=None, dependencies=None):
with self._links_wrapper(code, env, extra_args, dependencies) as p:
@@ -337,7 +341,7 @@ class CCompiler(Compiler):
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._links_wrapper(code, env, extra_args, dependencies) as p:
+ with self._links_wrapper(code, env, extra_args, dependencies, True) as p:
if p.returncode != 0:
mlog.debug('Could not compile test file %s: %d\n' % (
p.input_name,
@@ -367,24 +371,52 @@ class CCompiler(Compiler):
return self.compiles(t.format(**fargs), env, extra_args, dependencies)
def cross_compute_int(self, expression, low, high, guess, prefix, env, extra_args, dependencies):
+ # Try user's guess first
if isinstance(guess, int):
if self._compile_int('%s == %d' % (expression, guess), prefix, env, extra_args, dependencies):
return guess
- cur = low
- while low < high:
- cur = int((low + high) / 2)
- if cur == low:
- break
-
- if self._compile_int('%s >= %d' % (expression, cur), prefix, env, extra_args, dependencies):
- low = cur
+ # If no bounds are given, compute them in the limit of int32
+ maxint = 0x7fffffff
+ minint = -0x80000000
+ if not isinstance(low, int) or not isinstance(high, int):
+ if self._compile_int('%s >= 0' % (expression), prefix, env, extra_args, dependencies):
+ low = cur = 0
+ while self._compile_int('%s > %d' % (expression, cur), prefix, env, extra_args, dependencies):
+ low = cur + 1
+ if low > maxint:
+ raise EnvironmentException('Cross-compile check overflowed')
+ cur = cur * 2 + 1
+ if cur > maxint:
+ cur = maxint
+ high = cur
else:
+ low = cur = -1
+ while self._compile_int('%s < %d' % (expression, cur), prefix, env, extra_args, dependencies):
+ high = cur - 1
+ if high < minint:
+ raise EnvironmentException('Cross-compile check overflowed')
+ cur = cur * 2
+ if cur < minint:
+ cur = minint
+ low = cur
+ else:
+ # Sanity check limits given by user
+ if high < low:
+ raise EnvironmentException('high limit smaller than low limit')
+ condition = '%s <= %d && %s >= %d' % (expression, high, expression, low)
+ if not self._compile_int(condition, prefix, env, extra_args, dependencies):
+ raise EnvironmentException('Value out of given range')
+
+ # Binary search
+ while low != high:
+ cur = low + int((high - low) / 2)
+ if self._compile_int('%s <= %d' % (expression, cur), prefix, env, extra_args, dependencies):
high = cur
+ else:
+ low = cur + 1
- if self._compile_int('%s == %d' % (expression, cur), prefix, env, extra_args, dependencies):
- return cur
- raise EnvironmentException('Cross-compile check overflowed')
+ return low
def compute_int(self, expression, low, high, guess, prefix, env, extra_args=None, dependencies=None):
if extra_args is None:
@@ -416,7 +448,7 @@ class CCompiler(Compiler):
}}'''
if not self.compiles(t.format(**fargs), env, extra_args, dependencies):
return -1
- return self.cross_compute_int('sizeof(%s)' % typename, 1, 1024, None, prefix, env, extra_args, dependencies)
+ 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):
if extra_args is None:
@@ -454,7 +486,7 @@ class CCompiler(Compiler):
char c;
{type} target;
}};'''
- return self.cross_compute_int('offsetof(struct tmp, target)', 1, 1024, None, t.format(**fargs), env, extra_args, dependencies)
+ 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):
if extra_args is None:
@@ -708,7 +740,7 @@ class CCompiler(Compiler):
args = self.get_cross_extra_flags(env, link=False)
args += self.get_compiler_check_args()
n = 'symbols_have_underscore_prefix'
- with self.compile(code, args, 'compile') as p:
+ with self.compile(code, args, 'compile', want_output=True) as p:
if p.returncode != 0:
m = 'BUG: Unable to compile {!r} check: {}'
raise RuntimeError(m.format(n, p.stdo))
@@ -726,7 +758,7 @@ class CCompiler(Compiler):
return False
raise RuntimeError('BUG: {!r} check failed unexpectedly'.format(n))
- def get_library_naming(self, env, libtype):
+ def get_library_naming(self, env, libtype, strict=False):
'''
Get library prefixes and suffixes for the target platform ordered by
priority
@@ -734,7 +766,10 @@ class CCompiler(Compiler):
stlibext = ['a']
# We've always allowed libname to be both `foo` and `libfoo`,
# and now people depend on it
- prefixes = ['lib', '']
+ if strict and self.id != 'msvc': # lib prefix is not usually used with msvc
+ prefixes = ['lib']
+ else:
+ prefixes = ['lib', '']
# Library suffixes and prefixes
if for_darwin(env.is_cross_build(), env):
shlibext = ['dylib']
@@ -807,7 +842,12 @@ class CCompiler(Compiler):
return ['-pthread']
def has_multi_arguments(self, args, env):
- for arg in args:
+ for arg in args[:]:
+ # some compilers, e.g. GCC, don't warn for unsupported warning-disable
+ # flags, so when we are testing a flag like "-Wno-forgotten-towel", also
+ # check the equivalent enable flag too "-Wforgotten-towel"
+ if arg.startswith('-Wno-'):
+ args.append('-W' + arg[5:])
if arg.startswith('-Wl,'):
mlog.warning('''{} looks like a linker argument, but has_argument
and other similar methods only support checking compiler arguments.
@@ -888,6 +928,29 @@ class GnuCCompiler(GnuCompiler, CCompiler):
return ['-fpch-preprocess', '-include', os.path.basename(header)]
+class ElbrusCCompiler(GnuCCompiler, ElbrusCompiler):
+ def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None, defines=None, **kwargs):
+ GnuCCompiler.__init__(self, exelist, version, gcc_type, is_cross, exe_wrapper, defines, **kwargs)
+ ElbrusCompiler.__init__(self, gcc_type, defines)
+
+ # It does support some various ISO standards and c/gnu 90, 9x, 1x in addition to those which GNU CC supports.
+ def get_options(self):
+ opts = {'c_std': coredata.UserComboOption('c_std', 'C language standard to use',
+ ['none', 'c89', 'c90', 'c9x', 'c99', 'c1x', 'c11',
+ 'gnu89', 'gnu90', 'gnu9x', 'gnu99', 'gnu1x', 'gnu11',
+ 'iso9899:2011', 'iso9899:1990', 'iso9899:199409', 'iso9899:1999'],
+ 'none')}
+ return opts
+
+ # 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):
+ if funcname == 'lchmod':
+ return False
+ else:
+ return super().has_function(funcname, prefix, env, extra_args, dependencies)
+
+
class IntelCCompiler(IntelCompiler, CCompiler):
def __init__(self, exelist, version, icc_type, is_cross, exe_wrapper=None, **kwargs):
CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwargs)
@@ -1030,6 +1093,9 @@ class VisualStudioCCompiler(CCompiler):
def build_rpath_args(self, build_dir, from_dir, rpath_paths, build_rpath, install_rpath):
return []
+ def openmp_flags(self):
+ return ['/openmp']
+
# FIXME, no idea what these should be.
def thread_flags(self, env):
return []
@@ -1166,3 +1232,22 @@ class VisualStudioCCompiler(CCompiler):
if 'INCLUDE' not in os.environ:
return []
return os.environ['INCLUDE'].split(os.pathsep)
+
+
+class ArmCCompiler(ArmCompiler, CCompiler):
+ def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwargs):
+ CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwargs)
+ ArmCompiler.__init__(self)
+
+ def get_options(self):
+ opts = {'c_std': coredata.UserComboOption('c_std', 'C language standard to use',
+ ['none', 'c90', 'c99'],
+ 'none')}
+ return opts
+
+ def get_option_compile_args(self, options):
+ args = []
+ std = options['c_std']
+ if std.value != 'none':
+ args.append('--' + std.value)
+ return args
diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py
index a28a225..37326d8 100644
--- a/mesonbuild/compilers/compilers.py
+++ b/mesonbuild/compilers/compilers.py
@@ -55,7 +55,6 @@ for _l in clike_langs:
clike_suffixes += lang_suffixes[_l]
clike_suffixes += ('h', 'll', 's')
-# XXX: Use this in is_library()?
soregex = re.compile(r'.*\.so(\.[0-9]+)?(\.[0-9]+)?(\.[0-9]+)?$')
# All these are only for C-like languages; see `clike_langs` above.
@@ -102,6 +101,10 @@ def is_object(fname):
def is_library(fname):
if hasattr(fname, 'fname'):
fname = fname.fname
+
+ if soregex.match(fname):
+ return True
+
suffix = fname.split('.')[-1]
return suffix in lib_suffixes
@@ -113,6 +116,13 @@ gnulike_buildtype_args = {'plain': [],
'release': ['-O3'],
'minsize': ['-Os', '-g']}
+arm_buildtype_args = {'plain': [],
+ 'debug': ['-O0', '--debug'],
+ 'debugoptimized': ['-O1', '--debug'],
+ 'release': ['-O3', '-Otime'],
+ 'minsize': ['-O3', '-Ospace'],
+ }
+
msvc_buildtype_args = {'plain': [],
'debug': ["/MDd", "/ZI", "/Ob0", "/Od", "/RTC1"],
'debugoptimized': ["/MD", "/Zi", "/O2", "/Ob1"],
@@ -134,6 +144,13 @@ gnulike_buildtype_linker_args = {'plain': [],
'minsize': [],
}
+arm_buildtype_linker_args = {'plain': [],
+ 'debug': [],
+ 'debugoptimized': [],
+ 'release': [],
+ 'minsize': [],
+ }
+
msvc_buildtype_linker_args = {'plain': [],
'debug': [],
'debugoptimized': [],
@@ -526,15 +543,22 @@ class CompilerArgs(list):
def append_direct(self, arg):
'''
Append the specified argument without any reordering or de-dup
+ except for absolute paths where the order of include search directories
+ is not relevant
'''
- super().append(arg)
+ if os.path.isabs(arg):
+ self.append(arg)
+ else:
+ super().append(arg)
def extend_direct(self, iterable):
'''
Extend using the elements in the specified iterable without any
- reordering or de-dup
+ reordering or de-dup except for absolute paths where the order of
+ include search directories is not relevant
'''
- super().extend(iterable)
+ for elem in iterable:
+ self.append_direct(elem)
def __add__(self, args):
new = CompilerArgs(self, self.compiler)
@@ -601,6 +625,8 @@ class Compiler:
# Libraries to ignore in find_library() since they are provided by the
# compiler or the C library. Currently only used for MSVC.
ignore_libs = ()
+ # Cache for the result of compiler checks which can be cached
+ compiler_check_cache = {}
def __init__(self, exelist, version, **kwargs):
if isinstance(exelist, str):
@@ -659,6 +685,12 @@ class Compiler:
def get_always_args(self):
return []
+ def can_linker_accept_rsp(self):
+ """
+ Determines whether the linker can accept arguments using the @rsp syntax.
+ """
+ return mesonlib.is_windows()
+
def get_linker_always_args(self):
return []
@@ -753,9 +785,23 @@ class Compiler:
return os.path.join(dirname, 'output.' + suffix)
@contextlib.contextmanager
- def compile(self, code, extra_args=None, mode='link'):
+ def compile(self, code, extra_args=None, mode='link', want_output=False):
if extra_args is None:
+ textra_args = None
extra_args = []
+ else:
+ textra_args = tuple(extra_args)
+ key = (code, textra_args, mode)
+ if not want_output:
+ if key in self.compiler_check_cache:
+ p = self.compiler_check_cache[key]
+ mlog.debug('Using cached compile:')
+ mlog.debug('Cached command line: ', ' '.join(p.commands), '\n')
+ mlog.debug('Code:\n', code)
+ mlog.debug('Cached compiler stdout:\n', p.stdo)
+ mlog.debug('Cached compiler stderr:\n', p.stde)
+ yield p
+ raise StopIteration
try:
with tempfile.TemporaryDirectory() as tmpdirname:
if isinstance(code, str):
@@ -765,7 +811,6 @@ class Compiler:
ofile.write(code)
elif isinstance(code, mesonlib.File):
srcname = code.fname
- output = self._get_compile_output(tmpdirname, mode)
# Construct the compiler command-line
commands = CompilerArgs(self)
@@ -778,6 +823,7 @@ class Compiler:
if mode == 'preprocess':
commands += self.get_preprocess_only_args()
else:
+ output = self._get_compile_output(tmpdirname, mode)
commands += self.get_output_args(output)
# Generate full command-line with the exelist
commands = self.get_exelist() + commands.to_native()
@@ -788,8 +834,12 @@ class Compiler:
p, p.stdo, p.stde = Popen_safe(commands, cwd=tmpdirname)
mlog.debug('Compiler stdout:\n', p.stdo)
mlog.debug('Compiler stderr:\n', p.stde)
+ p.commands = commands
p.input_name = srcname
- p.output_name = output
+ if want_output:
+ p.output_name = output
+ else:
+ self.compiler_check_cache[key] = p
yield p
except (PermissionError, OSError):
# On Windows antivirus programs and the like hold on to files so
@@ -887,6 +937,9 @@ class Compiler:
def thread_flags(self, env):
return []
+ def openmp_flags(self):
+ raise EnvironmentException('Language %s does not support OpenMP flags.' % self.get_display_language())
+
GCC_STANDARD = 0
GCC_OSX = 1
@@ -909,14 +962,16 @@ ICC_WIN = 2
GNU_LD_AS_NEEDED = '-Wl,--as-needed'
APPLE_LD_AS_NEEDED = '-Wl,-dead_strip_dylibs'
-def get_gcc_soname_args(gcc_type, prefix, shlib_name, suffix, path, soversion, is_shared_module):
+def get_gcc_soname_args(gcc_type, prefix, shlib_name, suffix, path, soversion, version, is_shared_module):
if soversion is None:
sostr = ''
else:
sostr = '.' + soversion
- if gcc_type in (GCC_STANDARD, GCC_MINGW, GCC_CYGWIN):
- # Might not be correct for mingw but seems to work.
+ if gcc_type == GCC_STANDARD:
return ['-Wl,-soname,%s%s.%s%s' % (prefix, shlib_name, suffix, sostr)]
+ elif gcc_type in (GCC_MINGW, GCC_CYGWIN):
+ # For PE/COFF the soname argument has no effect with GNU LD
+ return []
elif gcc_type == GCC_OSX:
if is_shared_module:
return []
@@ -924,7 +979,15 @@ def get_gcc_soname_args(gcc_type, prefix, shlib_name, suffix, path, soversion, i
if soversion is not None:
install_name += '.' + soversion
install_name += '.dylib'
- return ['-install_name', os.path.join('@rpath', install_name)]
+ args = ['-install_name', os.path.join('@rpath', install_name)]
+ if version and len(version.split('.')) == 3:
+ splitted = version.split('.')
+ major = int(splitted[0])
+ minor = int(splitted[1])
+ revision = int(splitted[2])
+ args += ['-compatibility_version', '%d' % (major + minor + 1)]
+ args += ['-current_version', '%d.%d' % (major + minor + 1, revision)]
+ return args
else:
raise RuntimeError('Not implemented yet.')
@@ -980,7 +1043,7 @@ def gnulike_default_include_dirs(compiler, lang):
stdout=subprocess.PIPE,
env=env
)
- stderr = p.stderr.read().decode('utf-8')
+ stderr = p.stderr.read().decode('utf-8', errors='replace')
parse_state = 0
paths = []
for line in stderr.split('\n'):
@@ -1062,8 +1125,8 @@ class GnuCompiler:
def split_shlib_to_parts(self, fname):
return os.path.dirname(fname), fname
- def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, is_shared_module):
- return get_gcc_soname_args(self.gcc_type, prefix, shlib_name, suffix, path, soversion, is_shared_module)
+ def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, version, is_shared_module):
+ return get_gcc_soname_args(self.gcc_type, prefix, shlib_name, suffix, path, soversion, version, is_shared_module)
def get_std_shared_lib_link_args(self):
return ['-shared']
@@ -1092,6 +1155,32 @@ class GnuCompiler:
def get_default_include_dirs(self):
return gnulike_default_include_dirs(self.exelist, self.language)
+ def openmp_flags(self):
+ return ['-fopenmp']
+
+
+class ElbrusCompiler(GnuCompiler):
+ # Elbrus compiler is nearly like GCC, but does not support
+ # PCH, LTO, sanitizers and color output as of version 1.21.x.
+ def __init__(self, gcc_type, defines):
+ GnuCompiler.__init__(self, gcc_type, defines)
+ self.id = 'lcc'
+ self.base_options = ['b_pgo', 'b_coverage',
+ 'b_ndebug', 'b_staticpic',
+ 'b_lundef', 'b_asneeded']
+
+ def get_library_dirs(self):
+ env = os.environ.copy()
+ env['LC_ALL'] = 'C'
+ stdo = Popen_safe(self.exelist + ['--print-search-dirs'], env=env)[1]
+ for line in stdo.split('\n'):
+ if line.startswith('libraries:'):
+ # lcc does not include '=' in --print-search-dirs output.
+ libstr = line.split(' ', 1)[1]
+ return libstr.split(':')
+ return []
+
+
class ClangCompiler:
def __init__(self, clang_type):
@@ -1138,7 +1227,7 @@ class ClangCompiler:
# so it might change semantics at any time.
return ['-include-pch', os.path.join(pch_dir, self.get_pch_name(header))]
- def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, is_shared_module):
+ def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, version, is_shared_module):
if self.clang_type == CLANG_STANDARD:
gcc_type = GCC_STANDARD
elif self.clang_type == CLANG_OSX:
@@ -1147,7 +1236,7 @@ class ClangCompiler:
gcc_type = GCC_MINGW
else:
raise MesonException('Unreachable code when converting clang type to gcc type.')
- return get_gcc_soname_args(gcc_type, prefix, shlib_name, suffix, path, soversion, is_shared_module)
+ return get_gcc_soname_args(gcc_type, prefix, shlib_name, suffix, path, soversion, version, is_shared_module)
def has_multi_arguments(self, args, env):
myargs = ['-Werror=unknown-warning-option', '-Werror=unused-command-line-argument']
@@ -1187,6 +1276,15 @@ class ClangCompiler:
def get_default_include_dirs(self):
return gnulike_default_include_dirs(self.exelist, self.language)
+ def openmp_flags(self):
+ if version_compare(self.version, '>=3.8.0'):
+ return ['-fopenmp']
+ elif version_compare(self.version, '>=3.7.0'):
+ return ['-fopenmp=libomp']
+ else:
+ # Shouldn't work, but it'll be checked explicitly in the OpenMP dependency.
+ return []
+
# Tested on linux for ICC 14.0.3, 15.0.6, 16.0.4, 17.0.1
class IntelCompiler:
@@ -1221,7 +1319,7 @@ class IntelCompiler:
def split_shlib_to_parts(self, fname):
return os.path.dirname(fname), fname
- def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, is_shared_module):
+ def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, version, is_shared_module):
if self.icc_type == ICC_STANDARD:
gcc_type = GCC_STANDARD
elif self.icc_type == ICC_OSX:
@@ -1230,7 +1328,7 @@ class IntelCompiler:
gcc_type = GCC_MINGW
else:
raise MesonException('Unreachable code when converting icc type to gcc type.')
- return get_gcc_soname_args(gcc_type, prefix, shlib_name, suffix, path, soversion, is_shared_module)
+ return get_gcc_soname_args(gcc_type, prefix, shlib_name, suffix, path, soversion, version, is_shared_module)
# TODO: centralise this policy more globally, instead
# of fragmenting it into GnuCompiler and ClangCompiler
@@ -1248,3 +1346,79 @@ class IntelCompiler:
def get_default_include_dirs(self):
return gnulike_default_include_dirs(self.exelist, self.language)
+
+ def openmp_flags(self):
+ if version_compare(self.version, '>=15.0.0'):
+ return ['-qopenmp']
+ else:
+ return ['-openmp']
+
+
+class ArmCompiler:
+ # Functionality that is common to all ARM family compilers.
+ def __init__(self):
+ if not self.is_cross:
+ raise EnvironmentException('armcc supports only cross-compilation.')
+ self.id = 'arm'
+ default_warn_args = []
+ self.warn_args = {'1': default_warn_args,
+ '2': default_warn_args + [],
+ '3': default_warn_args + []}
+ # Assembly
+ self.can_compile_suffixes.add('s')
+
+ def can_linker_accept_rsp(self):
+ return False
+
+ def get_pic_args(self):
+ # FIXME: Add /ropi, /rwpi, /fpic etc. qualifiers to --apcs
+ return []
+
+ def get_buildtype_args(self, buildtype):
+ return arm_buildtype_args[buildtype]
+
+ def get_buildtype_linker_args(self, buildtype):
+ return arm_buildtype_linker_args[buildtype]
+
+ # Override CCompiler.get_always_args
+ def get_always_args(self):
+ return []
+
+ # Override CCompiler.get_dependency_gen_args
+ def get_dependency_gen_args(self, outtarget, outfile):
+ return []
+
+ # Override CCompiler.get_std_shared_lib_link_args
+ def get_std_shared_lib_link_args(self):
+ return []
+
+ def get_pch_use_args(self, pch_dir, header):
+ # FIXME: Add required arguments
+ # NOTE from armcc user guide:
+ # "Support for Precompiled Header (PCH) files is deprecated from ARM Compiler 5.05
+ # onwards on all platforms. Note that ARM Compiler on Windows 8 never supported
+ # PCH files."
+ return []
+
+ def get_pch_suffix(self):
+ # NOTE from armcc user guide:
+ # "Support for Precompiled Header (PCH) files is deprecated from ARM Compiler 5.05
+ # onwards on all platforms. Note that ARM Compiler on Windows 8 never supported
+ # PCH files."
+ return 'pch'
+
+ def thread_flags(self, env):
+ return []
+
+ def thread_link_flags(self, env):
+ return []
+
+ def get_linker_exelist(self):
+ args = ['armlink']
+ return args
+
+ def get_coverage_args(self):
+ return []
+
+ def get_coverage_link_args(self):
+ return []
diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py
index 1fa6f15..8dd2306 100644
--- a/mesonbuild/compilers/cpp.py
+++ b/mesonbuild/compilers/cpp.py
@@ -25,7 +25,9 @@ from .compilers import (
msvc_winlibs,
ClangCompiler,
GnuCompiler,
+ ElbrusCompiler,
IntelCompiler,
+ ArmCompiler,
)
class CPPCompiler(CCompiler):
@@ -133,6 +135,29 @@ class GnuCPPCompiler(GnuCompiler, CPPCompiler):
return ['-fpch-preprocess', '-include', os.path.basename(header)]
+class ElbrusCPPCompiler(GnuCPPCompiler, ElbrusCompiler):
+ def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None, defines=None, **kwargs):
+ GnuCPPCompiler.__init__(self, exelist, version, gcc_type, is_cross, exe_wrapper, defines, **kwargs)
+ ElbrusCompiler.__init__(self, gcc_type, defines)
+
+ # It does not support c++/gnu++ 17 and 1z, but still does support 0x, 1y, and gnu++98.
+ def get_options(self):
+ opts = super().get_options()
+ opts['cpp_std'] = coredata.UserComboOption('cpp_std', 'C++ language standard to use',
+ ['none', 'c++98', 'c++03', 'c++0x', 'c++11', 'c++14', 'c++1y',
+ 'gnu++98', 'gnu++03', 'gnu++0x', 'gnu++11', 'gnu++14', 'gnu++1y'],
+ 'none')
+ return opts
+
+ # 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):
+ if funcname == 'lchmod':
+ return False
+ else:
+ return super().has_function(funcname, prefix, env, extra_args, dependencies)
+
+
class IntelCPPCompiler(IntelCompiler, CPPCompiler):
def __init__(self, exelist, version, icc_type, is_cross, exe_wrap, **kwargs):
CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap, **kwargs)
@@ -215,3 +240,30 @@ class VisualStudioCPPCompiler(VisualStudioCCompiler, CPPCompiler):
# Visual Studio C++ compiler doesn't support -fpermissive,
# so just use the plain C args.
return super(VisualStudioCCompiler, self).get_compiler_check_args()
+
+
+class ArmCPPCompiler(ArmCompiler, CPPCompiler):
+ def __init__(self, exelist, version, is_cross, exe_wrap=None, **kwargs):
+ CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap, **kwargs)
+ ArmCompiler.__init__(self)
+
+ def get_options(self):
+ opts = {'cpp_std': coredata.UserComboOption('cpp_std', 'C++ language standard to use',
+ ['none', 'c++03', 'c++11'],
+ 'none')}
+ return opts
+
+ def get_option_compile_args(self, options):
+ args = []
+ std = options['cpp_std']
+ if std.value == 'c++11':
+ args.append('--cpp11')
+ elif std.value == 'c++03':
+ args.append('--cpp')
+ return args
+
+ def get_option_link_args(self, options):
+ return []
+
+ def get_compiler_check_args(self):
+ return []
diff --git a/mesonbuild/compilers/cs.py b/mesonbuild/compilers/cs.py
index f78e364..581b458 100644
--- a/mesonbuild/compilers/cs.py
+++ b/mesonbuild/compilers/cs.py
@@ -41,7 +41,7 @@ class CsCompiler(Compiler):
def get_link_args(self, fname):
return ['-r:' + fname]
- def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, is_shared_module):
+ def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, version, is_shared_module):
return []
def get_werror_args(self):
diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py
index 474e1bd..b76bfba 100644
--- a/mesonbuild/compilers/d.py
+++ b/mesonbuild/compilers/d.py
@@ -89,9 +89,9 @@ class DCompiler(Compiler):
def get_std_shared_lib_link_args(self):
return ['-shared']
- def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, is_shared_module):
+ def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, version, is_shared_module):
# FIXME: Make this work for Windows, MacOS and cross-compiling
- return get_gcc_soname_args(GCC_STANDARD, prefix, shlib_name, suffix, path, soversion, is_shared_module)
+ return get_gcc_soname_args(GCC_STANDARD, prefix, shlib_name, suffix, path, soversion, version, is_shared_module)
def get_feature_args(self, kwargs, build_to_src):
res = []
diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py
index f9fcc1c..9d3240f 100644
--- a/mesonbuild/compilers/fortran.py
+++ b/mesonbuild/compilers/fortran.py
@@ -27,6 +27,7 @@ from .compilers import (
gnulike_buildtype_args,
gnulike_buildtype_linker_args,
Compiler,
+ ElbrusCompiler,
IntelCompiler,
)
@@ -93,8 +94,8 @@ end program prog
def split_shlib_to_parts(self, fname):
return os.path.dirname(fname), fname
- def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, is_shared_module):
- return get_gcc_soname_args(self.gcc_type, prefix, shlib_name, suffix, path, soversion, is_shared_module)
+ def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, version, is_shared_module):
+ return get_gcc_soname_args(self.gcc_type, prefix, shlib_name, suffix, path, soversion, version, is_shared_module)
def get_dependency_gen_args(self, outtarget, outfile):
# Disabled until this is fixed:
@@ -179,6 +180,15 @@ class GnuFortranCompiler(FortranCompiler):
"""
return ['-Wl,--out-implib=' + implibname]
+ def openmp_flags(self):
+ return ['-fopenmp']
+
+
+class ElbrusFortranCompiler(GnuFortranCompiler, ElbrusCompiler):
+ def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None, defines=None, **kwargs):
+ GnuFortranCompiler.__init__(self, exelist, version, gcc_type, is_cross, exe_wrapper, defines, **kwargs)
+ ElbrusCompiler.__init__(self, gcc_type, defines)
+
class G95FortranCompiler(FortranCompiler):
def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwags):
@@ -224,6 +234,9 @@ class SunFortranCompiler(FortranCompiler):
def get_module_outdir_args(self, path):
return ['-moddir=' + path]
+ def openmp_flags(self):
+ return ['-xopenmp']
+
class IntelFortranCompiler(IntelCompiler, FortranCompiler):
std_warn_args = ['-warn', 'all']
@@ -256,6 +269,10 @@ class PathScaleFortranCompiler(FortranCompiler):
def get_std_warn_args(self, level):
return PathScaleFortranCompiler.std_warn_args
+ def openmp_flags(self):
+ return ['-mp']
+
+
class PGIFortranCompiler(FortranCompiler):
std_warn_args = ['-Minform=inform']
@@ -275,6 +292,9 @@ class PGIFortranCompiler(FortranCompiler):
def get_no_warn_args(self):
return ['-silent']
+ def openmp_flags(self):
+ return ['-fopenmp']
+
class Open64FortranCompiler(FortranCompiler):
std_warn_args = ['-fullwarn']
@@ -289,6 +309,9 @@ class Open64FortranCompiler(FortranCompiler):
def get_warn_args(self, level):
return Open64FortranCompiler.std_warn_args
+ def openmp_flags(self):
+ return ['-mp']
+
class NAGFortranCompiler(FortranCompiler):
std_warn_args = []
@@ -302,3 +325,6 @@ class NAGFortranCompiler(FortranCompiler):
def get_warn_args(self, level):
return NAGFortranCompiler.std_warn_args
+
+ def openmp_flags(self):
+ return ['-openmp']
diff --git a/mesonbuild/compilers/java.py b/mesonbuild/compilers/java.py
index a8138d7..1213d18 100644
--- a/mesonbuild/compilers/java.py
+++ b/mesonbuild/compilers/java.py
@@ -25,7 +25,7 @@ class JavaCompiler(Compiler):
self.id = 'unknown'
self.javarunner = 'java'
- def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, is_shared_module):
+ def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, version, is_shared_module):
return []
def get_werror_args(self):
diff --git a/mesonbuild/compilers/vala.py b/mesonbuild/compilers/vala.py
index 9ab5c8a..6194d1a 100644
--- a/mesonbuild/compilers/vala.py
+++ b/mesonbuild/compilers/vala.py
@@ -35,10 +35,10 @@ class ValaCompiler(Compiler):
return False # Because compiles into C.
def get_output_args(self, target):
- return ['-o', target]
+ return [] # Because compiles into C.
def get_compile_only_args(self):
- return ['-C']
+ return [] # Because compiles into C.
def get_pic_args(self):
return []
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index 88d007a..918671a 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -44,21 +44,17 @@ class UserOption:
def validate_value(self, value):
raise RuntimeError('Derived option class did not override validate_value.')
+ def set_value(self, newvalue):
+ self.value = self.validate_value(newvalue)
+
class UserStringOption(UserOption):
def __init__(self, name, description, value, choices=None, yielding=None):
super().__init__(name, description, choices, yielding)
self.set_value(value)
- def validate(self, value):
+ def validate_value(self, value):
if not isinstance(value, str):
raise MesonException('Value "%s" for string option "%s" is not a string.' % (str(value), self.name))
-
- def set_value(self, newvalue):
- self.validate(newvalue)
- self.value = newvalue
-
- def validate_value(self, value):
- self.validate(value)
return value
class UserBooleanOption(UserOption):
@@ -66,23 +62,17 @@ class UserBooleanOption(UserOption):
super().__init__(name, description, [True, False], yielding)
self.set_value(value)
- def tobool(self, thing):
- if isinstance(thing, bool):
- return thing
- if thing.lower() == 'true':
- return True
- if thing.lower() == 'false':
- return False
- raise MesonException('Value %s is not boolean (true or false).' % thing)
-
- def set_value(self, newvalue):
- self.value = self.tobool(newvalue)
-
def __bool__(self):
return self.value
def validate_value(self, value):
- return self.tobool(value)
+ if isinstance(value, bool):
+ return value
+ if value.lower() == 'true':
+ return True
+ if value.lower() == 'false':
+ return False
+ raise MesonException('Value %s is not boolean (true or false).' % value)
class UserIntegerOption(UserOption):
def __init__(self, name, description, min_value, max_value, value, yielding=None):
@@ -97,16 +87,16 @@ class UserIntegerOption(UserOption):
c.append('<=' + str(max_value))
self.choices = ', '.join(c)
- def set_value(self, newvalue):
- if isinstance(newvalue, str):
- newvalue = self.toint(newvalue)
- if not isinstance(newvalue, int):
+ def validate_value(self, value):
+ if isinstance(value, str):
+ value = self.toint(value)
+ if not isinstance(value, int):
raise MesonException('New value for integer option is not an integer.')
- if self.min_value is not None and newvalue < self.min_value:
- raise MesonException('New value %d is less than minimum value %d.' % (newvalue, self.min_value))
- if self.max_value is not None and newvalue > self.max_value:
- raise MesonException('New value %d is more than maximum value %d.' % (newvalue, self.max_value))
- self.value = newvalue
+ if self.min_value is not None and value < self.min_value:
+ raise MesonException('New value %d is less than minimum value %d.' % (value, self.min_value))
+ if self.max_value is not None and value > self.max_value:
+ raise MesonException('New value %d is more than maximum value %d.' % (value, self.max_value))
+ return value
def toint(self, valuestring):
try:
@@ -114,9 +104,6 @@ class UserIntegerOption(UserOption):
except ValueError:
raise MesonException('Value string "%s" is not convertable to an integer.' % valuestring)
- def validate_value(self, value):
- return self.toint(value)
-
class UserComboOption(UserOption):
def __init__(self, name, description, choices, value, yielding=None):
super().__init__(name, description, choices, yielding)
@@ -127,23 +114,18 @@ class UserComboOption(UserOption):
raise MesonException('Combo choice elements must be strings.')
self.set_value(value)
- def set_value(self, newvalue):
- if newvalue not in self.choices:
- optionsstring = ', '.join(['"%s"' % (item,) for item in self.choices])
- raise MesonException('Value "%s" for combo option "%s" is not one of the choices. Possible choices are: %s.' % (newvalue, self.name, optionsstring))
- self.value = newvalue
-
def validate_value(self, value):
if value not in self.choices:
- raise MesonException('Value %s not one of accepted values.' % value)
+ optionsstring = ', '.join(['"%s"' % (item,) for item in self.choices])
+ raise MesonException('Value "%s" for combo option "%s" is not one of the choices. Possible choices are: %s.' % (value, self.name, optionsstring))
return value
class UserArrayOption(UserOption):
def __init__(self, name, description, value, **kwargs):
super().__init__(name, description, kwargs.get('choices', []), yielding=kwargs.get('yielding', None))
- self.set_value(value, user_input=False)
+ self.value = self.validate_value(value, user_input=False)
- def validate(self, value, user_input):
+ def validate_value(self, value, user_input=True):
# User input is for options defined on the command line (via -D
# options). Users can put their input in as a comma separated
# string, but for defining options in meson_options.txt the format
@@ -176,13 +158,6 @@ This will become a hard error in the future.''')
', '.join(bad), ', '.join(self.choices)))
return newvalue
- def set_value(self, newvalue, user_input=True):
- self.value = self.validate(newvalue, user_input)
-
- def validate_value(self, value):
- self.validate(value)
- return value
-
# This class contains all data that must persist over multiple
# invocations of Meson. It is roughly the same thing as
# cmakecache.
@@ -210,7 +185,6 @@ class CoreData:
self.compilers = OrderedDict()
self.cross_compilers = OrderedDict()
self.deps = OrderedDict()
- self.modules = {}
# Only to print a warning if it changes between Meson invocations.
self.pkgconf_envvar = os.environ.get('PKG_CONFIG_PATH', '')
diff --git a/mesonbuild/dependencies/__init__.py b/mesonbuild/dependencies/__init__.py
index 4796980..1c67311 100644
--- a/mesonbuild/dependencies/__init__.py
+++ b/mesonbuild/dependencies/__init__.py
@@ -18,7 +18,7 @@ from .base import ( # noqa: F401
ExternalDependency, ExternalLibrary, ExtraFrameworkDependency, InternalDependency,
PkgConfigDependency, find_external_dependency, get_dep_identifier, packages, _packages_accept_language)
from .dev import GMockDependency, GTestDependency, LLVMDependency, ValgrindDependency
-from .misc import (MPIDependency, Python3Dependency, ThreadDependency, PcapDependency, CupsDependency, LibWmfDependency)
+from .misc import (MPIDependency, OpenMPDependency, Python3Dependency, ThreadDependency, PcapDependency, CupsDependency, LibWmfDependency)
from .platform import AppleFrameworks
from .ui import GLDependency, GnuStepDependency, Qt4Dependency, Qt5Dependency, SDL2Dependency, WxDependency, VulkanDependency
@@ -33,6 +33,7 @@ packages.update({
# From misc:
'boost': BoostDependency,
'mpi': MPIDependency,
+ 'openmp': OpenMPDependency,
'python3': Python3Dependency,
'threads': ThreadDependency,
'pcap': PcapDependency,
@@ -53,4 +54,5 @@ packages.update({
})
_packages_accept_language.update({
'mpi',
+ 'openmp',
})
diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py
index 0375102..2a19544 100644
--- a/mesonbuild/dependencies/base.py
+++ b/mesonbuild/dependencies/base.py
@@ -134,6 +134,9 @@ class Dependency:
def get_exe_args(self, compiler):
return []
+ def need_openmp(self):
+ return False
+
def need_threads(self):
return False
@@ -362,6 +365,8 @@ class PkgConfigDependency(ExternalDependency):
# The class's copy of the pkg-config path. Avoids having to search for it
# multiple times in the same Meson invocation.
class_pkgbin = None
+ # We cache all pkg-config subprocess invocations to avoid redundant calls
+ pkgbin_cache = {}
def __init__(self, name, environment, kwargs, language=None):
super().__init__('pkgconfig', environment, language, kwargs)
@@ -459,12 +464,22 @@ class PkgConfigDependency(ExternalDependency):
return s.format(self.__class__.__name__, self.name, self.is_found,
self.version_reqs)
- def _call_pkgbin(self, args, env=None):
- if not env:
- env = os.environ
+ def _call_pkgbin_real(self, args, env):
p, out = Popen_safe(self.pkgbin.get_command() + args, env=env)[0:2]
return p.returncode, out.strip()
+ def _call_pkgbin(self, args, env=None):
+ if env is None:
+ fenv = env
+ env = os.environ
+ else:
+ fenv = frozenset(env.items())
+ targs = tuple(args)
+ cache = PkgConfigDependency.pkgbin_cache
+ if (self.pkgbin, targs, fenv) not in cache:
+ cache[(self.pkgbin, targs, fenv)] = self._call_pkgbin_real(args, env)
+ return cache[(self.pkgbin, targs, fenv)]
+
def _convert_mingw_paths(self, args):
'''
Both MSVC and native Python on Windows cannot handle MinGW-esque /c/foo
diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py
index 2a218be..d4525b1 100644
--- a/mesonbuild/dependencies/misc.py
+++ b/mesonbuild/dependencies/misc.py
@@ -237,6 +237,38 @@ class MPIDependency(ExternalDependency):
[os.path.join(libdir, 'msmpi.lib')])
+class OpenMPDependency(ExternalDependency):
+ # Map date of specification release (which is the macro value) to a version.
+ VERSIONS = {
+ '201511': '4.5',
+ '201307': '4.0',
+ '201107': '3.1',
+ '200805': '3.0',
+ '200505': '2.5',
+ '200203': '2.0',
+ '199810': '1.0',
+ }
+
+ def __init__(self, environment, kwargs):
+ language = kwargs.get('language')
+ super().__init__('openmp', environment, language, kwargs)
+ self.is_found = False
+ openmp_date = self.compiler.get_define('_OPENMP', '', self.env, [], [self])
+ if openmp_date:
+ self.version = self.VERSIONS[openmp_date]
+ if self.compiler.has_header('omp.h', '', self.env, dependencies=[self]):
+ self.is_found = True
+ else:
+ mlog.log(mlog.yellow('WARNING:'), 'OpenMP found but omp.h missing.')
+ if self.is_found:
+ mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.green('YES'), self.version)
+ else:
+ mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.red('NO'))
+
+ def need_openmp(self):
+ return True
+
+
class ThreadDependency(ExternalDependency):
def __init__(self, environment, kwargs):
super().__init__('threads', environment, None, {})
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index 0115fb3..6920b8d 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -38,6 +38,8 @@ from .compilers import (
is_source,
)
from .compilers import (
+ ArmCCompiler,
+ ArmCPPCompiler,
ClangCCompiler,
ClangCPPCompiler,
ClangObjCCompiler,
@@ -48,6 +50,9 @@ from .compilers import (
GnuFortranCompiler,
GnuObjCCompiler,
GnuObjCPPCompiler,
+ ElbrusCCompiler,
+ ElbrusCPPCompiler,
+ ElbrusFortranCompiler,
IntelCCompiler,
IntelCPPCompiler,
IntelFortranCompiler,
@@ -223,6 +228,9 @@ def detect_cpu(compilers):
except mesonlib.MesonException:
pass
return 'x86_64'
+ if trial == 'e2k':
+ # Make more precise CPU detection for Elbrus platform.
+ trial = platform.processor().lower()
# Add fixes here as bugs are reported.
return trial
@@ -421,6 +429,15 @@ class Environment:
return dot.join((major, minor, patch))
@staticmethod
+ def get_lcc_version_from_defines(defines):
+ dot = '.'
+ generation_and_major = defines.get('__LCC__', '100')
+ generation = generation_and_major[:1]
+ major = generation_and_major[1:]
+ minor = defines.get('__LCC_MINOR__', '0')
+ return dot.join((generation, major, minor))
+
+ @staticmethod
def get_gnu_compiler_type(defines):
# Detect GCC type (Apple, MinGW, Cygwin, Unix)
if '__APPLE__' in defines:
@@ -504,6 +521,8 @@ class Environment:
if found_cl in watcom_cls:
continue
arg = '/?'
+ elif 'armcc' in compiler[0]:
+ arg = '--vsn'
else:
arg = '--version'
try:
@@ -513,15 +532,27 @@ class Environment:
continue
version = search_version(out)
full_version = out.split('\n', 1)[0]
+
+ guess_gcc_or_lcc = False
if 'Free Software Foundation' in out:
+ guess_gcc_or_lcc = 'gcc'
+ if 'e2k' in out and 'lcc' in out:
+ guess_gcc_or_lcc = 'lcc'
+
+ if guess_gcc_or_lcc:
defines = self.get_gnu_compiler_defines(compiler)
if not defines:
popen_exceptions[' '.join(compiler)] = 'no pre-processor defines'
continue
gtype = self.get_gnu_compiler_type(defines)
- version = self.get_gnu_version_from_defines(defines)
- cls = GnuCCompiler if lang == 'c' else GnuCPPCompiler
+ if guess_gcc_or_lcc == 'lcc':
+ version = self.get_lcc_version_from_defines(defines)
+ cls = ElbrusCCompiler if lang == 'c' else ElbrusCPPCompiler
+ else:
+ version = self.get_gnu_version_from_defines(defines)
+ cls = GnuCCompiler if lang == 'c' else GnuCPPCompiler
return cls(ccache + compiler, version, gtype, is_cross, exe_wrap, defines, full_version=full_version)
+
if 'clang' in out:
if 'Apple' in out or mesonlib.for_darwin(want_cross, self):
cltype = CLANG_OSX
@@ -550,6 +581,9 @@ class Environment:
inteltype = ICC_STANDARD
cls = IntelCCompiler if lang == 'c' else IntelCPPCompiler
return cls(ccache + compiler, version, inteltype, is_cross, exe_wrap, full_version=full_version)
+ if 'ARM' in out:
+ cls = ArmCCompiler if lang == 'c' else ArmCPPCompiler
+ return cls(ccache + compiler, version, is_cross, exe_wrap, full_version=full_version)
self._handle_exceptions(popen_exceptions, compilers)
def detect_c_compiler(self, want_cross):
@@ -574,14 +608,25 @@ class Environment:
version = search_version(out)
full_version = out.split('\n', 1)[0]
+ guess_gcc_or_lcc = False
if 'GNU Fortran' in out:
+ guess_gcc_or_lcc = 'gcc'
+ if 'e2k' in out and 'lcc' in out:
+ guess_gcc_or_lcc = 'lcc'
+
+ if guess_gcc_or_lcc:
defines = self.get_gnu_compiler_defines(compiler)
if not defines:
popen_exceptions[' '.join(compiler)] = 'no pre-processor defines'
continue
gtype = self.get_gnu_compiler_type(defines)
- version = self.get_gnu_version_from_defines(defines)
- return GnuFortranCompiler(compiler, version, gtype, is_cross, exe_wrap, defines, full_version=full_version)
+ if guess_gcc_or_lcc == 'lcc':
+ version = self.get_lcc_version_from_defines(defines)
+ cls = ElbrusFortranCompiler
+ else:
+ version = self.get_gnu_version_from_defines(defines)
+ cls = GnuFortranCompiler
+ return cls(compiler, version, gtype, is_cross, exe_wrap, defines, full_version=full_version)
if 'G95' in out:
return G95FortranCompiler(compiler, version, is_cross, exe_wrap, full_version=full_version)
@@ -626,7 +671,7 @@ class Environment:
popen_exceptions[' '.join(compiler + arg)] = e
continue
version = search_version(out)
- if 'Free Software Foundation' in out:
+ if 'Free Software Foundation' in out or ('e2k' in out and 'lcc' in out):
defines = self.get_gnu_compiler_defines(compiler)
if not defines:
popen_exceptions[' '.join(compiler)] = 'no pre-processor defines'
@@ -653,7 +698,7 @@ class Environment:
popen_exceptions[' '.join(compiler + arg)] = e
continue
version = search_version(out)
- if 'Free Software Foundation' in out:
+ if 'Free Software Foundation' in out or ('e2k' in out and 'lcc' in out):
defines = self.get_gnu_compiler_defines(compiler)
if not defines:
popen_exceptions[' '.join(compiler)] = 'no pre-processor defines'
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index 9bdc323..2c92895 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -984,20 +984,20 @@ class CompilerHolder(InterpreterObject):
check_stringlist(args)
expression = args[0]
prefix = kwargs.get('prefix', '')
- l = kwargs.get('low', -1024)
- h = kwargs.get('high', 1024)
+ low = kwargs.get('low', None)
+ high = kwargs.get('high', None)
guess = kwargs.get('guess', None)
if not isinstance(prefix, str):
raise InterpreterException('Prefix argument of compute_int must be a string.')
- if not isinstance(l, int):
+ if low is not None and not isinstance(low, int):
raise InterpreterException('Low argument of compute_int must be an int.')
- if not isinstance(h, int):
+ if high is not None and not isinstance(high, int):
raise InterpreterException('High argument of compute_int must be an int.')
if guess is not None and not isinstance(guess, int):
raise InterpreterException('Guess argument of compute_int must be an int.')
extra_args = self.determine_args(kwargs)
deps = self.determine_dependencies(kwargs)
- res = self.compiler.compute_int(expression, l, h, guess, prefix, self.environment, extra_args, deps)
+ res = self.compiler.compute_int(expression, low, high, guess, prefix, self.environment, extra_args, deps)
mlog.log('Computing int of "%s": %d' % (expression, res))
return res
@@ -1304,6 +1304,7 @@ class MesonMain(InterpreterObject):
'add_install_script': self.add_install_script_method,
'add_postconf_script': self.add_postconf_script_method,
'install_dependency_manifest': self.install_dependency_manifest_method,
+ 'override_find_program': self.override_find_program_method,
'project_version': self.project_version_method,
'project_license': self.project_license_method,
'version': self.version_method,
@@ -1416,6 +1417,26 @@ class MesonMain(InterpreterObject):
raise InterpreterException('Argument must be a string.')
self.build.dep_manifest_name = args[0]
+ def override_find_program_method(self, args, kwargs):
+ if len(args) != 2:
+ raise InterpreterException('Override needs two arguments')
+ name = args[0]
+ exe = args[1]
+ if not isinstance(name, str):
+ raise InterpreterException('First argument must be a string')
+ if hasattr(exe, 'held_object'):
+ exe = exe.held_object
+ if isinstance(exe, mesonlib.File):
+ abspath = exe.absolute_path(self.interpreter.environment.source_dir,
+ self.interpreter.environment.build_dir)
+ if not os.path.exists(abspath):
+ raise InterpreterException('Tried to override %s with a file that does not exist.' % name)
+ exe = dependencies.ExternalProgram(abspath)
+ if not isinstance(exe, dependencies.ExternalProgram):
+ # FIXME, make this work if the exe is an Executable target.
+ raise InterpreterException('Second argument must be an external program.')
+ self.interpreter.add_find_program_override(name, exe)
+
def project_version_method(self, args, kwargs):
return self.build.dep_manifest[self.interpreter.active_projectname]['version']
@@ -1463,7 +1484,7 @@ permitted_kwargs = {'add_global_arguments': {'language'},
'add_test_setup': {'exe_wrapper', 'gdb', 'timeout_multiplier', 'env'},
'benchmark': {'args', 'env', 'should_fail', 'timeout', 'workdir', 'suite'},
'build_target': known_build_target_kwargs,
- 'configure_file': {'input', 'output', 'configuration', 'command', 'install_dir', 'capture', 'install'},
+ 'configure_file': {'input', 'output', 'configuration', 'command', 'install_dir', 'capture', 'install', 'format'},
'custom_target': {'input', 'output', 'command', 'install', 'install_dir', 'build_always', 'capture', 'depends', 'depend_files', 'depfile', 'build_by_default'},
'dependency': {'default_options', 'fallback', 'language', 'main', 'method', 'modules', 'optional_modules', 'native', 'required', 'static', 'version'},
'declare_dependency': {'include_directories', 'link_with', 'sources', 'dependencies', 'compile_args', 'link_args', 'link_whole', 'version'},
@@ -1493,7 +1514,7 @@ permitted_kwargs = {'add_global_arguments': {'language'},
class Interpreter(InterpreterBase):
def __init__(self, build, backend, subproject='', subdir='', subproject_dir='subprojects',
- default_project_options=[]):
+ modules = None, default_project_options=[]):
super().__init__(build.environment.get_source_dir(), subdir)
self.an_unpicklable_object = mesonlib.an_unpicklable_object
self.build = build
@@ -1501,6 +1522,10 @@ class Interpreter(InterpreterBase):
self.coredata = self.environment.get_coredata()
self.backend = backend
self.subproject = subproject
+ if modules is None:
+ self.modules = {}
+ else:
+ self.modules = modules
# Subproject directory is usually the name of the subproject, but can
# be different for dependencies provided by wrap files.
self.subproject_directory_name = subdir.split(os.path.sep)[-1]
@@ -1579,14 +1604,14 @@ class Interpreter(InterpreterBase):
'run_command': self.func_run_command,
'set_variable': self.func_set_variable,
'subdir': self.func_subdir,
+ 'subdir_done': self.func_subdir_done,
'subproject': self.func_subproject,
'shared_library': self.func_shared_lib,
'shared_module': self.func_shared_module,
'static_library': self.func_static_lib,
'both_libraries': self.func_both_lib,
'test': self.func_test,
- 'vcs_tag': self.func_vcs_tag,
- 'subdir_done': self.func_subdir_done,
+ 'vcs_tag': self.func_vcs_tag
})
if 'MESON_UNIT_TEST' in os.environ:
self.funcs.update({'exception': self.func_exception})
@@ -1683,13 +1708,13 @@ class Interpreter(InterpreterBase):
plainname = modname.split('-', 1)[1]
mlog.warning('Module %s has no backwards or forwards compatibility and might not exist in future releases.' % modname, location=node)
modname = 'unstable_' + plainname
- if modname not in self.environment.coredata.modules:
+ if modname not in self.modules:
try:
module = importlib.import_module('mesonbuild.modules.' + modname)
except ImportError:
raise InvalidArguments('Module "%s" does not exist' % (modname, ))
- self.environment.coredata.modules[modname] = module.initialize()
- return ModuleHolder(modname, self.environment.coredata.modules[modname], self)
+ self.modules[modname] = module.initialize(self)
+ return ModuleHolder(modname, self.modules[modname], self)
@stringArgs
@noKwargs
@@ -1864,21 +1889,24 @@ external dependencies (including libraries) must go to "dependencies".''')
subdir = os.path.join(self.subproject_dir, resolved)
os.makedirs(os.path.join(self.build.environment.get_build_dir(), subdir), exist_ok=True)
self.global_args_frozen = True
- mlog.log('\nExecuting subproject ', mlog.bold(dirname), '.\n', sep='')
- subi = Interpreter(self.build, self.backend, dirname, subdir, self.subproject_dir,
- mesonlib.stringlistify(kwargs.get('default_options', [])))
- subi.subprojects = self.subprojects
-
- subi.subproject_stack = self.subproject_stack + [dirname]
- current_active = self.active_projectname
- subi.run()
+ mlog.log()
+ with mlog.nested():
+ mlog.log('\nExecuting subproject ', mlog.bold(dirname), '.\n', sep='')
+ subi = Interpreter(self.build, self.backend, dirname, subdir, self.subproject_dir,
+ self.modules, mesonlib.stringlistify(kwargs.get('default_options', [])))
+ subi.subprojects = self.subprojects
+
+ subi.subproject_stack = self.subproject_stack + [dirname]
+ current_active = self.active_projectname
+ subi.run()
+ mlog.log('\nSubproject', mlog.bold(dirname), 'finished.')
+
if 'version' in kwargs:
pv = subi.project_version
wanted = kwargs['version']
if pv == 'undefined' or not mesonlib.version_compare(pv, wanted):
raise InterpreterException('Subproject %s version is %s but %s required.' % (dirname, pv, wanted))
self.active_projectname = current_active
- mlog.log('\nSubproject', mlog.bold(dirname), 'finished.')
self.build.subprojects[dirname] = subi.project_version
self.subprojects.update(subi.subprojects)
self.subprojects[dirname] = SubprojectHolder(subi)
@@ -2225,7 +2253,7 @@ to directly access options of other subprojects.''')
break
self.coredata.base_options[optname] = oobj
- def program_from_cross_file(self, prognames):
+ def program_from_cross_file(self, prognames, silent=False):
bins = self.environment.cross_info.config['binaries']
for p in prognames:
if hasattr(p, 'held_object'):
@@ -2236,11 +2264,11 @@ to directly access options of other subprojects.''')
raise InterpreterException('Executable name must be a string.')
if p in bins:
exename = bins[p]
- extprog = dependencies.ExternalProgram(exename)
+ extprog = dependencies.ExternalProgram(exename, silent=silent)
progobj = ExternalProgramHolder(extprog)
return progobj
- def program_from_system(self, args):
+ def program_from_system(self, args, silent=False):
# Search for scripts relative to current subdir.
# Do not cache found programs because find_program('foobar')
# might give different results when run from different source dirs.
@@ -2259,11 +2287,55 @@ to directly access options of other subprojects.''')
else:
raise InvalidArguments('find_program only accepts strings and '
'files, not {!r}'.format(exename))
- extprog = dependencies.ExternalProgram(exename, search_dir=search_dir)
+ extprog = dependencies.ExternalProgram(exename, search_dir=search_dir,
+ silent=silent)
progobj = ExternalProgramHolder(extprog)
if progobj.found():
return progobj
+ def program_from_overrides(self, command_names, silent=False):
+ for name in command_names:
+ if not isinstance(name, str):
+ continue
+ if name in self.build.find_overrides:
+ exe = self.build.find_overrides[name]
+ if not silent:
+ mlog.log('Program', mlog.bold(name), 'found:', mlog.green('YES'),
+ '(overridden: %s)' % ' '.join(exe.command))
+ return ExternalProgramHolder(exe)
+ return None
+
+ def store_name_lookups(self, command_names):
+ for name in command_names:
+ if isinstance(name, str):
+ self.build.searched_programs.add(name)
+
+ def add_find_program_override(self, name, exe):
+ if name in self.build.searched_programs:
+ raise InterpreterException('Tried to override finding of executable "%s" which has already been found.'
+ % name)
+ if name in self.build.find_overrides:
+ raise InterpreterException('Tried to override executable "%s" which has already been overridden.'
+ % name)
+ self.build.find_overrides[name] = exe
+
+ 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:
+ progobj = self.program_from_cross_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()):
+ raise InvalidArguments('Program(s) {!r} not found or not executable'.format(args))
+ if progobj is None:
+ return ExternalProgramHolder(dependencies.NonExistingExternalProgram())
+ # Only store successful lookups
+ self.store_name_lookups(args)
+ return progobj
+
@permittedKwargs(permitted_kwargs['find_program'])
def func_find_program(self, node, args, kwargs):
if not args:
@@ -2271,20 +2343,10 @@ to directly access options of other subprojects.''')
required = kwargs.get('required', True)
if not isinstance(required, bool):
raise InvalidArguments('"required" argument must be a boolean.')
- progobj = None
- if self.build.environment.is_cross_build():
- use_native = kwargs.get('native', False)
- if not isinstance(use_native, bool):
- raise InvalidArguments('Argument to "native" must be a boolean.')
- if not use_native:
- progobj = self.program_from_cross_file(args)
- if progobj is None:
- progobj = self.program_from_system(args)
- if required and (progobj is None or not progobj.found()):
- raise InvalidArguments('Program(s) {!r} not found or not executable'.format(args))
- if progobj is None:
- return ExternalProgramHolder(dependencies.NonExistingExternalProgram())
- return progobj
+ use_native = kwargs.get('native', False)
+ if not isinstance(use_native, bool):
+ raise InvalidArguments('Argument to "native" must be a boolean.')
+ return self.find_program_impl(args, native=use_native, required=required, silent=False)
def func_find_library(self, node, args, kwargs):
raise InvalidCode('find_library() is removed, use meson.get_compiler(\'name\').find_library() instead.\n'
@@ -2406,10 +2468,13 @@ to directly access options of other subprojects.''')
dep = None
# Search for it outside the project
- try:
- dep = dependencies.find_external_dependency(name, self.environment, kwargs)
- except DependencyException as e:
- exception = e
+ if self.coredata.wrap_mode != WrapMode.forcefallback or 'fallback' not in kwargs:
+ try:
+ dep = dependencies.find_external_dependency(name, self.environment, kwargs)
+ except DependencyException as e:
+ exception = e
+ else:
+ exception = DependencyException("fallback for %s not found" % name)
# Search inside the projects list
if not dep or not dep.found():
@@ -2688,7 +2753,7 @@ root and issuing %s.
exe = args[1]
if not isinstance(exe, (ExecutableHolder, JarHolder, ExternalProgramHolder)):
if isinstance(exe, mesonlib.File):
- exe = self.func_find_program(node, (args[1], ), {})
+ exe = self.func_find_program(node, args[1], {})
else:
raise InterpreterException('Second argument must be executable.')
par = kwargs.get('is_parallel', True)
@@ -2884,6 +2949,16 @@ root and issuing %s.
if 'command' not in kwargs:
raise InterpreterException('"capture" keyword requires "command" keyword.')
+ if 'format' in kwargs:
+ format = kwargs['format']
+ if not isinstance(format, str):
+ raise InterpreterException('"format" keyword must be a string.')
+ else:
+ format = 'meson'
+
+ if format not in ('meson', 'cmake', 'cmake@'):
+ raise InterpreterException('"format" possible values are "meson", "cmake" or "cmake@".')
+
# Validate input
inputfile = None
ifile_abs = None
@@ -2923,7 +2998,7 @@ root and issuing %s.
if inputfile is not None:
os.makedirs(os.path.join(self.environment.build_dir, self.subdir), exist_ok=True)
missing_variables = mesonlib.do_conf_file(ifile_abs, ofile_abs,
- conf.held_object)
+ conf.held_object, format)
if missing_variables:
var_list = ", ".join(map(repr, sorted(missing_variables)))
mlog.warning(
diff --git a/mesonbuild/linkers.py b/mesonbuild/linkers.py
index 2333e27..cb07c5e 100644
--- a/mesonbuild/linkers.py
+++ b/mesonbuild/linkers.py
@@ -13,9 +13,14 @@
# limitations under the License.
from .mesonlib import Popen_safe
+from . import mesonlib
class StaticLinker:
- pass
+ def can_linker_accept_rsp(self):
+ """
+ Determines whether the linker can accept arguments using the @rsp syntax.
+ """
+ return mesonlib.is_windows()
class VisualStudioLinker(StaticLinker):
@@ -51,6 +56,9 @@ class VisualStudioLinker(StaticLinker):
def thread_link_flags(self, env):
return []
+ def openmp_flags(self):
+ return []
+
def get_option_link_args(self, options):
return []
@@ -75,6 +83,12 @@ class ArLinker(StaticLinker):
self.std_args = ['csrD']
else:
self.std_args = ['csr']
+ # For 'armar' the options should be prefixed with '-'.
+ if 'armar' in stdo:
+ self.std_args = ['-csr']
+
+ def can_linker_accept_rsp(self):
+ return False
def build_rpath_args(self, build_dir, from_dir, rpath_paths, build_rpath, install_rpath):
return []
@@ -103,6 +117,9 @@ class ArLinker(StaticLinker):
def thread_link_flags(self, env):
return []
+ def openmp_flags(self):
+ return []
+
def get_option_link_args(self, options):
return []
diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py
index a076e3e..8a2b67c 100644
--- a/mesonbuild/mesonlib.py
+++ b/mesonbuild/mesonlib.py
@@ -541,8 +541,13 @@ def has_path_sep(name, sep='/\\'):
return True
return False
-def do_replacement(regex, line, confdata):
+def do_replacement(regex, line, format, confdata):
missing_variables = set()
+ start_tag = '@'
+ backslash_tag = '\\@'
+ if format == 'cmake':
+ start_tag = '${'
+ backslash_tag = '\\${'
def variable_replace(match):
# Pairs of escape characters before '@' or '\@'
@@ -550,8 +555,8 @@ def do_replacement(regex, line, confdata):
num_escapes = match.end(0) - match.start(0)
return '\\' * (num_escapes // 2)
# Single escape character and '@'
- elif match.group(0) == '\\@':
- return '@'
+ elif match.group(0) == backslash_tag:
+ return start_tag
# Template variable to be replaced
else:
varname = match.group(1)
@@ -591,7 +596,7 @@ def do_mesondefine(line, confdata):
raise MesonException('#mesondefine argument "%s" is of unknown type.' % varname)
-def do_conf_file(src, dst, confdata):
+def do_conf_file(src, dst, confdata, format):
try:
with open(src, encoding='utf-8') as f:
data = f.readlines()
@@ -599,14 +604,24 @@ def do_conf_file(src, dst, confdata):
raise MesonException('Could not read input file %s: %s' % (src, str(e)))
# Only allow (a-z, A-Z, 0-9, _, -) as valid characters for a define
# Also allow escaping '@' with '\@'
- regex = re.compile(r'(?:\\\\)+(?=\\?@)|\\@|@([-a-zA-Z0-9_]+)@')
+ if format in ['meson', 'cmake@']:
+ regex = re.compile(r'(?:\\\\)+(?=\\?@)|\\@|@([-a-zA-Z0-9_]+)@')
+ elif format == 'cmake':
+ regex = re.compile(r'(?:\\\\)+(?=\\?\$)|\\\${|\${([-a-zA-Z0-9_]+)}')
+ else:
+ raise MesonException('Format "{}" not handled'.format(format))
+
+ search_token = '#mesondefine'
+ if format != 'meson':
+ search_token = '#cmakedefine'
+
result = []
missing_variables = set()
for line in data:
- if line.startswith('#mesondefine'):
+ if line.startswith(search_token):
line = do_mesondefine(line, confdata)
else:
- line, missing = do_replacement(regex, line, confdata)
+ line, missing = do_replacement(regex, line, format, confdata)
missing_variables.update(missing)
result.append(line)
dst_tmp = dst + '~'
@@ -734,7 +749,9 @@ def expand_arguments(args):
return expended_args
def Popen_safe(args, write=None, stderr=subprocess.PIPE, **kwargs):
- if sys.version_info < (3, 6) or not sys.stdout.encoding:
+ import locale
+ encoding = locale.getpreferredencoding()
+ if sys.version_info < (3, 6) or not sys.stdout.encoding or encoding.upper() != 'UTF-8':
return Popen_safe_legacy(args, write=write, stderr=stderr, **kwargs)
p = subprocess.Popen(args, universal_newlines=True,
close_fds=False,
diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py
index 651224e..daf5907 100644
--- a/mesonbuild/mesonmain.py
+++ b/mesonbuild/mesonmain.py
@@ -210,7 +210,8 @@ class MesonApp:
# Post-conf scripts must be run after writing coredata or else introspection fails.
g.run_postconf_scripts()
except:
- os.unlink(cdf)
+ if 'cdf' in locals():
+ os.unlink(cdf)
raise
def run_script_command(args):
diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py
index 74d26da..5a9d4cf 100644
--- a/mesonbuild/mintro.py
+++ b/mesonbuild/mintro.py
@@ -46,7 +46,7 @@ def buildparser():
help='List external dependencies.')
parser.add_argument('--projectinfo', action='store_true', dest='projectinfo', default=False,
help='Information about projects.')
- parser.add_argument('builddir', nargs='?', help='The build directory')
+ parser.add_argument('builddir', nargs='?', default='.', help='The build directory')
return parser
def determine_installed_path(target, installdata):
diff --git a/mesonbuild/mlog.py b/mesonbuild/mlog.py
index 347cede..6cbaf60 100644
--- a/mesonbuild/mlog.py
+++ b/mesonbuild/mlog.py
@@ -13,6 +13,7 @@
# limitations under the License.
import sys, os, platform, io
+from contextlib import contextmanager
"""This is (mostly) a standalone module used to write logging
information about Meson runs. Some output goes to screen,
@@ -25,6 +26,7 @@ else:
log_dir = None
log_file = None
log_fname = 'meson-log.txt'
+log_depth = 0
def initialize(logdir):
global log_dir, log_file
@@ -77,15 +79,21 @@ def process_markup(args, keep):
return arr
def force_print(*args, **kwargs):
+ iostr = io.StringIO()
+ kwargs['file'] = iostr
+ print(*args, **kwargs)
+
+ raw = iostr.getvalue()
+ if log_depth > 0:
+ prepend = '|' * log_depth
+ raw = prepend + raw.replace('\n', '\n' + prepend, raw.count('\n') - 1)
+
# _Something_ is going to get printed.
try:
- print(*args, **kwargs)
+ print(raw, end='')
except UnicodeEncodeError:
- iostr = io.StringIO()
- kwargs['file'] = iostr
- print(*args, **kwargs)
- cleaned = iostr.getvalue().encode('ascii', 'replace').decode('ascii')
- print(cleaned)
+ cleaned = raw.encode('ascii', 'replace').decode('ascii')
+ print(cleaned, end='')
def debug(*args, **kwargs):
arr = process_markup(args, False)
@@ -146,3 +154,12 @@ def format_list(list):
return list[0]
else:
return ''
+
+@contextmanager
+def nested():
+ global log_depth
+ log_depth += 1
+ try:
+ yield
+ finally:
+ log_depth -= 1
diff --git a/mesonbuild/modules/__init__.py b/mesonbuild/modules/__init__.py
index bf513fd..55bbbd3 100644
--- a/mesonbuild/modules/__init__.py
+++ b/mesonbuild/modules/__init__.py
@@ -18,26 +18,15 @@ class permittedSnippetKwargs:
return f(s, interpreter, state, args, kwargs)
return wrapped
-_found_programs = {}
-
class ExtensionModule:
- def __init__(self):
+ def __init__(self, interpreter):
+ self.interpreter = interpreter
self.snippets = set() # List of methods that operate only on the interpreter.
def is_snippet(self, funcname):
return funcname in self.snippets
-def find_program(program_name, target_name):
- if program_name in _found_programs:
- return _found_programs[program_name]
- program = dependencies.ExternalProgram(program_name)
- if not program.found():
- m = "Target {!r} can't be generated as {!r} could not be found"
- raise MesonException(m.format(target_name, program_name))
- _found_programs[program_name] = program
- return program
-
def get_include_args(include_dirs, prefix='-I'):
'''
diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py
index 30364a6..5455118 100644
--- a/mesonbuild/modules/gnome.py
+++ b/mesonbuild/modules/gnome.py
@@ -25,7 +25,7 @@ from .. import mesonlib
from .. import compilers
from .. import interpreter
from . import GResourceTarget, GResourceHeaderTarget, GirTarget, TypelibTarget, VapiTarget
-from . import find_program, get_include_args
+from . import get_include_args
from . import ExtensionModule
from . import ModuleReturnValue
from ..mesonlib import MesonException, OrderedSet, Popen_safe, extract_as_list
@@ -45,14 +45,14 @@ gdbuswarning_printed = False
gresource_warning_printed = False
_gir_has_extra_lib_arg = None
-def gir_has_extra_lib_arg():
+def gir_has_extra_lib_arg(intr_obj):
global _gir_has_extra_lib_arg
if _gir_has_extra_lib_arg is not None:
return _gir_has_extra_lib_arg
_gir_has_extra_lib_arg = False
try:
- g_ir_scanner = find_program('g-ir-scanner', '').get_command()
+ g_ir_scanner = intr_obj.find_program_impl('g-ir-scanner').get_command()
opts = Popen_safe(g_ir_scanner + ['--help'], stderr=subprocess.STDOUT)[1]
_gir_has_extra_lib_arg = '--extra-library' in opts
except (MesonException, FileNotFoundError, subprocess.CalledProcessError):
@@ -302,7 +302,7 @@ class GnomeModule(ExtensionModule):
link_command.append('-Wl,-rpath,' + libdir)
if depends:
depends.append(lib)
- if gir_has_extra_lib_arg() and use_gir_args:
+ if gir_has_extra_lib_arg(self.interpreter) and use_gir_args:
link_command.append('--extra-library=' + lib.name)
else:
link_command.append('-l' + lib.name)
@@ -369,7 +369,7 @@ class GnomeModule(ExtensionModule):
mlog.log('dependency {!r} not handled to build gir files'.format(dep))
continue
- if gir_has_extra_lib_arg() and use_gir_args:
+ if gir_has_extra_lib_arg(self.interpreter) and use_gir_args:
fixed_ldflags = OrderedSet()
for ldflag in ldflags:
if ldflag.startswith("-l"):
@@ -388,8 +388,8 @@ class GnomeModule(ExtensionModule):
raise MesonException('Gir takes one argument')
if kwargs.get('install_dir'):
raise MesonException('install_dir is not supported with generate_gir(), see "install_dir_gir" and "install_dir_typelib"')
- giscanner = find_program('g-ir-scanner', 'Gir')
- gicompiler = find_program('g-ir-compiler', 'Gir')
+ giscanner = self.interpreter.find_program_impl('g-ir-scanner')
+ gicompiler = self.interpreter.find_program_impl('g-ir-compiler')
girtarget = args[0]
while hasattr(girtarget, 'held_object'):
girtarget = girtarget.held_object
@@ -637,7 +637,7 @@ class GnomeModule(ExtensionModule):
srcdir = os.path.join(state.build_to_src, state.subdir)
outdir = state.subdir
- cmd = [find_program('glib-compile-schemas', 'gsettings-compile')]
+ cmd = [self.interpreter.find_program_impl('glib-compile-schemas')]
cmd += ['--targetdir', outdir, srcdir]
kwargs['command'] = cmd
kwargs['input'] = []
@@ -869,22 +869,21 @@ This will become a hard error in the future.''')
return []
@permittedKwargs({'interface_prefix', 'namespace', 'object_manager', 'build_by_default',
- 'annotations', 'docbook'})
+ 'annotations', 'docbook', 'install', 'install_header'})
def gdbus_codegen(self, state, args, kwargs):
if len(args) != 2:
raise MesonException('Gdbus_codegen takes two arguments, name and xml file.')
namebase = args[0]
xml_file = args[1]
target_name = namebase + '-gdbus'
- cmd = [find_program('gdbus-codegen', target_name)]
+ cmd = [self.interpreter.find_program_impl('gdbus-codegen')]
if 'interface_prefix' in kwargs:
cmd += ['--interface-prefix', kwargs.pop('interface_prefix')]
if 'namespace' in kwargs:
cmd += ['--c-namespace', kwargs.pop('namespace')]
if kwargs.get('object_manager', False):
cmd += ['--c-generate-object-manager']
- if 'docbook' in kwargs:
- cmd += ['--generate-docbook', kwargs.pop('docbook')]
+ build_by_default = kwargs.get('build_by_default', False)
# Annotations are a bit ugly in that they are a list of lists of strings...
annotations = kwargs.pop('annotations', [])
@@ -898,21 +897,74 @@ This will become a hard error in the future.''')
raise MesonException('Annotations must be made up of 3 strings for ELEMENT, KEY, and VALUE')
cmd += ['--annotate'] + annotation
- # https://git.gnome.org/browse/glib/commit/?id=ee09bb704fe9ccb24d92dd86696a0e6bb8f0dc1a
- if mesonlib.version_compare(self._get_native_glib_version(state), '>= 2.51.3'):
- cmd += ['--output-directory', '@OUTDIR@', '--generate-c-code', namebase, '@INPUT@']
+ # https://git.gnome.org/browse/glib/commit/?id=e4d68c7b3e8b01ab1a4231bf6da21d045cb5a816
+ if mesonlib.version_compare(self._get_native_glib_version(state), '>= 2.55.2'):
+ targets = []
+ install_header = kwargs.get('install_header', False)
+ install_dir = kwargs.get('install_dir', state.environment.coredata.get_builtin_option('includedir'))
+
+ output = namebase + '.c'
+ custom_kwargs = {'input': xml_file,
+ 'output': output,
+ 'command': cmd + ['--body', '--output', '@OUTDIR@/' + output, '@INPUT@'],
+ 'build_by_default': build_by_default
+ }
+ targets.append(build.CustomTarget(output, state.subdir, state.subproject, custom_kwargs))
+
+ output = namebase + '.h'
+ custom_kwargs = {'input': xml_file,
+ 'output': output,
+ 'command': cmd + ['--header', '--output', '@OUTDIR@/' + output, '@INPUT@'],
+ 'build_by_default': build_by_default,
+ 'install': install_header,
+ 'install_dir': install_dir
+ }
+ targets.append(build.CustomTarget(output, state.subdir, state.subproject, custom_kwargs))
+
+ if 'docbook' in kwargs:
+ docbook = kwargs['docbook']
+ if not isinstance(docbook, str):
+ raise MesonException('docbook value must be a string.')
+
+ docbook_cmd = cmd + ['--output-directory', '@OUTDIR@', '--generate-docbook', docbook, '@INPUT@']
+
+ output = namebase + '-docbook'
+ custom_kwargs = {'input': xml_file,
+ 'output': output,
+ 'command': docbook_cmd,
+ 'build_by_default': build_by_default
+ }
+ targets.append(build.CustomTarget(output, state.subdir, state.subproject, custom_kwargs))
+
+ objects = targets
else:
- self._print_gdbus_warning()
- cmd += ['--generate-c-code', '@OUTDIR@/' + namebase, '@INPUT@']
- outputs = [namebase + '.c', namebase + '.h']
- custom_kwargs = {'input': xml_file,
- 'output': outputs,
- 'command': cmd
- }
- if 'build_by_default' in kwargs:
- custom_kwargs['build_by_default'] = kwargs['build_by_default']
- ct = build.CustomTarget(target_name, state.subdir, state.subproject, custom_kwargs)
- return ModuleReturnValue(ct, [ct])
+ if 'docbook' in kwargs:
+ docbook = kwargs['docbook']
+ if not isinstance(docbook, str):
+ raise MesonException('docbook value must be a string.')
+
+ cmd += ['--generate-docbook', docbook]
+
+ # https://git.gnome.org/browse/glib/commit/?id=ee09bb704fe9ccb24d92dd86696a0e6bb8f0dc1a
+ if mesonlib.version_compare(self._get_native_glib_version(state), '>= 2.51.3'):
+ cmd += ['--output-directory', '@OUTDIR@', '--generate-c-code', namebase, '@INPUT@']
+ else:
+ self._print_gdbus_warning()
+ cmd += ['--generate-c-code', '@OUTDIR@/' + namebase, '@INPUT@']
+ outputs = [namebase + '.c', namebase + '.h']
+ custom_kwargs = {'input': xml_file,
+ 'output': outputs,
+ 'command': cmd,
+ 'build_by_default': build_by_default
+ }
+ ct = build.CustomTarget(target_name, state.subdir, state.subproject, custom_kwargs)
+ # Ensure that the same number (and order) of arguments are returned
+ # regardless of the gdbus-codegen (glib) version being used
+ targets = [ct, ct]
+ if 'docbook' in kwargs:
+ targets.append(ct)
+ objects = [ct]
+ return ModuleReturnValue(targets, objects)
@permittedKwargs({'sources', 'c_template', 'h_template', 'install_header', 'install_dir',
'comments', 'identifier_prefix', 'symbol_prefix', 'eprod', 'vprod',
@@ -961,7 +1013,7 @@ This will become a hard error in the future.''')
elif arg not in known_custom_target_kwargs:
raise MesonException(
'Mkenums does not take a %s keyword argument.' % (arg, ))
- cmd = [find_program('glib-mkenums', 'mkenums')] + cmd
+ cmd = [self.interpreter.find_program_impl(['glib-mkenums', 'mkenums'])] + cmd
custom_kwargs = {}
for arg in known_custom_target_kwargs:
if arg in kwargs:
@@ -1046,6 +1098,12 @@ This will become a hard error in the future.''')
raise MesonException(
'Sources keyword argument must be a string or array.')
+ # The `install_header` argument will be used by mkenums() when
+ # not using template files, so we need to forcibly unset it
+ # when generating the C source file, otherwise we will end up
+ # installing it
+ c_file_kwargs['install_header'] = False
+
header_prefix = kwargs.get('header_prefix', '')
decl_decorator = kwargs.get('decorator', '')
func_prefix = kwargs.get('function_prefix', '')
@@ -1151,7 +1209,7 @@ G_END_DECLS'''
new_genmarshal = mesonlib.version_compare(self._get_native_glib_version(state), '>= 2.53.3')
- cmd = [find_program('glib-genmarshal', output + '_genmarshal')]
+ cmd = [self.interpreter.find_program_impl('glib-genmarshal')]
known_kwargs = ['internal', 'nostdinc', 'skip_source', 'stdinc',
'valist_marshallers', 'extra_args']
known_custom_target_kwargs = ['build_always', 'depends',
@@ -1297,9 +1355,9 @@ G_END_DECLS'''
pkg_cmd, vapi_depends, vapi_packages, vapi_includes = self._extract_vapi_packages(state, kwargs)
target_name = 'generate_vapi({})'.format(library)
if 'VAPIGEN' in os.environ:
- cmd = [find_program(os.environ['VAPIGEN'], target_name)]
+ cmd = [self.interpreter.find_program_impl(os.environ['VAPIGEN'])]
else:
- cmd = [find_program('vapigen', target_name)]
+ cmd = [self.interpreter.find_program_impl('vapigen')]
cmd += ['--quiet', '--library=' + library, '--directory=' + build_dir]
cmd += self._vapi_args_to_command('--vapidir=', 'vapi_dirs', kwargs)
cmd += self._vapi_args_to_command('--metadatadir=', 'metadata_dirs', kwargs)
@@ -1354,5 +1412,5 @@ G_END_DECLS'''
created_values.append(rv)
return ModuleReturnValue(rv, created_values)
-def initialize():
- return GnomeModule()
+def initialize(*args, **kwargs):
+ return GnomeModule(*args, **kwargs)
diff --git a/mesonbuild/modules/i18n.py b/mesonbuild/modules/i18n.py
index 6c02fbb..4281200 100644
--- a/mesonbuild/modules/i18n.py
+++ b/mesonbuild/modules/i18n.py
@@ -143,5 +143,5 @@ class I18nModule(ExtensionModule):
return ModuleReturnValue(None, targets)
-def initialize():
- return I18nModule()
+def initialize(*args, **kwargs):
+ return I18nModule(*args, **kwargs)
diff --git a/mesonbuild/modules/modtest.py b/mesonbuild/modules/modtest.py
index 758eeae..533989f 100644
--- a/mesonbuild/modules/modtest.py
+++ b/mesonbuild/modules/modtest.py
@@ -24,5 +24,5 @@ class TestModule(ExtensionModule):
rv = ModuleReturnValue(None, [])
return rv
-def initialize():
- return TestModule()
+def initialize(*args, **kwargs):
+ return TestModule(*args, **kwargs)
diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py
index c587f84..934e2f4 100644
--- a/mesonbuild/modules/pkgconfig.py
+++ b/mesonbuild/modules/pkgconfig.py
@@ -87,10 +87,11 @@ class DependenciesHelper:
processed_reqs = []
processed_cflags = []
for obj in libs:
+ shared_library_only = getattr(obj, 'shared_library_only', False)
if hasattr(obj, 'pcdep'):
pcdeps = mesonlib.listify(obj.pcdep)
for d in pcdeps:
- processed_reqs += d.name
+ processed_reqs.append(d.name)
self.add_version_reqs(d.name, obj.version_reqs)
elif hasattr(obj, 'generated_pc'):
processed_reqs.append(obj.generated_pc)
@@ -105,7 +106,7 @@ class DependenciesHelper:
if obj.found():
processed_libs += obj.get_link_args()
processed_cflags += obj.get_compile_args()
- elif isinstance(obj, build.SharedLibrary) and obj.shared_library_only:
+ elif isinstance(obj, build.SharedLibrary) and shared_library_only:
# Do not pull dependencies for shared libraries because they are
# only required for static linking. Adding private requires has
# the side effect of exposing their cflags, which is the
@@ -118,11 +119,15 @@ class DependenciesHelper:
obj.generated_pc = self.name
elif isinstance(obj, (build.SharedLibrary, build.StaticLibrary)):
processed_libs.append(obj)
- self.add_priv_libs(obj.get_dependencies())
- self.add_priv_libs(obj.get_external_deps())
if public:
if not hasattr(obj, 'generated_pc'):
obj.generated_pc = self.name
+ if isinstance(obj, build.StaticLibrary) and public:
+ self.add_pub_libs(obj.get_dependencies())
+ self.add_pub_libs(obj.get_external_deps())
+ else:
+ self.add_priv_libs(obj.get_dependencies())
+ self.add_priv_libs(obj.get_external_deps())
elif isinstance(obj, str):
processed_libs.append(obj)
else:
@@ -132,9 +137,11 @@ class DependenciesHelper:
def add_version_reqs(self, name, version_reqs):
if version_reqs:
- vreqs = self.version_reqs.get(name, [])
- vreqs += mesonlib.stringlistify(version_reqs)
- self.version_reqs[name] = vreqs
+ if name not in self.version_reqs:
+ self.version_reqs[name] = set()
+ # We could have '>=1.0' or '>= 1.0', remove spaces to normalize
+ new_vreqs = [s.replace(' ', '') for s in mesonlib.stringlistify(version_reqs)]
+ self.version_reqs[name].update(new_vreqs)
def split_version_req(self, s):
for op in ['>=', '<=', '!=', '==', '=', '>', '<']:
@@ -386,5 +393,5 @@ class PkgConfigModule(ExtensionModule):
res = build.Data(mesonlib.File(True, state.environment.get_scratch_dir(), pcfile), pkgroot)
return ModuleReturnValue(res, [res])
-def initialize():
- return PkgConfigModule()
+def initialize(*args, **kwargs):
+ return PkgConfigModule(*args, **kwargs)
diff --git a/mesonbuild/modules/python3.py b/mesonbuild/modules/python3.py
index d2bf1dc..79da29a 100644
--- a/mesonbuild/modules/python3.py
+++ b/mesonbuild/modules/python3.py
@@ -23,8 +23,8 @@ from ..build import known_shmod_kwargs
class Python3Module(ExtensionModule):
- def __init__(self):
- super().__init__()
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
self.snippets.add('extension_module')
@permittedSnippetKwargs(known_shmod_kwargs)
@@ -69,5 +69,5 @@ class Python3Module(ExtensionModule):
return ModuleReturnValue(path, [])
-def initialize():
- return Python3Module()
+def initialize(*args, **kwargs):
+ return Python3Module(*args, **kwargs)
diff --git a/mesonbuild/modules/qt.py b/mesonbuild/modules/qt.py
index f5ce1ed..39c65ed 100644
--- a/mesonbuild/modules/qt.py
+++ b/mesonbuild/modules/qt.py
@@ -15,7 +15,7 @@
import os
from .. import mlog
from .. import build
-from ..mesonlib import MesonException, Popen_safe, extract_as_list
+from ..mesonlib import MesonException, Popen_safe, extract_as_list, File
from ..dependencies import Qt4Dependency, Qt5Dependency
import xml.etree.ElementTree as ET
from . import ModuleReturnValue, get_include_args
@@ -71,19 +71,47 @@ class QtBaseModule:
mlog.log(' {}:'.format(compiler_name.lower()), mlog.red('NO'))
self.tools_detected = True
- def parse_qrc(self, state, fname):
- abspath = os.path.join(state.environment.source_dir, state.subdir, fname)
- relative_part = os.path.dirname(fname)
+ def parse_qrc(self, state, rcc_file):
+ if type(rcc_file) is str:
+ abspath = os.path.join(state.environment.source_dir, state.subdir, rcc_file)
+ rcc_dirname = os.path.dirname(abspath)
+ elif type(rcc_file) is File:
+ abspath = rcc_file.absolute_path(state.environment.source_dir, state.environment.build_dir)
+ rcc_dirname = os.path.dirname(abspath)
+
try:
tree = ET.parse(abspath)
root = tree.getroot()
result = []
for child in root[0]:
if child.tag != 'file':
- mlog.warning("malformed rcc file: ", os.path.join(state.subdir, fname))
+ mlog.warning("malformed rcc file: ", os.path.join(state.subdir, rcc_file))
break
else:
- result.append(os.path.join(relative_part, child.text))
+ resource_path = child.text
+ # We need to guess if the pointed resource is:
+ # a) in build directory -> implies a generated file
+ # b) in source directory
+ # c) somewhere else external dependency file to bundle
+ #
+ # Also from qrc documentation: relative path are always from qrc file
+ # So relative path must always be computed from qrc file !
+ if os.path.isabs(resource_path):
+ # a)
+ if resource_path.startswith(os.path.abspath(state.environment.build_dir)):
+ resource_relpath = os.path.relpath(resource_path, state.environment.build_dir)
+ result.append(File(is_built=True, subdir='', fname=resource_relpath))
+ # either b) or c)
+ else:
+ result.append(File(is_built=False, subdir=state.subdir, fname=resource_path))
+ else:
+ path_from_rcc = os.path.normpath(os.path.join(rcc_dirname, resource_path))
+ # a)
+ if path_from_rcc.startswith(state.environment.build_dir):
+ result.append(File(is_built=True, subdir=state.subdir, fname=resource_path))
+ # b)
+ else:
+ result.append(File(is_built=False, subdir=state.subdir, fname=path_from_rcc))
return result
except Exception:
return []
@@ -102,11 +130,11 @@ class QtBaseModule:
if len(rcc_files) > 0:
if not self.rcc.found():
raise MesonException(err_msg.format('RCC', 'rcc-qt{}'.format(self.qt_version), self.qt_version))
- qrc_deps = []
- for i in rcc_files:
- qrc_deps += self.parse_qrc(state, i)
# custom output name set? -> one output file, multiple otherwise
if len(args) > 0:
+ qrc_deps = []
+ for i in rcc_files:
+ qrc_deps += self.parse_qrc(state, i)
name = args[0]
rcc_kwargs = {'input': rcc_files,
'output': name + '.cpp',
@@ -116,7 +144,11 @@ class QtBaseModule:
sources.append(res_target)
else:
for rcc_file in rcc_files:
- basename = os.path.basename(rcc_file)
+ qrc_deps = self.parse_qrc(state, rcc_file)
+ if type(rcc_file) is str:
+ basename = os.path.basename(rcc_file)
+ elif type(rcc_file) is File:
+ basename = os.path.basename(rcc_file.fname)
name = 'qt' + str(self.qt_version) + '-' + basename.replace('.', '_')
rcc_kwargs = {'input': rcc_file,
'output': name + '.cpp',
diff --git a/mesonbuild/modules/qt4.py b/mesonbuild/modules/qt4.py
index 3011de7..29992d5 100644
--- a/mesonbuild/modules/qt4.py
+++ b/mesonbuild/modules/qt4.py
@@ -19,11 +19,11 @@ from . import ExtensionModule
class Qt4Module(ExtensionModule, QtBaseModule):
- def __init__(self):
+ def __init__(self, interpreter):
QtBaseModule.__init__(self, qt_version=4)
- ExtensionModule.__init__(self)
+ ExtensionModule.__init__(self, interpreter)
-def initialize():
+def initialize(*args, **kwargs):
mlog.warning('rcc dependencies will not work properly until this upstream issue is fixed:',
mlog.bold('https://bugreports.qt.io/browse/QTBUG-45460'))
- return Qt4Module()
+ return Qt4Module(*args, **kwargs)
diff --git a/mesonbuild/modules/qt5.py b/mesonbuild/modules/qt5.py
index 7b7acbb..19623ac 100644
--- a/mesonbuild/modules/qt5.py
+++ b/mesonbuild/modules/qt5.py
@@ -19,11 +19,11 @@ from . import ExtensionModule
class Qt5Module(ExtensionModule, QtBaseModule):
- def __init__(self):
+ def __init__(self, interpreter):
QtBaseModule.__init__(self, qt_version=5)
- ExtensionModule.__init__(self)
+ ExtensionModule.__init__(self, interpreter)
-def initialize():
+def initialize(*args, **kwargs):
mlog.warning('rcc dependencies will not work reliably until this upstream issue is fixed:',
mlog.bold('https://bugreports.qt.io/browse/QTBUG-45460'))
- return Qt5Module()
+ return Qt5Module(*args, **kwargs)
diff --git a/mesonbuild/modules/rpm.py b/mesonbuild/modules/rpm.py
index dbb01f7..ba5bcaa 100644
--- a/mesonbuild/modules/rpm.py
+++ b/mesonbuild/modules/rpm.py
@@ -32,10 +32,17 @@ class RPMModule(ExtensionModule):
def generate_spec_template(self, state, args, kwargs):
compiler_deps = set()
for compiler in state.compilers.values():
+ # Elbrus has one 'lcc' package for every compiler
if isinstance(compiler, compilers.GnuCCompiler):
compiler_deps.add('gcc')
elif isinstance(compiler, compilers.GnuCPPCompiler):
compiler_deps.add('gcc-c++')
+ elif isinstance(compiler, compilers.ElbrusCCompiler):
+ compiler_deps.add('lcc')
+ elif isinstance(compiler, compilers.ElbrusCPPCompiler):
+ compiler_deps.add('lcc')
+ elif isinstance(compiler, compilers.ElbrusFortranCompiler):
+ compiler_deps.add('lcc')
elif isinstance(compiler, compilers.ValaCompiler):
compiler_deps.add('vala')
elif isinstance(compiler, compilers.GnuFortranCompiler):
@@ -160,5 +167,5 @@ class RPMModule(ExtensionModule):
mlog.log('RPM spec template written to %s.spec.\n' % proj)
return ModuleReturnValue(None, [])
-def initialize():
- return RPMModule()
+def initialize(*args, **kwargs):
+ return RPMModule(*args, **kwargs)
diff --git a/mesonbuild/modules/unstable_icestorm.py b/mesonbuild/modules/unstable_icestorm.py
index 1f548b6..55c647f 100644
--- a/mesonbuild/modules/unstable_icestorm.py
+++ b/mesonbuild/modules/unstable_icestorm.py
@@ -18,17 +18,17 @@ from . import ExtensionModule
class IceStormModule(ExtensionModule):
- def __init__(self):
- super().__init__()
+ def __init__(self, interpreter):
+ super().__init__(interpreter)
self.snippets.add('project')
self.yosys_bin = None
def detect_binaries(self, interpreter):
- self.yosys_bin = interpreter.func_find_program(None, ['yosys'], {})
- self.arachne_bin = interpreter.func_find_program(None, ['arachne-pnr'], {})
- self.icepack_bin = interpreter.func_find_program(None, ['icepack'], {})
- self.iceprog_bin = interpreter.func_find_program(None, ['iceprog'], {})
- self.icetime_bin = interpreter.func_find_program(None, ['icetime'], {})
+ self.yosys_bin = interpreter.find_program_impl(['yosys'])
+ self.arachne_bin = interpreter.find_program_impl(['arachne-pnr'])
+ self.icepack_bin = interpreter.find_program_impl(['icepack'])
+ self.iceprog_bin = interpreter.find_program_impl(['iceprog'])
+ self.icetime_bin = interpreter.find_program_impl(['icetime'])
def project(self, interpreter, state, args, kwargs):
if not self.yosys_bin:
@@ -80,5 +80,5 @@ class IceStormModule(ExtensionModule):
interpreter.func_run_target(None, [time_name], {
'command': [self.icetime_bin, bin_target]})
-def initialize():
- return IceStormModule()
+def initialize(*args, **kwargs):
+ return IceStormModule(*args, **kwargs)
diff --git a/mesonbuild/modules/unstable_simd.py b/mesonbuild/modules/unstable_simd.py
index b774cff..c41e96c 100644
--- a/mesonbuild/modules/unstable_simd.py
+++ b/mesonbuild/modules/unstable_simd.py
@@ -18,8 +18,8 @@ from . import ExtensionModule
class SimdModule(ExtensionModule):
- def __init__(self):
- super().__init__()
+ def __init__(self, interpreter):
+ super().__init__(interpreter)
self.snippets.add('check')
# FIXME add Altivec and AVX512.
self.isets = ('mmx',
@@ -79,5 +79,5 @@ class SimdModule(ExtensionModule):
result.append(interpreter.func_static_lib(None, [libname], lib_kwargs))
return [result, cdata]
-def initialize():
- return SimdModule()
+def initialize(*args, **kwargs):
+ return SimdModule(*args, **kwargs)
diff --git a/mesonbuild/modules/windows.py b/mesonbuild/modules/windows.py
index dc6e9d8..62cb9d1 100644
--- a/mesonbuild/modules/windows.py
+++ b/mesonbuild/modules/windows.py
@@ -104,5 +104,5 @@ class WindowsModule(ExtensionModule):
return ModuleReturnValue(res_targets, [res_targets])
-def initialize():
- return WindowsModule()
+def initialize(*args, **kwargs):
+ return WindowsModule(*args, **kwargs)
diff --git a/mesonbuild/mparser.py b/mesonbuild/mparser.py
index 0e7524c..9e43065 100644
--- a/mesonbuild/mparser.py
+++ b/mesonbuild/mparser.py
@@ -13,9 +13,44 @@
# limitations under the License.
import re
+import codecs
from .mesonlib import MesonException
from . import mlog
+# This is the regex for the supported escape sequences of a regular string
+# literal, like 'abc\x00'
+ESCAPE_SEQUENCE_SINGLE_RE = re.compile(r'''
+ ( \\U........ # 8-digit hex escapes
+ | \\u.... # 4-digit hex escapes
+ | \\x.. # 2-digit hex escapes
+ | \\[0-7]{1,3} # Octal escapes
+ | \\N\{[^}]+\} # Unicode characters by name
+ | \\[\\'abfnrtv] # Single-character escapes
+ )''', re.UNICODE | re.VERBOSE)
+
+# This is the regex for the supported escape sequences of a multiline string
+# literal, like '''abc\x00'''. The only difference is that single quote (')
+# doesn't require escaping.
+ESCAPE_SEQUENCE_MULTI_RE = re.compile(r'''
+ ( \\U........ # 8-digit hex escapes
+ | \\u.... # 4-digit hex escapes
+ | \\x.. # 2-digit hex escapes
+ | \\[0-7]{1,3} # Octal escapes
+ | \\N\{[^}]+\} # Unicode characters by name
+ | \\[\\abfnrtv] # Single-character escapes
+ )''', re.UNICODE | re.VERBOSE)
+
+class MesonUnicodeDecodeError(MesonException):
+ def __init__(self, match):
+ super().__init__("%s" % match)
+ self.match = match
+
+def decode_match(match):
+ try:
+ return codecs.decode(match.group(0), 'unicode_escape')
+ except UnicodeDecodeError as err:
+ raise MesonUnicodeDecodeError(match.group(0))
+
class ParseException(MesonException):
def __init__(self, text, line, lineno, colno):
# Format as error message, followed by the line with the error, followed by a caret to show the error column.
@@ -112,7 +147,6 @@ class Lexer:
par_count = 0
bracket_count = 0
col = 0
- newline_rx = re.compile(r'(?<!\\)((?:\\\\)*)\\n')
while loc < len(self.code):
matched = False
value = None
@@ -145,12 +179,18 @@ class Lexer:
if match_text.find("\n") != -1:
mlog.warning("""Newline character in a string detected, use ''' (three single quotes) for multiline strings instead.
This will become a hard error in a future Meson release.""", self.getline(line_start), lineno, col)
- value = match_text[1:-1].replace(r"\'", "'")
- value = newline_rx.sub(r'\1\n', value)
- value = value.replace(r" \\ ".strip(), r" \ ".strip())
+ value = match_text[1:-1]
+ try:
+ value = ESCAPE_SEQUENCE_SINGLE_RE.sub(decode_match, value)
+ except MesonUnicodeDecodeError as err:
+ raise MesonException("Failed to parse escape sequence: '{}' in string:\n {}".format(err.match, match_text))
elif tid == 'multiline_string':
tid = 'string'
value = match_text[3:-3]
+ try:
+ value = ESCAPE_SEQUENCE_MULTI_RE.sub(decode_match, value)
+ except MesonUnicodeDecodeError as err:
+ raise MesonException("Failed to parse escape sequence: '{}' in string:\n{}".format(err.match, match_text))
lines = match_text.split('\n')
if len(lines) > 1:
lineno += len(lines) - 1
diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py
index 91567f2..110a94e 100644
--- a/mesonbuild/mtest.py
+++ b/mesonbuild/mtest.py
@@ -476,6 +476,25 @@ TIMEOUT: %4d
(prj_match, st_match) = TestHarness.split_suite_string(suite)
for prjst in test.suite:
(prj, st) = TestHarness.split_suite_string(prjst)
+
+ # the SUITE can be passed as
+ # suite_name
+ # or
+ # project_name:suite_name
+ # so we need to select only the test belonging to project_name
+
+ # this if hanlde the first case (i.e., SUITE == suite_name)
+
+ # in this way we can run tests belonging to different
+ # (sub)projects which share the same suite_name
+ if not st_match and st == prj_match:
+ return True
+
+ # these two conditions are needed to handle the second option
+ # i.e., SUITE == project_name:suite_name
+
+ # in this way we select the only the tests of
+ # project_name with suite_name
if prj_match and prj != prj_match:
continue
if st_match and st != st_match:
diff --git a/mesonbuild/scripts/depfixer.py b/mesonbuild/scripts/depfixer.py
index ee63147..41ede1d 100644
--- a/mesonbuild/scripts/depfixer.py
+++ b/mesonbuild/scripts/depfixer.py
@@ -14,6 +14,7 @@
import sys, struct
+import shutil, subprocess
SHT_STRTAB = 3
DT_NEEDED = 1
@@ -337,20 +338,68 @@ class Elf(DataSizes):
entry.write(self.bf)
return None
+def fix_elf(fname, new_rpath, verbose=True):
+ with Elf(fname, verbose) as e:
+ if new_rpath is None:
+ e.print_rpath()
+ e.print_runpath()
+ else:
+ e.fix_rpath(new_rpath)
+
+def get_darwin_rpaths_to_remove(fname):
+ out = subprocess.check_output(['otool', '-l', fname], universal_newlines=True)
+ result = []
+ current_cmd = 'FOOBAR'
+ for line in out.split('\n'):
+ line = line.strip()
+ if ' ' not in line:
+ continue
+ key, value = line.strip().split(' ', 1)
+ if key == 'cmd':
+ current_cmd = value
+ if key == 'path' and current_cmd == 'LC_RPATH':
+ rp = value.split('(', 1)[0].strip()
+ result.append(rp)
+ return result
+
+def fix_darwin(fname, new_rpath):
+ try:
+ rpaths = get_darwin_rpaths_to_remove(fname)
+ except subprocess.CalledProcessError:
+ # Otool failed, which happens when invoked on a
+ # non-executable target. Just return.
+ return
+ try:
+ for rp in rpaths:
+ subprocess.check_call(['install_name_tool', '-delete_rpath', rp, fname])
+ if new_rpath != '':
+ subprocess.check_call(['install_name_tool', '-add_rpath', new_rpath, fname])
+ except Exception as e:
+ raise
+ sys.exit(0)
+
+def fix_rpath(fname, new_rpath, verbose=True):
+ try:
+ fix_elf(fname, new_rpath, verbose)
+ return 0
+ except SystemExit as e:
+ if isinstance(e.code, int) and e.code == 0:
+ pass
+ else:
+ raise
+ if shutil.which('install_name_tool'):
+ fix_darwin(fname, new_rpath)
+ return 0
+
def run(args):
if len(args) < 1 or len(args) > 2:
print('This application resets target rpath.')
print('Don\'t run this unless you know what you are doing.')
print('%s: <binary file> <prefix>' % sys.argv[0])
sys.exit(1)
- with Elf(args[0]) as e:
- if len(args) == 1:
- e.print_rpath()
- e.print_runpath()
- else:
- new_rpath = args[1]
- e.fix_rpath(new_rpath)
- return 0
+ fname = args[0]
+ new_rpath = None if len(args) == 1 else args[1]
+ return fix_rpath(fname, new_rpath)
if __name__ == '__main__':
- run(sys.argv[1:])
+ sys.exit(run(sys.argv[1:]))
diff --git a/mesonbuild/scripts/meson_install.py b/mesonbuild/scripts/meson_install.py
index 1414ace..013f2a0 100644
--- a/mesonbuild/scripts/meson_install.py
+++ b/mesonbuild/scripts/meson_install.py
@@ -291,12 +291,6 @@ def run_install_script(d):
print('Failed to run install script {!r}'.format(name))
sys.exit(1)
-def is_elf_platform():
- platname = platform.system().lower()
- if platname == 'darwin' or platname == 'windows' or platname == 'cygwin':
- return False
- return True
-
def check_for_stampfile(fname):
'''Some languages e.g. Rust have output files
whose names are not known at configure time.
@@ -372,10 +366,9 @@ def install_targets(d):
print("Symlink creation does not work on this platform. "
"Skipping all symlinking.")
printed_symlink_error = True
- if is_elf_platform() and os.path.isfile(outname):
+ if os.path.isfile(outname):
try:
- e = depfixer.Elf(outname, False)
- e.fix_rpath(install_rpath)
+ depfixer.fix_rpath(outname, install_rpath, False)
except SystemExit as e:
if isinstance(e.code, int) and e.code == 0:
pass
diff --git a/mesonbuild/wrap/__init__.py b/mesonbuild/wrap/__init__.py
index 019634c..6e2bc83 100644
--- a/mesonbuild/wrap/__init__.py
+++ b/mesonbuild/wrap/__init__.py
@@ -25,7 +25,12 @@ from enum import Enum
# to use 'nofallback' so that any 'copylib' wraps will be
# download as subprojects.
#
+# --wrap-mode=forcefallback will ignore external dependencies,
+# even if they match the version requirements, and automatically
+# use the fallback if one was provided. This is useful for example
+# to make sure a project builds when using the fallbacks.
+#
# Note that these options do not affect subprojects that
# are git submodules since those are only usable in git
# repositories, and you almost always want to download them.
-WrapMode = Enum('WrapMode', 'default nofallback nodownload')
+WrapMode = Enum('WrapMode', 'default nofallback nodownload forcefallback')
diff --git a/run_unittests.py b/run_unittests.py
index 879048b..a6be2e2 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -42,6 +42,7 @@ from mesonbuild.mesonlib import (
from mesonbuild.environment import Environment, detect_ninja
from mesonbuild.mesonlib import MesonException, EnvironmentException
from mesonbuild.dependencies import PkgConfigDependency, ExternalProgram
+import mesonbuild.modules.pkgconfig
from run_tests import exe_suffix, get_fake_options
from run_tests import get_builddir_target_args, get_backend_commands, Backend
@@ -198,6 +199,12 @@ class InternalTests(unittest.TestCase):
# Direct-adding the same library again still adds it
l.append_direct('-lbar')
self.assertEqual(l, ['-Lfoodir', '-lfoo', '-Lbardir', '-lbar', '-lbar'])
+ # Direct-adding with absolute path deduplicates
+ l.append_direct('/libbaz.a')
+ self.assertEqual(l, ['-Lfoodir', '-lfoo', '-Lbardir', '-lbar', '-lbar', '/libbaz.a'])
+ # Adding libbaz again does nothing
+ l.append_direct('/libbaz.a')
+ self.assertEqual(l, ['-Lfoodir', '-lfoo', '-Lbardir', '-lbar', '-lbar', '/libbaz.a'])
def test_string_templates_substitution(self):
dictfunc = mesonbuild.mesonlib.get_filenames_templates_dict
@@ -448,6 +455,19 @@ class InternalTests(unittest.TestCase):
if f.name != 'add_release_note_snippets_here':
self.assertTrue(False, 'A file without .md suffix in snippets dir: ' + f.name)
+ def test_pkgconfig_module(self):
+ deps = mesonbuild.modules.pkgconfig.DependenciesHelper("thislib")
+
+ class Mock:
+ pass
+
+ mock = Mock()
+ mock.pcdep = Mock()
+ mock.pcdep.name = "some_name"
+ mock.version_reqs = []
+ deps.add_pub_libs([mock])
+ self.assertEqual(deps.format_reqs(deps.pub_reqs), "some_name")
+
class BasePlatformTests(unittest.TestCase):
def setUp(self):
@@ -462,6 +482,7 @@ class BasePlatformTests(unittest.TestCase):
self.backend = getattr(Backend, os.environ.get('MESON_UNIT_TEST_BACKEND', 'ninja'))
self.meson_mainfile = os.path.join(src_root, 'meson.py')
self.meson_args = ['--backend=' + self.backend.name]
+ self.meson_cross_file = None
self.meson_command = meson_command + self.meson_args
self.mconf_command = meson_command + ['configure']
self.mintro_command = meson_command + ['introspect']
@@ -547,6 +568,8 @@ class BasePlatformTests(unittest.TestCase):
if default_args:
args += ['--prefix', self.prefix,
'--libdir', self.libdir]
+ if self.meson_cross_file:
+ args += ['--cross-file', self.meson_cross_file]
self.privatedir = os.path.join(self.builddir, 'meson-private')
if inprocess:
try:
@@ -950,6 +973,12 @@ class AllPlatformTests(BasePlatformTests):
self.uninstall()
self.assertPathDoesNotExist(exename)
+ def test_forcefallback(self):
+ testdir = os.path.join(self.unit_test_dir, '27 forcefallback')
+ self.init(testdir, ['--wrap-mode=forcefallback'])
+ self.build()
+ self.run_tests()
+
def test_testsetups(self):
if not shutil.which('valgrind'):
raise unittest.SkipTest('Valgrind not installed.')
@@ -1089,7 +1118,7 @@ class AllPlatformTests(BasePlatformTests):
incs = [a for a in shlex.split(execmd) if a.startswith("-I")]
self.assertEqual(len(incs), 9)
# target private dir
- self.assertPathEqual(incs[0], "-Isub4/someexe@exe")
+ self.assertPathEqual(incs[0], "-Isub4/sub4@@someexe@exe")
# target build subdir
self.assertPathEqual(incs[1], "-Isub4")
# target source subdir
@@ -1321,7 +1350,8 @@ class AllPlatformTests(BasePlatformTests):
# \n is never substituted by the GNU pre-processor via a -D define
# ' and " confuse shlex.split() even when they are escaped
# % and # confuse the MSVC preprocessor
- value = 'spaces and fun!@$^&*()-=_+{}[]:;<>?,./~`'
+ # !, ^, *, and < confuse lcc preprocessor
+ value = 'spaces and fun@$&()-=_+{}[]:;>?,./~`'
os.environ['CPPFLAGS'] = '-D{}="{}"'.format(define, value)
os.environ['CFLAGS'] = '-DMESON_FAIL_VALUE=cflags-read'.format(define)
self.init(testdir, ['-D{}={}'.format(define, value)])
@@ -1888,6 +1918,15 @@ int main(int argc, char **argv) {
self.init(testdir, extra_args=['--layout=flat'])
self.build()
+ def test_identical_target_name_in_subdir_flat_layout(self):
+ '''
+ Test that identical targets in different subdirs do not collide
+ if layout is flat.
+ '''
+ testdir = os.path.join(self.common_test_dir, '189 same target name flat layout')
+ self.init(testdir, extra_args=['--layout=flat'])
+ self.build()
+
def test_flock(self):
exception_raised = False
with tempfile.TemporaryDirectory() as tdir:
@@ -1924,6 +1963,55 @@ recommended as it can lead to undefined behaviour on some platforms''')
exe = os.path.join(self.builddir, 'main')
self.assertEqual(b'NDEBUG=0', subprocess.check_output(exe).strip())
+ def test_guessed_linker_dependencies(self):
+ '''
+ Test that meson adds dependencies for libraries based on the final
+ linker command line.
+ '''
+ # build library
+ testdirbase = os.path.join(self.unit_test_dir, '26 guessed linker dependencies')
+ testdirlib = os.path.join(testdirbase, 'lib')
+ extra_args = None
+ env = Environment(testdirlib, self.builddir, self.meson_command,
+ get_fake_options(self.prefix), [])
+ if env.detect_c_compiler(False).get_id() != 'msvc':
+ # static libraries are not linkable with -l with msvc because meson installs them
+ # as .a files which unix_args_to_native will not know as it expects libraries to use
+ # .lib as extension. For a DLL the import library is installed as .lib. Thus for msvc
+ # this tests needs to use shared libraries to test the path resolving logic in the
+ # dependency generation code path.
+ extra_args = ['--default-library', 'static']
+ self.init(testdirlib, extra_args=extra_args)
+ self.build()
+ self.install()
+ libbuilddir = self.builddir
+ installdir = self.installdir
+ libdir = os.path.join(self.installdir, self.prefix.lstrip('/').lstrip('\\'), 'lib')
+
+ # build user of library
+ self.new_builddir()
+ # replace is needed because meson mangles platform pathes passed via LDFLAGS
+ os.environ["LDFLAGS"] = '-L{}'.format(libdir.replace('\\', '/'))
+ self.init(os.path.join(testdirbase, 'exe'))
+ del os.environ["LDFLAGS"]
+ self.build()
+ self.assertBuildIsNoop()
+
+ # rebuild library
+ exebuilddir = self.builddir
+ self.installdir = installdir
+ self.builddir = libbuilddir
+ # Microsoft's compiler is quite smart about touching import libs on changes,
+ # so ensure that there is actually a change in symbols.
+ self.setconf('-Dmore_exports=true')
+ self.build()
+ self.install()
+ # no ensure_backend_detects_changes needed because self.setconf did that already
+
+ # assert user of library will be rebuild
+ self.builddir = exebuilddir
+ self.assertRebuiltTarget('app')
+
class FailureTests(BasePlatformTests):
'''
@@ -2523,8 +2611,8 @@ class LinuxlikeTests(BasePlatformTests):
def test_unity_subproj(self):
testdir = os.path.join(self.common_test_dir, '49 subproject')
self.init(testdir, extra_args='--unity=subprojects')
- self.assertPathExists(os.path.join(self.builddir, 'subprojects/sublib/sublib@@simpletest@exe/simpletest-unity.c'))
- self.assertPathExists(os.path.join(self.builddir, 'subprojects/sublib/sublib@@sublib@sha/sublib-unity.c'))
+ self.assertPathExists(os.path.join(self.builddir, 'subprojects/sublib/subprojects@sublib@@simpletest@exe/simpletest-unity.c'))
+ self.assertPathExists(os.path.join(self.builddir, 'subprojects/sublib/subprojects@sublib@@sublib@sha/sublib-unity.c'))
self.assertPathDoesNotExist(os.path.join(self.builddir, 'user@exe/user-unity.c'))
self.build()
@@ -2739,11 +2827,12 @@ cpu = 'armv7' # Not sure if correct.
endian = 'little'
''' % os.path.join(testdir, 'some_cross_tool.py'))
crossfile.flush()
- self.init(testdir, ['--cross-file=' + crossfile.name])
+ self.meson_cross_file = crossfile.name
+ self.init(testdir)
def test_reconfigure(self):
testdir = os.path.join(self.unit_test_dir, '13 reconfigure')
- self.init(testdir, ['-Db_lto=true'], default_args=False)
+ self.init(testdir, ['-Db_coverage=true'], default_args=False)
self.build('reconfigure')
def test_vala_generated_source_buildir_inside_source_tree(self):
@@ -2816,6 +2905,27 @@ endian = 'little'
self.assertTrue(os.path.isfile(test_exe))
subprocess.check_call(test_exe, env=myenv)
+ @unittest.skipIf(shutil.which('pkg-config') is None, 'Pkg-config not found.')
+ def test_pkgconfig_internal_libraries(self):
+ '''
+ '''
+ with tempfile.TemporaryDirectory() as tempdirname:
+ # build library
+ testdirbase = os.path.join(self.unit_test_dir, '28 pkgconfig use libraries')
+ testdirlib = os.path.join(testdirbase, 'lib')
+ self.init(testdirlib, extra_args=['--prefix=' + tempdirname,
+ '--libdir=lib',
+ '--default-library=static'], default_args=False)
+ self.build()
+ self.install(use_destdir=False)
+
+ # build user of library
+ pkg_dir = os.path.join(tempdirname, 'lib/pkgconfig')
+ os.environ['PKG_CONFIG_PATH'] = pkg_dir
+ self.new_builddir()
+ self.init(os.path.join(testdirbase, 'app'))
+ self.build()
+
class LinuxArmCrossCompileTests(BasePlatformTests):
'''
@@ -2824,7 +2934,7 @@ class LinuxArmCrossCompileTests(BasePlatformTests):
def setUp(self):
super().setUp()
src_root = os.path.dirname(__file__)
- self.meson_command += ['--cross=' + os.path.join(src_root, 'cross', 'ubuntu-armhf.txt')]
+ self.meson_cross_file = os.path.join(src_root, 'cross', 'ubuntu-armhf.txt')
def test_cflags_cross_environment_pollution(self):
'''
@@ -2838,6 +2948,21 @@ class LinuxArmCrossCompileTests(BasePlatformTests):
compdb = self.get_compdb()
self.assertNotIn('-DBUILD_ENVIRONMENT_ONLY', compdb[0]['command'])
+ def test_cross_file_overrides_always_args(self):
+ '''
+ Test that $lang_args in cross files always override get_always_args().
+ Needed for overriding the default -D_FILE_OFFSET_BITS=64 on some
+ architectures such as some Android versions and Raspbian.
+ https://github.com/mesonbuild/meson/issues/3049
+ https://github.com/mesonbuild/meson/issues/3089
+ '''
+ testdir = os.path.join(self.unit_test_dir, '29 cross file overrides always args')
+ self.meson_cross_file = os.path.join(self.unit_test_dir, 'ubuntu-armhf-overrides.txt')
+ self.init(testdir)
+ compdb = self.get_compdb()
+ self.assertRegex(compdb[0]['command'], '-D_FILE_OFFSET_BITS=64.*-U_FILE_OFFSET_BITS')
+ self.build()
+
class PythonTests(BasePlatformTests):
'''
diff --git a/test cases/common/112 has arg/meson.build b/test cases/common/112 has arg/meson.build
index 27290a1..ba07311 100644
--- a/test cases/common/112 has arg/meson.build
+++ b/test cases/common/112 has arg/meson.build
@@ -39,11 +39,17 @@ assert(l2.length() == 0, 'First supported did not return empty array.')
if cc.get_id() == 'gcc'
pre_arg = '-Wformat'
- anti_pre_arg = '-Wno-format'
+ # NOTE: We have special handling for -Wno-foo args because gcc silently
+ # ignores unknown -Wno-foo args unless you pass -Werror, so for this test, we
+ # pass it as two separate arguments.
+ anti_pre_arg = ['-W', 'no-format']
arg = '-Werror=format-security'
assert(not cc.has_multi_arguments([anti_pre_arg, arg]), 'Arg that should be broken is not.')
assert(cc.has_multi_arguments(pre_arg), 'Arg that should have worked does not work.')
assert(cc.has_multi_arguments([pre_arg, arg]), 'Arg that should have worked does not work.')
+ # Test that gcc correctly errors out on unknown -Wno flags
+ assert(not cc.has_argument('-Wno-lol-meson-test-flags'), 'should error out on unknown -Wno args')
+ assert(not cc.has_multi_arguments(['-Wno-pragmas', '-Wno-lol-meson-test-flags']), 'should error out even if some -Wno args are valid')
endif
if cc.get_id() == 'clang' and cc.version().version_compare('<=4.0.0')
diff --git a/test cases/common/13 pch/meson.build b/test cases/common/13 pch/meson.build
index 9ed6512..e144aa5 100644
--- a/test cases/common/13 pch/meson.build
+++ b/test cases/common/13 pch/meson.build
@@ -1,4 +1,10 @@
project('pch test', 'c')
+cc = meson.get_compiler('c')
+cc_id = cc.get_id()
+if cc_id == 'lcc'
+ error('MESON_SKIP_TEST: Elbrus compiler does not support PCH.')
+endif
+
exe = executable('prog', 'prog.c',
c_pch : ['pch/prog_pch.c', 'pch/prog.h'])
diff --git a/test cases/common/132 dependency file generation/meson.build b/test cases/common/132 dependency file generation/meson.build
index dcfdcd9..cd66cb7 100644
--- a/test cases/common/132 dependency file generation/meson.build
+++ b/test cases/common/132 dependency file generation/meson.build
@@ -1,11 +1,13 @@
project('dep file gen', 'c')
-cc_id = meson.get_compiler('c').get_id()
-if cc_id == 'intel'
- # ICC does not escape spaces in paths in the dependency file, so Ninja
+cc_id = meson.get_compiler('c').get_id()
+cc_ver = meson.get_compiler('c').version()
+
+if cc_id == 'intel' or (cc_id == 'lcc' and cc_ver.version_compare('<=1.23.08')
+ # ICC and LCC <= 1.23.08 do not escape spaces in paths in the dependency file, so Ninja
# (correctly) thinks that the rule has multiple outputs and errors out:
# 'depfile has multiple output paths'
- error('MESON_SKIP_TEST: Skipping test with Intel compiler because it generates broken dependency files')
+ error('MESON_SKIP_TEST: Skipping test because your compiler is known to generate broken dependency files')
endif
e = executable('main file', 'main .c')
diff --git a/test cases/common/142 compute int/config.h.in b/test cases/common/142 compute int/config.h.in
index ad8d077..0de63ab 100644
--- a/test cases/common/142 compute int/config.h.in
+++ b/test cases/common/142 compute int/config.h.in
@@ -1,2 +1,4 @@
#define INTSIZE @INTSIZE@
#define FOOBAR_IN_CONFIG_H @FOOBAR@
+#define MAXINT @MAXINT@
+#define MININT @MININT@
diff --git a/test cases/common/142 compute int/meson.build b/test cases/common/142 compute int/meson.build
index 43553fe..22bd266 100644
--- a/test cases/common/142 compute int/meson.build
+++ b/test cases/common/142 compute int/meson.build
@@ -7,11 +7,15 @@ cc = meson.get_compiler('c')
intsize = cc.compute_int('sizeof(int)', low : 1, high : 16, guess : 4)
foobar = cc.compute_int('FOOBAR_IN_FOOBAR_H', prefix : '#include "foobar.h"', include_directories : inc)
+maxint = cc.compute_int('INT_MAX', prefix: '#include <limits.h>')
+minint = cc.compute_int('INT_MIN', prefix: '#include <limits.h>')
cd = configuration_data()
cd.set('INTSIZE', intsize)
cd.set('FOOBAR', foobar)
cd.set('CONFIG', 'config.h')
+cd.set('MAXINT', maxint)
+cd.set('MININT', minint)
configure_file(input : 'config.h.in', output : 'config.h', configuration : cd)
s = configure_file(input : 'prog.c.in', output : 'prog.c', configuration : cd)
@@ -23,11 +27,15 @@ cpp = meson.get_compiler('cpp')
intsize = cpp.compute_int('sizeof(int)')
foobar = cpp.compute_int('FOOBAR_IN_FOOBAR_H', prefix : '#include "foobar.h"', include_directories : inc)
+maxint = cpp.compute_int('INT_MAX', prefix: '#include <limits.h>')
+minint = cpp.compute_int('INT_MIN', prefix: '#include <limits.h>')
cdpp = configuration_data()
cdpp.set('INTSIZE', intsize)
cdpp.set('FOOBAR', foobar)
cdpp.set('CONFIG', 'config.hpp')
+cdpp.set('MAXINT', maxint)
+cdpp.set('MININT', minint)
configure_file(input : 'config.h.in', output : 'config.hpp', configuration : cdpp)
spp = configure_file(input : 'prog.c.in', output : 'prog.cc', configuration : cdpp)
diff --git a/test cases/common/142 compute int/prog.c.in b/test cases/common/142 compute int/prog.c.in
index 3ff1463..ff1ad55 100644
--- a/test cases/common/142 compute int/prog.c.in
+++ b/test cases/common/142 compute int/prog.c.in
@@ -1,6 +1,7 @@
#include "@CONFIG@"
#include <stdio.h>
#include <wchar.h>
+#include <limits.h>
#include "foobar.h"
int main(int argc, char **argv) {
@@ -12,5 +13,13 @@ int main(int argc, char **argv) {
fprintf(stderr, "Mismatch: computed int %d, should be %d.\n", FOOBAR_IN_CONFIG_H, FOOBAR_IN_FOOBAR_H);
return 1;
}
+ if(MAXINT != INT_MAX) {
+ fprintf(stderr, "Mismatch: computed max int %d, should be %d.\n", MAXINT, INT_MAX);
+ return 1;
+ }
+ if(MININT != INT_MIN) {
+ fprintf(stderr, "Mismatch: computed min int %d, should be %d.\n", MININT, INT_MIN);
+ return 1;
+ }
return 0;
}
diff --git a/test cases/common/16 configure file/config7.h.in b/test cases/common/16 configure file/config7.h.in
new file mode 100644
index 0000000..edd0bb3
--- /dev/null
+++ b/test cases/common/16 configure file/config7.h.in
@@ -0,0 +1,16 @@
+/* No escape */
+#define MESSAGE1 "${var1}"
+
+/* Single escape means no replace */
+#define MESSAGE2 "\${var1}"
+
+/* Replace pairs of escapes before '@' or '\@' with escape characters
+ * (note we have to double number of pairs due to C string escaping)
+ */
+#define MESSAGE3 "\\\\${var1}"
+
+/* Pairs of escapes and then single escape to avoid replace */
+#define MESSAGE4 "\\\\\${var1}"
+
+/* Check escape character outside variables */
+#define MESSAGE5 "\\ ${ \${ \\\\${ \\\\\${"
diff --git a/test cases/common/16 configure file/meson.build b/test cases/common/16 configure file/meson.build
index 71a2563..5c3a1a5 100644
--- a/test cases/common/16 configure file/meson.build
+++ b/test cases/common/16 configure file/meson.build
@@ -137,3 +137,15 @@ cfile = configure_file(input : 'config.h.in',
output : 'do_not_get_installed.h',
install_dir : '',
configuration : conf)
+
+# Test escaping with cmake format
+conf7 = configuration_data()
+conf7.set('var1', 'foo')
+conf7.set('var2', 'bar')
+configure_file(
+ input : 'config7.h.in',
+ output : '@BASENAME@',
+ format : 'cmake',
+ configuration : conf7
+)
+test('test7', executable('prog7', 'prog7.c'))
diff --git a/test cases/common/16 configure file/prog7.c b/test cases/common/16 configure file/prog7.c
new file mode 100644
index 0000000..0bb7d13
--- /dev/null
+++ b/test cases/common/16 configure file/prog7.c
@@ -0,0 +1,10 @@
+#include <string.h>
+#include <config7.h>
+
+int main(int argc, char **argv) {
+ return strcmp(MESSAGE1, "foo")
+ || strcmp(MESSAGE2, "${var1}")
+ || strcmp(MESSAGE3, "\\foo")
+ || strcmp(MESSAGE4, "\\${var1}")
+ || strcmp(MESSAGE5, "\\ ${ ${ \\${ \\${");
+}
diff --git a/test cases/common/168 disabler/meson.build b/test cases/common/168 disabler/meson.build
index 7ca82b7..1956cd3 100644
--- a/test cases/common/168 disabler/meson.build
+++ b/test cases/common/168 disabler/meson.build
@@ -21,7 +21,7 @@ else
number = 2
endif
-assert(d == 0, 'Plain if handled incorrectly, value should be 0 but is @0@'.format(number))
+assert(number == 0, 'Plain if handled incorrectly, value should be 0 but is @0@'.format(number))
if d.found()
number = 1
@@ -29,6 +29,6 @@ else
number = 2
endif
-assert(d == 1, 'If found handled incorrectly, value should be 1 but is @0@'.format(number))
+assert(number == 2, 'If found handled incorrectly, value should be 2 but is @0@'.format(number))
diff --git a/test cases/failing/17 same name/file.c b/test cases/common/183 same target name/file.c
index 6f1c172..6f1c172 100644
--- a/test cases/failing/17 same name/file.c
+++ b/test cases/common/183 same target name/file.c
diff --git a/test cases/failing/17 same name/meson.build b/test cases/common/183 same target name/meson.build
index 4e585d5..4e585d5 100644
--- a/test cases/failing/17 same name/meson.build
+++ b/test cases/common/183 same target name/meson.build
diff --git a/test cases/failing/17 same name/sub/file2.c b/test cases/common/183 same target name/sub/file2.c
index a5e453d..a5e453d 100644
--- a/test cases/failing/17 same name/sub/file2.c
+++ b/test cases/common/183 same target name/sub/file2.c
diff --git a/test cases/failing/17 same name/sub/meson.build b/test cases/common/183 same target name/sub/meson.build
index 610a4a3..610a4a3 100644
--- a/test cases/failing/17 same name/sub/meson.build
+++ b/test cases/common/183 same target name/sub/meson.build
diff --git a/test cases/common/189 same target name flat layout/foo.c b/test cases/common/189 same target name flat layout/foo.c
new file mode 100644
index 0000000..ed42789
--- /dev/null
+++ b/test cases/common/189 same target name flat layout/foo.c
@@ -0,0 +1 @@
+int meson_test_main_foo(void) { return 10; }
diff --git a/test cases/common/189 same target name flat layout/main.c b/test cases/common/189 same target name flat layout/main.c
new file mode 100644
index 0000000..6f02aeb
--- /dev/null
+++ b/test cases/common/189 same target name flat layout/main.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+int meson_test_main_foo(void);
+int meson_test_subproj_foo(void);
+
+int main(void) {
+ if (meson_test_main_foo() != 10) {
+ printf("Failed meson_test_main_foo\n");
+ return 1;
+ }
+ if (meson_test_subproj_foo() != 20) {
+ printf("Failed meson_test_subproj_foo\n");
+ return 1;
+ }
+ return 0;
+}
diff --git a/test cases/common/189 same target name flat layout/meson.build b/test cases/common/189 same target name flat layout/meson.build
new file mode 100644
index 0000000..a3c95fa
--- /dev/null
+++ b/test cases/common/189 same target name flat layout/meson.build
@@ -0,0 +1,11 @@
+project('subdir targets', 'c')
+
+# Idea behind this test is to create targets with identical name
+# but different output files. We can do this by choosing different
+# name_prefix of libraries. Target id does not depend on name_prefix.
+
+main_foo = static_library('foo', 'foo.c', name_prefix : 'main')
+subdir('subdir') # defines subdir_foo
+
+exe = executable('prog', 'main.c', link_with : [main_foo, subdir_foo])
+test('main test', exe)
diff --git a/test cases/common/189 same target name flat layout/subdir/foo.c b/test cases/common/189 same target name flat layout/subdir/foo.c
new file mode 100644
index 0000000..f334292
--- /dev/null
+++ b/test cases/common/189 same target name flat layout/subdir/foo.c
@@ -0,0 +1 @@
+int meson_test_subproj_foo(void) { return 20; }
diff --git a/test cases/common/189 same target name flat layout/subdir/meson.build b/test cases/common/189 same target name flat layout/subdir/meson.build
new file mode 100644
index 0000000..223a5ef
--- /dev/null
+++ b/test cases/common/189 same target name flat layout/subdir/meson.build
@@ -0,0 +1 @@
+subdir_foo = static_library('foo', 'foo.c', name_prefix : 'subdir')
diff --git a/test cases/common/190 escape and unicode/file.c.in b/test cases/common/190 escape and unicode/file.c.in
new file mode 100644
index 0000000..413ed42
--- /dev/null
+++ b/test cases/common/190 escape and unicode/file.c.in
@@ -0,0 +1,5 @@
+#include<stdio.h>
+const char* does_it_work() {
+ printf("{NAME}\n");
+ return "yes it does";
+}
diff --git a/test cases/common/190 escape and unicode/file.py b/test cases/common/190 escape and unicode/file.py
new file mode 100644
index 0000000..af67a09
--- /dev/null
+++ b/test cases/common/190 escape and unicode/file.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python3
+
+import sys
+import os
+
+with open(sys.argv[1]) as fh:
+ content = fh.read().replace("{NAME}", sys.argv[2])
+
+with open(os.path.join(sys.argv[3]), 'w') as fh:
+ fh.write(content)
diff --git a/test cases/common/190 escape and unicode/find.py b/test cases/common/190 escape and unicode/find.py
new file mode 100644
index 0000000..34a3eb8
--- /dev/null
+++ b/test cases/common/190 escape and unicode/find.py
@@ -0,0 +1,9 @@
+#!/usr/bin/env python3
+
+import os
+import sys
+
+for fh in os.listdir('.'):
+ if os.path.isfile(fh):
+ if fh.endswith('.c'):
+ sys.stdout.write(fh + '\0')
diff --git a/test cases/common/190 escape and unicode/fun.c b/test cases/common/190 escape and unicode/fun.c
new file mode 100644
index 0000000..8eeb8ea
--- /dev/null
+++ b/test cases/common/190 escape and unicode/fun.c
@@ -0,0 +1,3 @@
+int a_fun() {
+ return 1;
+}
diff --git a/test cases/common/190 escape and unicode/main.c b/test cases/common/190 escape and unicode/main.c
new file mode 100644
index 0000000..0bcde16
--- /dev/null
+++ b/test cases/common/190 escape and unicode/main.c
@@ -0,0 +1,12 @@
+#include <string.h>
+
+const char* does_it_work();
+
+int a_fun();
+
+int main() {
+ if(strcmp(does_it_work(), "yes it does") != 0) {
+ return -a_fun();
+ }
+ return 0;
+}
diff --git a/test cases/common/190 escape and unicode/meson.build b/test cases/common/190 escape and unicode/meson.build
new file mode 100644
index 0000000..65377b6
--- /dev/null
+++ b/test cases/common/190 escape and unicode/meson.build
@@ -0,0 +1,24 @@
+project('180 escape', 'c')
+
+gen = generator(find_program('file.py'), arguments:['@INPUT@', 'erd\u0151', '@OUTPUT@'], output: '@BASENAME@')
+
+gen_file = gen.process('file.c.in')
+
+find_file_list = run_command(find_program('find.py'))
+assert(find_file_list.returncode() == 0, 'Didn\'t find any files.')
+
+# Strings should support both octal \ooo and hex \xhh encodings
+
+found_files_oct = []
+foreach l : find_file_list.stdout().strip('\0').split('\000')
+ found_files_oct += [files(l)]
+endforeach
+
+test('first', executable('first', found_files_oct + [gen_file]))
+
+found_files_hex = []
+foreach l : find_file_list.stdout().strip('\x00').split('\x00')
+ found_files_hex += [files(l)]
+endforeach
+
+test('second', executable('second', found_files_hex + [gen_file]))
diff --git a/test cases/common/190 find override/meson.build b/test cases/common/190 find override/meson.build
new file mode 100644
index 0000000..3b8af80
--- /dev/null
+++ b/test cases/common/190 find override/meson.build
@@ -0,0 +1,12 @@
+project('find program override', 'c')
+
+gencodegen = find_program('gencodegen', required : false)
+
+assert(not gencodegen.found(), 'gencodegen is an internal program, should not be found')
+
+# Test the check-if-found-else-override workflow
+if not gencodegen.found()
+ subdir('subdir')
+endif
+
+subdir('otherdir')
diff --git a/test cases/common/190 find override/otherdir/main.c b/test cases/common/190 find override/otherdir/main.c
new file mode 100644
index 0000000..2cef67c
--- /dev/null
+++ b/test cases/common/190 find override/otherdir/main.c
@@ -0,0 +1,5 @@
+int be_seeing_you();
+
+int main(int argc, char **argv) {
+ return be_seeing_you() == 6 ? 0 : 1;
+}
diff --git a/test cases/common/190 find override/otherdir/main2.c b/test cases/common/190 find override/otherdir/main2.c
new file mode 100644
index 0000000..6d71688
--- /dev/null
+++ b/test cases/common/190 find override/otherdir/main2.c
@@ -0,0 +1,5 @@
+int number_returner();
+
+int main(int argc, char **argv) {
+ return number_returner() == 100 ? 0 : 1;
+}
diff --git a/test cases/common/190 find override/otherdir/meson.build b/test cases/common/190 find override/otherdir/meson.build
new file mode 100644
index 0000000..dc41f5b
--- /dev/null
+++ b/test cases/common/190 find override/otherdir/meson.build
@@ -0,0 +1,26 @@
+gen = find_program('codegen') # Should use overridden value set in "subdir".
+
+src = custom_target('arrival',
+ input : 'source.desc',
+ output : 'file.c',
+ command : [gen, '@INPUT@', '@OUTPUT@']
+ )
+
+e = executable('six', 'main.c', src)
+
+test('six', e)
+
+# The same again, but this time with a program that was genererated
+# with configure_file.
+
+gen = find_program('gencodegen')
+
+src = custom_target('hundred',
+ input : 'source2.desc',
+ output : 'file2.c',
+ command : [gen, '@INPUT@', '@OUTPUT@']
+ )
+
+e = executable('hundred', 'main2.c', src)
+
+test('hundred', e)
diff --git a/test cases/common/190 find override/otherdir/source.desc b/test cases/common/190 find override/otherdir/source.desc
new file mode 100644
index 0000000..8b19c9c
--- /dev/null
+++ b/test cases/common/190 find override/otherdir/source.desc
@@ -0,0 +1 @@
+be_seeing_you
diff --git a/test cases/common/190 find override/otherdir/source2.desc b/test cases/common/190 find override/otherdir/source2.desc
new file mode 100644
index 0000000..965f868
--- /dev/null
+++ b/test cases/common/190 find override/otherdir/source2.desc
@@ -0,0 +1 @@
+number_returner
diff --git a/test cases/common/190 find override/subdir/converter.py b/test cases/common/190 find override/subdir/converter.py
new file mode 100755
index 0000000..ee2ff85
--- /dev/null
+++ b/test cases/common/190 find override/subdir/converter.py
@@ -0,0 +1,15 @@
+#!/usr/bin/env python3
+
+import sys
+import pathlib
+
+[ifilename, ofilename] = sys.argv[1:3]
+
+ftempl = '''int %s() {
+ return 6;
+}
+'''
+
+d = pathlib.Path(ifilename).read_text().split('\n')[0].strip()
+
+pathlib.Path(ofilename).write_text(ftempl % d)
diff --git a/test cases/common/190 find override/subdir/gencodegen.py.in b/test cases/common/190 find override/subdir/gencodegen.py.in
new file mode 100755
index 0000000..57d9c40
--- /dev/null
+++ b/test cases/common/190 find override/subdir/gencodegen.py.in
@@ -0,0 +1,15 @@
+#!/usr/bin/env python3
+
+import sys
+import pathlib
+
+[ifilename, ofilename] = sys.argv[1:3]
+
+ftempl = '''int %s() {
+ return @NUMBER@;
+}
+'''
+
+d = pathlib.Path(ifilename).read_text().split('\n')[0].strip()
+
+pathlib.Path(ofilename).write_text(ftempl % d)
diff --git a/test cases/common/190 find override/subdir/meson.build b/test cases/common/190 find override/subdir/meson.build
new file mode 100644
index 0000000..e5de34d
--- /dev/null
+++ b/test cases/common/190 find override/subdir/meson.build
@@ -0,0 +1,14 @@
+x = find_program('converter.py')
+
+meson.override_find_program('codegen', x)
+
+# Override a command with a generated script
+
+cdata = configuration_data()
+
+cdata.set('NUMBER', 100)
+numprog = configure_file(input : 'gencodegen.py.in',
+ output : 'gencodegen.py',
+ configuration : cdata)
+
+meson.override_find_program('gencodegen', numprog)
diff --git a/test cases/common/190 openmp/main.c b/test cases/common/190 openmp/main.c
new file mode 100644
index 0000000..cc81f48
--- /dev/null
+++ b/test cases/common/190 openmp/main.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+#include <omp.h>
+
+int main(void) {
+#ifdef _OPENMP
+ if (omp_get_max_threads() == 2) {
+ return 0;
+ } else {
+ printf("Max threads is %d not 2.\n", omp_get_max_threads());
+ return 1;
+ }
+#else
+ printf("_OPENMP is not defined; is OpenMP compilation working?\n");
+ return 1;
+#endif
+}
diff --git a/test cases/common/190 openmp/main.cpp b/test cases/common/190 openmp/main.cpp
new file mode 100644
index 0000000..b12be3f
--- /dev/null
+++ b/test cases/common/190 openmp/main.cpp
@@ -0,0 +1,16 @@
+#include <iostream>
+#include <omp.h>
+
+int main(void) {
+#ifdef _OPENMP
+ if (omp_get_max_threads() == 2) {
+ return 0;
+ } else {
+ std::cout << "Max threads is " << omp_get_max_threads() << " not 2." << std::endl;
+ return 1;
+ }
+#else
+ printf("_OPENMP is not defined; is OpenMP compilation working?\n");
+ return 1;
+#endif
+}
diff --git a/test cases/common/190 openmp/main.f90 b/test cases/common/190 openmp/main.f90
new file mode 100644
index 0000000..c062d86
--- /dev/null
+++ b/test cases/common/190 openmp/main.f90
@@ -0,0 +1,8 @@
+program main
+ if (omp_get_max_threads() .eq. 2) then
+ stop 0
+ else
+ print *, 'Max threads is', omp_get_max_threads(), 'not 2.'
+ stop 1
+ endif
+end program main
diff --git a/test cases/common/190 openmp/meson.build b/test cases/common/190 openmp/meson.build
new file mode 100644
index 0000000..a05ca59
--- /dev/null
+++ b/test cases/common/190 openmp/meson.build
@@ -0,0 +1,40 @@
+project('openmp', 'c', 'cpp')
+
+cc = meson.get_compiler('c')
+if cc.get_id() == 'gcc' and cc.version().version_compare('<4.2.0')
+ error('MESON_SKIP_TEST gcc is too old to support OpenMP.')
+endif
+if cc.get_id() == 'clang' and cc.version().version_compare('<3.7.0')
+ error('MESON_SKIP_TEST clang is too old to support OpenMP.')
+endif
+if cc.get_id() == 'msvc' and cc.version().version_compare('<17')
+ error('MESON_SKIP_TEST msvc is too old to support OpenMP.')
+endif
+if host_machine.system() == 'darwin'
+ error('MESON_SKIP_TEST macOS does not support OpenMP.')
+endif
+
+openmp = dependency('openmp')
+
+exec = executable('exec',
+ 'main.c',
+ dependencies : [openmp])
+
+execpp = executable('execpp',
+ 'main.cpp',
+ dependencies : [openmp])
+
+env = environment()
+env.set('OMP_NUM_THREADS', '2')
+
+test('OpenMP C', exec, env : env)
+test('OpenMP C++', execpp, env : env)
+
+
+if add_languages('fortran', required : false)
+ exef = executable('exef',
+ 'main.f90',
+ dependencies : [openmp])
+
+ test('OpenMP Fortran', execpp, env : env)
+endif
diff --git a/test cases/common/22 header in file list/meson.build b/test cases/common/22 header in file list/meson.build
index cc30c71..ff42cc4 100644
--- a/test cases/common/22 header in file list/meson.build
+++ b/test cases/common/22 header in file list/meson.build
@@ -1,4 +1,14 @@
project('header in file list', 'c')
+cc_id = meson.get_compiler('c').get_id()
+cc_ver = meson.get_compiler('c').version()
+
+if cc_id == 'intel' or (cc_id == 'lcc' and cc_ver.version_compare('<=1.23.08')
+ # ICC and LCC <= 1.23.08 do not escape spaces in paths in the dependency file, so Ninja
+ # (correctly) thinks that the rule has multiple outputs and errors out:
+ # 'depfile has multiple output paths'
+ error('MESON_SKIP_TEST: Skipping test because your compiler is known to generate broken dependency files')
+endif
+
exe = executable('prog', 'prog.c', 'header.h')
test('basic', exe)
diff --git a/test cases/common/33 try compile/meson.build b/test cases/common/33 try compile/meson.build
index 09ca395..cb1037d 100644
--- a/test cases/common/33 try compile/meson.build
+++ b/test cases/common/33 try compile/meson.build
@@ -1,11 +1,11 @@
project('try compile', 'c', 'cpp')
code = '''#include<stdio.h>
-void func() { printf("Something.\n"); }
+void func() { printf("Something.\\n"); }
'''
breakcode = '''#include<nonexisting.h>
-void func() { printf("This won't work.\n"); }
+void func() { printf("This won't work.\\n"); }
'''
foreach compiler : [meson.get_compiler('c'), meson.get_compiler('cpp')]
diff --git a/test cases/common/39 tryrun/meson.build b/test cases/common/39 tryrun/meson.build
index c64446f..daf5be7 100644
--- a/test cases/common/39 tryrun/meson.build
+++ b/test cases/common/39 tryrun/meson.build
@@ -13,8 +13,8 @@ endif
ok_code = '''#include<stdio.h>
int main(int argc, char **argv) {
- printf("%s\n", "stdout");
- fprintf(stderr, "%s\n", "stderr");
+ printf("%s\\n", "stdout");
+ fprintf(stderr, "%s\\n", "stderr");
return 0;
}
'''
diff --git a/test cases/common/42 string operations/meson.build b/test cases/common/42 string operations/meson.build
index a43de70..1c289eb 100644
--- a/test cases/common/42 string operations/meson.build
+++ b/test cases/common/42 string operations/meson.build
@@ -77,21 +77,21 @@ assert('"1.1.20"'.strip('"') == '1.1.20', '" badly stripped')
assert('"1.1.20"'.strip('".') == '1.1.20', '". badly stripped')
assert('"1.1.20" '.strip('" ') == '1.1.20', '". badly stripped')
-bs_b = '''\b'''
-bs_bs_b = '''\\b'''
+bs_c = '''\c'''
+bs_bs_c = '''\\\c'''
nl = '''
'''
-bs_n = '''\n'''
+bs_n = '''\\n'''
bs_nl = '''\
'''
-bs_bs_n = '''\\n'''
-bs_bs_nl = '''\\
+bs_bs_n = '''\\\\n'''
+bs_bs_nl = '''\\\\
'''
-assert('\b' == bs_b, 'Single backslash broken')
-assert('\\b' == bs_b, 'Double backslash broken')
-assert('\\\b' == bs_bs_b, 'Three backslash broken')
-assert('\\\\b' == bs_bs_b, 'Four backslash broken')
+assert('\c' == bs_c, 'Single backslash broken')
+assert('\\c' == bs_c, 'Double backslash broken')
+assert('\\\c' == bs_bs_c, 'Three backslash broken')
+assert('\\\\c' == bs_bs_c, 'Four backslash broken')
assert('\n' == nl, 'Newline escape broken')
assert('\\n' == bs_n, 'Double backslash broken before n')
assert('\\\n' == bs_nl, 'Three backslash broken before n')
diff --git a/test cases/common/51 pkgconfig-gen/dependencies/meson.build b/test cases/common/51 pkgconfig-gen/dependencies/meson.build
index d13f009..047e7e7 100644
--- a/test cases/common/51 pkgconfig-gen/dependencies/meson.build
+++ b/test cases/common/51 pkgconfig-gen/dependencies/meson.build
@@ -5,12 +5,13 @@ pkgg = import('pkgconfig')
# libmain internally use libinternal and expose libexpose in its API
exposed_lib = shared_library('libexposed', 'exposed.c')
internal_lib = shared_library('libinternal', 'internal.c')
-main_lib = static_library('libmain', link_with : [exposed_lib, internal_lib])
+main_lib = both_libraries('libmain', link_with : [exposed_lib, internal_lib])
pkgg.generate(exposed_lib)
# Declare a few different Dependency objects
pc_dep = dependency('libfoo', version : '>=1.0')
+pc_dep_dup = dependency('libfoo', version : '>= 1.0')
notfound_dep = dependency('notfound', required : false)
threads_dep = dependency('threads')
custom_dep = declare_dependency(link_args : ['-lcustom'], compile_args : ['-DCUSTOM'])
@@ -24,9 +25,10 @@ custom2_dep = declare_dependency(link_args : ['-lcustom2'], compile_args : ['-DC
# - Having custom_dep in libraries and libraries_private should only add it in Libs
# - Having custom2_dep in libraries_private should not add its Cflags
# - Having pc_dep in libraries_private should add it in Requires.private
+# - pc_dep_dup is the same library and same version, should be ignored
# - notfound_dep is not required so it shouldn't appear in the pc file.
pkgg.generate(libraries : [main_lib, exposed_lib, threads_dep , custom_dep],
- libraries_private : [custom_dep, custom2_dep, pc_dep, notfound_dep],
+ libraries_private : [custom_dep, custom2_dep, pc_dep, pc_dep_dup, notfound_dep],
version : '1.0',
name : 'dependency-test',
filebase : 'dependency-test',
diff --git a/test cases/common/64 custom header generator/meson.build b/test cases/common/64 custom header generator/meson.build
index 33ba4c5..2279513 100644
--- a/test cases/common/64 custom header generator/meson.build
+++ b/test cases/common/64 custom header generator/meson.build
@@ -1,5 +1,15 @@
project('custom header generator', 'c')
+cc_id = meson.get_compiler('c').get_id()
+cc_ver = meson.get_compiler('c').version()
+
+if cc_id == 'intel' or (cc_id == 'lcc' and cc_ver.version_compare('<=1.23.08')
+ # ICC and LCC <= 1.23.08 do not escape spaces in paths in the dependency file, so Ninja
+ # (correctly) thinks that the rule has multiple outputs and errors out:
+ # 'depfile has multiple output paths'
+ error('MESON_SKIP_TEST: Skipping test because your compiler is known to generate broken dependency files')
+endif
+
gen = find_program('makeheader.py')
generated_h = custom_target('makeheader.py',
diff --git a/test cases/failing/17 same target/file.c b/test cases/failing/17 same target/file.c
new file mode 100644
index 0000000..7412372
--- /dev/null
+++ b/test cases/failing/17 same target/file.c
@@ -0,0 +1 @@
+int func() { return 0; }
diff --git a/test cases/failing/17 same target/meson.build b/test cases/failing/17 same target/meson.build
new file mode 100644
index 0000000..ee586d0
--- /dev/null
+++ b/test cases/failing/17 same target/meson.build
@@ -0,0 +1,4 @@
+project('same target', 'c')
+
+static_library('foo', 'file.c')
+static_library('foo', 'file.c')
diff --git a/test cases/failing/72 invalid escape char/meson.build b/test cases/failing/72 invalid escape char/meson.build
new file mode 100644
index 0000000..b4e9196
--- /dev/null
+++ b/test cases/failing/72 invalid escape char/meson.build
@@ -0,0 +1,4 @@
+# Make sure meson exits on invalid string
+# The string below contains an invalid unicode code point
+
+'my name is what \uxyzo who are you'
diff --git a/test cases/failing/72 override used/meson.build b/test cases/failing/72 override used/meson.build
new file mode 100644
index 0000000..61885bb
--- /dev/null
+++ b/test cases/failing/72 override used/meson.build
@@ -0,0 +1,5 @@
+project('overridde an already found exe', 'c')
+
+old = find_program('something.py')
+replacement = find_program('other.py')
+meson.override_find_program('something.py', replacement)
diff --git a/test cases/failing/72 override used/other.py b/test cases/failing/72 override used/other.py
new file mode 100755
index 0000000..f62ba96
--- /dev/null
+++ b/test cases/failing/72 override used/other.py
@@ -0,0 +1,3 @@
+#!/usr/bin/env python3
+
+print('Doing something else.')
diff --git a/test cases/failing/72 override used/something.py b/test cases/failing/72 override used/something.py
new file mode 100755
index 0000000..64c9454
--- /dev/null
+++ b/test cases/failing/72 override used/something.py
@@ -0,0 +1,3 @@
+#!/usr/bin/env python3
+
+print('Doing something.')
diff --git a/test cases/failing/73 dual override/meson.build b/test cases/failing/73 dual override/meson.build
new file mode 100644
index 0000000..e5f86ba
--- /dev/null
+++ b/test cases/failing/73 dual override/meson.build
@@ -0,0 +1,5 @@
+project('yo dawg', 'c')
+
+p = find_program('overrides.py')
+meson.override_find_program('override', p)
+meson.override_find_program('override', p)
diff --git a/test cases/failing/73 dual override/overrides.py b/test cases/failing/73 dual override/overrides.py
new file mode 100644
index 0000000..49e9b7a
--- /dev/null
+++ b/test cases/failing/73 dual override/overrides.py
@@ -0,0 +1,4 @@
+#!/usr/bin/env python3
+
+print('Yo dawg, we put overrides in your overrides,')
+print('so now you can override when you override.')
diff --git a/test cases/frameworks/4 qt/meson.build b/test cases/frameworks/4 qt/meson.build
index b508df3..e8d12b6 100644
--- a/test cases/frameworks/4 qt/meson.build
+++ b/test cases/frameworks/4 qt/meson.build
@@ -56,7 +56,7 @@ foreach qt : ['qt4', 'qt5']
endif
# Test that setting a unique name with a positional argument works
- qtmodule.preprocess(qt + 'teststuff', qresources : ['stuff.qrc', 'stuff2.qrc'], method : get_option('method'))
+ qtmodule.preprocess(qt + 'teststuff', qresources : files(['stuff.qrc', 'stuff2.qrc']), method : get_option('method'))
qexe = executable(qt + 'app',
sources : ['main.cpp', 'mainWindow.cpp', # Sources that don't need preprocessing.
diff --git a/test cases/frameworks/4 qt/subfolder/generator.py b/test cases/frameworks/4 qt/subfolder/generator.py
new file mode 100644
index 0000000..045d99a
--- /dev/null
+++ b/test cases/frameworks/4 qt/subfolder/generator.py
@@ -0,0 +1,6 @@
+#!/usr/bin/env python3
+import sys
+
+if len(sys.argv) > 1:
+ with open(sys.argv[1], "w") as output:
+ output.write("Hello World")
diff --git a/test cases/frameworks/4 qt/subfolder/main.cpp b/test cases/frameworks/4 qt/subfolder/main.cpp
index 61cc9d4..9661811 100644
--- a/test cases/frameworks/4 qt/subfolder/main.cpp
+++ b/test cases/frameworks/4 qt/subfolder/main.cpp
@@ -1,9 +1,28 @@
#include <QImage>
+#include <QFile>
+#include <QString>
int main(int argc, char **argv) {
+ #ifndef UNITY_BUILD
Q_INIT_RESOURCE(stuff3);
- QImage qi(":/thing.png");
- if(qi.width() != 640) {
+ Q_INIT_RESOURCE(stuff4);
+ #endif
+
+ for(auto fname:{":/thing.png", ":/thing4.png"})
+ {
+ QImage img1(fname);
+ if(img1.width() != 640) {
+ return 1;
+ }
+ }
+
+ for(auto fname:{":/txt_resource.txt",":/txt_resource2.txt"})
+ {
+ QFile file(fname);
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
+ return 1;
+ QString line = file.readLine();
+ if(line.compare("Hello World"))
return 1;
}
return 0;
diff --git a/test cases/frameworks/4 qt/subfolder/meson.build b/test cases/frameworks/4 qt/subfolder/meson.build
index d3ff609..f1b84e6 100644
--- a/test cases/frameworks/4 qt/subfolder/meson.build
+++ b/test cases/frameworks/4 qt/subfolder/meson.build
@@ -1,4 +1,32 @@
-qresources = qtmodule.preprocess(qresources : 'resources/stuff3.qrc')
+simple_gen = find_program('generator.py', required : true)
-app = executable('subfolder', 'main.cpp', qresources, dependencies : qtdep)
+txt_resource = custom_target('txt_resource',
+ output : 'txt_resource.txt',
+ command : [simple_gen, '@OUTPUT@'],
+)
+
+cfg = configuration_data()
+
+cfg.set('filepath', meson.current_source_dir()+'/../thing2.png')
+cfg.set('txt_resource', txt_resource.full_path())
+# here we abuse the system by guessing build dir layout
+cfg.set('txt_resource2', 'txt_resource.txt')
+
+
+rc_file = configure_file(
+ configuration : cfg,
+ input : 'resources/stuff4.qrc.in',
+ output : 'stuff4.qrc',
+)
+
+extra_cpp_args = []
+if meson.is_unity()
+ extra_cpp_args += '-DUNITY_BUILD'
+ qresources = qtmodule.preprocess(qt + '_subfolder_unity_ressource',qresources : ['resources/stuff3.qrc', rc_file])
+else
+ qresources = qtmodule.preprocess(qresources : ['resources/stuff3.qrc', rc_file])
+endif
+
+app = executable('subfolder', 'main.cpp', qresources, dependencies : qtdep, cpp_args: extra_cpp_args)
+test(qt + 'subfolder', app)
diff --git a/test cases/frameworks/4 qt/subfolder/resources/stuff4.qrc.in b/test cases/frameworks/4 qt/subfolder/resources/stuff4.qrc.in
new file mode 100644
index 0000000..c30a358
--- /dev/null
+++ b/test cases/frameworks/4 qt/subfolder/resources/stuff4.qrc.in
@@ -0,0 +1,8 @@
+<!DOCTYPE RCC>
+<RCC version="1.0">
+ <qresource>
+ <file alias="thing4.png">@filepath@</file>
+ <file alias="txt_resource.txt">@txt_resource@</file>
+ <file alias="txt_resource2.txt">@txt_resource2@</file>
+ </qresource>
+</RCC>
diff --git a/test cases/frameworks/7 gnome/gdbus/meson.build b/test cases/frameworks/7 gnome/gdbus/meson.build
index ea91caa..57d7f23 100644
--- a/test cases/frameworks/7 gnome/gdbus/meson.build
+++ b/test cases/frameworks/7 gnome/gdbus/meson.build
@@ -1,3 +1,12 @@
+gdbus_src = gnome.gdbus_codegen('generated-gdbus-no-docbook', 'com.example.Sample.xml',
+ interface_prefix : 'com.example.',
+ namespace : 'Sample',
+ annotations : [
+ ['com.example.Hello()', 'org.freedesktop.DBus.Deprecated', 'true']
+ ],
+)
+assert(gdbus_src.length() == 2, 'expected 2 targets')
+
gdbus_src = gnome.gdbus_codegen('generated-gdbus', 'com.example.Sample.xml',
interface_prefix : 'com.example.',
namespace : 'Sample',
@@ -6,6 +15,7 @@ gdbus_src = gnome.gdbus_codegen('generated-gdbus', 'com.example.Sample.xml',
],
docbook : 'generated-gdbus-doc'
)
+assert(gdbus_src.length() == 3, 'expected 3 targets')
gdbus_exe = executable('gdbus-test', 'gdbusprog.c',
gdbus_src,
diff --git a/test cases/frameworks/7 gnome/installed_files.txt b/test cases/frameworks/7 gnome/installed_files.txt
index c7c704f..ac132ef 100644
--- a/test cases/frameworks/7 gnome/installed_files.txt
+++ b/test cases/frameworks/7 gnome/installed_files.txt
@@ -1,6 +1,7 @@
usr/include/enums.h
usr/include/enums2.h
usr/include/enums3.h
+usr/include/enums5.h
usr/include/marshaller.h
usr/lib/?libgir_lib.so
usr/lib/?libdep1lib.so
diff --git a/test cases/frameworks/7 gnome/mkenums/meson.build b/test cases/frameworks/7 gnome/mkenums/meson.build
index 9963455..44c21cb 100644
--- a/test cases/frameworks/7 gnome/mkenums/meson.build
+++ b/test cases/frameworks/7 gnome/mkenums/meson.build
@@ -123,6 +123,7 @@ enums4 = gnome.mkenums_simple('enums4', sources : 'meson-sample.h',
enumexe4 = executable('enumprog4', 'main4.c', enums4, dependencies : gobj)
enums5 = gnome.mkenums_simple('enums5', sources : 'meson-sample.h',
+ install_header : true,
decorator : 'MESON_EXPORT',
header_prefix : '#include "meson-decls.h"')
enumexe5 = executable('enumprog5', main, enums5, dependencies : gobj)
diff --git a/test cases/unit/13 reconfigure/meson.build b/test cases/unit/13 reconfigure/meson.build
index 102180e..453644a 100644
--- a/test cases/unit/13 reconfigure/meson.build
+++ b/test cases/unit/13 reconfigure/meson.build
@@ -1,5 +1,5 @@
project('reconfigure test', ['c'])
-if get_option('b_lto') != true
- error('b_lto not set')
+if get_option('b_coverage') != true
+ error('b_coverage not set')
endif
diff --git a/test cases/unit/26 guessed linker dependencies/exe/app.c b/test cases/unit/26 guessed linker dependencies/exe/app.c
new file mode 100644
index 0000000..1031a42
--- /dev/null
+++ b/test cases/unit/26 guessed linker dependencies/exe/app.c
@@ -0,0 +1,6 @@
+void liba_func();
+
+int main() {
+ liba_func();
+ return 0;
+}
diff --git a/test cases/unit/26 guessed linker dependencies/exe/meson.build b/test cases/unit/26 guessed linker dependencies/exe/meson.build
new file mode 100644
index 0000000..8bb1bd7
--- /dev/null
+++ b/test cases/unit/26 guessed linker dependencies/exe/meson.build
@@ -0,0 +1,7 @@
+project('exe', ['c'])
+
+executable('app',
+ 'app.c',
+ # Use uninterpreted strings to avoid path finding by dependency or compiler.find_library
+ link_args: ['-ltest-lib']
+ )
diff --git a/test cases/unit/26 guessed linker dependencies/lib/lib.c b/test cases/unit/26 guessed linker dependencies/lib/lib.c
new file mode 100644
index 0000000..1a8f94d
--- /dev/null
+++ b/test cases/unit/26 guessed linker dependencies/lib/lib.c
@@ -0,0 +1,20 @@
+#if defined _WIN32
+ #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
+
+void DLL_PUBLIC liba_func() {
+}
+
+#ifdef MORE_EXPORTS
+
+void DLL_PUBLIC libb_func() {
+}
+
+#endif
diff --git a/test cases/unit/26 guessed linker dependencies/lib/meson.build b/test cases/unit/26 guessed linker dependencies/lib/meson.build
new file mode 100644
index 0000000..36df112
--- /dev/null
+++ b/test cases/unit/26 guessed linker dependencies/lib/meson.build
@@ -0,0 +1,11 @@
+project('lib1', ['c'])
+
+c_args = []
+
+# Microsoft's compiler is quite smart about touching import libs on changes,
+# so ensure that there is actually a change in symbols.
+if get_option('more_exports')
+ c_args += '-DMORE_EXPORTS'
+endif
+
+a = library('test-lib', 'lib.c', c_args: c_args, install: true)
diff --git a/test cases/unit/26 guessed linker dependencies/lib/meson_options.txt b/test cases/unit/26 guessed linker dependencies/lib/meson_options.txt
new file mode 100644
index 0000000..2123e45
--- /dev/null
+++ b/test cases/unit/26 guessed linker dependencies/lib/meson_options.txt
@@ -0,0 +1 @@
+option('more_exports', type : 'boolean', value : false)
diff --git a/test cases/unit/27 forcefallback/meson.build b/test cases/unit/27 forcefallback/meson.build
new file mode 100644
index 0000000..e6a90ea
--- /dev/null
+++ b/test cases/unit/27 forcefallback/meson.build
@@ -0,0 +1,8 @@
+project('mainproj', 'c',
+ default_options : ['wrap_mode=forcefallback'])
+
+zlib_dep = dependency('zlib', fallback: ['notzlib', 'zlib_dep'])
+
+test_not_zlib = executable('test_not_zlib', ['test_not_zlib.c'], dependencies: [zlib_dep])
+
+test('test_not_zlib', test_not_zlib)
diff --git a/test cases/unit/27 forcefallback/subprojects/notzlib/meson.build b/test cases/unit/27 forcefallback/subprojects/notzlib/meson.build
new file mode 100644
index 0000000..254a136
--- /dev/null
+++ b/test cases/unit/27 forcefallback/subprojects/notzlib/meson.build
@@ -0,0 +1,7 @@
+project('notzlib', 'c')
+
+notzlib_sources = ['notzlib.c']
+
+notzlib = library('notzlib', notzlib_sources)
+
+zlib_dep = declare_dependency(link_with: notzlib, include_directories: include_directories(['.']))
diff --git a/test cases/unit/27 forcefallback/subprojects/notzlib/notzlib.c b/test cases/unit/27 forcefallback/subprojects/notzlib/notzlib.c
new file mode 100644
index 0000000..c3b6bf9
--- /dev/null
+++ b/test cases/unit/27 forcefallback/subprojects/notzlib/notzlib.c
@@ -0,0 +1,6 @@
+#include "notzlib.h"
+
+int not_a_zlib_function (void)
+{
+ return 42;
+}
diff --git a/test cases/unit/27 forcefallback/subprojects/notzlib/notzlib.h b/test cases/unit/27 forcefallback/subprojects/notzlib/notzlib.h
new file mode 100644
index 0000000..695921d
--- /dev/null
+++ b/test cases/unit/27 forcefallback/subprojects/notzlib/notzlib.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#if defined _WIN32 || defined __CYGWIN__
+#if defined BUILDING_DLL
+ #define DLL_PUBLIC __declspec(dllexport)
+#else
+ #define DLL_PUBLIC __declspec(dllimport)
+#endif
+#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 not_a_zlib_function (void);
diff --git a/test cases/unit/27 forcefallback/test_not_zlib.c b/test cases/unit/27 forcefallback/test_not_zlib.c
new file mode 100644
index 0000000..36256af
--- /dev/null
+++ b/test cases/unit/27 forcefallback/test_not_zlib.c
@@ -0,0 +1,8 @@
+#include <notzlib.h>
+
+int main (int ac, char **av)
+{
+ if (not_a_zlib_function () != 42)
+ return 1;
+ return 0;
+}
diff --git a/test cases/unit/28 pkgconfig use libraries/app/app.c b/test cases/unit/28 pkgconfig use libraries/app/app.c
new file mode 100644
index 0000000..b271a9e
--- /dev/null
+++ b/test cases/unit/28 pkgconfig use libraries/app/app.c
@@ -0,0 +1,6 @@
+void libb_func();
+
+int main() {
+ libb_func();
+ return 0;
+}
diff --git a/test cases/unit/28 pkgconfig use libraries/app/meson.build b/test cases/unit/28 pkgconfig use libraries/app/meson.build
new file mode 100644
index 0000000..3d85a32
--- /dev/null
+++ b/test cases/unit/28 pkgconfig use libraries/app/meson.build
@@ -0,0 +1,5 @@
+project('app', ['c'])
+
+b = dependency('test-b')
+
+executable('app', 'app.c', dependencies : [b])
diff --git a/test cases/unit/28 pkgconfig use libraries/lib/liba.c b/test cases/unit/28 pkgconfig use libraries/lib/liba.c
new file mode 100644
index 0000000..e98906b
--- /dev/null
+++ b/test cases/unit/28 pkgconfig use libraries/lib/liba.c
@@ -0,0 +1,2 @@
+void liba_func() {
+}
diff --git a/test cases/unit/28 pkgconfig use libraries/lib/libb.c b/test cases/unit/28 pkgconfig use libraries/lib/libb.c
new file mode 100644
index 0000000..3160e5f
--- /dev/null
+++ b/test cases/unit/28 pkgconfig use libraries/lib/libb.c
@@ -0,0 +1,5 @@
+void liba_func();
+
+void libb_func() {
+ liba_func();
+}
diff --git a/test cases/unit/28 pkgconfig use libraries/lib/meson.build b/test cases/unit/28 pkgconfig use libraries/lib/meson.build
new file mode 100644
index 0000000..748adf4
--- /dev/null
+++ b/test cases/unit/28 pkgconfig use libraries/lib/meson.build
@@ -0,0 +1,16 @@
+project('lib', ['c'])
+
+a = library('test-a', 'liba.c', install: true)
+
+b = library('test-b', 'libb.c', link_with: a, install: true)
+
+import('pkgconfig').generate(
+ version: '0.0',
+ description: 'test library',
+ filebase: 'test-b',
+ name: 'test library',
+ libraries: [b],
+ subdirs: ['.']
+)
+
+
diff --git a/test cases/unit/29 cross file overrides always args/meson.build b/test cases/unit/29 cross file overrides always args/meson.build
new file mode 100644
index 0000000..ef6556e
--- /dev/null
+++ b/test cases/unit/29 cross file overrides always args/meson.build
@@ -0,0 +1,3 @@
+project('cross compile args override always args', 'c')
+
+executable('no-file-offset-bits', 'test.c')
diff --git a/test cases/unit/29 cross file overrides always args/test.c b/test cases/unit/29 cross file overrides always args/test.c
new file mode 100644
index 0000000..315f92e
--- /dev/null
+++ b/test cases/unit/29 cross file overrides always args/test.c
@@ -0,0 +1,8 @@
+#ifdef _FILE_OFFSET_BITS
+ #error "_FILE_OFFSET_BITS should not be set"
+#endif
+
+int main(int argc, char *argv[])
+{
+ return 0;
+}
diff --git a/test cases/unit/29 cross file overrides always args/ubuntu-armhf-overrides.txt b/test cases/unit/29 cross file overrides always args/ubuntu-armhf-overrides.txt
new file mode 100644
index 0000000..a00a7d1
--- /dev/null
+++ b/test cases/unit/29 cross file overrides always args/ubuntu-armhf-overrides.txt
@@ -0,0 +1,19 @@
+[binaries]
+# we could set exe_wrapper = qemu-arm-static but to test the case
+# when cross compiled binaries can't be run we don't do that
+c = '/usr/bin/arm-linux-gnueabihf-gcc'
+cpp = '/usr/bin/arm-linux-gnueabihf-g++'
+rust = ['rustc', '--target', 'arm-unknown-linux-gnueabihf', '-C', 'linker=/usr/bin/arm-linux-gnueabihf-gcc-7']
+ar = '/usr/arm-linux-gnueabihf/bin/ar'
+strip = '/usr/arm-linux-gnueabihf/bin/strip'
+pkgconfig = '/usr/bin/arm-linux-gnueabihf-pkg-config'
+
+[properties]
+root = '/usr/arm-linux-gnueabihf'
+c_args = ['-U_FILE_OFFSET_BITS']
+
+[host_machine]
+system = 'linux'
+cpu_family = 'arm'
+cpu = 'armv7' # Not sure if correct.
+endian = 'little'