aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml5
-rw-r--r--ciimage/Dockerfile2
-rw-r--r--docs/markdown/Configuring-a-build-directory.md4
-rw-r--r--docs/markdown/Cross-compilation.md4
-rw-r--r--docs/markdown/Dependencies.md78
-rw-r--r--docs/markdown/FAQ.md197
-rw-r--r--docs/markdown/Generating-sources.md80
-rw-r--r--docs/markdown/Gnome-module.md4
-rw-r--r--docs/markdown/IDE-integration.md10
-rw-r--r--docs/markdown/Pkgconfig-module.md5
-rw-r--r--docs/markdown/Reference-manual.md49
-rw-r--r--docs/markdown/Reference-tables.md2
-rw-r--r--docs/markdown/Release-notes-for-0.45.0.md192
-rw-r--r--docs/markdown/Release-notes-for-0.46.0.md16
-rw-r--r--docs/markdown/Subprojects.md24
-rw-r--r--docs/markdown/snippets/altered-logging.md5
-rw-r--r--docs/markdown/snippets/compiler-object-run_command.md10
-rw-r--r--docs/markdown/snippets/config-tool-cross.md13
-rw-r--r--docs/markdown/snippets/csc.md4
-rw-r--r--docs/markdown/snippets/declare_dependency-link_whole.md4
-rw-r--r--docs/markdown/snippets/deprecations.md14
-rw-r--r--docs/markdown/snippets/fpga.md12
-rw-r--r--docs/markdown/snippets/gen-subdirs.md21
-rw-r--r--docs/markdown/snippets/hexnumbers.md5
-rw-r--r--docs/markdown/snippets/if-release.md7
-rw-r--r--docs/markdown/snippets/improved-help.md6
-rw-r--r--docs/markdown/snippets/improved-meson-init.md19
-rw-r--r--docs/markdown/snippets/install_subdir-strip_directory.md4
-rw-r--r--docs/markdown/snippets/installdir.md5
-rw-r--r--docs/markdown/snippets/intopt.md6
-rw-r--r--docs/markdown/snippets/pkgconfig-requires-non-string.md5
-rw-r--r--docs/markdown/snippets/project-license.md4
-rw-r--r--docs/markdown/snippets/rust-cross.md16
-rw-r--r--docs/markdown/snippets/rust-private-disambiguation.md6
-rw-r--r--docs/markdown/snippets/templates.md8
-rw-r--r--docs/markdown/snippets/windows-resources-custom-targets.md3
-rw-r--r--docs/markdown/snippets/wrap_promote.md11
-rw-r--r--docs/markdown/snippets/yield.md8
-rw-r--r--docs/sitemap.txt1
-rwxr-xr-xghwt.py2
-rw-r--r--man/meson.12
-rw-r--r--man/mesonconf.12
-rw-r--r--man/mesonintrospect.12
-rw-r--r--man/mesontest.12
-rw-r--r--man/wraptool.12
-rwxr-xr-xmeson.py4
-rw-r--r--mesonbuild/backend/backends.py11
-rw-r--r--mesonbuild/backend/ninjabackend.py45
-rw-r--r--mesonbuild/backend/vs2010backend.py2
-rw-r--r--mesonbuild/backend/xcodebackend.py8
-rw-r--r--mesonbuild/build.py30
-rw-r--r--mesonbuild/compilers/c.py4
-rw-r--r--mesonbuild/compilers/cpp.py2
-rw-r--r--mesonbuild/coredata.py10
-rw-r--r--mesonbuild/dependencies/base.py35
-rw-r--r--mesonbuild/dependencies/boost.py2
-rw-r--r--mesonbuild/dependencies/ui.py24
-rw-r--r--mesonbuild/environment.py9
-rw-r--r--mesonbuild/interpreter.py69
-rw-r--r--mesonbuild/interpreterbase.py2
-rw-r--r--mesonbuild/mconf.py169
-rw-r--r--mesonbuild/mesonlib.py9
-rw-r--r--mesonbuild/mesonmain.py31
-rw-r--r--mesonbuild/minit.py155
-rw-r--r--mesonbuild/mintro.py44
-rw-r--r--mesonbuild/mlog.py29
-rw-r--r--mesonbuild/modules/gnome.py2
-rw-r--r--mesonbuild/modules/pkgconfig.py33
-rw-r--r--mesonbuild/modules/python3.py1
-rw-r--r--mesonbuild/modules/unstable_icestorm.py13
-rw-r--r--mesonbuild/mtest.py172
-rw-r--r--mesonbuild/rewriter.py6
-rw-r--r--mesonbuild/scripts/meson_install.py2
-rwxr-xr-xmsi/createmsi.py5
-rwxr-xr-xrun_project_tests.py2
-rwxr-xr-xrun_unittests.py122
-rw-r--r--setup.py6
-rw-r--r--test cases/common/145 whole archive/exe3/meson.build1
-rw-r--r--test cases/common/145 whole archive/exe4/meson.build1
-rw-r--r--test cases/common/145 whole archive/meson.build18
-rw-r--r--test cases/common/145 whole archive/sh_func2_dep_func1/meson.build4
-rw-r--r--test cases/common/145 whole archive/sh_func2_transdep_func1/meson.build6
-rw-r--r--test cases/common/180 generator link whole/export.h18
-rwxr-xr-xtest cases/common/180 generator link whole/generator.py30
-rw-r--r--test cases/common/180 generator link whole/main.c11
-rw-r--r--test cases/common/180 generator link whole/meson.build65
-rw-r--r--test cases/common/180 generator link whole/meson_test_function.tmpl0
-rw-r--r--test cases/common/180 generator link whole/pull_meson_test_function.c6
-rw-r--r--test cases/common/181 initial c_args/meson.build7
-rw-r--r--test cases/common/181 initial c_args/test_args.txt4
-rw-r--r--test cases/common/51 pkgconfig-gen/dependencies/meson.build16
-rw-r--r--test cases/common/51 pkgconfig-gen/meson.build6
-rw-r--r--test cases/common/64 custom header generator/meson.build6
-rwxr-xr-xtest cases/common/72 build always/version_gen.py12
-rw-r--r--test cases/common/98 gen extra/srcgen3.py1
-rw-r--r--test cases/frameworks/10 gtk-doc/include/meson.build3
-rw-r--r--test cases/frameworks/10 gtk-doc/installed_files.txt (renamed from test cases/frameworks/10 gtk-doc/installed_files.txt.bak)12
-rw-r--r--test cases/frameworks/14 doxygen/include/comedian.h2
-rw-r--r--test cases/frameworks/14 doxygen/include/spede.h7
-rw-r--r--test cases/frameworks/14 doxygen/meson.build6
-rw-r--r--test cases/frameworks/14 doxygen/src/spede.cpp2
-rw-r--r--test cases/unit/13 testsetup selection/main.c3
-rw-r--r--test cases/unit/13 testsetup selection/meson.build10
-rw-r--r--test cases/unit/13 testsetup selection/subprojects/bar/bar.c3
-rw-r--r--test cases/unit/13 testsetup selection/subprojects/bar/meson.build6
-rw-r--r--test cases/unit/13 testsetup selection/subprojects/foo/foo.c3
-rw-r--r--test cases/unit/13 testsetup selection/subprojects/foo/meson.build4
-rw-r--r--test cases/unit/23 compiler run_command/meson.build10
108 files changed, 1562 insertions, 660 deletions
diff --git a/.travis.yml b/.travis.yml
index f077c9c..48cfb38 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -30,7 +30,8 @@ matrix:
before_install:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi
- - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install python3; fi
+ - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew uninstall python mercurial; fi
+ - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install python@2 python@3 mercurial qt; fi
# Use a Ninja with QuLogic's patch: https://github.com/ninja-build/ninja/issues/1219
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then mkdir -p $HOME/tools; curl -L http://nirbheek.in/files/binaries/ninja/macos/ninja -o $HOME/tools/ninja; chmod +x $HOME/tools/ninja; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker pull jpakkane/mesonci:artful; fi
@@ -49,4 +50,4 @@ script:
withgit \
/bin/sh -c "cd /root && mkdir -p tools; wget -c http://nirbheek.in/files/binaries/ninja/linux-amd64/ninja -O /root/tools/ninja; chmod +x /root/tools/ninja; CC=$CC CXX=$CXX OBJC=$CC OBJCXX=$CXX PATH=/root/tools:$PATH MESON_FIXED_NINJA=1 ./run_tests.py -- $MESON_ARGS && chmod -R a+rwX .coverage"
fi
- - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then SDKROOT=$(xcodebuild -version -sdk macosx Path) CPPFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib OBJC=$CC OBJCXX=$CXX PATH=$HOME/tools:$PATH MESON_FIXED_NINJA=1 ./run_tests.py --backend=ninja -- $MESON_ARGS ; fi
+ - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then SDKROOT=$(xcodebuild -version -sdk macosx Path) CPPFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib OBJC=$CC OBJCXX=$CXX PATH=$HOME/tools:/usr/local/opt/qt/bin:$PATH MESON_FIXED_NINJA=1 ./run_tests.py --backend=ninja -- $MESON_ARGS ; fi
diff --git a/ciimage/Dockerfile b/ciimage/Dockerfile
index 05e679e..72788c3 100644
--- a/ciimage/Dockerfile
+++ b/ciimage/Dockerfile
@@ -14,3 +14,5 @@ RUN apt-get -y update && apt-get -y upgrade \
&& apt-get -y install libwmf-dev \
&& apt-get -y install qt4-linguist-tools qttools5-dev-tools \
&& python3 -m pip install hotdoc codecov
+
+ENV LANG='C.UTF-8'
diff --git a/docs/markdown/Configuring-a-build-directory.md b/docs/markdown/Configuring-a-build-directory.md
index 774addf..8e016e2 100644
--- a/docs/markdown/Configuring-a-build-directory.md
+++ b/docs/markdown/Configuring-a-build-directory.md
@@ -9,9 +9,7 @@ generated. For example you might want to change from a debug build
into a release build, set custom compiler flags, change the build
options provided in your `meson_options.txt` file and so on.
-The main tool for this is the `meson configure` command. You may also use the
-`mesongui` graphical application if you want. However this document
-describes the use of the command line client.
+The main tool for this is the `meson configure` command.
You invoke `meson configure` by giving it the location of your build dir. If
omitted, the current working directory is used instead. Here's a
diff --git a/docs/markdown/Cross-compilation.md b/docs/markdown/Cross-compilation.md
index c1ad317..520a081 100644
--- a/docs/markdown/Cross-compilation.md
+++ b/docs/markdown/Cross-compilation.md
@@ -261,7 +261,7 @@ myvar = meson.get_cross_property('somekey')
## Cross file locations
As of version 0.44.0 meson supports loading cross files from system locations
-on Linux and the BSDs. This will be $XDG_DATA_DIRS/meson/cross, or if
+(except on Windows). This will be $XDG_DATA_DIRS/meson/cross, or if
XDG_DATA_DIRS is undefined, then /usr/local/share/meson/cross and
/usr/share/meson/cross will be tried in that order, for system wide cross
files. User local files can be put in $XDG_DATA_HOME/meson/cross, or
@@ -272,7 +272,7 @@ The order of locations tried is as follows:
- The user local location
- The system wide locations in order
-Linux and BSD distributions are encouraged to ship cross files either with
+Distributions are encouraged to ship cross files either with
their cross compiler toolchain packages or as a standalone package, and put
them in one of the system paths referenced above.
diff --git a/docs/markdown/Dependencies.md b/docs/markdown/Dependencies.md
index 74a918a..12e1b1f 100644
--- a/docs/markdown/Dependencies.md
+++ b/docs/markdown/Dependencies.md
@@ -61,7 +61,7 @@ zdep_prefix = zdep.get_pkgconfig_variable('libdir', define_variable: ['prefix',
The dependency detector works with all libraries that provide a
`pkg-config` file. Unfortunately several packages don't provide
pkg-config files. Meson has autodetection support for some of these,
-and they are described later on this page.
+and they are described [later in this page](#dependencies-with-custom-lookup-functionality).
# Declaring your own
@@ -111,6 +111,14 @@ of all the work behind the scenes to make this work.
# Dependencies with custom lookup functionality
+## AppleFrameworks
+
+Use the `modules` keyword to list frameworks required, e.g.
+
+```meson
+dep = find_dep('appleframeworks', modules : 'foundation')
+```
+
## Boost
Boost is not a single dependency but rather a group of different
@@ -138,7 +146,11 @@ can set the BOOST_ROOT, BOOST_INCLUDEDIR, and/or BOOST_LIBRARYDIR
environment variables.
You can set the argument `threading` to `single` to use boost libraries that
-has been compiled for single-threaded use instead.
+have been compiled for single-threaded use instead.
+
+## GL
+
+This finds the OpenGL library in a way appropriate to the platform.
## GTest and GMock
@@ -160,9 +172,9 @@ test('gtest test', e)
MPI is supported for C, C++ and Fortran. Because dependencies are
language-specific, you must specify the requested language using the
`language` keyword argument, i.e.,
- * `dependency('mpi', language='c')` for the C MPI headers and libraries
- * `dependency('mpi', language='cpp')` for the C++ MPI headers and libraries
- * `dependency('mpi', language='fortran')` for the Fortran MPI headers and libraries
+ * `dependency('mpi', language: 'c')` for the C MPI headers and libraries
+ * `dependency('mpi', language: 'cpp')` for the C++ MPI headers and libraries
+ * `dependency('mpi', language: 'fortran')` for the Fortran MPI headers and libraries
Meson prefers pkg-config for MPI, but if your MPI implementation does
not provide them, it will search for the standard wrapper executables,
@@ -171,9 +183,9 @@ are not in your path, they can be specified by setting the standard
environment variables `MPICC`, `MPICXX`, `MPIFC`, `MPIF90`, or
`MPIF77`, during configuration.
-## Qt5
+## Qt4 & Qt5
-Meson has native Qt5 support. Its usage is best demonstrated with an
+Meson has native Qt support. Its usage is best demonstrated with an
example.
```meson
@@ -204,12 +216,26 @@ the list of sources for the target. The `modules` keyword of
`dependency` works just like it does with Boost. It tells which
subparts of Qt the program uses.
+## SDL2
+
+SDL2 can be located using `pkg-confg`, the `sdl2-config` config tool, or as an
+OSX framework.
+
+## Valgrind
+
+Meson will find valgrind using `pkg-config`, but only uses the compilation flags
+and avoids trying to link with it's non-PIC static libs.
+
+## Vulkan
+
+Vulkan can be located using `pkg-config`, or the `VULKAN_SDK` environment variable.
+
## Dependencies using config tools
-CUPS, LLVM, PCAP, WxWidgets, libwmf, and GnuStep either do not provide
-pkg-config modules or additionally can be detected via a config tool
+CUPS, LLVM, PCAP, [WxWidgets](#wxwidgets), libwmf, and GnuStep either do not
+provide pkg-config modules or additionally can be detected via a config tool
(cups-config, llvm-config, etc). Meson has native support for these tools, and
-then can be found like other dependencies:
+they can be found like other dependencies:
```meson
pcap_dep = dependency('pcap', version : '>=1.0')
@@ -224,6 +250,30 @@ tools support. You can force one or another via the method keyword:
wmf_dep = dependency('wmf', method : 'config-tool')
```
+## WxWidgets
+
+Similar to [Boost](#boost), WxWidgets is not a single library but rather
+a collection of modules. WxWidgets is supported via `wx-config`.
+Meson substitutes `modules` to `wx-config` invocation, it generates
+- `compile_args` using `wx-config --cxxflags $modules...`
+- `link_args` using `wx-config --libs $modules...`
+
+### Example
+
+```meson
+wx_dep = dependency(
+ 'wxwidgets', version : '>=3.0.0', modules : ['std', 'stc'],
+)
+```
+
+```shell
+# compile_args:
+$ wx-config --cxxflags std stc
+
+# link_args:
+$ wx-config --libs std stc
+```
+
## LLVM
Meson has native support for LLVM going back to version LLVM version 3.5.
@@ -257,10 +307,10 @@ llvm_dep = dependency(
Python3 is handled specially by meson:
1. Meson tries to use `pkg-config`.
-1. If `pkg-config` fails meson uses fallback:
- - On Windows fallback is current `python3` interpreter.
- - On OSX fallback is framework dependency from `/Library/Frameworks`.
+1. If `pkg-config` fails meson uses a fallback:
+ - On Windows the fallback is the current `python3` interpreter.
+ - On OSX the fallback is a framework dependency from `/Library/Frameworks`.
Note that `python3` found by this dependency might differ from the one used in
-`python3` module because modules uses current interpreter but dependency tries
+`python3` module because modules uses the current interpreter, but dependency tries
`pkg-config` first.
diff --git a/docs/markdown/FAQ.md b/docs/markdown/FAQ.md
index 441cd69..1dbc80a 100644
--- a/docs/markdown/FAQ.md
+++ b/docs/markdown/FAQ.md
@@ -7,9 +7,16 @@ See also [How do I do X in Meson](howtox.md).
## Why is it called Meson?
-When the name was originally chosen, there were two main limitations: there must not exist either a Debian package or a Sourceforge project of the given name. This ruled out tens of potential project names. At some point the name Gluon was considered. Gluons are elementary particles that hold protons and neutrons together, much like a build system's job is to take pieces of source code and a compiler and bind them to a complete whole.
+When the name was originally chosen, there were two main limitations:
+there must not exist either a Debian package or a Sourceforge project
+of the given name. This ruled out tens of potential project names. At
+some point the name Gluon was considered. Gluons are elementary
+particles that hold protons and neutrons together, much like a build
+system's job is to take pieces of source code and a compiler and bind
+them to a complete whole.
-Unfortunately this name was taken, too. Then the rest of subatomic particles were examined and Meson was found to be available.
+Unfortunately this name was taken, too. Then the rest of subatomic
+particles were examined and Meson was found to be available.
## What is the correct way to use threads (such as pthreads)?
@@ -17,23 +24,34 @@ Unfortunately this name was taken, too. Then the rest of subatomic particles wer
thread_dep = dependency('threads')
```
-This will set up everything on your behalf. People coming from Autotools or CMake want to do this by looking for `libpthread.so` manually. Don't do that, it has tricky corner cases especially when cross compiling.
+This will set up everything on your behalf. People coming from
+Autotools or CMake want to do this by looking for `libpthread.so`
+manually. Don't do that, it has tricky corner cases especially when
+cross compiling.
## How to use Meson on a host where it is not available in system packages?
-Starting from version 0.29.0, Meson is available from the [Python Package Index](https://pypi.python.org/pypi/meson/), so installing it simply a matter of running this command:
+Starting from version 0.29.0, Meson is available from the [Python
+Package Index](https://pypi.python.org/pypi/meson/), so installing it
+simply a matter of running this command:
```console
$ pip3 install <your options here> meson
```
-If you don't have access to PyPI, that is not a problem either. Meson has been designed to be easily runnable from an extracted source tarball or even a git checkout. First you need to download Meson. Then use this command to set up you build instead of plain `meson`.
+If you don't have access to PyPI, that is not a problem either. Meson
+has been designed to be easily runnable from an extracted source
+tarball or even a git checkout. First you need to download Meson. Then
+use this command to set up you build instead of plain `meson`.
```console
$ /path/to/meson.py <options>
```
-After this you don't have to care about invoking Meson any more. It remembers where it was originally invoked from and calls itself appropriately. As a user the only thing you need to do is to `cd` into your build directory and invoke `ninja`.
+After this you don't have to care about invoking Meson any more. It
+remembers where it was originally invoked from and calls itself
+appropriately. As a user the only thing you need to do is to `cd` into
+your build directory and invoke `ninja`.
## Why can't I specify target files with a wildcard?
@@ -43,17 +61,34 @@ Instead of specifying files explicitly, people seem to want to do this:
executable('myprog', sources : '*.cpp') # This does NOT work!
```
-Meson does not support this syntax and the reason for this is simple. This can not be made both reliable and fast. By reliable we mean that if the user adds a new source file to the subdirectory, Meson should detect that and make it part of the build automatically.
+Meson does not support this syntax and the reason for this is
+simple. This can not be made both reliable and fast. By reliable we
+mean that if the user adds a new source file to the subdirectory,
+Meson should detect that and make it part of the build automatically.
-One of the main requirements of Meson is that it must be fast. This means that a no-op build in a tree of 10 000 source files must take no more than a fraction of a second. This is only possible because Meson knows the exact list of files to check. If any target is specified as a wildcard glob, this is no longer possible. Meson would need to re-evaluate the glob every time and compare the list of files produced against the previous list. This means inspecting the entire source tree (because the glob pattern could be `src/\*/\*/\*/\*.cpp` or something like that). This is impossible to do efficiently.
+One of the main requirements of Meson is that it must be fast. This
+means that a no-op build in a tree of 10 000 source files must take no
+more than a fraction of a second. This is only possible because Meson
+knows the exact list of files to check. If any target is specified as
+a wildcard glob, this is no longer possible. Meson would need to
+re-evaluate the glob every time and compare the list of files produced
+against the previous list. This means inspecting the entire source
+tree (because the glob pattern could be `src/\*/\*/\*/\*.cpp` or
+something like that). This is impossible to do efficiently.
-The main backend of Meson is Ninja, which does not support wildcard matches either, and for the same reasons.
+The main backend of Meson is Ninja, which does not support wildcard
+matches either, and for the same reasons.
Because of this, all source files must be specified explicitly.
## But I really want to use wildcards!
-If the tradeoff between reliability and convenience is acceptable to you, then Meson gives you all the tools necessary to do wildcard globbing. You are allowed to run arbitrary commands during configuration. First you need to write a script that locates the files to compile. Here's a simple shell script that writes all `.c` files in the current directory, one per line.
+If the tradeoff between reliability and convenience is acceptable to
+you, then Meson gives you all the tools necessary to do wildcard
+globbing. You are allowed to run arbitrary commands during
+configuration. First you need to write a script that locates the files
+to compile. Here's a simple shell script that writes all `.c` files in
+the current directory, one per line.
```bash
@@ -72,17 +107,37 @@ sources = c.stdout().strip().split('\n')
e = executable('prog', sources)
```
-The script can be any executable, so it can be written in shell, Python, Lua, Perl or whatever you wish.
+The script can be any executable, so it can be written in shell,
+Python, Lua, Perl or whatever you wish.
-As mentioned above, the tradeoff is that just adding new files to the source directory does *not* add them to the build automatically. To add them you need to tell Meson to reinitialize itself. The simplest way is to touch the `meson.build` file in your source root. Then Meson will reconfigure itself next time the build command is run. Advanced users can even write a small background script that utilizes a filesystem event queue, such as [inotify](https://en.wikipedia.org/wiki/Inotify), to do this automatically.
+As mentioned above, the tradeoff is that just adding new files to the
+source directory does *not* add them to the build automatically. To
+add them you need to tell Meson to reinitialize itself. The simplest
+way is to touch the `meson.build` file in your source root. Then Meson
+will reconfigure itself next time the build command is run. Advanced
+users can even write a small background script that utilizes a
+filesystem event queue, such as
+[inotify](https://en.wikipedia.org/wiki/Inotify), to do this
+automatically.
## Should I use `subdir` or `subproject`?
-The answer is almost always `subdir`. Subproject exists for a very specific use case: embedding external dependencies into your build process. As an example, suppose we are writing a game and wish to use SDL. Let us further suppose that SDL comes with a Meson build definition. Let us suppose even further that we don't want to use prebuilt binaries but want to compile SDL for ourselves.
+The answer is almost always `subdir`. Subproject exists for a very
+specific use case: embedding external dependencies into your build
+process. As an example, suppose we are writing a game and wish to use
+SDL. Let us further suppose that SDL comes with a Meson build
+definition. Let us suppose even further that we don't want to use
+prebuilt binaries but want to compile SDL for ourselves.
-In this case you would use `subproject`. The way to do it would be to grab the source code of SDL and put it inside your own source tree. Then you would do `sdl = subproject('sdl')`, which would cause Meson to build SDL as part of your build and would then allow you to link against it or do whatever else you may prefer.
+In this case you would use `subproject`. The way to do it would be to
+grab the source code of SDL and put it inside your own source
+tree. Then you would do `sdl = subproject('sdl')`, which would cause
+Meson to build SDL as part of your build and would then allow you to
+link against it or do whatever else you may prefer.
-For every other use you would use `subdir`. As an example, if you wanted to build a shared library in one dir and link tests against it in another dir, you would do something like this:
+For every other use you would use `subdir`. As an example, if you
+wanted to build a shared library in one dir and link tests against it
+in another dir, you would do something like this:
```meson
project('simple', 'c')
@@ -92,27 +147,53 @@ subdir('tests') # test binaries would link against the library here
## Why is there not a Make backend?
-Because Make is slow. This is not an implementation issue, Make simply can not be made fast. For further info we recommend you read [this post](http://neugierig.org/software/chromium/notes/2011/02/ninja.html) by Evan Martin, the author of Ninja. Makefiles also have a syntax that is very unpleasant to write which makes them a big maintenance burden.
+Because Make is slow. This is not an implementation issue, Make simply
+can not be made fast. For further info we recommend you read [this
+post](http://neugierig.org/software/chromium/notes/2011/02/ninja.html)
+by Evan Martin, the author of Ninja. Makefiles also have a syntax that
+is very unpleasant to write which makes them a big maintenance burden.
-The only reason why one would use Make instead of Ninja is working on a platform that does not have a Ninja port. Even in this case it is an order of magnitude less work to port Ninja than it is to write a Make backend for Meson.
+The only reason why one would use Make instead of Ninja is working on
+a platform that does not have a Ninja port. Even in this case it is an
+order of magnitude less work to port Ninja than it is to write a Make
+backend for Meson.
Just use Ninja, you'll be happier that way. I guarantee it.
## Why is Meson not just a Python module so I could code my build setup in Python?
-A related question to this is *Why is Meson's configuration language not Turing-complete?*
+A related question to this is *Why is Meson's configuration language
+not Turing-complete?*
-There are many good reasons for this, most of which are summarized on this web page: [Against The Use Of Programming Languages in Configuration Files](https://taint.org/2011/02/18/001527a.html).
+There are many good reasons for this, most of which are summarized on
+this web page: [Against The Use Of Programming Languages in
+Configuration Files](https://taint.org/2011/02/18/001527a.html).
-In addition to those reasons, not exposing Python or any other "real" programming language makes it possible to port Meson's implementation to a different language. This might become necessary if, for example, Python turns out to be a performance bottleneck. This is an actual problem that has caused complications for GNU Autotools and SCons.
+In addition to those reasons, not exposing Python or any other "real"
+programming language makes it possible to port Meson's implementation
+to a different language. This might become necessary if, for example,
+Python turns out to be a performance bottleneck. This is an actual
+problem that has caused complications for GNU Autotools and SCons.
## How do I do the equivalent of Libtools export-symbol and export-regex?
-Either by using [GCC symbol visibility](https://gcc.gnu.org/wiki/Visibility) or by writing a [linker script](https://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_mono/ld.html). This has the added benefit that your symbol definitions are in a standalone file instead of being buried inside your build definitions. An example can be found [here](https://github.com/jpakkane/meson/tree/master/test%20cases/linuxlike/3%20linker%20script).
+Either by using [GCC symbol
+visibility](https://gcc.gnu.org/wiki/Visibility) or by writing a
+[linker
+script](https://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_mono/ld.html). This
+has the added benefit that your symbol definitions are in a standalone
+file instead of being buried inside your build definitions. An example
+can be found
+[here](https://github.com/jpakkane/meson/tree/master/test%20cases/linuxlike/3%20linker%20script).
## My project works fine on Linux and MinGW but fails with MSVC due to a missing .lib file
-With GCC, all symbols on shared libraries are exported automatically unless you specify otherwise. With MSVC no symbols are exported by default. If your shared library exports no symbols, MSVC will silently not produce an import library file leading to failures. The solution is to add symbol visibility definitions [as specified in GCC wiki](https://gcc.gnu.org/wiki/Visibility).
+With GCC, all symbols on shared libraries are exported automatically
+unless you specify otherwise. With MSVC no symbols are exported by
+default. If your shared library exports no symbols, MSVC will silently
+not produce an import library file leading to failures. The solution
+is to add symbol visibility definitions [as specified in GCC
+wiki](https://gcc.gnu.org/wiki/Visibility).
## I added some compiler flags and now the build fails with weird errors. What is happening?
@@ -123,7 +204,13 @@ executable('foobar', ...
c_args : '-some_arg -other_arg')
```
-Meson is *explicit*. In this particular case it will **not** automatically split your strings at whitespaces, instead it will take it as is and work extra hard to pass it to the compiler unchanged, including quoting it properly over shell invocations. This is mandatory to make e.g. files with spaces in them work flawlessly. To pass multiple command line arguments, you need to explicitly put them in an array like this:
+Meson is *explicit*. In this particular case it will **not**
+automatically split your strings at whitespaces, instead it will take
+it as is and work extra hard to pass it to the compiler unchanged,
+including quoting it properly over shell invocations. This is
+mandatory to make e.g. files with spaces in them work flawlessly. To
+pass multiple command line arguments, you need to explicitly put them
+in an array like this:
```meson
executable('foobar', ...
@@ -138,20 +225,66 @@ You probably had a project that looked something like this:
project('foobar', 'cpp')
```
-This defaults to `c++11` on GCC compilers. Suppose you want to use `c++14` instead, so you change the definition to this:
+This defaults to `c++11` on GCC compilers. Suppose you want to use
+`c++14` instead, so you change the definition to this:
```meson
project('foobar', 'cpp', default_options : ['cpp_std=c++14'])
```
-But when you recompile, it still uses `c++11`. The reason for this is that default options are only looked at when you are setting up a build directory for the very first time. After that the setting is considered to have a value and thus the default value is ignored. To change an existing build dir to `c++14`, either reconfigure your build dir with `meson configure` or delete the build dir and recreate it from scratch.
+But when you recompile, it still uses `c++11`. The reason for this is
+that default options are only looked at when you are setting up a
+build directory for the very first time. After that the setting is
+considered to have a value and thus the default value is ignored. To
+change an existing build dir to `c++14`, either reconfigure your build
+dir with `meson configure` or delete the build dir and recreate it
+from scratch.
+
+The reason we don't automatically change the option value when the
+default is changed is that it is impossible to know to do that
+reliably. The actual question that we need to solve is "if the
+option's value is foo and the default value is bar, should we change
+the option value to bar also". There are many choices:
+
+ - if the user has changed the value themselves from the default, then
+ we must not change it back
+
+ - if the user has not changed the value, but changes the default
+ value, then this section's premise would seem to indicate that the
+ value should be changed
+
+ - suppose the user changes the value from the default to foo, then
+ back to bar and then changes the default value to bar, the correct
+ step to take is ambiguous by itself
+
+In order to solve the latter question we would need to remember not
+only the current and old value, but also all the times the user has
+changed the value and from which value to which other value. Since
+people don't remember their own actions that far back, toggling
+between states based on long history would be confusing.
+
+Because of this we do the simple an understandable thing: default
+values are only defaults and will never affect the value of an option
+once set.
## Does wrap download sources behind my back?
-It does not. In order for Meson to download anything from the net while building, two conditions must be met.
-
-First of all there needs to be a `.wrap` file with a download URL in the `subprojects` directory. If one does not exist, Meson will not download anything.
-
-The second requirement is that there needs to be an explicit subproject invocation in your `meson.build` files. Either `subproject('foobar')` or `dependency('foobar', fallback : ['foobar', 'foo_dep'])`. If these declarations either are not in any build file or they are not called (due to e.g. `if/else`) then nothing is downloaded.
-
-If this is not sufficient for you, starting from release 0.40.0 Meson 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.
+It does not. In order for Meson to download anything from the net
+while building, two conditions must be met.
+
+First of all there needs to be a `.wrap` file with a download URL in
+the `subprojects` directory. If one does not exist, Meson will not
+download anything.
+
+The second requirement is that there needs to be an explicit
+subproject invocation in your `meson.build` files. Either
+`subproject('foobar')` or `dependency('foobar', fallback : ['foobar',
+'foo_dep'])`. If these declarations either are not in any build file
+or they are not called (due to e.g. `if/else`) then nothing is
+downloaded.
+
+If this is not sufficient for you, starting from release 0.40.0 Meson
+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.
diff --git a/docs/markdown/Generating-sources.md b/docs/markdown/Generating-sources.md
index a160095..cbe6c0d 100644
--- a/docs/markdown/Generating-sources.md
+++ b/docs/markdown/Generating-sources.md
@@ -4,23 +4,32 @@ short-description: Generation of source files before compilation
# Generating sources
- Sometimes source files need to be preprocessed before they are passed to the actual compiler. As an example you might want build an IDL compiler and then run some files through that to generate actual source files. In Meson this is done with [`generator()`](Reference-manual.md#generator) or [`custom_target()`](Reference-manual.md#custom_target).
+Sometimes source files need to be preprocessed before they are passed
+to the actual compiler. As an example you might want build an IDL
+compiler and then run some files through that to generate actual
+source files. In Meson this is done with
+[`generator()`](Reference-manual.md#generator) or
+[`custom_target()`](Reference-manual.md#custom_target).
## Using custom_target()
-Let's say you have a build target that must be built using sources generated by a compiler. The compiler can either be a built target:
+Let's say you have a build target that must be built using sources
+generated by a compiler. The compiler can either be a built target:
```meson
mycomp = executable('mycompiler', 'compiler.c')
```
-Or an external program provided by the system, or script inside the source tree:
+Or an external program provided by the system, or script inside the
+source tree:
```meson
mycomp = find_program('mycompiler')
```
-Custom targets can take zero or more input files and use them to generate one or more output files. Using a custom target, you can run this compiler at build time to generate the sources:
+Custom targets can take zero or more input files and use them to
+generate one or more output files. Using a custom target, you can run
+this compiler at build time to generate the sources:
```meson
gen_src = custom_target('gen-output',
@@ -31,7 +40,9 @@ gen_src = custom_target('gen-output',
'--h-out', '@OUTPUT1@'])
```
-The `@INPUT@` there will be transformed to `'somefile1.c' 'file2.c'`. Just like the output, you can also refer to each input file individually by index.
+The `@INPUT@` there will be transformed to `'somefile1.c'
+'file2.c'`. Just like the output, you can also refer to each input
+file individually by index.
Then you just put that in your program and you're done.
@@ -41,11 +52,21 @@ executable('program', 'main.c', gen_src)
## Using generator()
-Generators are similar to custom targets, except that we define a *generator*, which defines how to transform an input file into one or more output files, and then use that on as many input files as we want.
+Generators are similar to custom targets, except that we define a
+*generator*, which defines how to transform an input file into one or
+more output files, and then use that on as many input files as we
+want.
-Note that generators should only be used for outputs that will only be used as inputs for a build target or a custom target. When you use the processed output of a generator in multiple targets, the generator will be run multiple times to create outputs for each target. Each output will be created in a target-private directory `@BUILD_DIR@`.
+Note that generators should only be used for outputs that will only be
+used as inputs for a build target or a custom target. When you use the
+processed output of a generator in multiple targets, the generator
+will be run multiple times to create outputs for each target. Each
+output will be created in a target-private directory `@BUILD_DIR@`.
-If you want to generate files for general purposes such as for generating headers to be used by several sources, or data that will be installed, and so on, use a [`custom_target()`](Reference-manual.md#custom_target) instead.
+If you want to generate files for general purposes such as for
+generating headers to be used by several sources, or data that will be
+installed, and so on, use a
+[`custom_target()`](Reference-manual.md#custom_target) instead.
```meson
@@ -54,9 +75,23 @@ gen = generator(mycomp,
arguments : ['@INPUT@', '@OUTPUT@'])
```
-The first argument is the executable file to run. The next file specifies a name generation rule. It specifies how to build the output file name for a given input name. `@BASENAME@` is a placeholder for the input file name without preceding path or suffix (if any). So if the input file name were `some/path/filename.idl`, then the output name would be `filename.c`. You can also use `@PLAINNAME@`, which preserves the suffix which would result in a file called `filename.idl.c`. The last line specifies the command line arguments to pass to the executable. `@INPUT@` and `@OUTPUT@` are placeholders for the input and output files, respectively, and will be automatically filled in by Meson. If your rule produces multiple output files and you need to pass them to the command line, append the location to the output holder like this: `@OUTPUT0@`, `@OUTPUT1@` and so on.
-
-With this rule specified we can generate source files and add them to a target.
+The first argument is the executable file to run. The next file
+specifies a name generation rule. It specifies how to build the output
+file name for a given input name. `@BASENAME@` is a placeholder for
+the input file name without preceding path or suffix (if any). So if
+the input file name were `some/path/filename.idl`, then the output
+name would be `filename.c`. You can also use `@PLAINNAME@`, which
+preserves the suffix which would result in a file called
+`filename.idl.c`. The last line specifies the command line arguments
+to pass to the executable. `@INPUT@` and `@OUTPUT@` are placeholders
+for the input and output files, respectively, and will be
+automatically filled in by Meson. If your rule produces multiple
+output files and you need to pass them to the command line, append the
+location to the output holder like this: `@OUTPUT0@`, `@OUTPUT1@` and
+so on.
+
+With this rule specified we can generate source files and add them to
+a target.
```meson
gen_src = gen.process('input1.idl', 'input2.idl')
@@ -67,19 +102,32 @@ Generators can also generate multiple output files with unknown names:
```meson
gen2 = generator(someprog,
- outputs : ['@BASENAME@.c', '@BASENAME@.h'],
+ output : ['@BASENAME@.c', '@BASENAME@.h'],
arguments : ['--out_dir=@BUILD_DIR@', '@INPUT@'])
```
-In this case you can not use the plain `@OUTPUT@` variable, as it would be ambiguous. This program only needs to know the output directory, it will generate the file names by itself.
-
-To make passing different additional arguments to the generator program at each use possible, you can use the `@EXTRA_ARGS@` string in the `arguments` list. Note that this placeholder can only be present as a whole string, and not as a substring. The main reason is that it represents a list of strings, which may be empty, or contain multiple elements; and in either case, interpolating it into the middle of a single string would be troublesome. If there are no extra arguments passed in from a `process()` invocation, the placeholder is entirely omitted from the actual list of arguments, so an empty string won't be passed to the generator program because of this. If there are multiple elements in `extra_args`, they are inserted into to the actual argument list as separate elements.
+In this case you can not use the plain `@OUTPUT@` variable, as it
+would be ambiguous. This program only needs to know the output
+directory, it will generate the file names by itself.
+
+To make passing different additional arguments to the generator
+program at each use possible, you can use the `@EXTRA_ARGS@` string in
+the `arguments` list. Note that this placeholder can only be present
+as a whole string, and not as a substring. The main reason is that it
+represents a list of strings, which may be empty, or contain multiple
+elements; and in either case, interpolating it into the middle of a
+single string would be troublesome. If there are no extra arguments
+passed in from a `process()` invocation, the placeholder is entirely
+omitted from the actual list of arguments, so an empty string won't be
+passed to the generator program because of this. If there are multiple
+elements in `extra_args`, they are inserted into to the actual
+argument list as separate elements.
```meson
gen3 = generator(genprog,
output : '@BASENAME@.cc',
arguments : ['@INPUT@', '@EXTRA_ARGS@', '@OUTPUT@'])
-gen3_src1 = gen3.process('input1.y)
+gen3_src1 = gen3.process('input1.y')
gen3_src2 = gen3.process('input2.y', extra_args: '--foo')
gen3_src3 = gen3.process('input3.y', extra_args: ['--foo', '--bar'])
```
diff --git a/docs/markdown/Gnome-module.md b/docs/markdown/Gnome-module.md
index fbf9530..ad3715e 100644
--- a/docs/markdown/Gnome-module.md
+++ b/docs/markdown/Gnome-module.md
@@ -123,7 +123,9 @@ Returns an array of two elements which are: `[c_source, header_file]`
### gnome.mkenums()
Generates enum files for GObject using the `glib-mkenums` tool. The
-first argument is the base name of the output files.
+first argument is the base name of the output files, unless `c_template`
+and `h_template` are specified. In this case, the output files will be
+the base name of the values passed as templates.
This method is essentially a wrapper around the `glib-mkenums` tool's
command line API. It is the most featureful method for enum creation.
diff --git a/docs/markdown/IDE-integration.md b/docs/markdown/IDE-integration.md
index f7939dd..f608c5c 100644
--- a/docs/markdown/IDE-integration.md
+++ b/docs/markdown/IDE-integration.md
@@ -6,7 +6,7 @@ short-description: Meson's API to integrate Meson support into an IDE
Meson has exporters for Visual Studio and XCode, but writing a custom backend for every IDE out there is not a scalable approach. To solve this problem, Meson provides an API that makes it easy for any IDE or build tool to integrate Meson builds and provide an experience comparable to a solution native to the IDE.
-The basic tool for this is a script called `mesonintrospect.py`. Some distro packages might not expose this script in the regular path, and in this case you need to execute it from the install directory.
+The basic tool for this is `meson introspect`.
The first thing to do when setting up a Meson project in an IDE is to select the source and build directories. For this example we assume that the source resides in an Eclipse-like directory called `workspace/project` and the build tree is nested inside it as `workspace/project/build`. First we initialise Meson by running the following command in the source directory.
@@ -16,13 +16,13 @@ For the remainder of the document we assume that all commands are executed insid
The first thing you probably want is to get a list of top level targets. For that we use the introspection tool. It comes with extensive command line help so we recommend using that in case problems appear.
- mesonintrospect.py --targets
+ meson introspect --targets
The JSON formats will not be specified in this document. The easiest way of learning them is to look at sample output from the tool.
Once you have a list of targets, you probably need the list of source files that comprise the target. To get this list for a target, say `exampletarget`, issue the following command.
- mesonintrospect.py --target-files exampletarget
+ meson introspect --target-files exampletarget
In order to make code completion work, you need the compiler flags for each compilation step. Meson does not provide this itself, but the Ninja tool Meson uses to build does provide it. To find out the compile steps necessary to build target foo, issue the following command.
@@ -32,7 +32,7 @@ Note that if the target has dependencies (such as generated sources), then the c
The next thing to display is the list of options that can be set. These include build type and so on. Here's how to extract them.
- mesonintrospect.py --buildoptions
+ meson introspect --buildoptions
To set the options, use the `meson configure` command.
@@ -40,6 +40,6 @@ Compilation and unit tests are done as usual by running the `ninja` and `ninja t
When these tests fail, the user probably wants to run the failing test in a debugger. To make this as integrated as possible, extract the test test setups with this command.
- mesonintrospect.py --tests
+ meson introspect --tests
This provides you with all the information needed to run the test: what command to execute, command line arguments and environment variable settings.
diff --git a/docs/markdown/Pkgconfig-module.md b/docs/markdown/Pkgconfig-module.md
index cbe01b4..853cf50 100644
--- a/docs/markdown/Pkgconfig-module.md
+++ b/docs/markdown/Pkgconfig-module.md
@@ -38,8 +38,9 @@ keyword arguments.
search path, for example if you install headers into
`${PREFIX}/include/foobar-1`, the correct value for this argument
would be `foobar-1`
-- `requires` list of strings to put in the `Requires` field
-- `requires_private` list of strings to put in the `Requires.private`
+- `requires` list of strings, pkgconfig-dependencies or libraries that
+ `pkgconfig.generate()` was used on to put in the `Requires` field
+- `requires_private` same as `requires` but for `Requires.private` field
field
- `url` a string with a url for the library
- `variables` a list of strings with custom variables to add to the
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md
index 4dc87c9..589baf1 100644
--- a/docs/markdown/Reference-manual.md
+++ b/docs/markdown/Reference-manual.md
@@ -267,6 +267,8 @@ keyword arguments.
- `include_directories`, the directories to add to header search path
- `link_args`, link arguments to use
- `link_with`, libraries to link against
+ - `link_whole`, libraries to link fully, same as [`executable`](#executable)
+ Since 0.46.0
- `sources`, sources to add to targets (or generated header files
that should be built before sources including them are built)
- `version`, the version of this dependency, such as `1.2.3`
@@ -433,7 +435,7 @@ be passed to [shared and static libraries](#library).
- `install_dir` override install directory for this file. The value is
relative to the `prefix` specified. F.ex, if you want to install
plugins into a subdir, you'd use something like this: `install_dir :
- get_option('libdir') + '/projectname-1.0'`.
+ join_paths(get_option('libdir'), 'projectname-1.0'`).
- `install_rpath` a string to set the target's rpath to after install
(but *not* before that)
- `objects` list of prebuilt object files (usually for third party
@@ -580,7 +582,7 @@ the following special substitutions:
- `@PLAINNAME@`: the complete input file name, e.g: `foo.c` becomes `foo.c` (unchanged)
- `@BASENAME@`: the base of the input filename, e.g.: `foo.c.y` becomes `foo.c` (extension is removed)
-Each string passed to the `outputs` keyword argument *must* be
+Each string passed to the `output` keyword argument *must* be
constructed using one or both of these two substitutions.
In addition to the above substitutions, the `arguments` keyword
@@ -613,8 +615,13 @@ Obtains the value of the [project build option](Build-options.md) specified in t
Note that the value returned for built-in options that end in `dir` such as
`bindir` and `libdir` is always a path relative to (and inside) the `prefix`.
+
The only exceptions are: `sysconfdir`, `localstatedir`, and `sharedstatedir`
-which will return the value passed during configuration as-is.
+which will return the value passed during configuration as-is, which may be
+absolute, or relative to `prefix`. [`install_dir` arguments](Installing.md)
+handles that as expected, but if you need the absolute path to one of these
+e.g. to use in a define etc., you should use `join_paths(get_option('prefix'),
+get_option('localstatedir')))`
### get_variable()
@@ -661,6 +668,10 @@ Note that this function call itself does not add the directories into
the search path, since there is no global search path. For something
like that, see [`add_project_arguments()`](#add_project_arguments).
+See also `implicit_include_directories` parameter of
+[executable()](#executable), which adds current source and build directories
+to include path.
+
Each directory given is converted to two include paths: one that is
relative to the source root and one relative to the build root.
@@ -976,14 +987,20 @@ Project supports the following keyword arguments.
runresult run_command(command, list_of_args)
```
-Runs the command specified in positional arguments. Returns [an opaque
-object](#run-result-object) containing the result of the
-invocation. The script is run from an *unspecified* directory, and
+Runs the command specified in positional arguments.
+`command` can be a string, or the output of [`find_program()`](#find_program),
+[`files()`](#files) or [`configure_file()`](#configure_file), or
+[a compiler object](#compiler-object).
+
+Returns [an opaque object](#run-result-object) containing the result of the
+invocation. The command is run from an *unspecified* directory, and
Meson will set three environment variables `MESON_SOURCE_ROOT`,
`MESON_BUILD_ROOT` and `MESON_SUBDIR` that specify the source
directory, build directory and subdirectory the target was defined in,
respectively.
+See also [External commands](External-commands.md).
+
### run_target
``` meson
@@ -1134,6 +1151,8 @@ subproject. However, if you want to use a dependency object from
inside a subproject, an easier way is to use the `fallback:` keyword
argument to [`dependency()`](#dependency).
+[See additional documentation](Subprojects.md).
+
### test()
``` meson
@@ -1191,10 +1210,18 @@ be up to date on every build. Keywords are similar to `custom_target`.
Meson will read the contents of `input`, substitute the
`replace_string` with the detected revision number, and write the
-result to `output`. This method returns an opaque
-[`custom_target`](#custom_target) object that can be used as
-source. If you desire more specific behavior than what this command
-provides, you should use `custom_target`.
+result to `output`. This method returns a
+[`custom_target`](#custom_target) object that (as usual) should be
+used to signal dependencies if other targets use the file outputted
+by this.
+
+For example, if you generate a header with this and want to use that in
+a build target, you must add the return value to the sources of that
+build target. Without that, Meson will not know the order in which to
+build the targets.
+
+If you desire more specific behavior than what this command provides,
+you should use `custom_target`.
## Built-in objects
@@ -1780,7 +1807,7 @@ opaque object representing it.
- `get_variable(name)` fetches the specified variable from inside the
subproject. This is useful to, for instance, get a [declared
- dependency](#declare_dependency) from the subproject.
+ dependency](#declare_dependency) from the [subproject](Subprojects.md).
### `run result` object
diff --git a/docs/markdown/Reference-tables.md b/docs/markdown/Reference-tables.md
index 4b7006e..7611232 100644
--- a/docs/markdown/Reference-tables.md
+++ b/docs/markdown/Reference-tables.md
@@ -70,7 +70,7 @@ future releases.
These are the parameter names for passing language specific arguments to your build target.
| Language | Parameter name |
-| ----- | -----
+| ----- | ----- |
| C | c_args |
| C++ | cpp_args |
| C# | cs_args |
diff --git a/docs/markdown/Release-notes-for-0.45.0.md b/docs/markdown/Release-notes-for-0.45.0.md
index b3df71c..6b24183 100644
--- a/docs/markdown/Release-notes-for-0.45.0.md
+++ b/docs/markdown/Release-notes-for-0.45.0.md
@@ -1,16 +1,194 @@
---
title: Release 0.45
-short-description: Release notes for 0.45 (preliminary)
+short-description: Release notes for 0.45
...
# New features
-This page is a placeholder for the eventual release notes.
+## Python minimum version is now 3.5
-Notable new features should come with release note updates. This is
-done by creating a file snippet called `snippets/featurename.md` and
-whose contents should look like this:
+Meson will from this version on require Python version 3.5 or newer.
- ## Feature name
+## Config-Tool based dependencies can be specified in a cross file
- A short description explaining the new feature and how it should be used.
+Tools like LLVM and pcap use a config tool for dependencies, this is a
+script or binary that is run to get configuration information (cflags,
+ldflags, etc) from.
+
+These binaries may now be specified in the `binaries` section of a
+cross file.
+
+```dosini
+[binaries]
+cc = ...
+llvm-config = '/usr/bin/llvm-config32'
+```
+
+## Visual Studio C# compiler support
+
+In addition to the Mono C# compiler we also support Visual Studio's C#
+compiler. Currently this is only supported on the Ninja backend.
+
+## Removed two deprecated features
+
+The standalone `find_library` function has been a no-op for a long
+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')
+
+This is now an error. The correct format for this is now:
+
+ run_target('targetname',
+ command : ['command', 'arg1', 'arg2'])
+
+## Experimental FPGA support
+
+This version adds support for generating, analysing and uploading FPGA
+programs using the [IceStorm
+toolchain](http://www.clifford.at/icestorm/). This support is
+experimental and is currently limited to the `iCE 40` series of FPGA
+chips.
+
+FPGA generation integrates with other parts of Meson seamlessly. As an
+example, [here](https://github.com/jpakkane/lm32) is an example
+project that compiles a simple firmware into Verilog and combines that
+with an lm32 softcore processor.
+
+## Generator outputs can preserve directory structure
+
+Normally when generating files with a generator, Meson flattens the
+input files so they all go in the same directory. Some code
+generators, such as Protocol Buffers, require that the generated files
+have the same directory layout as the input files used to generate
+them. This can now be achieved like this:
+
+```meson
+g = generator(...) # Compiles protobuf sources
+generated = gen.process('com/mesonbuild/one.proto',
+ 'com/mesonbuild/two.proto',
+ preserve_path_from : meson.current_source_dir())
+```
+
+This would cause the following files to be generated inside the target
+private directory:
+
+ com/mesonbuild/one.pb.h
+ com/mesonbuild/one.pb.cc
+ com/mesonbuild/two.pb.h
+ com/mesonbuild/two.pb.cc
+
+## Hexadecimal string literals
+
+Hexadecimal integer literals can now be used in build and option files.
+
+ int_255 = 0xFF
+
+## b_ndebug : if-release
+
+The value `if-release` can be given for the `b_ndebug` project option.
+
+This will make the `NDEBUG` pre-compiler macro to be defined for release
+type builds as if the `b_ndebug` project option had had the value `true`
+defined for it.
+
+## `install_data()` defaults to `{datadir}/{projectname}`
+
+If `install_data()` is not given an `install_dir` keyword argument, the
+target directory defaults to `{datadir}/{projectname}` (e.g.
+`/usr/share/myproj`).
+
+## install_subdir() supports strip_directory
+
+If strip_directory=true install_subdir() installs directory contents
+instead of directory itself, stripping basename of the source directory.
+
+## Integer options
+
+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)
+
+## New method meson.project_license()
+
+The `meson` builtin object now has a `project_license()` method that
+returns a list of all licenses for the project.
+
+## Rust cross-compilation
+
+Cross-compilation is now supported for Rust targets. Like other
+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:
+
+```
+[binaries]
+c = '/usr/bin/arm-linux-gnueabihf-gcc-7'
+rust = [
+ 'rustc',
+ '--target', 'arm-unknown-linux-gnueabihf',
+ '-C', 'linker=/usr/bin/arm-linux-gnueabihf-gcc-7',
+]
+```
+
+## Rust compiler-private library disambiguation
+
+When building a Rust target with Rust library dependencies, an
+`--extern` argument is now specified to avoid ambiguity between the
+dependency library, and any crates of the same name in `rustc`'s
+private sysroot.
+
+## Project templates
+
+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
+```
+
+## Improve test setup selection
+
+Test setups are now identified (also) by the project they belong to
+and it is possible to select the used test setup from a specific
+project. E.g. to use a test setup `some_setup` from project
+`some_project` for all executed tests one can use
+
+ meson test --setup some_project:some_setup
+
+Should one rather want test setups to be used from the same project as
+where the current test itself has been defined, one can use just
+
+ meson test --setup some_setup
+
+In the latter case every (sub)project must have a test setup `some_setup`
+defined in it.
+
+## Can use custom targets as Windows resource files
+
+The `compile_resources()` function of the `windows` module can now be used on custom targets as well as regular files.
+# Can promote dependencies with wrap command
+
+The `promote` command makes it easy to copy nested dependencies to the top level.
+
+ meson wrap promote scommon
+
+This will search the project tree for a subproject called `scommon`
+and copy it to the top level.
+
+If there are many embedded subprojects with the same name, you have to
+specify which one to promote manually like this:
+
+ meson wrap promote subprojects/s1/subprojects/scommon
+
+## Yielding subproject option to superproject
+
+Normally project options are specific to the current project. However
+sometimes you want to have an option whose value is the same over all
+projects. This can be achieved with the new `yield` keyword for
+options. When set to `true`, getting the value of this option in
+`meson.build` files gets the value from the option with the same name
+in the master project (if such an option exists).
diff --git a/docs/markdown/Release-notes-for-0.46.0.md b/docs/markdown/Release-notes-for-0.46.0.md
new file mode 100644
index 0000000..395a94d
--- /dev/null
+++ b/docs/markdown/Release-notes-for-0.46.0.md
@@ -0,0 +1,16 @@
+---
+title: Release 0.46
+short-description: Release notes for 0.46 (preliminary)
+...
+
+# New features
+
+This page is a placeholder for the eventual release notes.
+
+Notable new features should come with release note updates. This is
+done by creating a file snippet called `snippets/featurename.md` and
+whose contents should look like this:
+
+ ## Feature name
+
+ A short description explaining the new feature and how it should be used.
diff --git a/docs/markdown/Subprojects.md b/docs/markdown/Subprojects.md
index 0d1442e..ad2aae2 100644
--- a/docs/markdown/Subprojects.md
+++ b/docs/markdown/Subprojects.md
@@ -77,3 +77,27 @@ subproject `b` and have `b` also use `a`.
Meson ships with a dependency system to automatically obtain
dependency subprojects. It is documented in the [Wrap dependency
system manual](Wrap-dependency-system-manual.md).
+
+# Why must all subprojects be inside a single directory?
+
+There are several reasons.
+
+First of all, to maintain any sort of sanity, the system must prevent going
+inside other subprojects with `subdir()` or variations thereof. Having the
+subprojects in well defined places makes this easy. If subprojects could be
+anywhere at all, it would be a lot harder.
+
+Second of all it is extremely important that end users can easily see what
+subprojects any project has. Because they are in one, and only one, place,
+reviewing them becomes easy.
+
+This is also a question of convention. Since all Meson projects have the same
+layout w.r.t subprojects, switching between projects becomes easier. You don't
+have to spend time on a new project traipsing through the source tree looking
+for subprojects. They are always in the same place.
+
+Finally if you can have subprojects anywhere, this increases the possibility of
+having many different (possibly incompatible) versions of a dependency in your
+source tree. Then changing some code (such as changing the order you traverse
+directories) may cause a completely different version of the subproject to be
+used by accident.
diff --git a/docs/markdown/snippets/altered-logging.md b/docs/markdown/snippets/altered-logging.md
new file mode 100644
index 0000000..4ff9bb0
--- /dev/null
+++ b/docs/markdown/snippets/altered-logging.md
@@ -0,0 +1,5 @@
+## Log output slightly changed
+
+The format of some human-readable diagnostic messages has changed in
+minor ways. In case you are parsing these messages, you may need to
+adjust your code.
diff --git a/docs/markdown/snippets/compiler-object-run_command.md b/docs/markdown/snippets/compiler-object-run_command.md
new file mode 100644
index 0000000..0308416
--- /dev/null
+++ b/docs/markdown/snippets/compiler-object-run_command.md
@@ -0,0 +1,10 @@
+## Compiler object can now be passed to run_command()
+
+This can be used to run the current compiler with the specified arguments
+to obtain additional information from it.
+One of the use cases is to get the location of development files for the
+GCC plugins:
+
+ cc = meson.get_compiler('c')
+ result = run_command(cc, '-print-file-name=plugin')
+ plugin_dev_path = result.stdout().strip()
diff --git a/docs/markdown/snippets/config-tool-cross.md b/docs/markdown/snippets/config-tool-cross.md
deleted file mode 100644
index 1102481..0000000
--- a/docs/markdown/snippets/config-tool-cross.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Config-Tool based dependencies can be specified in a cross file
-
-Tools like LLVM and pcap use a config tool for dependencies, this is a script
-or binary that is run to get configuration information (cflags, ldflags, etc)
-from.
-
-These binaries may now be specified in the `binaries` section of a cross file.
-
-```dosini
-[binaries]
-cc = ...
-llvm-config = '/usr/bin/llvm-config32'
-```
diff --git a/docs/markdown/snippets/csc.md b/docs/markdown/snippets/csc.md
deleted file mode 100644
index 90a6f7f..0000000
--- a/docs/markdown/snippets/csc.md
+++ /dev/null
@@ -1,4 +0,0 @@
-## Visual Studio C# compiler support
-
-In addition to the Mono C# compiler we also support Visual Studio's C#
-compiler. Currently this is only supported on the Ninja backend.
diff --git a/docs/markdown/snippets/declare_dependency-link_whole.md b/docs/markdown/snippets/declare_dependency-link_whole.md
new file mode 100644
index 0000000..827b1f6
--- /dev/null
+++ b/docs/markdown/snippets/declare_dependency-link_whole.md
@@ -0,0 +1,4 @@
+## declare_dependency() supports link_whole
+
+`declare_dependency()` supports `link_whole` parameter.
+`link_whole` propagates to build target that uses dependency.
diff --git a/docs/markdown/snippets/deprecations.md b/docs/markdown/snippets/deprecations.md
deleted file mode 100644
index adab2e6..0000000
--- a/docs/markdown/snippets/deprecations.md
+++ /dev/null
@@ -1,14 +0,0 @@
-## Removed two deprecated features
-
-The standalone `find_library` function has been a no-op for a long
-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')
-
-This is now an error. The correct format for this is now:
-
- run_target('targetname',
- command : ['command', 'arg1', 'arg2'])
diff --git a/docs/markdown/snippets/fpga.md b/docs/markdown/snippets/fpga.md
deleted file mode 100644
index b5e4938..0000000
--- a/docs/markdown/snippets/fpga.md
+++ /dev/null
@@ -1,12 +0,0 @@
-## Experimental FPGA support
-
-This version adds support for generating, analysing and uploading FPGA
-programs using the [IceStorm
-toolchain](http://www.clifford.at/icestorm/). This support is
-experimental and is currently limited to the `iCE 40` series of FPGA
-chips.
-
-FPGA generation integrates with other parts of Meson seamlessly. As an
-example, [here](https://github.com/jpakkane/lm32) is an example
-project that compiles a simple firmware into Verilog and combines that
-with an lm32 softcore processor.
diff --git a/docs/markdown/snippets/gen-subdirs.md b/docs/markdown/snippets/gen-subdirs.md
deleted file mode 100644
index fdb5945..0000000
--- a/docs/markdown/snippets/gen-subdirs.md
+++ /dev/null
@@ -1,21 +0,0 @@
-## Generator outputs can preserve directory structure
-
-Normally when generating files with a generator, Meson flattens the
-input files so they all go in the same directory. Some code
-generators, such as Protocol Buffers, require that the generated files
-have the same directory layout as the input files used to generate
-them. This can now be achieved like this:
-
-```meson
-g = generator(...) # Compiles protobuf sources
-generated = gen.process('com/mesonbuild/one.proto',
- 'com/mesonbuild/two.proto',
- preserve_path_from : meson.current_source_dir())
-
-This would cause the following files to be generated inside the target
-private directory:
-
- com/mesonbuild/one.pb.h
- com/mesonbuild/one.pb.cc
- com/mesonbuild/two.pb.h
- com/mesonbuild/two.pb.cc
diff --git a/docs/markdown/snippets/hexnumbers.md b/docs/markdown/snippets/hexnumbers.md
deleted file mode 100644
index 840c0cb..0000000
--- a/docs/markdown/snippets/hexnumbers.md
+++ /dev/null
@@ -1,5 +0,0 @@
-## Hexadecimal string literals
-
-Hexadecimal integer literals can now be used in build and option files.
-
- int_255 = 0xFF
diff --git a/docs/markdown/snippets/if-release.md b/docs/markdown/snippets/if-release.md
deleted file mode 100644
index 96e12ef..0000000
--- a/docs/markdown/snippets/if-release.md
+++ /dev/null
@@ -1,7 +0,0 @@
-## b_ndebug : if-release
-
-The value `if-release` can be given for the `b_ndebug` project option.
-
-This will make the `NDEBUG` pre-compiler macro to be defined for release
-type builds as if the `b_ndebug` project option had had the value `true`
-defined for it.
diff --git a/docs/markdown/snippets/improved-help.md b/docs/markdown/snippets/improved-help.md
new file mode 100644
index 0000000..db7e852
--- /dev/null
+++ b/docs/markdown/snippets/improved-help.md
@@ -0,0 +1,6 @@
+## "meson help" now shows command line help
+
+Command line parsing is now less surprising. "meson help" is now
+equivalent to "meson --help" and "meson help <subcommand>" is
+equivalent to "meson <subcommand> --help", instead of creating a build
+directory called "help" in these cases.
diff --git a/docs/markdown/snippets/improved-meson-init.md b/docs/markdown/snippets/improved-meson-init.md
new file mode 100644
index 0000000..ec17bc4
--- /dev/null
+++ b/docs/markdown/snippets/improved-meson-init.md
@@ -0,0 +1,19 @@
+## Autogeneration of simple meson.build files
+
+A feature to generate a meson.build file compiling given C/C++ source
+files into a single executable has been added to "meson init". By
+default, it will take all recognizable source files in the current
+directory. You can also specify a list of dependencies with the -d
+flag and automatically invoke a build with the -b flag to check if the
+code builds with those dependencies.
+
+For example,
+
+```meson
+meson init -fbd sdl2,gl
+```
+
+will look for C or C++ files in the current directory, generate a
+meson.build for them with the dependencies of sdl2 and gl and
+immediately try to build it, overwriting any previous meson.build and
+build directory.
diff --git a/docs/markdown/snippets/install_subdir-strip_directory.md b/docs/markdown/snippets/install_subdir-strip_directory.md
deleted file mode 100644
index 9ddb4a4..0000000
--- a/docs/markdown/snippets/install_subdir-strip_directory.md
+++ /dev/null
@@ -1,4 +0,0 @@
-## install_subdir() supports strip_directory
-
-If strip_directory=true install_subdir() installs directory contents
-instead of directory itself, stripping basename of the source directory.
diff --git a/docs/markdown/snippets/installdir.md b/docs/markdown/snippets/installdir.md
deleted file mode 100644
index c709ffe..0000000
--- a/docs/markdown/snippets/installdir.md
+++ /dev/null
@@ -1,5 +0,0 @@
-## `install_data()` defaults to `{datadir}/{projectname}`
-
-If `install_data()` is not given an `install_dir` keyword argument, the
-target directory defaults to `{datadir}/{projectname}` (e.g.
-`/usr/share/myproj`).
diff --git a/docs/markdown/snippets/intopt.md b/docs/markdown/snippets/intopt.md
deleted file mode 100644
index daf660b..0000000
--- a/docs/markdown/snippets/intopt.md
+++ /dev/null
@@ -1,6 +0,0 @@
-## Integer options
-
-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)
diff --git a/docs/markdown/snippets/pkgconfig-requires-non-string.md b/docs/markdown/snippets/pkgconfig-requires-non-string.md
new file mode 100644
index 0000000..abf85b0
--- /dev/null
+++ b/docs/markdown/snippets/pkgconfig-requires-non-string.md
@@ -0,0 +1,5 @@
+## pkgconfig.generate() requires parameters non-string arguments
+
+`pkgconfig.generate()` `requires` and `requires_private` parameters
+accept pkgconfig-dependencies and libraries that pkgconfig-files were
+generated for.
diff --git a/docs/markdown/snippets/project-license.md b/docs/markdown/snippets/project-license.md
deleted file mode 100644
index 5da2c6a..0000000
--- a/docs/markdown/snippets/project-license.md
+++ /dev/null
@@ -1,4 +0,0 @@
-## New method meson.project_license()
-
-The `meson` builtin object now has a `project_license()` method that returns a
-list of all licenses for the project.
diff --git a/docs/markdown/snippets/rust-cross.md b/docs/markdown/snippets/rust-cross.md
deleted file mode 100644
index 7f18c44..0000000
--- a/docs/markdown/snippets/rust-cross.md
+++ /dev/null
@@ -1,16 +0,0 @@
-## Rust cross-compilation
-
-Cross-compilation is now supported for Rust targets. Like other
-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:
-
-```
-[binaries]
-c = '/usr/bin/arm-linux-gnueabihf-gcc-7'
-rust = [
- 'rustc',
- '--target', 'arm-unknown-linux-gnueabihf',
- '-C', 'linker=/usr/bin/arm-linux-gnueabihf-gcc-7',
-]
-```
diff --git a/docs/markdown/snippets/rust-private-disambiguation.md b/docs/markdown/snippets/rust-private-disambiguation.md
deleted file mode 100644
index 6988a7a..0000000
--- a/docs/markdown/snippets/rust-private-disambiguation.md
+++ /dev/null
@@ -1,6 +0,0 @@
-## Rust compiler-private library disambiguation
-
-When building a Rust target with Rust library dependencies, an
-`--extern` argument is now specified to avoid ambiguity between the
-dependency library, and any crates of the same name in `rustc`'s
-private sysroot.
diff --git a/docs/markdown/snippets/templates.md b/docs/markdown/snippets/templates.md
deleted file mode 100644
index 6f0474d..0000000
--- a/docs/markdown/snippets/templates.md
+++ /dev/null
@@ -1,8 +0,0 @@
-## Project templates
-
-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
-```
diff --git a/docs/markdown/snippets/windows-resources-custom-targets.md b/docs/markdown/snippets/windows-resources-custom-targets.md
deleted file mode 100644
index a2dce3a..0000000
--- a/docs/markdown/snippets/windows-resources-custom-targets.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## Can use custom targets as Windows resource files
-
-The `compile_resources()` function of the `windows` module can now be used on custom targets as well as regular files.
diff --git a/docs/markdown/snippets/wrap_promote.md b/docs/markdown/snippets/wrap_promote.md
deleted file mode 100644
index 20fee47..0000000
--- a/docs/markdown/snippets/wrap_promote.md
+++ /dev/null
@@ -1,11 +0,0 @@
-# Can promote dependencies with wrap command
-
-The `promote` command makes it easy to copy nested dependencies to the top level.
-
- meson wrap promote scommon
-
-This will search the project tree for a subproject called `scommon` and copy it to the top level.
-
-If there are many embedded subprojects with the same name, you have to specify which one to promote manually like this:
-
- meson wrap promote subprojects/s1/subprojects/scommon
diff --git a/docs/markdown/snippets/yield.md b/docs/markdown/snippets/yield.md
deleted file mode 100644
index 3880e67..0000000
--- a/docs/markdown/snippets/yield.md
+++ /dev/null
@@ -1,8 +0,0 @@
-## Yielding subproject option to superproject
-
-Normally project options are specific to the current project. However
-sometimes you want to have an option whose value is the same over all
-projects. This can be achieved with the new `yield` keyword for
-options. When set to `true`, getting the value of this option in
-`meson.build` files gets the value from the option with the same name
-in the master project (if such an option exists).
diff --git a/docs/sitemap.txt b/docs/sitemap.txt
index 144ca4a..844b600 100644
--- a/docs/sitemap.txt
+++ b/docs/sitemap.txt
@@ -65,6 +65,7 @@ index.md
Shipping-prebuilt-binaries-as-wraps.md
fallback-wraptool.md
Release-notes.md
+ Release-notes-for-0.46.0.md
Release-notes-for-0.45.0.md
Release-notes-for-0.44.0.md
Release-notes-for-0.43.0.md
diff --git a/ghwt.py b/ghwt.py
index bf06e19..32db4be 100755
--- a/ghwt.py
+++ b/ghwt.py
@@ -55,7 +55,7 @@ def unpack(sproj, branch, outdir):
print(' expected:', dig)
print(' obtained:', should)
return 1
- spdir = os.path.split(outdir)[0]
+ spdir = os.path.dirname(outdir)
ofilename = os.path.join(spdir, config['wrap-file']['source_filename'])
with open(ofilename, 'wb') as ofile:
ofile.write(us)
diff --git a/man/meson.1 b/man/meson.1
index 4429fa2..19ad737 100644
--- a/man/meson.1
+++ b/man/meson.1
@@ -1,4 +1,4 @@
-.TH MESON "1" "December 2017" "meson 0.44.0" "User Commands"
+.TH MESON "1" "March 2018" "meson 0.45.0" "User Commands"
.SH NAME
meson - a high productivity build system
.SH DESCRIPTION
diff --git a/man/mesonconf.1 b/man/mesonconf.1
index 3a83473..b189663 100644
--- a/man/mesonconf.1
+++ b/man/mesonconf.1
@@ -1,4 +1,4 @@
-.TH MESONCONF "1" "December 2017" "mesonconf 0.44.0" "User Commands"
+.TH MESONCONF "1" "March 2018" "mesonconf 0.45.0" "User Commands"
.SH NAME
mesonconf - a tool to configure Meson builds
.SH DESCRIPTION
diff --git a/man/mesonintrospect.1 b/man/mesonintrospect.1
index 27f39c0..61aa381 100644
--- a/man/mesonintrospect.1
+++ b/man/mesonintrospect.1
@@ -1,4 +1,4 @@
-.TH MESONINTROSPECT "1" "December 2017" "mesonintrospect 0.44.0" "User Commands"
+.TH MESONINTROSPECT "1" "March 2017" "mesonintrospect 0.45.0" "User Commands"
.SH NAME
mesonintrospect - a tool to extract information about a Meson build
.SH DESCRIPTION
diff --git a/man/mesontest.1 b/man/mesontest.1
index d2b2743..9a9f743 100644
--- a/man/mesontest.1
+++ b/man/mesontest.1
@@ -1,4 +1,4 @@
-.TH MESON "1" "December 2017" "meson 0.44.0" "User Commands"
+.TH MESON "1" "March 2018" "meson 0.45.0" "User Commands"
.SH NAME
mesontest - test tool for the Meson build system
.SH DESCRIPTION
diff --git a/man/wraptool.1 b/man/wraptool.1
index 113b33c..93ec457 100644
--- a/man/wraptool.1
+++ b/man/wraptool.1
@@ -1,4 +1,4 @@
-.TH WRAPTOOL "1" "December 2017" "meson 0.44.0" "User Commands"
+.TH WRAPTOOL "1" "March 2018" "meson 0.45.0" "User Commands"
.SH NAME
wraptool - source dependency downloader
.SH DESCRIPTION
diff --git a/meson.py b/meson.py
index 13bc870..abbac6f 100755
--- a/meson.py
+++ b/meson.py
@@ -14,8 +14,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from mesonbuild import mesonmain, mesonlib
-import sys, os, locale
+from mesonbuild import mesonmain
+import sys, os
def main():
# Always resolve the command path so Ninja can find it for regen, tests, etc.
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index b547bc3..a8e8164 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -65,9 +65,10 @@ class ExecutableSerialisation:
self.capture = capture
class TestSerialisation:
- def __init__(self, name, suite, fname, is_cross_built, exe_wrapper, is_parallel, cmd_args, env,
- should_fail, timeout, workdir, extra_paths):
+ def __init__(self, name, project, suite, fname, is_cross_built, exe_wrapper, is_parallel,
+ cmd_args, env, should_fail, timeout, workdir, extra_paths):
self.name = name
+ self.project_name = project
self.suite = suite
self.fname = fname
self.is_cross_built = is_cross_built
@@ -603,9 +604,9 @@ class Backend:
cmd_args.append(self.get_target_filename(a))
else:
raise MesonException('Bad object in test command.')
- ts = TestSerialisation(t.get_name(), t.suite, cmd, is_cross, exe_wrapper,
- t.is_parallel, cmd_args, t.env, t.should_fail,
- t.timeout, t.workdir, extra_paths)
+ ts = TestSerialisation(t.get_name(), t.project_name, t.suite, cmd, is_cross,
+ exe_wrapper, t.is_parallel, cmd_args, t.env,
+ t.should_fail, t.timeout, t.workdir, extra_paths)
arr.append(ts)
pickle.dump(arr, datafile)
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index 9284f8a..df1f427 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -12,8 +12,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import os, pickle, re, shlex, subprocess, sys
+import os, pickle, re, shlex, subprocess
from collections import OrderedDict
+import itertools
from pathlib import PurePath
from . import backends
@@ -115,7 +116,6 @@ class NinjaBuildElement:
(name, elems) = e
should_quote = name not in raw_names
line = ' %s = ' % name
- noq_templ = "%s"
newelems = []
for i in elems:
if not should_quote or i == '&&': # Hackety hack hack
@@ -264,7 +264,7 @@ int dummy;
vala_header = File.from_built_file(self.get_target_dir(target), target.vala_header)
header_deps.append(vala_header)
# Recurse and find generated headers
- for dep in target.link_targets:
+ for dep in itertools.chain(target.link_targets, target.link_whole_targets):
if isinstance(dep, (build.StaticLibrary, build.SharedLibrary)):
header_deps += self.get_generated_headers(dep)
return header_deps
@@ -660,11 +660,30 @@ int dummy;
# Alias that runs the target defined above
self.create_target_alias('meson-coverage-html', outfile)
elem = NinjaBuildElement(self.all_outputs, os.path.join(htmloutdir, 'index.html'), 'CUSTOM_COMMAND', '')
- command = [lcov_exe, '--directory', self.environment.get_build_dir(),
- '--capture', '--output-file', covinfo, '--no-checksum',
- '&&', genhtml_exe, '--prefix', self.environment.get_build_dir(),
- '--output-directory', htmloutdir, '--title', 'Code coverage',
- '--legend', '--show-details', covinfo]
+
+ subproject_dir = self.build.get_subproject_dir()
+ command = [lcov_exe,
+ '--directory', self.environment.get_build_dir(),
+ '--capture',
+ '--output-file', covinfo,
+ '--no-checksum',
+ '&&', lcov_exe,
+ '--extract',
+ covinfo,
+ os.path.join(self.environment.get_source_dir(), '*'),
+ '--output-file', covinfo,
+ '&&', lcov_exe,
+ '--remove',
+ covinfo,
+ os.path.join(self.environment.get_source_dir(), subproject_dir, '*'),
+ '--output-file', covinfo,
+ '&&', genhtml_exe,
+ '--prefix', self.environment.get_build_dir(),
+ '--output-directory', htmloutdir,
+ '--title', 'Code coverage',
+ '--legend',
+ '--show-details',
+ covinfo]
elem.add_item('COMMAND', command)
elem.add_item('DESC', 'Generating HTML coverage report.')
elem.write(outfile)
@@ -1083,7 +1102,7 @@ int dummy;
the build directory.
"""
result = OrderedSet()
- for dep in target.link_targets + target.link_whole_targets:
+ for dep in itertools.chain(target.link_targets, target.link_whole_targets):
for i in dep.sources:
if hasattr(i, 'fname'):
i = i.fname
@@ -1870,7 +1889,6 @@ rule FORTRAN_DEP_HACK
infilelist = genlist.get_inputs()
outfilelist = genlist.get_outputs()
extra_dependencies = [os.path.join(self.build_to_src, i) for i in genlist.extra_depends]
- source_target_dir = self.get_target_source_dir(target)
for i in range(len(infilelist)):
if len(generator.outputs) == 1:
sole_output = os.path.join(self.get_target_private_dir(target), outfilelist[i])
@@ -1895,7 +1913,6 @@ rule FORTRAN_DEP_HACK
# We have consumed output files, so drop them from the list of remaining outputs.
if sole_output == '':
outfilelist = outfilelist[len(generator.outputs):]
- relout = self.get_target_private_dir(target)
args = self.replace_paths(target, args, override_subdir=subdir)
cmdlist = exe_arr + self.replace_extra_args(args, genlist)
if generator.capture:
@@ -2712,3 +2729,9 @@ rule FORTRAN_DEP_HACK
elem = NinjaBuildElement(self.all_outputs, deps, 'phony', '')
elem.write(outfile)
+
+def load(build_dir):
+ filename = os.path.join(build_dir, 'meson-private', 'install.dat')
+ with open(filename, 'rb') as f:
+ obj = pickle.load(f)
+ return obj
diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
index 057e7c9..7f4c2ef 100644
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import os, sys
+import os
import pickle
import xml.dom.minidom
import xml.etree.ElementTree as ET
diff --git a/mesonbuild/backend/xcodebackend.py b/mesonbuild/backend/xcodebackend.py
index 3ae31e4..9a9f88b 100644
--- a/mesonbuild/backend/xcodebackend.py
+++ b/mesonbuild/backend/xcodebackend.py
@@ -16,7 +16,7 @@ from . import backends
from .. import build
from .. import dependencies
from .. import mesonlib
-import uuid, os, sys
+import uuid, os
from ..mesonlib import MesonException
@@ -565,9 +565,7 @@ class XCodeBackend(backends.Backend):
self.write_line(');')
self.write_line('runOnlyForDeploymentPostprocessing = 0;')
self.write_line('shellPath = /bin/sh;')
- script_root = self.environment.get_script_dir()
- test_script = os.path.join(script_root, 'meson_test.py')
- cmd = mesonlib.python_command + [test_script, test_data, '--wd', self.environment.get_build_dir()]
+ cmd = mesonlib.meson_command + ['test', test_data, '-C', self.environment.get_build_dir()]
cmdstr = ' '.join(["'%s'" % i for i in cmd])
self.write_line('shellScript = "%s";' % cmdstr)
self.write_line('showEnvVarsInLog = 0;')
@@ -708,7 +706,7 @@ class XCodeBackend(backends.Backend):
if isinstance(target, build.SharedLibrary):
ldargs = ['-dynamiclib', '-Wl,-headerpad_max_install_names'] + dep_libs
install_path = os.path.join(self.environment.get_build_dir(), target.subdir, buildtype)
- dylib_version = target.version
+ dylib_version = target.soversion
else:
ldargs = dep_libs
install_path = ''
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index 6ed8843..5c9f346 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -15,6 +15,7 @@
import copy, os, re
from collections import OrderedDict
import itertools, pathlib
+import pickle
from . import environment
from . import dependencies
@@ -113,6 +114,7 @@ class Build:
self.static_linker = None
self.static_cross_linker = None
self.subprojects = {}
+ self.subproject_dir = ''
self.install_scripts = []
self.postconf_scripts = []
self.install_dirs = []
@@ -138,6 +140,9 @@ class Build:
def get_project(self):
return self.projects['']
+ def get_subproject_dir(self):
+ return self.subproject_dir
+
def get_targets(self):
return self.targets
@@ -793,7 +798,7 @@ This will become a hard error in a future Meson release.''')
def get_dependencies(self):
transitive_deps = []
- for t in self.link_targets + self.link_whole_targets:
+ for t in itertools.chain(self.link_targets, self.link_whole_targets):
transitive_deps.append(t)
if isinstance(t, StaticLibrary):
transitive_deps += t.get_dependencies()
@@ -837,12 +842,14 @@ This will become a hard error in a future Meson release.''')
self.add_include_dirs(dep.include_directories)
for l in dep.libraries:
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)
# Deps of deps.
self.add_deps(dep.ext_deps)
@@ -1928,3 +1935,22 @@ def get_sources_string_names(sources):
else:
raise AssertionError('Unknown source type: {!r}'.format(s))
return names
+
+def load(build_dir):
+ filename = os.path.join(build_dir, 'meson-private', 'build.dat')
+ load_fail_msg = 'Build data file {!r} is corrupted. Try with a fresh build tree.'.format(filename)
+ nonexisting_fail_msg = 'No such build data file as "{!r}".'.format(filename)
+ try:
+ with open(filename, 'rb') as f:
+ obj = pickle.load(f)
+ except FileNotFoundError:
+ raise MesonException(nonexisting_fail_msg)
+ except pickle.UnpicklingError:
+ raise MesonException(load_fail_msg)
+ if not isinstance(obj, Build):
+ raise MesonException(load_fail_msg)
+ return obj
+
+def save(obj, filename):
+ with open(filename, 'wb') as f:
+ pickle.dump(obj, f)
diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py
index 1c9b9b4..2d14116 100644
--- a/mesonbuild/compilers/c.py
+++ b/mesonbuild/compilers/c.py
@@ -525,7 +525,7 @@ class CCompiler(Compiler):
elif rtype == 'int':
try:
return int(res.stdout.strip())
- except:
+ except ValueError:
m = 'Return value of {}() is not an int'
raise EnvironmentException(m.format(fname))
@@ -1140,7 +1140,7 @@ class VisualStudioCCompiler(CCompiler):
# See boost/config/compiler/visualc.cpp for up to date mapping
try:
version = int(''.join(self.version.split('.')[0:2]))
- except:
+ except ValueError:
return None
if version < 1310:
return '7.0'
diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py
index c10f38e..1fa6f15 100644
--- a/mesonbuild/compilers/cpp.py
+++ b/mesonbuild/compilers/cpp.py
@@ -112,7 +112,7 @@ class GnuCPPCompiler(GnuCompiler, CPPCompiler):
if self.gcc_type == GCC_MINGW:
opts.update({
'cpp_winlibs': coredata.UserArrayOption('cpp_winlibs', 'Standard Win libraries to link against',
- gnu_winlibs), })
+ gnu_winlibs), })
return opts
def get_option_compile_args(self, options):
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index bae207b..993effc 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -21,7 +21,7 @@ from .mesonlib import MesonException
from .mesonlib import default_libdir, default_libexecdir, default_prefix
import ast
-version = '0.45.0.dev1'
+version = '0.46.0.dev1'
backendlist = ['ninja', 'vs', 'vs2010', 'vs2015', 'vs2017', 'xcode']
default_yielding = False
@@ -111,7 +111,7 @@ class UserIntegerOption(UserOption):
def toint(self, valuestring):
try:
return int(valuestring)
- except:
+ except ValueError:
raise MesonException('Value string "%s" is not convertable to an integer.' % valuestring)
def validate_value(self, value):
@@ -340,7 +340,8 @@ class CoreData:
return opt.validate_value(override_value)
raise MesonException('Tried to validate unknown option %s.' % option_name)
-def load(filename):
+def load(build_dir):
+ filename = os.path.join(build_dir, 'meson-private', 'coredata.dat')
load_fail_msg = 'Coredata file {!r} is corrupted. Try with a fresh build tree.'.format(filename)
try:
with open(filename, 'rb') as f:
@@ -354,7 +355,8 @@ def load(filename):
(obj.version, version))
return obj
-def save(obj, filename):
+def save(obj, build_dir):
+ filename = os.path.join(build_dir, 'meson-private', 'coredata.dat')
if obj.version != version:
raise MesonException('Fatal version mismatch corruption.')
with open(filename, 'wb') as f:
diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py
index 7a652a4..0375102 100644
--- a/mesonbuild/dependencies/base.py
+++ b/mesonbuild/dependencies/base.py
@@ -145,7 +145,7 @@ class Dependency:
class InternalDependency(Dependency):
- def __init__(self, version, incdirs, compile_args, link_args, libraries, sources, ext_deps):
+ def __init__(self, version, incdirs, compile_args, link_args, libraries, whole_libraries, sources, ext_deps):
super().__init__('internal', {})
self.version = version
self.is_found = True
@@ -153,6 +153,7 @@ class InternalDependency(Dependency):
self.compile_args = compile_args
self.link_args = link_args
self.libraries = libraries
+ self.whole_libraries = whole_libraries
self.sources = sources
self.ext_deps = ext_deps
@@ -380,9 +381,7 @@ class PkgConfigDependency(ExternalDependency):
pkgname = environment.cross_info.config['binaries']['pkgconfig']
potential_pkgbin = ExternalProgram(pkgname, silent=True)
if potential_pkgbin.found():
- # FIXME, we should store all pkg-configs in ExternalPrograms.
- # However that is too destabilizing a change to do just before release.
- self.pkgbin = potential_pkgbin.get_command()[0]
+ self.pkgbin = potential_pkgbin
PkgConfigDependency.class_pkgbin = self.pkgbin
else:
mlog.debug('Cross pkg-config %s not found.' % potential_pkgbin.name)
@@ -404,7 +403,7 @@ class PkgConfigDependency(ExternalDependency):
self.type_string = 'Native'
mlog.debug('Determining dependency {!r} with pkg-config executable '
- '{!r}'.format(name, self.pkgbin))
+ '{!r}'.format(name, self.pkgbin.get_path()))
ret, self.version = self._call_pkgbin(['--modversion', name])
if ret != 0:
if self.required:
@@ -463,7 +462,7 @@ class PkgConfigDependency(ExternalDependency):
def _call_pkgbin(self, args, env=None):
if not env:
env = os.environ
- p, out = Popen_safe([self.pkgbin] + args, env=env)[0:2]
+ p, out = Popen_safe(self.pkgbin.get_command() + args, env=env)[0:2]
return p.returncode, out.strip()
def _convert_mingw_paths(self, args):
@@ -608,21 +607,23 @@ class PkgConfigDependency(ExternalDependency):
pkgbin = os.environ[evar].strip()
else:
pkgbin = 'pkg-config'
- try:
- p, out = Popen_safe([pkgbin, '--version'])[0:2]
- if p.returncode != 0:
- # Set to False instead of None to signify that we've already
- # searched for it and not found it
+ pkgbin = ExternalProgram(pkgbin, silent=True)
+ if pkgbin.found():
+ try:
+ p, out = Popen_safe(pkgbin.get_command() + ['--version'])[0:2]
+ if p.returncode != 0:
+ mlog.warning('Found pkg-config {!r} but couldn\'t run it'
+ ''.format(' '.join(pkgbin.get_command())))
+ # Set to False instead of None to signify that we've already
+ # searched for it and not found it
+ pkgbin = False
+ except (FileNotFoundError, PermissionError):
pkgbin = False
- except (FileNotFoundError, PermissionError):
+ else:
pkgbin = False
- if pkgbin and not os.path.isabs(pkgbin) and shutil.which(pkgbin):
- # Sometimes shutil.which fails where Popen succeeds, so
- # only find the abs path if it can be found by shutil.which
- pkgbin = shutil.which(pkgbin)
if not self.silent:
if pkgbin:
- mlog.log('Found pkg-config:', mlog.bold(pkgbin),
+ mlog.log('Found pkg-config:', mlog.bold(pkgbin.get_path()),
'(%s)' % out.strip())
else:
mlog.log('Found Pkg-config:', mlog.red('NO'))
diff --git a/mesonbuild/dependencies/boost.py b/mesonbuild/dependencies/boost.py
index 03cc7b8..a17fb58 100644
--- a/mesonbuild/dependencies/boost.py
+++ b/mesonbuild/dependencies/boost.py
@@ -167,7 +167,7 @@ class BoostDependency(ExternalDependency):
invalid_modules = [x for x in invalid_modules if x not in remove]
if invalid_modules:
- mlog.log(mlog.red('ERROR:'), 'Invalid Boost modules: ' + ', '.join(invalid_modules))
+ mlog.error('Invalid Boost modules: ' + ', '.join(invalid_modules))
return True
else:
return False
diff --git a/mesonbuild/dependencies/ui.py b/mesonbuild/dependencies/ui.py
index 3e2d170..2f31196 100644
--- a/mesonbuild/dependencies/ui.py
+++ b/mesonbuild/dependencies/ui.py
@@ -17,14 +17,13 @@
import os
import re
-import shutil
import subprocess
from collections import OrderedDict
from .. import mlog
from .. import mesonlib
from ..mesonlib import (
- MesonException, Popen_safe, extract_as_list, for_windows,
+ MesonException, Popen_safe, extract_as_list, for_windows, for_cygwin,
version_compare_many
)
from ..environment import detect_cpu
@@ -282,10 +281,15 @@ class QtBaseDependency(ExternalDependency):
(k, v) = tuple(line.split(':', 1))
qvars[k] = v
if mesonlib.is_osx():
- return self._framework_detect(qvars, mods, kwargs)
+ self._framework_detect(qvars, mods, kwargs)
+ return qmake
incdir = qvars['QT_INSTALL_HEADERS']
self.compile_args.append('-I' + incdir)
libdir = qvars['QT_INSTALL_LIBS']
+ if for_cygwin(self.env.is_cross_build(), self.env):
+ shlibext = '.dll.a'
+ else:
+ shlibext = '.so'
# Used by self.compilers_detect()
self.bindir = self.get_qmake_host_bins(qvars)
self.is_found = True
@@ -307,7 +311,7 @@ class QtBaseDependency(ExternalDependency):
self.is_found = False
break
else:
- libfile = os.path.join(libdir, 'lib{}{}.so'.format(self.qtpkgname, module))
+ libfile = os.path.join(libdir, 'lib{}{}{}'.format(self.qtpkgname, module, shlibext))
if not os.path.isfile(libfile):
self.is_found = False
break
@@ -316,15 +320,23 @@ class QtBaseDependency(ExternalDependency):
def _framework_detect(self, qvars, modules, kwargs):
libdir = qvars['QT_INSTALL_LIBS']
+
+ # ExtraFrameworkDependency doesn't support any methods
+ fw_kwargs = kwargs.copy()
+ fw_kwargs.pop('method', None)
+
for m in modules:
fname = 'Qt' + m
fwdep = ExtraFrameworkDependency(fname, False, libdir, self.env,
- self.language, kwargs)
+ self.language, fw_kwargs)
self.compile_args.append('-F' + libdir)
if fwdep.found():
- self.is_found = True
self.compile_args += fwdep.get_compile_args()
self.link_args += fwdep.get_link_args()
+ else:
+ break
+ else:
+ self.is_found = True
# Used by self.compilers_detect()
self.bindir = self.get_qmake_host_bins(qvars)
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index f34a119..ff7c706 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -19,7 +19,6 @@ from .linkers import ArLinker, VisualStudioLinker
from . import mesonlib
from .mesonlib import EnvironmentException, Popen_safe
from . import mlog
-import sys
from . import compilers
from .compilers import (
@@ -265,8 +264,7 @@ class Environment:
os.makedirs(self.scratch_dir, exist_ok=True)
os.makedirs(self.log_dir, exist_ok=True)
try:
- cdf = os.path.join(self.get_build_dir(), Environment.coredata_file)
- self.coredata = coredata.load(cdf)
+ self.coredata = coredata.load(self.get_build_dir())
self.first_invocation = False
except FileNotFoundError:
# WARNING: Don't use any values from coredata in __init__. It gets
@@ -329,9 +327,8 @@ class Environment:
return self.cross_info is not None
def dump_coredata(self):
- cdf = os.path.join(self.get_build_dir(), Environment.coredata_file)
- coredata.save(self.coredata, cdf)
- return cdf
+ coredata.save(self.coredata, self.get_build_dir())
+ return os.path.join(self.get_build_dir(), Environment.coredata_file)
def get_script_dir(self):
import mesonbuild.scripts
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index 5c333a8..1819db4 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -653,10 +653,11 @@ class RunTargetHolder(InterpreterObject, ObjectHolder):
return r.format(self.__class__.__name__, h.get_id(), h.command)
class Test(InterpreterObject):
- def __init__(self, name, suite, exe, is_parallel, cmd_args, env, should_fail, timeout, workdir):
+ def __init__(self, name, project, suite, exe, is_parallel, cmd_args, env, should_fail, timeout, workdir):
InterpreterObject.__init__(self)
self.name = name
self.suite = suite
+ self.project_name = project
self.exe = exe
self.is_parallel = is_parallel
self.cmd_args = cmd_args
@@ -1389,7 +1390,7 @@ permitted_kwargs = {'add_global_arguments': {'language'},
'configure_file': {'input', 'output', 'configuration', 'command', 'install_dir', 'capture', 'install'},
'custom_target': {'input', 'output', 'command', 'install', 'install_dir', 'build_always', 'capture', 'depends', 'depend_files', 'depfile', 'build_by_default'},
'dependency': {'default_options', 'fallback', 'language', 'main', 'method', 'modules', 'optional_modules', 'native', 'required', 'static', 'version'},
- 'declare_dependency': {'include_directories', 'link_with', 'sources', 'dependencies', 'compile_args', 'link_args', 'version'},
+ 'declare_dependency': {'include_directories', 'link_with', 'sources', 'dependencies', 'compile_args', 'link_args', 'link_whole', 'version'},
'executable': exe_kwargs,
'find_program': {'required', 'native'},
'generator': {'arguments', 'output', 'depfile', 'capture', 'preserve_path_from'},
@@ -1621,6 +1622,7 @@ class Interpreter(InterpreterBase):
raise InterpreterException('Version must be a string.')
incs = extract_as_list(kwargs, 'include_directories', unholder=True)
libs = extract_as_list(kwargs, 'link_with', unholder=True)
+ libs_whole = extract_as_list(kwargs, 'link_whole', unholder=True)
sources = extract_as_list(kwargs, 'sources')
sources = listify(self.source_strings_to_files(sources), unholder=True)
deps = extract_as_list(kwargs, 'dependencies', unholder=True)
@@ -1640,7 +1642,7 @@ class Interpreter(InterpreterBase):
raise InterpreterException('''Entries in "link_with" may only be self-built targets,
external dependencies (including libraries) must go to "dependencies".''')
dep = dependencies.InternalDependency(version, incs, compile_args,
- link_args, libs, sources, final_deps)
+ link_args, libs, libs_whole, sources, final_deps)
return DependencyHolder(dep)
@noKwargs
@@ -1678,10 +1680,17 @@ external dependencies (including libraries) must go to "dependencies".''')
cargs = args[1:]
srcdir = self.environment.get_source_dir()
builddir = self.environment.get_build_dir()
- m = 'must be a string, or the output of find_program(), files(), or ' \
- 'configure_file(); not {!r}'
+ m = 'must be a string, or the output of find_program(), files() '\
+ 'or configure_file(), or a compiler object; not {!r}'
if isinstance(cmd, ExternalProgramHolder):
cmd = cmd.held_object
+ elif isinstance(cmd, CompilerHolder):
+ cmd = cmd.compiler.get_exelist()[0]
+ prog = ExternalProgram(cmd, silent=True)
+ if not prog.found():
+ raise InterpreterException('Program {!r} not found '
+ 'or not executable'.format(cmd))
+ cmd = prog
else:
if isinstance(cmd, mesonlib.File):
cmd = cmd.absolute_path(srcdir, builddir)
@@ -1762,6 +1771,12 @@ external dependencies (including libraries) must go to "dependencies".''')
try:
resolved = r.resolve(dirname)
except RuntimeError as e:
+ # if the reason subproject execution failed was because
+ # the directory doesn't exist, try to give some helpful
+ # advice if it's a nested subproject that needs
+ # promotion...
+ self.print_nested_info(dirname)
+
msg = 'Subproject directory {!r} does not exist and cannot be downloaded:\n{}'
raise InterpreterException(msg.format(os.path.join(self.subproject_dir, dirname), e))
subdir = os.path.join(self.subproject_dir, resolved)
@@ -1936,6 +1951,8 @@ to directly access options of other subprojects.''')
raise InterpreterException('Subproject_dir must not contain a ".." segment.')
self.subproject_dir = spdirname
+ self.build.subproject_dir = self.subproject_dir
+
if 'meson_version' in kwargs:
cv = coredata.version
pv = kwargs['meson_version']
@@ -2087,6 +2104,19 @@ to directly access options of other subprojects.''')
else:
version_string = ' (%s %s)' % (comp.id, comp.version)
mlog.log('Native %s compiler: ' % comp.get_display_language(), mlog.bold(' '.join(comp.get_exelist())), version_string, sep='')
+
+ # If <language>_args/_link_args settings are given on the
+ # command line, use them.
+ for optspec in self.build.environment.cmd_line_options.projectoptions:
+ (optname, optvalue) = optspec.split('=', maxsplit=1)
+ if optname.endswith('_link_args'):
+ lang = optname[:-10]
+ self.coredata.external_link_args.setdefault(lang, []).append(optvalue)
+ elif optname.endswith('_args'):
+ lang = optname[:-5]
+ self.coredata.external_args.setdefault(lang, []).append(optvalue)
+ # Otherwise, look for definitions from environment
+ # variables such as CFLAGS.
if not comp.get_language() in self.coredata.external_args:
(preproc_args, compile_args, link_args) = environment.get_args_from_envvars(comp)
self.coredata.external_preprocess_args[comp.get_language()] = preproc_args
@@ -2169,7 +2199,7 @@ to directly access options of other subprojects.''')
if progobj is None:
progobj = self.program_from_system(args)
if required and (progobj is None or not progobj.found()):
- raise InvalidArguments('Program "%s" not found or not executable' % args[0])
+ raise InvalidArguments('Program(s) {!r} not found or not executable'.format(args))
if progobj is None:
return ExternalProgramHolder(dependencies.NonExistingExternalProgram())
return progobj
@@ -2306,7 +2336,6 @@ to directly access options of other subprojects.''')
# we won't actually read all the build files.
return fallback_dep
if not dep:
- self.print_nested_info(name)
assert(exception is not None)
raise exception
@@ -2338,7 +2367,7 @@ root and issuing %s.
cmds = []
command_templ = 'meson wrap promote '
for l in found:
- cmds.append(command_templ + l[len(self.source_root)+1:])
+ cmds.append(command_templ + l[len(self.source_root) + 1:])
final_message = message + '\n'.join(cmds)
print(final_message)
@@ -2586,14 +2615,12 @@ root and issuing %s.
if not isinstance(timeout, int):
raise InterpreterException('Timeout must be an integer.')
suite = []
+ prj = self.subproject if self.is_subproject() else self.build.project_name
for s in mesonlib.stringlistify(kwargs.get('suite', '')):
if len(s) > 0:
s = ':' + s
- if self.is_subproject():
- suite.append(self.subproject.replace(' ', '_').replace(':', '_') + s)
- else:
- suite.append(self.build.project_name.replace(' ', '_').replace(':', '_') + s)
- t = Test(args[0], suite, exe.held_object, par, cmd_args, env, should_fail, timeout, workdir)
+ suite.append(prj.replace(' ', '_').replace(':', '_') + s)
+ t = Test(args[0], prj, suite, exe.held_object, par, cmd_args, env, should_fail, timeout, workdir)
if is_base_test:
self.build.tests.append(t)
mlog.debug('Adding test "', mlog.bold(args[0]), '".', sep='')
@@ -2892,8 +2919,10 @@ different subdirectory.
if len(args) != 1:
raise InterpreterException('Add_test_setup needs one argument for the setup name.')
setup_name = args[0]
- if re.fullmatch('[_a-zA-Z][_0-9a-zA-Z]*', setup_name) is None:
+ if re.fullmatch('([_a-zA-Z][_0-9a-zA-Z]*:)?[_a-zA-Z][_0-9a-zA-Z]*', setup_name) is None:
raise InterpreterException('Setup name may only contain alphanumeric characters.')
+ if ":" not in setup_name:
+ setup_name = (self.subproject if self.subproject else self.build.project_name) + ":" + setup_name
try:
inp = extract_as_list(kwargs, 'exe_wrapper')
exe_wrapper = []
@@ -2917,14 +2946,10 @@ different subdirectory.
if not isinstance(timeout_multiplier, int):
raise InterpreterException('Timeout multiplier must be a number.')
env = self.unpack_env_kwarg(kwargs)
- setupobj = build.TestSetup(exe_wrapper=exe_wrapper,
- gdb=gdb,
- timeout_multiplier=timeout_multiplier,
- env=env)
- if self.subproject == '':
- # Dunno what we should do with subprojects really. Let's start simple
- # and just use the master project ones.
- self.build.test_setups[setup_name] = setupobj
+ self.build.test_setups[setup_name] = build.TestSetup(exe_wrapper=exe_wrapper,
+ gdb=gdb,
+ timeout_multiplier=timeout_multiplier,
+ env=env)
@permittedKwargs(permitted_kwargs['add_global_arguments'])
@stringArgs
diff --git a/mesonbuild/interpreterbase.py b/mesonbuild/interpreterbase.py
index 0539b14..170df29 100644
--- a/mesonbuild/interpreterbase.py
+++ b/mesonbuild/interpreterbase.py
@@ -408,7 +408,7 @@ The result of this is undefined and will become a hard error in a future Meson r
varname = node.var_name
addition = self.evaluate_statement(node.value)
if is_disabler(addition):
- set_variable(varname, addition)
+ self.set_variable(varname, addition)
return
# Remember that all variables are immutable. We must always create a
# full new variable and then assign it.
diff --git a/mesonbuild/mconf.py b/mesonbuild/mconf.py
index 771e9ee..b409615 100644
--- a/mesonbuild/mconf.py
+++ b/mesonbuild/mconf.py
@@ -12,10 +12,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import sys, os
-import pickle
+import os
+import sys
import argparse
-from . import coredata, mesonlib
+from . import (coredata, mesonlib, build)
parser = argparse.ArgumentParser(prog='meson configure')
@@ -25,95 +25,73 @@ parser.add_argument('directory', nargs='*')
parser.add_argument('--clearcache', action='store_true', default=False,
help='Clear cached state (e.g. found dependencies)')
+
class ConfException(mesonlib.MesonException):
pass
+
class Conf:
def __init__(self, build_dir):
self.build_dir = build_dir
- self.coredata_file = os.path.join(build_dir, 'meson-private/coredata.dat')
- self.build_file = os.path.join(build_dir, 'meson-private/build.dat')
- if not os.path.isfile(self.coredata_file) or not os.path.isfile(self.build_file):
+ if not os.path.isdir(os.path.join(build_dir, 'meson-private')):
raise ConfException('Directory %s does not seem to be a Meson build directory.' % build_dir)
- with open(self.coredata_file, 'rb') as f:
- self.coredata = pickle.load(f)
- with open(self.build_file, 'rb') as f:
- self.build = pickle.load(f)
- if self.coredata.version != coredata.version:
- raise ConfException('Version mismatch (%s vs %s)' %
- (coredata.version, self.coredata.version))
+ self.build = build.load(self.build_dir)
+ self.coredata = coredata.load(self.build_dir)
def clear_cache(self):
self.coredata.deps = {}
def save(self):
# Only called if something has changed so overwrite unconditionally.
- with open(self.coredata_file, 'wb') as f:
- pickle.dump(self.coredata, f)
+ coredata.save(self.coredata, self.build_dir)
# We don't write the build file because any changes to it
# are erased when Meson is executed the next time, i.e. when
# Ninja is run.
- def print_aligned(self, arr):
+ @staticmethod
+ def print_aligned(arr):
+ def make_lower_case(val):
+ if isinstance(val, bool):
+ return str(val).lower()
+ elif isinstance(val, list):
+ return [make_lower_case(i) for i in val]
+ else:
+ return str(val)
+
if not arr:
return
- titles = {'name': 'Option', 'descr': 'Description', 'value': 'Current Value', 'choices': 'Possible Values'}
- len_name = longest_name = len(titles['name'])
- len_descr = longest_descr = len(titles['descr'])
- len_value = longest_value = len(titles['value'])
- longest_choices = 0 # not printed if we don't get any optional values
-
- # calculate the max length of each
- for x in arr:
- name = x['name']
- descr = x['descr']
- value = x['value'] if isinstance(x['value'], str) else str(x['value']).lower()
- choices = ''
- if isinstance(x['choices'], list):
- if x['choices']:
- x['choices'] = [s if isinstance(s, str) else str(s).lower() for s in x['choices']]
- choices = '[%s]' % ', '.join(map(str, x['choices']))
- elif x['choices']:
- choices = x['choices'] if isinstance(x['choices'], str) else str(x['choices']).lower()
- longest_name = max(longest_name, len(name))
- longest_descr = max(longest_descr, len(descr))
- longest_value = max(longest_value, len(value))
- longest_choices = max(longest_choices, len(choices))
+ titles = {'name': 'Option', 'descr': 'Description', 'value': 'Current Value', 'choices': 'Possible Values'}
- # update possible non strings
- x['value'] = value
- x['choices'] = choices
+ name_col = [titles['name'], '-' * len(titles['name'])]
+ value_col = [titles['value'], '-' * len(titles['value'])]
+ choices_col = [titles['choices'], '-' * len(titles['choices'])]
+ descr_col = [titles['descr'], '-' * len(titles['descr'])]
- # prints header
- namepad = ' ' * (longest_name - len_name)
- valuepad = ' ' * (longest_value - len_value)
- if longest_choices:
- len_choices = len(titles['choices'])
- longest_choices = max(longest_choices, len_choices)
- choicepad = ' ' * (longest_choices - len_choices)
- print(' %s%s %s%s %s%s %s' % (titles['name'], namepad, titles['value'], valuepad, titles['choices'], choicepad, titles['descr']))
- print(' %s%s %s%s %s%s %s' % ('-' * len_name, namepad, '-' * len_value, valuepad, '-' * len_choices, choicepad, '-' * len_descr))
- else:
- print(' %s%s %s%s %s' % (titles['name'], namepad, titles['value'], valuepad, titles['descr']))
- print(' %s%s %s%s %s' % ('-' * len_name, namepad, '-' * len_value, valuepad, '-' * len_descr))
+ choices_found = False
+ for opt in arr:
+ name_col.append(opt['name'])
+ descr_col.append(opt['descr'])
+ if isinstance(opt['value'], list):
+ value_col.append('[{0}]'.format(', '.join(make_lower_case(opt['value']))))
+ else:
+ value_col.append(make_lower_case(opt['value']))
+ if opt['choices']:
+ choices_found = True
+ choices_col.append('[{0}]'.format(', '.join(make_lower_case(opt['choices']))))
+ else:
+ choices_col.append('')
- # print values
- for i in arr:
- name = i['name']
- descr = i['descr']
- value = i['value']
- choices = i['choices']
+ col_widths = (max([len(i) for i in name_col], default=0),
+ max([len(i) for i in value_col], default=0),
+ max([len(i) for i in choices_col], default=0),
+ max([len(i) for i in descr_col], default=0))
- namepad = ' ' * (longest_name - len(name))
- valuepad = ' ' * (longest_value - len(value))
- if longest_choices:
- choicespad = ' ' * (longest_choices - len(choices))
- f = ' %s%s %s%s %s%s %s' % (name, namepad, value, valuepad, choices, choicespad, descr)
+ for line in zip(name_col, value_col, choices_col, descr_col):
+ if choices_found:
+ print(' {0:{width[0]}} {1:{width[1]}} {2:{width[2]}} {3:{width[3]}}'.format(*line, width=col_widths))
else:
- f = ' %s%s %s%s %s' % (name, namepad, value, valuepad, descr)
-
- print(f)
+ print(' {0:{width[0]}} {1:{width[1]}} {3:{width[3]}}'.format(*line, width=col_widths))
def set_options(self, options):
for o in options:
@@ -156,8 +134,7 @@ class Conf:
print('Core properties:')
print(' Source dir', self.build.environment.source_dir)
print(' Build dir ', self.build.environment.build_dir)
- print('')
- print('Core options:')
+ print('\nCore options:\n')
carr = []
for key in ['buildtype', 'warning_level', 'werror', 'strip', 'unity', 'default_library']:
carr.append({'name': key,
@@ -165,48 +142,39 @@ class Conf:
'value': self.coredata.get_builtin_option(key),
'choices': coredata.get_builtin_option_choices(key)})
self.print_aligned(carr)
- print('')
- bekeys = sorted(self.coredata.backend_options.keys())
- if not bekeys:
+ if not self.coredata.backend_options:
print(' No backend options\n')
else:
bearr = []
- for k in bekeys:
+ for k in sorted(self.coredata.backend_options):
o = self.coredata.backend_options[k]
bearr.append({'name': k, 'descr': o.description, 'value': o.value, 'choices': ''})
self.print_aligned(bearr)
- print('')
- print('Base options:')
- okeys = sorted(self.coredata.base_options.keys())
- if not okeys:
+ print('\nBase options:')
+ if not self.coredata.base_options:
print(' No base options\n')
else:
coarr = []
- for k in okeys:
+ for k in sorted(self.coredata.base_options):
o = self.coredata.base_options[k]
coarr.append({'name': k, 'descr': o.description, 'value': o.value, 'choices': o.choices})
self.print_aligned(coarr)
- print('')
- print('Compiler arguments:')
+ print('\nCompiler arguments:')
for (lang, args) in self.coredata.external_args.items():
print(' ' + lang + '_args', str(args))
- print('')
- print('Linker args:')
+ print('\nLinker args:')
for (lang, args) in self.coredata.external_link_args.items():
print(' ' + lang + '_link_args', str(args))
- print('')
- print('Compiler options:')
- okeys = sorted(self.coredata.compiler_options.keys())
- if not okeys:
+ print('\nCompiler options:')
+ if not self.coredata.compiler_options:
print(' No compiler options\n')
else:
coarr = []
- for k in okeys:
+ for k in self.coredata.compiler_options:
o = self.coredata.compiler_options[k]
coarr.append({'name': k, 'descr': o.description, 'value': o.value, 'choices': ''})
self.print_aligned(coarr)
- print('')
- print('Directories:')
+ print('\nDirectories:')
parr = []
for key in ['prefix',
'libdir',
@@ -227,30 +195,24 @@ class Conf:
'value': self.coredata.get_builtin_option(key),
'choices': coredata.get_builtin_option_choices(key)})
self.print_aligned(parr)
- print('')
- print('Project options:')
+ print('\nProject options:')
if not self.coredata.user_options:
print(' This project does not have any options')
else:
- options = self.coredata.user_options
- keys = list(options.keys())
- keys.sort()
optarr = []
- for key in keys:
- opt = options[key]
+ for key in sorted(self.coredata.user_options):
+ opt = self.coredata.user_options[key]
if (opt.choices is None) or (not opt.choices):
# Zero length list or string
choices = ''
else:
- # A non zero length list or string, convert to string
- choices = str(opt.choices)
+ choices = opt.choices
optarr.append({'name': key,
'descr': opt.description,
'value': opt.value,
'choices': choices})
self.print_aligned(optarr)
- print('')
- print('Testing options:')
+ print('\nTesting options:')
tarr = []
for key in ['stdsplit', 'errorlogs']:
tarr.append({'name': key,
@@ -259,6 +221,7 @@ class Conf:
'choices': coredata.get_builtin_option_choices(key)})
self.print_aligned(tarr)
+
def run(args):
args = mesonlib.expand_arguments(args)
if not args:
@@ -286,10 +249,10 @@ def run(args):
if save:
c.save()
except ConfException as e:
- print('Meson configurator encountered an error:\n')
- print(e)
- return 1
+ print('Meson configurator encountered an error:')
+ raise e
return 0
+
if __name__ == '__main__':
sys.exit(run(sys.argv[1:]))
diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py
index 9e0508b..4e72600 100644
--- a/mesonbuild/mesonlib.py
+++ b/mesonbuild/mesonlib.py
@@ -36,12 +36,11 @@ def detect_meson_py_location():
# $ <mesontool> <args> (gets run from /usr/bin/<mesontool>)
in_path_exe = shutil.which(c_fname)
if in_path_exe:
- m_dir, c_fname = os.path.split(in_path_exe)
- # Special case: when run like "./meson.py <opts>",
- # we need to expand it out, because, for example,
- # "ninja test" will be run from a different directory.
- if m_dir == '.':
+ if not os.path.isabs(in_path_exe):
m_dir = os.getcwd()
+ c_fname = in_path_exe
+ else:
+ m_dir, c_fname = os.path.split(in_path_exe)
else:
m_dir = os.path.abspath(c_dir)
diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py
index 7966d70..9c4498c 100644
--- a/mesonbuild/mesonmain.py
+++ b/mesonbuild/mesonmain.py
@@ -12,8 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import sys, stat, traceback, pickle, argparse
-import time, datetime
+import sys, stat, traceback, argparse
+import datetime
import os.path
from . import environment, interpreter, mesonlib
from . import build
@@ -196,6 +196,7 @@ class MesonApp:
mlog.log('Build machine cpu:', mlog.bold(intr.builtin['build_machine'].cpu_method([], {})))
intr.run()
try:
+ dumpfile = os.path.join(env.get_scratch_dir(), 'build.dat')
# We would like to write coredata as late as possible since we use the existence of
# this file to check if we generated the build file successfully. Since coredata
# includes settings, the build files must depend on it and appear newer. However, due
@@ -204,16 +205,13 @@ class MesonApp:
# possible, but before build files, and if any error occurs, delete it.
cdf = env.dump_coredata()
g.generate(intr)
- dumpfile = os.path.join(env.get_scratch_dir(), 'build.dat')
- with open(dumpfile, 'wb') as f:
- pickle.dump(b, f)
+ build.save(b, dumpfile)
# Post-conf scripts must be run after writing coredata or else introspection fails.
g.run_postconf_scripts()
except:
os.unlink(cdf)
raise
-
def run_script_command(args):
cmdname = args[0]
cmdargs = args[1:]
@@ -286,6 +284,13 @@ def run(original_args, mainfile=None):
# First check if we want to run a subcommand.
cmd_name = args[0]
remaining_args = args[1:]
+ # "help" is a special case: Since printing of the help may be
+ # delegated to a subcommand, we edit cmd_name before executing
+ # the rest of the logic here.
+ if cmd_name == 'help':
+ remaining_args += ['--help']
+ args = remaining_args
+ cmd_name = args[0]
if cmd_name == 'test':
return mtest.run(remaining_args)
elif cmd_name == 'setup':
@@ -299,7 +304,7 @@ def run(original_args, mainfile=None):
try:
return mconf.run(remaining_args)
except MesonException as e:
- mlog.log(mlog.red('\nError configuring project:'), e)
+ mlog.exception(e)
sys.exit(1)
elif cmd_name == 'wrap':
return wraptool.run(remaining_args)
@@ -319,8 +324,8 @@ def run(original_args, mainfile=None):
try:
sys.exit(run_script_command(args[1:]))
except MesonException as e:
- mlog.log(mlog.red('\nError in {} helper script:'.format(script)))
- mlog.log(e)
+ mlog.error('\nError in {} helper script:'.format(script))
+ mlog.exception(e)
sys.exit(1)
args = args[2:]
handshake = True
@@ -363,13 +368,7 @@ def run(original_args, mainfile=None):
app.generate()
except Exception as e:
if isinstance(e, MesonException):
- mlog.log()
- if hasattr(e, 'file') and hasattr(e, 'lineno') and hasattr(e, 'colno'):
- mlog.log('%s:%d:%d:' % (e.file, e.lineno, e.colno), mlog.red('ERROR: '), end='')
- else:
- mlog.log(mlog.red('ERROR: '), end='')
- # Error message
- mlog.log(e)
+ mlog.exception(e)
# Path to log file
mlog.shutdown()
logfile = os.path.join(app.build_dir, environment.Environment.log_dir, mlog.log_fname)
diff --git a/mesonbuild/minit.py b/mesonbuild/minit.py
index 98817cb..0461cd9 100644
--- a/mesonbuild/minit.py
+++ b/mesonbuild/minit.py
@@ -1,5 +1,4 @@
# Copyright 2017 The Meson development team
-from pyclbr import Function
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,8 +14,10 @@ from pyclbr import Function
"""Code that creates simple startup projects."""
-import os, sys, argparse, re
+import os, sys, argparse, re, shutil
from glob import glob
+from mesonbuild import mesonlib
+from mesonbuild.environment import detect_ninja
lib_h_template = '''#pragma once
#if defined _WIN32 || defined __CYGWIN__
@@ -107,7 +108,7 @@ pkg_mod.generate(
)
'''
-hello_c_template = '''#include <stdio.h>
+hello_c_template = '''#include <stdio.h>
#define PROJECT_NAME "{project_name}"
@@ -123,16 +124,15 @@ int main(int argc, char **argv) {{
hello_c_meson_template = '''project('{project_name}', 'c',
version : '{version}',
- default_options : ['warning_level=3',
- 'cpp_std=c++14'])
+ default_options : ['warning_level=3'])
exe = executable('{exe_name}', '{source_name}',
install : true)
-
+
test('basic', exe)
'''
-hello_cpp_template = '''#include <iostream>
+hello_cpp_template = '''#include <iostream>
#define PROJECT_NAME "{project_name}"
@@ -148,11 +148,12 @@ int main(int argc, char **argv) {{
hello_cpp_meson_template = '''project('{project_name}', 'cpp',
version : '{version}',
- default_options : ['warning_level=3'])
+ default_options : ['warning_level=3',
+ 'cpp_std=c++14'])
exe = executable('{exe_name}', '{source_name}',
install : true)
-
+
test('basic', exe)
'''
@@ -178,9 +179,9 @@ class {utoken}_PUBLIC {class_name} {{
public:
{class_name}();
int get_number() const;
-
+
private:
-
+
int number;
}};
@@ -270,7 +271,6 @@ ninja -C builddir
def create_exe_c_sample(project_name, project_version):
lowercase_token = re.sub(r'[^a-z0-9]', '_', project_name.lower())
- uppercase_token = lowercase_token.upper()
source_name = lowercase_token + '.c'
open(source_name, 'w').write(hello_c_template.format(project_name=project_name))
open('meson.build', 'w').write(hello_c_meson_template.format(project_name=project_name,
@@ -291,7 +291,7 @@ def create_lib_c_sample(project_name, version):
'function_name': function_name,
'header_file': lib_h_name,
'source_file': lib_c_name,
- 'test_source_file': test_c_name,
+ 'test_source_file': test_c_name,
'test_exe_name': lowercase_token,
'project_name': project_name,
'lib_name': lowercase_token,
@@ -305,13 +305,12 @@ def create_lib_c_sample(project_name, version):
def create_exe_cpp_sample(project_name, project_version):
lowercase_token = re.sub(r'[^a-z0-9]', '_', project_name.lower())
- uppercase_token = lowercase_token.upper()
source_name = lowercase_token + '.cpp'
open(source_name, 'w').write(hello_cpp_template.format(project_name=project_name))
open('meson.build', 'w').write(hello_cpp_meson_template.format(project_name=project_name,
- exe_name=lowercase_token,
- source_name=source_name,
- version=project_version))
+ exe_name=lowercase_token,
+ source_name=source_name,
+ version=project_version))
def create_lib_cpp_sample(project_name, version):
lowercase_token = re.sub(r'[^a-z0-9]', '_', project_name.lower())
@@ -328,7 +327,7 @@ def create_lib_cpp_sample(project_name, version):
'namespace': namespace,
'header_file': lib_h_name,
'source_file': lib_c_name,
- 'test_source_file': test_c_name,
+ 'test_source_file': test_c_name,
'test_exe_name': lowercase_token,
'project_name': project_name,
'lib_name': lowercase_token,
@@ -359,15 +358,123 @@ def create_sample(options):
raise RuntimeError('Unreachable code')
print(info_message)
+def autodetect_options(options, sample=False):
+ if not options.name:
+ options.name = os.path.basename(os.getcwd())
+ if not re.match('[a-zA-Z_][a-zA-Z0-9]*', options.name) and sample:
+ print('Name of current directory "{}" is not usable as a sample project name.\n'
+ 'Specify a project name with --name.'.format(options.name))
+ sys.exit(1)
+ print('Using "{}" (name of current directory) as project name.'
+ .format(options.name))
+ if not options.executable:
+ options.executable = options.name
+ print('Using "{}" (project name) as name of executable to build.'
+ .format(options.executable))
+ if sample:
+ # The rest of the autodetection is not applicable to generating sample projects.
+ return
+ if not options.srcfiles:
+ srcfiles = []
+ for f in os.listdir():
+ if f.endswith('.cc') or f.endswith('.cpp') or f.endswith('.c'):
+ srcfiles.append(f)
+ if not srcfiles:
+ print("No recognizable source files found.\n"
+ "Run me in an empty directory to create a sample project.")
+ sys.exit(1)
+ options.srcfiles = srcfiles
+ print("Detected source files: " + ' '.join(srcfiles))
+ if not options.language:
+ for f in options.srcfiles:
+ if f.endswith('.cc') or f.endswith('.cpp'):
+ options.language = 'cpp'
+ break
+ if f.endswith('.c'):
+ options.language = 'c'
+ break
+ if not options.language:
+ print("Can't autodetect language, please specify it with -l.")
+ sys.exit(1)
+ print("Detected language: " + options.language)
+
+meson_executable_template = '''project('{project_name}', '{language}',
+ version : '{version}',
+ default_options : [{default_options}])
+
+executable('{executable}',
+ {sourcespec},{depspec}
+ install : true)
+'''
+
+def create_meson_build(options):
+ if options.type != 'executable':
+ print('\nGenerating a meson.build file from existing sources is\n'
+ 'supported only for project type "executable".\n'
+ 'Run me in an empty directory to create a sample project.')
+ sys.exit(1)
+ default_options = ['warning_level=3']
+ if options.language == 'cpp':
+ # This shows how to set this very common option.
+ default_options += ['cpp_std=c++14']
+ # If we get a meson.build autoformatter one day, this code could
+ # be simplified quite a bit.
+ formatted_default_options = ', '.join("'{}'".format(x) for x in default_options)
+ sourcespec = ',\n '.join("'{}'".format(x) for x in options.srcfiles)
+ depspec = ''
+ if options.deps:
+ depspec = '\n dependencies : [\n '
+ depspec += ',\n '.join("dependency('{}')".format(x)
+ for x in options.deps.split(','))
+ depspec += '],'
+ content = meson_executable_template.format(project_name=options.name,
+ language=options.language,
+ version=options.version,
+ executable=options.executable,
+ sourcespec=sourcespec,
+ depspec=depspec,
+ default_options=formatted_default_options)
+ open('meson.build', 'w').write(content)
+ print('Generated meson.build file:\n\n' + content)
+
def run(args):
parser = argparse.ArgumentParser(prog='meson')
- parser.add_argument('--name', default = 'mesonsample')
+ parser.add_argument("srcfiles", metavar="sourcefile", nargs="*",
+ help="source files. default: all recognized files in current directory")
+ parser.add_argument("-n", "--name", help="project name. default: name of current directory")
+ parser.add_argument("-e", "--executable", help="executable name. default: project name")
+ parser.add_argument("-d", "--deps", help="dependencies, comma-separated")
+ parser.add_argument("-l", "--language", choices=['c', 'cpp'],
+ help="project language. default: autodetected based on source files")
+ parser.add_argument("-b", "--build", help="build after generation", action='store_true')
+ parser.add_argument("--builddir", help="directory for build", default='build')
+ parser.add_argument("-f", "--force", action="store_true",
+ help="force overwrite of existing files and directories.")
parser.add_argument('--type', default='executable',
choices=['executable', 'library'])
- parser.add_argument('--language', default='c', choices=['c', 'cpp'])
- parser.add_argument('--version', default='1.0')
+ parser.add_argument('--version', default='0.1')
options = parser.parse_args(args)
- if len(glob('*')) != 0:
- sys.exit('This command must be run in an empty directory.')
- create_sample(options)
+ if len(glob('*')) == 0:
+ autodetect_options(options, sample=True)
+ if not options.language:
+ print('Defaulting to generating a C language project.')
+ options.language = 'c'
+ create_sample(options)
+ else:
+ autodetect_options(options)
+ if os.path.isfile('meson.build') and not options.force:
+ print('meson.build already exists. Use --force to overwrite.')
+ sys.exit(1)
+ create_meson_build(options)
+ if options.build:
+ if os.path.isdir(options.builddir) and options.force:
+ print('Build directory already exists, deleting it.')
+ shutil.rmtree(options.builddir)
+ print('Building...')
+ err = os.system('{} "{}"'.format(' '.join(mesonlib.meson_command), options.builddir))
+ if err:
+ sys.exit(1)
+ err = os.system('{} -C "{}"'.format(detect_ninja(), options.builddir))
+ if err:
+ sys.exit(1)
return 0
diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py
index 8cf66af..1805e6c 100644
--- a/mesonbuild/mintro.py
+++ b/mesonbuild/mintro.py
@@ -19,8 +19,9 @@ tests and so on. All output is in JSON for simple parsing.
Currently only works for the Ninja backend. Others use generated
project files and don't need this info."""
-import json, pickle
-from . import coredata, build
+import json
+from . import build, mtest, coredata as cdata
+from .backend import ninjabackend
import argparse
import sys, os
import pathlib
@@ -132,16 +133,16 @@ def add_keys(optlist, options):
for key in keys:
opt = options[key]
optdict = {'name': key, 'value': opt.value}
- if isinstance(opt, coredata.UserStringOption):
+ if isinstance(opt, cdata.UserStringOption):
typestr = 'string'
- elif isinstance(opt, coredata.UserBooleanOption):
+ elif isinstance(opt, cdata.UserBooleanOption):
typestr = 'boolean'
- elif isinstance(opt, coredata.UserComboOption):
+ elif isinstance(opt, cdata.UserComboOption):
optdict['choices'] = opt.choices
typestr = 'combo'
- elif isinstance(opt, coredata.UserIntegerOption):
+ elif isinstance(opt, cdata.UserIntegerOption):
typestr = 'integer'
- elif isinstance(opt, coredata.UserArrayOption):
+ elif isinstance(opt, cdata.UserArrayOption):
typestr = 'array'
else:
raise RuntimeError("Unknown option type")
@@ -149,7 +150,7 @@ def add_keys(optlist, options):
optdict['description'] = opt.description
optlist.append(optdict)
-def list_buildsystem_files(coredata, builddata):
+def list_buildsystem_files(builddata):
src_dir = builddata.environment.get_source_dir()
# I feel dirty about this. But only slightly.
filelist = []
@@ -208,26 +209,15 @@ def run(args):
'change the working directory to it.')
return 1
- corefile = os.path.join(datadir, 'coredata.dat')
- buildfile = os.path.join(datadir, 'build.dat')
- installfile = os.path.join(datadir, 'install.dat')
- testfile = os.path.join(datadir, 'meson_test_setup.dat')
- benchmarkfile = os.path.join(datadir, 'meson_benchmark_setup.dat')
+ coredata = cdata.load(options.builddir)
+ builddata = build.load(options.builddir)
+ testdata = mtest.load_tests(options.builddir)
+ benchmarkdata = mtest.load_benchmarks(options.builddir)
- # Load all data files
- with open(corefile, 'rb') as f:
- coredata = pickle.load(f)
- with open(buildfile, 'rb') as f:
- builddata = pickle.load(f)
- with open(testfile, 'rb') as f:
- testdata = pickle.load(f)
- with open(benchmarkfile, 'rb') as f:
- benchmarkdata = pickle.load(f)
# Install data is only available with the Ninja backend
- if os.path.isfile(installfile):
- with open(installfile, 'rb') as f:
- installdata = pickle.load(f)
- else:
+ try:
+ installdata = ninjabackend.load(options.builddir)
+ except FileNotFoundError:
installdata = None
if options.list_targets:
@@ -237,7 +227,7 @@ def run(args):
elif options.target_files is not None:
list_target_files(options.target_files, coredata, builddata)
elif options.buildsystem_files:
- list_buildsystem_files(coredata, builddata)
+ list_buildsystem_files(builddata)
elif options.buildoptions:
list_buildoptions(coredata, builddata)
elif options.tests:
diff --git a/mesonbuild/mlog.py b/mesonbuild/mlog.py
index 3c34b85..347cede 100644
--- a/mesonbuild/mlog.py
+++ b/mesonbuild/mlog.py
@@ -102,19 +102,38 @@ def log(*args, **kwargs):
arr = process_markup(args, True)
force_print(*arr, **kwargs)
-def warning(*args, **kwargs):
+def _log_error(severity, *args, **kwargs):
from . import environment
-
- args = (yellow('WARNING:'),) + args
+ if severity == 'warning':
+ args = (yellow('WARNING:'),) + args
+ elif severity == 'error':
+ args = (red('ERROR:'),) + args
+ else:
+ assert False, 'Invalid severity ' + severity
if 'location' in kwargs:
location = kwargs['location']
del kwargs['location']
- location = '{}:{}:'.format(os.path.join(location.subdir, environment.build_filename), location.lineno)
- args = (location,) + args
+ location_str = '{}:{}:'.format(os.path.join(location.subdir,
+ environment.build_filename),
+ location.lineno)
+ args = (location_str,) + args
log(*args, **kwargs)
+def error(*args, **kwargs):
+ return _log_error('error', *args, **kwargs)
+
+def warning(*args, **kwargs):
+ return _log_error('warning', *args, **kwargs)
+
+def exception(e):
+ log()
+ if hasattr(e, 'file') and hasattr(e, 'lineno') and hasattr(e, 'colno'):
+ log('%s:%d:%d:' % (e.file, e.lineno, e.colno), red('ERROR: '), e)
+ else:
+ log(red('ERROR:'), e)
+
# Format a list for logging purposes as a string. It separates
# all but the last item with commas, and the last with 'and'.
def format_list(list):
diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py
index 569011e..8b6397e 100644
--- a/mesonbuild/modules/gnome.py
+++ b/mesonbuild/modules/gnome.py
@@ -1350,7 +1350,7 @@ G_END_DECLS'''
# - add relevant directories to include dirs
incs = [build.IncludeDirs(state.subdir, ['.'] + vapi_includes, False)]
sources = [vapi_target] + vapi_depends
- rv = InternalDependency(None, incs, [], [], link_with, sources, [])
+ rv = InternalDependency(None, incs, [], [], link_with, [], sources, [])
created_values.append(rv)
return ModuleReturnValue(rv, created_values)
diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py
index 5573a2e..074fc5a 100644
--- a/mesonbuild/modules/pkgconfig.py
+++ b/mesonbuild/modules/pkgconfig.py
@@ -44,22 +44,43 @@ class DependenciesHelper:
self.priv_reqs += reqs
def add_pub_reqs(self, reqs):
- self.pub_reqs += mesonlib.stringlistify(reqs)
+ self.pub_reqs += self._process_reqs(reqs)
def add_priv_reqs(self, reqs):
- self.priv_reqs += mesonlib.stringlistify(reqs)
+ self.priv_reqs += self._process_reqs(reqs)
+
+ def _process_reqs(self, reqs):
+ '''Returns string names of requirements'''
+ processed_reqs = []
+ for obj in mesonlib.listify(reqs, unholder=True):
+ if hasattr(obj, 'generated_pc'):
+ processed_reqs.append(obj.generated_pc)
+ elif hasattr(obj, 'pcdep'):
+ pcdeps = mesonlib.listify(obj.pcdep)
+ processed_reqs += [i.name for i in pcdeps]
+ elif isinstance(obj, dependencies.PkgConfigDependency):
+ if obj.found():
+ processed_reqs.append(obj.name)
+ elif isinstance(obj, str):
+ processed_reqs.append(obj)
+ elif isinstance(obj, dependencies.Dependency) and not obj.found():
+ pass
+ else:
+ raise mesonlib.MesonException('requires argument not a string, '
+ 'library with pkgconfig-generated file '
+ 'or pkgconfig-dependency object, '
+ 'got {!r}'.format(obj))
+ return processed_reqs
def add_cflags(self, cflags):
self.cflags += mesonlib.stringlistify(cflags)
def _process_libs(self, libs, public):
- libs = mesonlib.listify(libs)
+ libs = mesonlib.listify(libs, unholder=True)
processed_libs = []
processed_reqs = []
processed_cflags = []
for obj in libs:
- if hasattr(obj, 'held_object'):
- obj = obj.held_object
if hasattr(obj, 'pcdep'):
pcdeps = mesonlib.listify(obj.pcdep)
processed_reqs += [i.name for i in pcdeps]
@@ -96,7 +117,7 @@ class DependenciesHelper:
self.priv_reqs = list(set(self.priv_reqs))
self.cflags = list(set(self.cflags))
- # Remove from pivate libs/reqs if they are in public already
+ # Remove from private libs/reqs if they are in public already
self.priv_libs = [i for i in self.priv_libs if i not in self.pub_libs]
self.priv_reqs = [i for i in self.priv_reqs if i not in self.pub_reqs]
diff --git a/mesonbuild/modules/python3.py b/mesonbuild/modules/python3.py
index 989e839..9fd9f80 100644
--- a/mesonbuild/modules/python3.py
+++ b/mesonbuild/modules/python3.py
@@ -12,7 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import sys
import sysconfig
from .. import mesonlib, dependencies
diff --git a/mesonbuild/modules/unstable_icestorm.py b/mesonbuild/modules/unstable_icestorm.py
index 0b7b339..1f548b6 100644
--- a/mesonbuild/modules/unstable_icestorm.py
+++ b/mesonbuild/modules/unstable_icestorm.py
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from .. import mesonlib, compilers, mlog
+from .. import mesonlib
from . import ExtensionModule
@@ -33,7 +33,6 @@ class IceStormModule(ExtensionModule):
def project(self, interpreter, state, args, kwargs):
if not self.yosys_bin:
self.detect_binaries(interpreter)
- result = []
if not len(args):
raise mesonlib.MesonException('Project requires at least one argument, which is the project name.')
proj_name = args[0]
@@ -46,7 +45,7 @@ class IceStormModule(ExtensionModule):
all_sources = interpreter.source_strings_to_files(interpreter.flatten(arg_sources + kwarg_sources))
if 'constraint_file' not in kwargs:
raise mesonlib.MesonException('Constraint file not specified.')
-
+
constraint_file = interpreter.source_strings_to_files(kwargs['constraint_file'])
if len(constraint_file) != 1:
raise mesonlib.MesonException('Constraint file must contain one and only one entry.')
@@ -73,13 +72,13 @@ class IceStormModule(ExtensionModule):
'input': asc_target,
'output': bin_fname,
'command': [self.icepack_bin, '@INPUT@', '@OUTPUT@'],
- 'build_by_default' : True})
+ 'build_by_default': True})
- up_target = interpreter.func_run_target(None, [upload_name], {
+ interpreter.func_run_target(None, [upload_name], {
'command': [self.iceprog_bin, bin_target]})
- time_target = interpreter.func_run_target(None, [time_name], {
- 'command' : [self.icetime_bin, bin_target]})
+ interpreter.func_run_target(None, [time_name], {
+ 'command': [self.icetime_bin, bin_target]})
def initialize():
return IceStormModule()
diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py
index a697106..fbd6e8b 100644
--- a/mesonbuild/mtest.py
+++ b/mesonbuild/mtest.py
@@ -28,6 +28,7 @@ import concurrent.futures as conc
import platform
import signal
import random
+from copy import deepcopy
# GNU autotools interprets a return code of 77 from tests it executes to
# mean that the test should be skipped.
@@ -164,6 +165,22 @@ def run_with_mono(fname):
return True
return False
+def load_benchmarks(build_dir):
+ datafile = os.path.join(build_dir, 'meson-private', 'meson_benchmark_setup.dat')
+ if not os.path.isfile(datafile):
+ raise TestException('Directory ${!r} does not seem to be a Meson build directory.'.format(build_dir))
+ with open(datafile, 'rb') as f:
+ obj = pickle.load(f)
+ return obj
+
+def load_tests(build_dir):
+ datafile = os.path.join(build_dir, 'meson-private', 'meson_test_setup.dat')
+ if not os.path.isfile(datafile):
+ raise TestException('Directory ${!r} does not seem to be a Meson build directory.'.format(build_dir))
+ with open(datafile, 'rb') as f:
+ obj = pickle.load(f)
+ return obj
+
class TestHarness:
def __init__(self, options):
self.options = options
@@ -179,12 +196,10 @@ class TestHarness:
self.logfile = None
self.jsonlogfile = None
if self.options.benchmark:
- datafile = os.path.join(options.wd, 'meson-private', 'meson_benchmark_setup.dat')
+ self.tests = load_benchmarks(options.wd)
else:
- datafile = os.path.join(options.wd, 'meson-private', 'meson_test_setup.dat')
- if not os.path.isfile(datafile):
- raise TestException('Directory %s does not seem to be a Meson build directory.' % options.wd)
- self.load_datafile(datafile)
+ self.tests = load_tests(options.wd)
+ self.load_suites()
def __del__(self):
if self.logfile:
@@ -192,7 +207,39 @@ class TestHarness:
if self.jsonlogfile:
self.jsonlogfile.close()
- def run_single_test(self, wrap, test):
+ def merge_suite_options(self, options, test):
+ if ":" in options.setup:
+ if options.setup not in self.build_data.test_setups:
+ sys.exit("Unknown test setup '%s'." % options.setup)
+ current = self.build_data.test_setups[options.setup]
+ else:
+ full_name = test.project_name + ":" + options.setup
+ if full_name not in self.build_data.test_setups:
+ sys.exit("Test setup '%s' not found from project '%s'." % (options.setup, test.project_name))
+ current = self.build_data.test_setups[full_name]
+ if not options.gdb:
+ options.gdb = current.gdb
+ if options.timeout_multiplier is None:
+ options.timeout_multiplier = current.timeout_multiplier
+ # if options.env is None:
+ # options.env = current.env # FIXME, should probably merge options here.
+ if options.wrapper is not None and current.exe_wrapper is not None:
+ sys.exit('Conflict: both test setup and command line specify an exe wrapper.')
+ if options.wrapper is None:
+ options.wrapper = current.exe_wrapper
+ return current.env.get_env(os.environ.copy())
+
+ def get_test_env(self, options, test):
+ if options.setup:
+ env = self.merge_suite_options(options, test)
+ else:
+ env = os.environ.copy()
+ if isinstance(test.env, build.EnvironmentVariables):
+ test.env = test.env.get_env(env)
+ env.update(test.env)
+ return env
+
+ def run_single_test(self, test):
if test.fname[0].endswith('.jar'):
cmd = ['java', '-jar'] + test.fname
elif not test.is_cross_built and run_with_mono(test.fname[0]):
@@ -215,47 +262,64 @@ class TestHarness:
stde = None
returncode = GNU_SKIP_RETURNCODE
else:
+ test_opts = deepcopy(self.options)
+ test_env = self.get_test_env(test_opts, test)
+ wrap = self.get_wrapper(test_opts)
+
+ if test_opts.gdb:
+ test.timeout = None
+
cmd = wrap + cmd + test.cmd_args + self.options.test_args
starttime = time.time()
- child_env = os.environ.copy()
- child_env.update(self.options.global_env.get_env(child_env))
- if isinstance(test.env, build.EnvironmentVariables):
- test.env = test.env.get_env(child_env)
- child_env.update(test.env)
if len(test.extra_paths) > 0:
- child_env['PATH'] = os.pathsep.join(test.extra_paths + ['']) + child_env['PATH']
+ test_env['PATH'] = os.pathsep.join(test.extra_paths + ['']) + test_env['PATH']
# If MALLOC_PERTURB_ is not set, or if it is set to an empty value,
# (i.e., the test or the environment don't explicitly set it), set
# it ourselves. We do this unconditionally for regular tests
# because it is extremely useful to have.
# Setting MALLOC_PERTURB_="0" will completely disable this feature.
- if ('MALLOC_PERTURB_' not in child_env or not child_env['MALLOC_PERTURB_']) and not self.options.benchmark:
- child_env['MALLOC_PERTURB_'] = str(random.randint(1, 255))
+ if ('MALLOC_PERTURB_' not in test_env or not test_env['MALLOC_PERTURB_']) and not self.options.benchmark:
+ test_env['MALLOC_PERTURB_'] = str(random.randint(1, 255))
- setsid = None
stdout = None
stderr = None
if not self.options.verbose:
stdout = subprocess.PIPE
stderr = subprocess.PIPE if self.options and self.options.split else subprocess.STDOUT
- if not is_windows():
- setsid = os.setsid
+ # Let gdb handle ^C instead of us
+ if test_opts.gdb:
+ previous_sigint_handler = signal.getsignal(signal.SIGINT)
+ # Make the meson executable ignore SIGINT while gdb is running.
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
+
+ def preexec_fn():
+ if test_opts.gdb:
+ # Restore the SIGINT handler for the child process to
+ # ensure it can handle it.
+ signal.signal(signal.SIGINT, signal.SIG_DFL)
+ else:
+ # We don't want setsid() in gdb because gdb needs the
+ # terminal in order to handle ^C and not show tcsetpgrp()
+ # errors avoid not being able to use the terminal.
+ os.setsid()
p = subprocess.Popen(cmd,
stdout=stdout,
stderr=stderr,
- env=child_env,
+ env=test_env,
cwd=test.workdir,
- preexec_fn=setsid)
+ preexec_fn=preexec_fn if not is_windows() else None)
timed_out = False
kill_test = False
if test.timeout is None:
timeout = None
+ elif test_opts.timeout_multiplier is not None:
+ timeout = test.timeout * test_opts.timeout_multiplier
else:
- timeout = test.timeout * self.options.timeout_multiplier
+ timeout = test.timeout
try:
(stdo, stde) = p.communicate(timeout=timeout)
except subprocess.TimeoutExpired:
@@ -265,6 +329,10 @@ class TestHarness:
except KeyboardInterrupt:
mlog.warning("CTRL-C detected while running %s" % (test.name))
kill_test = True
+ finally:
+ if test_opts.gdb:
+ # Let us accept ^C again
+ signal.signal(signal.SIGINT, previous_sigint_handler)
if kill_test or timed_out:
# Python does not provide multiplatform support for
@@ -361,9 +429,6 @@ TIMEOUT: %4d
def doit(self):
if self.is_run:
raise RuntimeError('Test harness object can only be used once.')
- if not os.path.isfile(self.datafile):
- print('Test data file. Probably this means that you did not run this in the build directory.')
- return 1
self.is_run = True
tests = self.get_tests()
if not tests:
@@ -402,15 +467,6 @@ TIMEOUT: %4d
ss.add(s)
self.suites = list(ss)
- def load_tests(self):
- with open(self.datafile, 'rb') as f:
- self.tests = pickle.load(f)
-
- def load_datafile(self, datafile):
- self.datafile = datafile
- self.load_tests()
- self.load_suites()
-
def get_tests(self):
if not self.tests:
print('No tests defined.')
@@ -444,9 +500,9 @@ TIMEOUT: %4d
logfile_base = os.path.join(self.options.wd, 'meson-logs', self.options.logbase)
if self.options.wrapper:
- namebase = os.path.basename(self.get_wrapper()[0])
+ namebase = os.path.basename(self.get_wrapper(self.options)[0])
elif self.options.setup:
- namebase = self.options.setup
+ namebase = self.options.setup.replace(":", "_")
if namebase:
logfile_base += '-' + namebase.replace(' ', '_')
@@ -459,16 +515,16 @@ TIMEOUT: %4d
self.logfile.write('Log of Meson test suite run on %s\n\n'
% datetime.datetime.now().isoformat())
- def get_wrapper(self):
+ def get_wrapper(self, options):
wrap = []
- if self.options.gdb:
+ if options.gdb:
wrap = ['gdb', '--quiet', '--nh']
- if self.options.repeat > 1:
+ if options.repeat > 1:
wrap += ['-ex', 'run', '-ex', 'quit']
# Signal the end of arguments to gdb
wrap += ['--args']
- if self.options.wrapper:
- wrap += self.options.wrapper
+ if options.wrapper:
+ wrap += options.wrapper
assert(isinstance(wrap, list))
return wrap
@@ -487,28 +543,25 @@ TIMEOUT: %4d
futures = []
numlen = len('%d' % len(tests))
self.open_log_files()
- wrap = self.get_wrapper()
startdir = os.getcwd()
if self.options.wd:
os.chdir(self.options.wd)
+ self.build_data = build.load(os.getcwd())
try:
for _ in range(self.options.repeat):
for i, test in enumerate(tests):
visible_name = self.get_pretty_suite(test)
- if self.options.gdb:
- test.timeout = None
-
if not test.is_parallel or self.options.gdb:
self.drain_futures(futures)
futures = []
- res = self.run_single_test(wrap, test)
+ res = self.run_single_test(test)
self.print_stats(numlen, tests, visible_name, res, i)
else:
if not executor:
executor = conc.ThreadPoolExecutor(max_workers=self.options.num_processes)
- f = executor.submit(self.run_single_test, wrap, test)
+ f = executor.submit(self.run_single_test, test)
futures.append((f, numlen, tests, visible_name, i))
if self.options.repeat > 1 and self.fail_count:
break
@@ -549,26 +602,6 @@ def list_tests(th):
for t in tests:
print(th.get_pretty_suite(t))
-def merge_suite_options(options):
- buildfile = os.path.join(options.wd, 'meson-private/build.dat')
- with open(buildfile, 'rb') as f:
- build = pickle.load(f)
- setups = build.test_setups
- if options.setup not in setups:
- sys.exit('Unknown test setup: %s' % options.setup)
- current = setups[options.setup]
- if not options.gdb:
- options.gdb = current.gdb
- if options.timeout_multiplier is None:
- options.timeout_multiplier = current.timeout_multiplier
-# if options.env is None:
-# options.env = current.env # FIXME, should probably merge options here.
- if options.wrapper is not None and current.exe_wrapper is not None:
- sys.exit('Conflict: both test setup and command line specify an exe wrapper.')
- if options.wrapper is None:
- options.wrapper = current.exe_wrapper
- return current.env
-
def rebuild_all(wd):
if not os.path.isfile(os.path.join(wd, 'build.ninja')):
print("Only ninja backend is supported to rebuild tests before running them.")
@@ -594,15 +627,6 @@ def run(args):
if options.benchmark:
options.num_processes = 1
- if options.setup is not None:
- global_env = merge_suite_options(options)
- else:
- global_env = build.EnvironmentVariables()
- if options.timeout_multiplier is None:
- options.timeout_multiplier = 1
-
- setattr(options, 'global_env', global_env)
-
if options.verbose and options.quiet:
print('Can not be both quiet and verbose at the same time.')
return 1
diff --git a/mesonbuild/rewriter.py b/mesonbuild/rewriter.py
index 0191c30..fad7ba0 100644
--- a/mesonbuild/rewriter.py
+++ b/mesonbuild/rewriter.py
@@ -54,11 +54,7 @@ def run(args):
sys.exit('Unknown command: ' + options.commands[0])
except Exception as e:
if isinstance(e, MesonException):
- if hasattr(e, 'file') and hasattr(e, 'lineno') and hasattr(e, 'colno'):
- mlog.log(mlog.red('\nMeson encountered an error in file %s, line %d, column %d:' % (e.file, e.lineno, e.colno)))
- else:
- mlog.log(mlog.red('\nMeson encountered an error:'))
- mlog.log(e)
+ mlog.exception(e)
else:
traceback.print_exc()
return 1
diff --git a/mesonbuild/scripts/meson_install.py b/mesonbuild/scripts/meson_install.py
index cbc782d..f895f17 100644
--- a/mesonbuild/scripts/meson_install.py
+++ b/mesonbuild/scripts/meson_install.py
@@ -283,7 +283,7 @@ def run_install_script(d):
rc = subprocess.call(script + args, env=child_env)
if rc != 0:
sys.exit(rc)
- except:
+ except OSError:
print('Failed to run install script {!r}'.format(name))
sys.exit(1)
diff --git a/msi/createmsi.py b/msi/createmsi.py
index ec0340d..499f4b0 100755
--- a/msi/createmsi.py
+++ b/msi/createmsi.py
@@ -153,7 +153,7 @@ class PackageGenerator:
'SourceFile': self.redist_path,
'DiskId': '1',
'Language': '0',
- })
+ })
ET.SubElement(product, 'Property', {
'Id': 'WIXUI_INSTALLDIR',
@@ -185,7 +185,7 @@ class PackageGenerator:
'AllowAdvertise': 'no',
'Display': 'hidden',
'Level': '1',
- })
+ })
ET.SubElement(vcredist_feature, 'MergeRef', {'Id': 'VCRedist'})
ET.ElementTree(self.root).write(self.main_xml, encoding='utf-8', xml_declaration=True)
# ElementTree can not do prettyprinting so do it manually
@@ -223,7 +223,6 @@ class PackageGenerator:
})
self.component_num += 1
for f in cur_node.files:
- file_source = os.path.join(current_dir, f).replace('\\', '\\\\')
file_id = os.path.join(current_dir, f).replace('\\', '_').replace('#', '_').replace('-', '_')
ET.SubElement(comp_xml_node, 'File', {
'Id': file_id,
diff --git a/run_project_tests.py b/run_project_tests.py
index e9afa81..a1d36ef 100755
--- a/run_project_tests.py
+++ b/run_project_tests.py
@@ -109,8 +109,6 @@ def setup_commands(optbackend):
if backend is None:
if msbuild_exe is not None:
backend = 'vs' # Meson will auto-detect VS version to use
- elif mesonlib.is_osx():
- backend = 'xcode'
else:
backend = 'ninja'
# Set backend arguments for Meson
diff --git a/run_unittests.py b/run_unittests.py
index deb4204..bb8ce46 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -21,12 +21,11 @@ import tempfile
import textwrap
import os
import shutil
-import sys
import unittest
from unittest import mock
from configparser import ConfigParser
from glob import glob
-from pathlib import PurePath
+from pathlib import (PurePath, Path)
import mesonbuild.mlog
import mesonbuild.compilers
@@ -36,7 +35,7 @@ import mesonbuild.coredata
import mesonbuild.modules.gnome
from mesonbuild.interpreter import ObjectHolder
from mesonbuild.mesonlib import (
- is_linux, is_windows, is_osx, is_cygwin, is_dragonflybsd,
+ is_windows, is_osx, is_cygwin, is_dragonflybsd,
windows_proof_rmtree, python_command, meson_command, version_compare,
)
from mesonbuild.environment import Environment, detect_ninja
@@ -50,6 +49,9 @@ from run_tests import should_run_linux_cross_tests
def get_dynamic_section_entry(fname, entry):
+ if is_cygwin() or is_osx():
+ raise unittest.SkipTest('Test only applicable to ELF platforms')
+
try:
raw_out = subprocess.check_output(['readelf', '-d', fname],
universal_newlines=True)
@@ -427,6 +429,20 @@ class InternalTests(unittest.TestCase):
kwargs = {'sources': [1, 2, 3], 'pch_sources': [4, 5, 6]}
self.assertEqual([[1, 2, 3], [4, 5, 6]], extract(kwargs, 'sources', 'pch_sources'))
+ def test_snippets(self):
+ hashcounter = re.compile('^ *(#)+')
+ snippet_dir = Path('docs/markdown/snippets')
+ self.assertTrue(snippet_dir.is_dir())
+ for f in snippet_dir.glob('*'):
+ self.assertTrue(f.is_file())
+ if f.suffix == '.md':
+ for line in f.open():
+ m = re.match(hashcounter, line)
+ if m:
+ self.assertEqual(len(m.group(0)), 2, 'All headings in snippets must have two hash symbols: ' + f.name)
+ else:
+ if f.name != 'add_release_note_snippets_here':
+ self.assertTrue(False, 'A file without .md suffix in snippets dir: ' + f.name)
class BasePlatformTests(unittest.TestCase):
def setUp(self):
@@ -526,9 +542,15 @@ class BasePlatformTests(unittest.TestCase):
self.privatedir = os.path.join(self.builddir, 'meson-private')
if inprocess:
try:
- (returncode, out, _) = run_configure(self.meson_mainfile, self.meson_args + args + extra_args)
+ (returncode, out, err) = run_configure(self.meson_mainfile, self.meson_args + args + extra_args)
+ if 'MESON_SKIP_TEST' in out:
+ raise unittest.SkipTest('Project requested skipping.')
if returncode != 0:
self._print_meson_log()
+ print('Stdout:\n')
+ print(out)
+ print('Stderr:\n')
+ print(err)
raise RuntimeError('Configure failed')
except:
self._print_meson_log()
@@ -949,6 +971,31 @@ class AllPlatformTests(BasePlatformTests):
# Setup with only a timeout works
self._run(self.mtest_command + ['--setup=timeout'])
+ def test_testsetup_selection(self):
+ testdir = os.path.join(self.unit_test_dir, '13 testsetup selection')
+ self.init(testdir)
+ self.build()
+
+ # Run tests without setup
+ self.run_tests()
+
+ self.assertRaises(subprocess.CalledProcessError, self._run, self.mtest_command + ['--setup=missingfromfoo'])
+ self._run(self.mtest_command + ['--setup=missingfromfoo', '--no-suite=foo:'])
+
+ self._run(self.mtest_command + ['--setup=worksforall'])
+ self._run(self.mtest_command + ['--setup=main:worksforall'])
+
+ self.assertRaises(subprocess.CalledProcessError, self._run,
+ self.mtest_command + ['--setup=onlyinbar'])
+ self.assertRaises(subprocess.CalledProcessError, self._run,
+ self.mtest_command + ['--setup=onlyinbar', '--no-suite=main:'])
+ self._run(self.mtest_command + ['--setup=onlyinbar', '--no-suite=main:', '--no-suite=foo:'])
+ self._run(self.mtest_command + ['--setup=bar:onlyinbar'])
+ self.assertRaises(subprocess.CalledProcessError, self._run,
+ self.mtest_command + ['--setup=foo:onlyinbar'])
+ self.assertRaises(subprocess.CalledProcessError, self._run,
+ self.mtest_command + ['--setup=main:onlyinbar'])
+
def assertFailedTestCount(self, failure_count, command):
try:
self._run(command)
@@ -1331,9 +1378,9 @@ class AllPlatformTests(BasePlatformTests):
subprocess.check_call(['git', 'config',
'user.email', 'teh_coderz@example.com'], cwd=project_dir)
subprocess.check_call(['git', 'add', 'meson.build', 'distexe.c'], cwd=project_dir,
- stdout=subprocess.DEVNULL)
+ stdout=subprocess.DEVNULL)
subprocess.check_call(['git', 'commit', '-a', '-m', 'I am a project'], cwd=project_dir,
- stdout=subprocess.DEVNULL)
+ stdout=subprocess.DEVNULL)
try:
self.dist_impl(git_init)
@@ -1474,7 +1521,6 @@ int main(int argc, char **argv) {
cmd += ['-c', source, '-o', objectfile] + extra_args
subprocess.check_call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
-
def test_prebuilt_object(self):
(compiler, _, object_suffix, _) = self.detect_prebuild_env()
tdir = os.path.join(self.unit_test_dir, '14 prebuilt object')
@@ -1748,7 +1794,15 @@ int main(int argc, char **argv) {
workdir=tmpdir)
self._run(ninja,
workdir=os.path.join(tmpdir, 'builddir'))
-
+ with tempfile.TemporaryDirectory() as tmpdir:
+ open(os.path.join(tmpdir, 'foo.' + lang), 'w').write('int main() {}')
+ self._run(meson_command + ['init', '-b'], workdir=tmpdir)
+
+ # The test uses mocking and thus requires that
+ # the current process is the one to run the Meson steps.
+ # If we are using an external test executable (most commonly
+ # in Debian autopkgtests) then the mocking won't work.
+ @unittest.skipIf('MESON_EXE' in os.environ, 'MESON_EXE is defined, can not use mocking.')
def test_cross_file_system_paths(self):
if is_windows():
raise unittest.SkipTest('system crossfile paths not defined for Windows (yet)')
@@ -1796,6 +1850,14 @@ int main(int argc, char **argv) {
self.init(testdir, ['--cross-file=' + name], inprocess=True)
self.wipe()
+ def test_compiler_run_command(self):
+ '''
+ The test checks that the compiler object can be passed to
+ run_command().
+ '''
+ testdir = os.path.join(self.unit_test_dir, '23 compiler run_command')
+ self.init(testdir)
+
class FailureTests(BasePlatformTests):
'''
@@ -1961,8 +2023,8 @@ class FailureTests(BasePlatformTests):
env = Environment('', self.builddir, self.meson_command,
get_fake_options(self.prefix), [])
try:
- objc = env.detect_objc_compiler(False)
- objcpp = env.detect_objcpp_compiler(False)
+ env.detect_objc_compiler(False)
+ env.detect_objcpp_compiler(False)
except EnvironmentException:
code = "add_languages('objc')\nadd_languages('objcpp')"
self.assertMesonRaises(code, "Unknown compiler")
@@ -2103,6 +2165,9 @@ class LinuxlikeTests(BasePlatformTests):
is true and not when it is false. This can't be an ordinary test case
because we need to inspect the compiler database.
'''
+ if is_cygwin() or is_osx():
+ raise unittest.SkipTest('PIC not relevant')
+
testdir = os.path.join(self.common_test_dir, '3 static')
self.init(testdir)
compdb = self.get_compdb()
@@ -2169,6 +2234,14 @@ class LinuxlikeTests(BasePlatformTests):
'-llibinternal', '-lcustom2',
'-lfoo']))
+ cmd = ['pkg-config', 'requires-test']
+ out = self._run(cmd + ['--print-requires']).strip().split()
+ self.assertEqual(sorted(out), sorted(['libexposed', 'libfoo', 'libhello']))
+
+ cmd = ['pkg-config', 'requires-private-test']
+ out = self._run(cmd + ['--print-requires-private']).strip().split()
+ self.assertEqual(sorted(out), sorted(['libexposed', 'libfoo', 'libhello']))
+
def test_pkg_unfound(self):
testdir = os.path.join(self.unit_test_dir, '22 unfound pkgconfig')
self.init(testdir)
@@ -2182,6 +2255,8 @@ class LinuxlikeTests(BasePlatformTests):
database.
https://github.com/mesonbuild/meson/issues/864
'''
+ if not shutil.which('valac'):
+ raise unittest.SkipTest('valac not installed.')
testdir = os.path.join(self.vala_test_dir, '5 target glib')
self.init(testdir)
compdb = self.get_compdb()
@@ -2238,11 +2313,8 @@ class LinuxlikeTests(BasePlatformTests):
if not shutil.which('qmake-qt5'):
if not shutil.which('qmake'):
raise unittest.SkipTest('QMake not found')
- # For some inexplicable reason qmake --version gives different
- # results when run from the command line vs invoked by Python.
- # Check for both cases in case this behavior changes in the future.
- output = subprocess.getoutput(['qmake', '--version'])
- if 'Qt version 5' not in output and 'qt5' not in output:
+ output = subprocess.getoutput('qmake --version')
+ if 'Qt version 5' not in output:
raise unittest.SkipTest('Qmake found, but it is not for Qt 5.')
# Disable pkg-config codepath and force searching with qmake/qmake-qt5
testdir = os.path.join(self.framework_test_dir, '4 qt')
@@ -2254,6 +2326,9 @@ class LinuxlikeTests(BasePlatformTests):
self.assertTrue(msg in mesonlog or msg2 in mesonlog)
def _test_soname_impl(self, libpath, install):
+ if is_cygwin() or is_osx():
+ raise unittest.SkipTest('Test only applicable to ELF and linuxlike sonames')
+
testdir = os.path.join(self.unit_test_dir, '1 soname')
self.init(testdir)
self.build()
@@ -2327,7 +2402,9 @@ class LinuxlikeTests(BasePlatformTests):
# Check that all the listed -std=xxx options for this compiler work
# just fine when used
for v in compiler.get_options()[lang_std].choices:
- if compiler.get_id() == 'clang' and version_compare(compiler.version, '<5.0.0') and '17' in v:
+ if (compiler.get_id() == 'clang' and '17' in v and
+ (version_compare(compiler.version, '<5.0.0') or
+ (compiler.clang_type == mesonbuild.compilers.CLANG_OSX and version_compare(compiler.version, '<9.2')))):
continue
std_opt = '{}={}'.format(lang_std, v)
self.init(testdir, ['-D' + std_opt])
@@ -2460,6 +2537,9 @@ class LinuxlikeTests(BasePlatformTests):
self.assertNotIn('-Werror', c03_comp)
def test_run_installed(self):
+ if is_cygwin() or is_osx():
+ raise unittest.SkipTest('LD_LIBRARY_PATH and RPATH not applicable')
+
testdir = os.path.join(self.unit_test_dir, '7 run installed')
self.init(testdir)
self.build()
@@ -2529,6 +2609,8 @@ class LinuxlikeTests(BasePlatformTests):
self.assertTrue(gobject_found)
def test_build_rpath(self):
+ if is_cygwin():
+ raise unittest.SkipTest('Windows PE/COFF binaries do not use RPATH')
testdir = os.path.join(self.unit_test_dir, '11 build_rpath')
self.init(testdir)
self.build()
@@ -2546,6 +2628,9 @@ class LinuxlikeTests(BasePlatformTests):
self.assertEqual(install_rpath, 'baz')
def test_pch_with_address_sanitizer(self):
+ if is_cygwin():
+ raise unittest.SkipTest('asan not available on Cygwin')
+
testdir = os.path.join(self.common_test_dir, '13 pch')
self.init(testdir, ['-Db_sanitize=address'])
self.build()
@@ -2599,6 +2684,9 @@ endian = 'little'
Test that valac outputs generated C files in the expected location when
the builddir is a subdir of the source tree.
'''
+ if not shutil.which('valac'):
+ raise unittest.SkipTest('valac not installed.')
+
testdir = os.path.join(self.vala_test_dir, '8 generated sources')
newdir = os.path.join(self.builddir, 'srctree')
shutil.copytree(testdir, newdir)
@@ -2722,7 +2810,7 @@ def unset_envs():
if __name__ == '__main__':
unset_envs()
cases = ['InternalTests', 'AllPlatformTests', 'FailureTests']
- if is_linux():
+ if not is_windows():
cases += ['LinuxlikeTests']
if should_run_linux_cross_tests():
cases += ['LinuxArmCrossCompileTests']
diff --git a/setup.py b/setup.py
index 0852cd6..8382440 100644
--- a/setup.py
+++ b/setup.py
@@ -19,8 +19,9 @@ import sys
from mesonbuild.coredata import version
-if sys.version_info[0] < 3:
- print('Tried to install with Python 2, Meson only supports Python 3.')
+if sys.version_info < (3, 5, 0):
+ print('Tried to install with an unsupported version of Python. '
+ 'Meson requires Python 3.5.0 or greater')
sys.exit(1)
# We need to support Python installations that have nothing but the basic
@@ -62,6 +63,7 @@ setup(name='meson',
author_email='jpakkane@gmail.com',
url='http://mesonbuild.com',
license=' Apache License, Version 2.0',
+ python_requires='>=3.5',
packages=['mesonbuild',
'mesonbuild.backend',
'mesonbuild.compilers',
diff --git a/test cases/common/145 whole archive/exe3/meson.build b/test cases/common/145 whole archive/exe3/meson.build
new file mode 100644
index 0000000..82cf57e
--- /dev/null
+++ b/test cases/common/145 whole archive/exe3/meson.build
@@ -0,0 +1 @@
+exe3 = executable('prog3', '../prog.c', link_with : sh_func2_dep_func1)
diff --git a/test cases/common/145 whole archive/exe4/meson.build b/test cases/common/145 whole archive/exe4/meson.build
new file mode 100644
index 0000000..0781250
--- /dev/null
+++ b/test cases/common/145 whole archive/exe4/meson.build
@@ -0,0 +1 @@
+exe4 = executable('prog4', '../prog.c', link_with : sh_func2_transdep_func1)
diff --git a/test cases/common/145 whole archive/meson.build b/test cases/common/145 whole archive/meson.build
index 56da157..012df33 100644
--- a/test cases/common/145 whole archive/meson.build
+++ b/test cases/common/145 whole archive/meson.build
@@ -30,3 +30,21 @@ subdir('sh_only_link_whole')
subdir('exe2')
# Test that both func1 and func2 are accessible from shared library
test('prog2', exe2)
+
+# Test 3: link_whole can be used in declare_dependency()
+func1_dep = declare_dependency(link_whole : [st_func1])
+# Use dependency to link func1 into shared library
+subdir('sh_func2_dep_func1')
+# Link exe3 with shared library
+subdir('exe3')
+# Test that both func1 and func2 are accessible from shared library
+test('prog3', exe3)
+
+# Test 4: link_whole can be used in transitive declare_dependency()
+func1_trans_dep = declare_dependency(dependencies : func1_dep)
+# Use transitive dependency to link func1 into shared library
+subdir('sh_func2_transdep_func1')
+# Link exe4 with shared library
+subdir('exe4')
+# Test that both func1 and func2 are accessible from shared library
+test('prog4', exe4)
diff --git a/test cases/common/145 whole archive/sh_func2_dep_func1/meson.build b/test cases/common/145 whole archive/sh_func2_dep_func1/meson.build
new file mode 100644
index 0000000..92baca6
--- /dev/null
+++ b/test cases/common/145 whole archive/sh_func2_dep_func1/meson.build
@@ -0,0 +1,4 @@
+# Same as sh_func2_linked_func1, # func2.c does not depend on func1(),
+# so without link_whole compiler would throw func1() away.
+# This is the same version of the test with a dependency object instead.
+sh_func2_dep_func1 = shared_library('sh_func2_dep_func1', '../func2.c', dependencies : func1_dep)
diff --git a/test cases/common/145 whole archive/sh_func2_transdep_func1/meson.build b/test cases/common/145 whole archive/sh_func2_transdep_func1/meson.build
new file mode 100644
index 0000000..0703077
--- /dev/null
+++ b/test cases/common/145 whole archive/sh_func2_transdep_func1/meson.build
@@ -0,0 +1,6 @@
+# Same as sh_func2_dep_func1 but dependency is transitive.
+# func2.c does not have any reference to func1() so without link_whole compiler
+# should throw func1() out.
+sh_func2_transdep_func1 = shared_library(
+ 'sh_func2_transdep_func1', '../func2.c',
+ dependencies : func1_trans_dep)
diff --git a/test cases/common/180 generator link whole/export.h b/test cases/common/180 generator link whole/export.h
new file mode 100644
index 0000000..f4f6f45
--- /dev/null
+++ b/test cases/common/180 generator link whole/export.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#if defined BUILDING_EMBEDDED
+ #define DLL_PUBLIC
+#elif 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
diff --git a/test cases/common/180 generator link whole/generator.py b/test cases/common/180 generator link whole/generator.py
new file mode 100755
index 0000000..0076b74
--- /dev/null
+++ b/test cases/common/180 generator link whole/generator.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python3
+
+import os
+import os.path
+import sys
+
+
+def main():
+ name = os.path.splitext(os.path.basename(sys.argv[1]))[0]
+ out = sys.argv[2]
+ hname = os.path.join(out, name + '.h')
+ cname = os.path.join(out, name + '.c')
+ print(os.getcwd(), hname)
+ with open(hname, 'w') as hfile:
+ hfile.write('''
+#pragma once
+#include "export.h"
+int DLL_PUBLIC {name}();
+'''.format(name=name))
+ with open(cname, 'w') as cfile:
+ cfile.write('''
+#include "{name}.h"
+int {name}() {{
+ return {size};
+}}
+'''.format(name=name, size=len(name)))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test cases/common/180 generator link whole/main.c b/test cases/common/180 generator link whole/main.c
new file mode 100644
index 0000000..acf8717
--- /dev/null
+++ b/test cases/common/180 generator link whole/main.c
@@ -0,0 +1,11 @@
+#include "meson_test_function.h"
+
+#include <stdio.h>
+
+int main() {
+ if (meson_test_function() != 19) {
+ printf("Bad meson_test_function()\n");
+ return 1;
+ }
+ return 0;
+}
diff --git a/test cases/common/180 generator link whole/meson.build b/test cases/common/180 generator link whole/meson.build
new file mode 100644
index 0000000..30ae9c6
--- /dev/null
+++ b/test cases/common/180 generator link whole/meson.build
@@ -0,0 +1,65 @@
+project('generator link_whole', 'c')
+
+cc = meson.get_compiler('c')
+if cc.get_id() == 'msvc'
+ if cc.version().version_compare('<19')
+ error('MESON_SKIP_TEST link_whole only works on VS2015 or newer.')
+ endif
+endif
+
+# This just generates foo.h and foo.c with int foo() defined.
+gen_py = find_program('generator.py')
+gen = generator(gen_py,
+ output: ['@BASENAME@.h', '@BASENAME@.c'],
+ arguments : ['@INPUT@', '@BUILD_DIR@'])
+
+# Test 1: link directly into executable
+srcs = gen.process('meson_test_function.tmpl')
+exe = executable('exe1', [srcs, 'main.c'], c_args : '-DBUILDING_EMBEDDED')
+test('test1', exe)
+
+# Test 2: link into shared library and access from executable
+srcs = gen.process('meson_test_function.tmpl')
+shlib2 = shared_library('shlib2', [srcs], c_args : '-DBUILDING_DLL')
+exe = executable('exe2', 'main.c',
+ link_with : shlib2,
+ include_directories : shlib2.private_dir_include(),
+)
+test('test2', exe)
+
+# Test 3: link into static library and access from executable
+srcs = gen.process('meson_test_function.tmpl')
+stlib3 = static_library('stlib3', [srcs], c_args : '-DBUILDING_EMBEDDED')
+exe = executable('exe3', 'main.c',
+ c_args : '-DBUILDING_EMBEDDED',
+ link_with : stlib3,
+ include_directories : stlib3.private_dir_include(),
+)
+test('test3', exe)
+
+# Test 4: link into static library, link into shared
+# and access from executable. To make sure static_library
+# is not dropped use pull_meson_test_function helper.
+srcs = gen.process('meson_test_function.tmpl')
+stlib4 = static_library('stlib4', [srcs], c_args : '-DBUILDING_DLL')
+shlib4 = shared_library('shlib4', 'pull_meson_test_function.c',
+ c_args : '-DBUILDING_DLL',
+ link_with : stlib4,
+ include_directories : stlib4.private_dir_include(),
+)
+exe = executable('exe4', 'main.c',
+ link_with : shlib4,
+ include_directories : stlib4.private_dir_include(),
+)
+test('test4', exe)
+
+# Test 5: link into static library, link_whole into shared
+# and access from executable
+srcs = gen.process('meson_test_function.tmpl')
+stlib5 = static_library('stlib5', [srcs], c_args : '-DBUILDING_DLL')
+shlib5 = shared_library('shlib5', link_whole : stlib5)
+exe = executable('exe5', 'main.c',
+ link_with : shlib5,
+ include_directories : stlib5.private_dir_include(),
+)
+test('test5', exe)
diff --git a/test cases/common/180 generator link whole/meson_test_function.tmpl b/test cases/common/180 generator link whole/meson_test_function.tmpl
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test cases/common/180 generator link whole/meson_test_function.tmpl
diff --git a/test cases/common/180 generator link whole/pull_meson_test_function.c b/test cases/common/180 generator link whole/pull_meson_test_function.c
new file mode 100644
index 0000000..c54dda6
--- /dev/null
+++ b/test cases/common/180 generator link whole/pull_meson_test_function.c
@@ -0,0 +1,6 @@
+#include "export.h"
+#include "meson_test_function.h"
+
+int DLL_PUBLIC function_puller() {
+ return meson_test_function();
+}
diff --git a/test cases/common/181 initial c_args/meson.build b/test cases/common/181 initial c_args/meson.build
new file mode 100644
index 0000000..70a6e7a
--- /dev/null
+++ b/test cases/common/181 initial c_args/meson.build
@@ -0,0 +1,7 @@
+project('options', 'c')
+
+# Test passing c_args and c_link_args options from the command line.
+assert(get_option('c_args') == ['-march=native', '-funroll-loops'],
+ 'Incorrect value for c_args option.')
+assert(get_option('c_link_args') == ['-random_linker_option'],
+ 'Incorrect value for c_link_args option.')
diff --git a/test cases/common/181 initial c_args/test_args.txt b/test cases/common/181 initial c_args/test_args.txt
new file mode 100644
index 0000000..9a6da06
--- /dev/null
+++ b/test cases/common/181 initial c_args/test_args.txt
@@ -0,0 +1,4 @@
+# This file is not read by meson itself, but by the test framework.
+# It is not possible to pass arguments to meson from a file.
+['-Dc_args=-march=native', '-Dc_args=-funroll-loops',
+ '-Dc_link_args=-random_linker_option']
diff --git a/test cases/common/51 pkgconfig-gen/dependencies/meson.build b/test cases/common/51 pkgconfig-gen/dependencies/meson.build
index a767eb5..018b72f 100644
--- a/test cases/common/51 pkgconfig-gen/dependencies/meson.build
+++ b/test cases/common/51 pkgconfig-gen/dependencies/meson.build
@@ -21,7 +21,7 @@ custom_dep = declare_dependency(link_args : ['-lcustom'], compile_args : ['-DCUS
custom2_dep = declare_dependency(link_args : ['-lcustom2'], compile_args : ['-DCUSTOM2'])
# Generate a PC file:
-# - Having libmain in libraries should pull implicitely libexposed and libinternal in Libs.private
+# - Having libmain in libraries should pull implicitly libexposed and libinternal in Libs.private
# - Having libexposed in libraries should remove it from Libs.private
# - We generated a pc file for libexposed so it should be in Requires instead of Libs
# - Having threads_dep in libraries should add '-pthread' in both Libs and Cflags
@@ -36,3 +36,17 @@ pkgg.generate(libraries : [main_lib, exposed_lib, threads_dep , custom_dep],
filebase : 'dependency-test',
description : 'A dependency test.'
)
+
+pkgg.generate(
+ name : 'requires-test',
+ version : '1.0',
+ description : 'Dependency Requires field test.',
+ requires : [exposed_lib, pc_dep, 'libhello'],
+)
+
+pkgg.generate(
+ name : 'requires-private-test',
+ version : '1.0',
+ description : 'Dependency Requires.private field test.',
+ requires_private : [exposed_lib, pc_dep, 'libhello', notfound_dep],
+)
diff --git a/test cases/common/51 pkgconfig-gen/meson.build b/test cases/common/51 pkgconfig-gen/meson.build
index f9d7f7f..7e6c670 100644
--- a/test cases/common/51 pkgconfig-gen/meson.build
+++ b/test cases/common/51 pkgconfig-gen/meson.build
@@ -46,3 +46,9 @@ pkgg.generate(
description : 'A foo library.',
variables : ['foo=bar', 'datadir=${prefix}/data']
)
+
+pkgg.generate(
+ name : 'libhello',
+ description : 'A minimalistic pkgconfig file.',
+ version : libver,
+)
diff --git a/test cases/common/64 custom header generator/meson.build b/test cases/common/64 custom header generator/meson.build
index bcc9a53..33ba4c5 100644
--- a/test cases/common/64 custom header generator/meson.build
+++ b/test cases/common/64 custom header generator/meson.build
@@ -3,9 +3,9 @@ project('custom header generator', 'c')
gen = find_program('makeheader.py')
generated_h = custom_target('makeheader.py',
-output : 'myheader.lh', # Suffix not .h to ensure this works with custom suffixes, too.
-input : 'input.def',
-command : [gen, '@INPUT0@', '@OUTPUT0@', files('somefile.txt')])
+ output : 'myheader.lh', # Suffix not .h to ensure this works with custom suffixes, too.
+ input : 'input.def',
+ command : [gen, '@INPUT0@', '@OUTPUT0@', files('somefile.txt')])
prog = executable('prog', 'prog.c', generated_h)
test('gentest', prog)
diff --git a/test cases/common/72 build always/version_gen.py b/test cases/common/72 build always/version_gen.py
index d7b01ca..fbe2df9 100755
--- a/test cases/common/72 build always/version_gen.py
+++ b/test cases/common/72 build always/version_gen.py
@@ -6,14 +6,10 @@ def generate(infile, outfile, fallback):
workdir = os.path.split(infile)[0]
if workdir == '':
workdir = '.'
- version = fallback
try:
- p = subprocess.Popen(['git', 'describe'], cwd=workdir, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- (stdo, _) = p.communicate()
- if p.returncode == 0:
- version = stdo.decode().strip()
- except:
- pass
+ version = subprocess.check_output(['git', 'describe'], cwd=workdir).decode().strip()
+ except (subprocess.CalledProcessError, OSError, UnicodeDecodeError):
+ version = fallback
with open(infile) as f:
newdata = f.read().replace('@VERSION@', version)
try:
@@ -21,7 +17,7 @@ def generate(infile, outfile, fallback):
olddata = f.read()
if olddata == newdata:
return
- except:
+ except OSError:
pass
with open(outfile, 'w') as f:
f.write(newdata)
diff --git a/test cases/common/98 gen extra/srcgen3.py b/test cases/common/98 gen extra/srcgen3.py
index ad0a5cb..b737114 100644
--- a/test cases/common/98 gen extra/srcgen3.py
+++ b/test cases/common/98 gen extra/srcgen3.py
@@ -1,6 +1,5 @@
#!/usr/bin/env python3
-import os
import sys
import argparse
diff --git a/test cases/frameworks/10 gtk-doc/include/meson.build b/test cases/frameworks/10 gtk-doc/include/meson.build
index f6dd99f..aa32885 100644
--- a/test cases/frameworks/10 gtk-doc/include/meson.build
+++ b/test cases/frameworks/10 gtk-doc/include/meson.build
@@ -13,4 +13,5 @@ generate_enums_docbook = find_program('generate-enums-docbook.py')
docbook = custom_target('enum-docbook',
output : 'bar.xml',
- command : [generate_enums_docbook, '@OUTPUT@', 'BAR', 'BAR_TYPE', 'BAR_FOO'])
+ command : [generate_enums_docbook, '@OUTPUT@', 'BAR', 'BAR_TYPE', 'BAR_FOO'],
+ build_by_default : true)
diff --git a/test cases/frameworks/10 gtk-doc/installed_files.txt.bak b/test cases/frameworks/10 gtk-doc/installed_files.txt
index 9004af2..6f8ca01 100644
--- a/test cases/frameworks/10 gtk-doc/installed_files.txt.bak
+++ b/test cases/frameworks/10 gtk-doc/installed_files.txt
@@ -1,13 +1,15 @@
+usr/include/foo-version.h
+usr/share/gtk-doc/html/foobar/BAR.html
usr/share/gtk-doc/html/foobar/foobar.devhelp2
-usr/share/gtk-doc/html/foobar/foobar-foo.html
usr/share/gtk-doc/html/foobar/foobar.html
+usr/share/gtk-doc/html/foobar/foobar-foo.html
+usr/share/gtk-doc/html/foobar/foobar-foo-version.html
usr/share/gtk-doc/html/foobar/home.png
usr/share/gtk-doc/html/foobar/index.html
-usr/share/gtk-doc/html/foobar/index.sgml
-usr/share/gtk-doc/html/foobar/left-insensitive.png
usr/share/gtk-doc/html/foobar/left.png
-usr/share/gtk-doc/html/foobar/right-insensitive.png
+usr/share/gtk-doc/html/foobar/left-insensitive.png
usr/share/gtk-doc/html/foobar/right.png
+usr/share/gtk-doc/html/foobar/right-insensitive.png
usr/share/gtk-doc/html/foobar/style.css
-usr/share/gtk-doc/html/foobar/up-insensitive.png
usr/share/gtk-doc/html/foobar/up.png
+usr/share/gtk-doc/html/foobar/up-insensitive.png
diff --git a/test cases/frameworks/14 doxygen/include/comedian.h b/test cases/frameworks/14 doxygen/include/comedian.h
index 97b5086..d62b283 100644
--- a/test cases/frameworks/14 doxygen/include/comedian.h
+++ b/test cases/frameworks/14 doxygen/include/comedian.h
@@ -11,7 +11,7 @@ namespace Comedy {
* Do the thing people want to happen.
*/
virtual void tell_joke() = 0;
- virtual ~Comedian();
+ virtual ~Comedian(){};
};
}
diff --git a/test cases/frameworks/14 doxygen/include/spede.h b/test cases/frameworks/14 doxygen/include/spede.h
index 8175465..380708a 100644
--- a/test cases/frameworks/14 doxygen/include/spede.h
+++ b/test cases/frameworks/14 doxygen/include/spede.h
@@ -29,10 +29,7 @@ namespace Comedy {
throw std::runtime_error("Not implemented");
}
+ private:
+ int num_movies; ///< How many movies has he done.
};
-
-
-private:
-
- int num_movies; ///< How many movies has he done.
}
diff --git a/test cases/frameworks/14 doxygen/meson.build b/test cases/frameworks/14 doxygen/meson.build
index 55df316..023aa0e 100644
--- a/test cases/frameworks/14 doxygen/meson.build
+++ b/test cases/frameworks/14 doxygen/meson.build
@@ -1,5 +1,11 @@
project('doxygen test', 'cpp', version : '0.1.0')
+spede_inc = include_directories('include')
+
+spede_src = [ 'src/spede.cpp' ]
+
+spede_lib = library('spede', spede_src, include_directories: spede_inc)
+
doxygen = find_program('doxygen', required : false)
if not doxygen.found()
error('MESON_SKIP_TEST doxygen not found.')
diff --git a/test cases/frameworks/14 doxygen/src/spede.cpp b/test cases/frameworks/14 doxygen/src/spede.cpp
index 31c8fb2..d382902 100644
--- a/test cases/frameworks/14 doxygen/src/spede.cpp
+++ b/test cases/frameworks/14 doxygen/src/spede.cpp
@@ -42,7 +42,7 @@ int gesticulate(int force) {
Spede::Spede() : num_movies(100) {
}
-Spede::slap_forehead() {
+void Spede::slap_forehead() {
gesticulate(42);
}
diff --git a/test cases/unit/13 testsetup selection/main.c b/test cases/unit/13 testsetup selection/main.c
new file mode 100644
index 0000000..cb3f748
--- /dev/null
+++ b/test cases/unit/13 testsetup selection/main.c
@@ -0,0 +1,3 @@
+int main() {
+ return 0;
+}
diff --git a/test cases/unit/13 testsetup selection/meson.build b/test cases/unit/13 testsetup selection/meson.build
new file mode 100644
index 0000000..ae996c5
--- /dev/null
+++ b/test cases/unit/13 testsetup selection/meson.build
@@ -0,0 +1,10 @@
+project('main', 'c')
+
+main = executable('main', 'main.c')
+test('Test main', main)
+
+add_test_setup('worksforall')
+add_test_setup('missingfromfoo')
+
+subproject('foo')
+subproject('bar')
diff --git a/test cases/unit/13 testsetup selection/subprojects/bar/bar.c b/test cases/unit/13 testsetup selection/subprojects/bar/bar.c
new file mode 100644
index 0000000..cb3f748
--- /dev/null
+++ b/test cases/unit/13 testsetup selection/subprojects/bar/bar.c
@@ -0,0 +1,3 @@
+int main() {
+ return 0;
+}
diff --git a/test cases/unit/13 testsetup selection/subprojects/bar/meson.build b/test cases/unit/13 testsetup selection/subprojects/bar/meson.build
new file mode 100644
index 0000000..1155a88
--- /dev/null
+++ b/test cases/unit/13 testsetup selection/subprojects/bar/meson.build
@@ -0,0 +1,6 @@
+project('bar', 'c')
+bar = executable('bar', 'bar.c')
+test('Test bar', bar)
+add_test_setup('onlyinbar')
+add_test_setup('worksforall')
+add_test_setup('missingfromfoo')
diff --git a/test cases/unit/13 testsetup selection/subprojects/foo/foo.c b/test cases/unit/13 testsetup selection/subprojects/foo/foo.c
new file mode 100644
index 0000000..cb3f748
--- /dev/null
+++ b/test cases/unit/13 testsetup selection/subprojects/foo/foo.c
@@ -0,0 +1,3 @@
+int main() {
+ return 0;
+}
diff --git a/test cases/unit/13 testsetup selection/subprojects/foo/meson.build b/test cases/unit/13 testsetup selection/subprojects/foo/meson.build
new file mode 100644
index 0000000..2eef840
--- /dev/null
+++ b/test cases/unit/13 testsetup selection/subprojects/foo/meson.build
@@ -0,0 +1,4 @@
+project('foo', 'c')
+foo = executable('foo', 'foo.c')
+test('Test foo', foo)
+add_test_setup('worksforall')
diff --git a/test cases/unit/23 compiler run_command/meson.build b/test cases/unit/23 compiler run_command/meson.build
new file mode 100644
index 0000000..6d9e0b9
--- /dev/null
+++ b/test cases/unit/23 compiler run_command/meson.build
@@ -0,0 +1,10 @@
+project('compiler_object_in_run_command', 'c')
+cc = meson.get_compiler('c')
+
+# This test only checks that the compiler object can be passed to
+# run_command(). If the compiler has been launched, it is expected
+# to output something either to stdout or to stderr.
+result = run_command(cc, '--version')
+if result.stdout() == '' and result.stderr() == ''
+ error('No output in stdout and stderr. Did the compiler run at all?')
+endif