aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.appveyor.yml29
-rw-r--r--.travis.yml12
-rw-r--r--ciimage/Dockerfile15
-rw-r--r--contributing.txt2
-rw-r--r--cross/ubuntu-armhf.txt4
-rw-r--r--data/macros.meson7
-rw-r--r--data/shell-completions/zsh/_meson213
-rw-r--r--data/syntax-highlighting/emacs/meson.el (renamed from data/meson.el)0
-rw-r--r--data/syntax-highlighting/vim/README (renamed from syntax-highlighting/vim/README)0
-rw-r--r--data/syntax-highlighting/vim/ftdetect/meson.vim (renamed from syntax-highlighting/vim/ftdetect/meson.vim)0
-rw-r--r--data/syntax-highlighting/vim/indent/meson.vim (renamed from syntax-highlighting/vim/indent/meson.vim)4
-rw-r--r--data/syntax-highlighting/vim/syntax/meson.vim (renamed from syntax-highlighting/vim/syntax/meson.vim)0
-rw-r--r--docs/images/gtksample.pngbin4543 -> 3853 bytes
-rw-r--r--docs/markdown/Build-options.md13
-rw-r--r--docs/markdown/Comparisons.md30
-rw-r--r--docs/markdown/Compiler-properties.md35
-rw-r--r--docs/markdown/Configuring-a-build-directory.md6
-rw-r--r--docs/markdown/Cross-compilation.md1
-rw-r--r--docs/markdown/Custom-build-targets.md2
-rw-r--r--docs/markdown/D.md89
-rw-r--r--docs/markdown/Dependencies.md86
-rw-r--r--docs/markdown/Design-rationale.md20
-rw-r--r--docs/markdown/FAQ.md4
-rw-r--r--docs/markdown/Generating-sources.md2
-rw-r--r--docs/markdown/Getting-meson.md2
-rw-r--r--docs/markdown/Gnome-module.md28
-rw-r--r--docs/markdown/IDE-integration.md2
-rw-r--r--docs/markdown/Installing.md4
-rw-r--r--docs/markdown/Module-reference.md2
-rw-r--r--docs/markdown/Pkgconfig-module.md2
-rw-r--r--docs/markdown/Precompiled-headers.md2
-rw-r--r--docs/markdown/Qt5-module.md19
-rw-r--r--docs/markdown/Reference-manual.md76
-rw-r--r--docs/markdown/Reference-tables.md60
-rw-r--r--docs/markdown/Release-notes-for-0.43.0.md121
-rw-r--r--docs/markdown/Release-notes-for-0.44.0.md16
-rw-r--r--docs/markdown/Subprojects.md2
-rw-r--r--docs/markdown/Syntax.md93
-rw-r--r--docs/markdown/Unit-tests.md24
-rw-r--r--docs/markdown/Users.md4
-rw-r--r--docs/markdown/Using-multiple-build-directories.md4
-rw-r--r--docs/markdown/Using-wraptool.md2
-rw-r--r--docs/markdown/Vala.md14
-rw-r--r--docs/markdown/Wrap-dependency-system-manual.md4
-rw-r--r--docs/markdown/Wrap-review-guidelines.md2
-rw-r--r--docs/markdown/howtox.md6
-rw-r--r--docs/markdown/i18n-module.md4
-rw-r--r--docs/markdown/index.md6
-rw-r--r--docs/markdown/snippets/add_release_note_snippets_here0
-rw-r--r--docs/markdown/snippets/cross_find.md15
-rw-r--r--docs/markdown/snippets/get-supported-arguments.md23
-rw-r--r--docs/markdown/snippets/llvm-static-linking.md8
-rw-r--r--docs/markdown/snippets/prefix-dependent-defaults.md10
-rw-r--r--docs/markdown/snippets/qt5-moc_extra_arguments.md8
-rw-r--r--docs/markdown/snippets/warning_function6
-rw-r--r--docs/sitemap.txt3
-rwxr-xr-xghwt.py5
-rw-r--r--man/meson.118
-rw-r--r--man/mesonconf.12
-rw-r--r--man/mesonintrospect.12
-rw-r--r--man/mesontest.12
-rw-r--r--man/wraptool.12
-rw-r--r--manual tests/10 svn wrap/meson.build10
-rw-r--r--manual tests/10 svn wrap/prog.c6
-rw-r--r--manual tests/10 svn wrap/subprojects/samplesubproject.wrap4
-rwxr-xr-xmeson.py2
-rw-r--r--mesonbuild/backend/backends.py39
-rw-r--r--mesonbuild/backend/ninjabackend.py104
-rw-r--r--mesonbuild/backend/vs2010backend.py64
-rw-r--r--mesonbuild/build.py285
-rw-r--r--mesonbuild/compilers/c.py68
-rw-r--r--mesonbuild/compilers/compilers.py49
-rw-r--r--mesonbuild/compilers/d.py55
-rw-r--r--mesonbuild/coredata.py46
-rw-r--r--mesonbuild/dependencies/__init__.py3
-rw-r--r--mesonbuild/dependencies/base.py24
-rw-r--r--mesonbuild/dependencies/dev.py163
-rw-r--r--mesonbuild/dependencies/misc.py496
-rw-r--r--mesonbuild/dependencies/ui.py9
-rw-r--r--mesonbuild/environment.py26
-rw-r--r--mesonbuild/interpreter.py494
-rw-r--r--mesonbuild/interpreterbase.py37
-rw-r--r--mesonbuild/mconf.py2
-rw-r--r--mesonbuild/mesonlib.py83
-rw-r--r--mesonbuild/mesonmain.py47
-rw-r--r--mesonbuild/mintro.py3
-rw-r--r--mesonbuild/modules/__init__.py21
-rw-r--r--mesonbuild/modules/gnome.py159
-rw-r--r--mesonbuild/modules/i18n.py46
-rw-r--r--mesonbuild/modules/modtest.py2
-rw-r--r--mesonbuild/modules/pkgconfig.py19
-rw-r--r--mesonbuild/modules/python3.py3
-rw-r--r--mesonbuild/modules/qt.py146
-rw-r--r--mesonbuild/modules/qt4.py147
-rw-r--r--mesonbuild/modules/qt5.py153
-rw-r--r--mesonbuild/modules/rpm.py2
-rw-r--r--mesonbuild/modules/unstable_simd.py4
-rw-r--r--mesonbuild/modules/windows.py8
-rw-r--r--mesonbuild/mtest.py4
-rw-r--r--mesonbuild/optinterpreter.py29
-rw-r--r--[-rwxr-xr-x]mesonbuild/rewriter.py2
-rw-r--r--mesonbuild/scripts/gettext.py5
-rw-r--r--mesonbuild/scripts/gtkdochelper.py3
-rw-r--r--mesonbuild/scripts/meson_install.py34
-rw-r--r--mesonbuild/scripts/regen_checker.py8
-rw-r--r--mesonbuild/wrap/wrap.py116
-rwxr-xr-xmesonrewriter.py3
-rw-r--r--[-rwxr-xr-x]msi/License.rtf0
-rwxr-xr-xmsi/createmsi.py53
-rwxr-xr-xrun_project_tests.py74
-rwxr-xr-xrun_tests.py10
-rwxr-xr-xrun_unittests.py195
-rw-r--r--setup.cfg8
-rw-r--r--test cases/common/114 multiple dir configure file/meson.build4
-rw-r--r--test cases/common/114 multiple dir configure file/subdir/foo.txt0
-rw-r--r--test cases/common/114 multiple dir configure file/subdir/meson.build7
-rw-r--r--test cases/common/140 get define/meson_options.txt2
-rw-r--r--test cases/common/145 whole archive/allofme/meson.build1
-rw-r--r--test cases/common/145 whole archive/exe/meson.build2
-rw-r--r--test cases/common/145 whole archive/exe2/meson.build1
-rw-r--r--test cases/common/145 whole archive/meson.build20
-rw-r--r--test cases/common/145 whole archive/shlib/meson.build4
-rw-r--r--test cases/common/145 whole archive/stlib/meson.build1
-rw-r--r--test cases/common/145 whole archive/wholeshlib/meson.build1
-rw-r--r--test cases/common/146 C and CPP link/dummy.c0
-rw-r--r--test cases/common/146 C and CPP link/meson.build36
-rw-r--r--test cases/common/146 C and CPP link/sub.c19
-rw-r--r--test cases/common/146 C and CPP link/sub.h16
-rw-r--r--test cases/common/147 mesonintrospect from scripts/check_env.py4
-rw-r--r--test cases/common/159 reserved targets/meson.build5
-rw-r--r--test cases/common/161 index customtarget/gen_sources.py49
-rw-r--r--test cases/common/161 index customtarget/lib.c20
-rw-r--r--test cases/common/161 index customtarget/meson.build32
-rw-r--r--test cases/common/161 index customtarget/subdir/foo.c22
-rw-r--r--test cases/common/161 index customtarget/subdir/meson.build19
-rw-r--r--test cases/common/162 wrap file should not failed/meson.build7
-rw-r--r--test cases/common/162 wrap file should not failed/src/meson.build2
-rw-r--r--test cases/common/162 wrap file should not failed/src/subprojects/foo/prog2.c7
-rw-r--r--test cases/common/162 wrap file should not failed/src/subprojects/prog.c7
-rw-r--r--test cases/common/162 wrap file should not failed/subprojects/packagecache/zlib-1.2.8-8-wrap.zip1
-rw-r--r--test cases/common/162 wrap file should not failed/subprojects/packagecache/zlib-1.2.8.tar.gz1
-rw-r--r--test cases/common/162 wrap file should not failed/subprojects/zlib-1.2.8/foo.c3
-rw-r--r--test cases/common/162 wrap file should not failed/subprojects/zlib-1.2.8/meson.build2
-rw-r--r--test cases/common/162 wrap file should not failed/subprojects/zlib.wrap10
-rw-r--r--test cases/common/163 includedir subproj/meson.build9
-rw-r--r--test cases/common/163 includedir subproj/prog.c4
-rw-r--r--test cases/common/163 includedir subproj/subprojects/inctest/include/incfile.h2
-rw-r--r--test cases/common/163 includedir subproj/subprojects/inctest/meson.build13
-rw-r--r--test cases/common/163 subproject dir name collision/a.c13
-rw-r--r--test cases/common/163 subproject dir name collision/custom_subproject_dir/B/b.c20
-rw-r--r--test cases/common/163 subproject dir name collision/custom_subproject_dir/B/meson.build4
-rw-r--r--test cases/common/163 subproject dir name collision/custom_subproject_dir/C/c.c14
-rw-r--r--test cases/common/163 subproject dir name collision/custom_subproject_dir/C/meson.build2
-rw-r--r--test cases/common/163 subproject dir name collision/meson.build12
-rw-r--r--test cases/common/163 subproject dir name collision/other_subdir/custom_subproject_dir/other.c19
-rw-r--r--test cases/common/163 subproject dir name collision/other_subdir/meson.build1
-rw-r--r--test cases/common/42 string operations/meson.build7
-rw-r--r--test cases/common/47 options/meson.build1
-rw-r--r--test cases/common/90 identical target name in subproject/meson.build1
-rw-r--r--test cases/common/90 identical target name in subproject/subprojects/foo/meson.build1
-rw-r--r--test cases/common/98 gen extra/meson.build27
-rw-r--r--test cases/common/98 gen extra/name.l3
-rw-r--r--test cases/common/98 gen extra/srcgen2.py32
-rw-r--r--test cases/common/98 gen extra/srcgen3.py16
-rw-r--r--test cases/d/3 shared library/meson.build4
-rw-r--r--test cases/d/4 library versions/meson.build4
-rw-r--r--test cases/d/7 multilib/meson.build4
-rw-r--r--test cases/d/9 features/app.d51
-rw-r--r--test cases/d/9 features/data/food.txt6
-rw-r--r--test cases/d/9 features/data/people.txt5
-rw-r--r--test cases/d/9 features/meson.build29
-rw-r--r--test cases/failing/60 assign custom target index/meson.build24
-rw-r--r--test cases/failing/61 getoption prefix/meson.build5
-rw-r--r--test cases/failing/61 getoption prefix/subprojects/abc/meson.build1
-rw-r--r--test cases/failing/61 getoption prefix/subprojects/abc/meson_options.txt1
-rw-r--r--test cases/failing/62 bad option argument/meson.build3
-rw-r--r--test cases/failing/62 bad option argument/meson_options.txt1
-rw-r--r--test cases/failing/63 subproj filegrab/meson.build5
-rw-r--r--test cases/failing/63 subproj filegrab/prog.c1
-rw-r--r--test cases/failing/63 subproj filegrab/subprojects/a/meson.build3
-rw-r--r--test cases/failing/64 grab subproj/meson.build7
-rw-r--r--test cases/failing/64 grab subproj/subprojects/foo/meson.build3
-rw-r--r--test cases/failing/64 grab subproj/subprojects/foo/sub.c6
-rw-r--r--test cases/failing/65 grab sibling/meson.build3
-rw-r--r--test cases/failing/65 grab sibling/subprojects/a/meson.build3
-rw-r--r--test cases/failing/65 grab sibling/subprojects/b/meson.build3
-rw-r--r--test cases/failing/65 grab sibling/subprojects/b/sneaky.c6
-rw-r--r--test cases/failing/66 string as link target/meson.build2
-rw-r--r--test cases/failing/66 string as link target/prog.c1
-rw-r--r--test cases/frameworks/1 boost/meson.build5
-rw-r--r--test cases/frameworks/1 boost/nolinkexe.cc12
-rw-r--r--test cases/frameworks/15 llvm/meson.build41
-rwxr-xr-xtest cases/frameworks/17 mpi/is_artful.py9
-rw-r--r--test cases/frameworks/17 mpi/meson.build10
-rw-r--r--test cases/frameworks/19 pcap/meson.build3
-rw-r--r--test cases/frameworks/21 libwmf/libwmf_prog.c8
-rw-r--r--test cases/frameworks/21 libwmf/meson.build9
-rw-r--r--test cases/frameworks/4 qt/main.cpp19
-rw-r--r--test cases/frameworks/4 qt/mainWindow.ui24
-rw-r--r--test cases/frameworks/4 qt/manualinclude.cpp7
-rw-r--r--test cases/frameworks/4 qt/manualinclude.h6
-rw-r--r--test cases/frameworks/4 qt/meson.build28
-rw-r--r--test cases/frameworks/4 qt/plugin/plugin.cpp12
-rw-r--r--test cases/frameworks/4 qt/plugin/plugin.h14
-rw-r--r--test cases/frameworks/4 qt/plugin/plugin.json3
-rw-r--r--test cases/frameworks/4 qt/pluginInterface/plugin_if.h21
-rw-r--r--test cases/frameworks/7 gnome/gir/dep1/meson.build1
-rw-r--r--test cases/frameworks/7 gnome/gir/meson.build2
-rw-r--r--test cases/unit/13 reconfigure/meson.build5
-rw-r--r--test cases/unit/14 prebuilt object/main.c (renamed from test cases/prebuilt/1 object/main.c)0
-rw-r--r--test cases/unit/14 prebuilt object/meson.build (renamed from test cases/prebuilt/1 object/meson.build)0
-rw-r--r--test cases/unit/14 prebuilt object/source.c (renamed from test cases/prebuilt/1 object/source.c)0
-rw-r--r--test cases/unit/15 prebuilt static/libdir/best.c (renamed from test cases/prebuilt/2 static/libdir/best.c)0
-rw-r--r--test cases/unit/15 prebuilt static/libdir/best.h (renamed from test cases/prebuilt/2 static/libdir/best.h)0
-rw-r--r--test cases/unit/15 prebuilt static/libdir/meson.build (renamed from test cases/prebuilt/2 static/libdir/meson.build)0
-rw-r--r--test cases/unit/15 prebuilt static/main.c (renamed from test cases/prebuilt/2 static/main.c)0
-rw-r--r--test cases/unit/15 prebuilt static/meson.build (renamed from test cases/prebuilt/2 static/meson.build)0
-rw-r--r--test cases/unit/16 prebuilt shared/alexandria.c6
-rw-r--r--test cases/unit/16 prebuilt shared/alexandria.h20
-rw-r--r--test cases/unit/16 prebuilt shared/another_visitor.c10
-rw-r--r--test cases/unit/16 prebuilt shared/meson.build14
-rw-r--r--test cases/unit/16 prebuilt shared/patron.c8
-rw-r--r--test cases/vala/12 custom output/bar.vala0
-rw-r--r--test cases/vala/12 custom output/meson.build10
-rw-r--r--test cases/vala/22 same target in directories/Subdir/Subdir2/Test.vala5
-rw-r--r--test cases/vala/22 same target in directories/Subdir/Test.vala5
-rw-r--r--test cases/vala/22 same target in directories/Subdir2/Test.vala5
-rw-r--r--test cases/vala/22 same target in directories/Test.vala5
-rw-r--r--test cases/vala/22 same target in directories/meson.build13
-rw-r--r--test cases/vala/22 same target in directories/prog.vala8
-rwxr-xr-xtools/boost_names.py187
231 files changed, 4167 insertions, 1605 deletions
diff --git a/.appveyor.yml b/.appveyor.yml
index d8a4b12..c0edf5c 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -19,10 +19,12 @@ environment:
- arch: x86
compiler: msvc2015
backend: ninja
+ BOOST_ROOT: C:\Libraries\Boost_1_59_0
- arch: x86
compiler: msvc2015
backend: vs2015
+ BOOST_ROOT: C:\Libraries\Boost_1_59_0
- arch: x64
compiler: cygwin
@@ -36,11 +38,13 @@ environment:
compiler: msvc2017
backend: ninja
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+ BOOST_ROOT: C:\Libraries\Boost_1_64_0
- arch: x64
compiler: msvc2017
backend: vs2017
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+ BOOST_ROOT: C:\Libraries\Boost_1_64_0
platform:
- x64
@@ -49,19 +53,27 @@ branches:
only:
- master
-skip_commits:
- files:
- - docs/**/*
+init:
+ - ps: |
+ If($Env:compiler -like 'msvc2010') {
+ Set-WinSystemLocale de-DE
+ Start-Sleep -s 5
+ Restart-Computer
+ }
install:
- cmd: set "ORIG_PATH=%PATH%"
- # Boost 1.56.0: https://www.appveyor.com/docs/build-environment/#boost
- #- cmd: set "BOOST_ROOT=C:\Libraries\boost"
+ # Use a Ninja with QuLogic's patch: https://github.com/ninja-build/ninja/issues/1219
+ - cmd: set "MESON_FIXED_NINJA=1"
+ - ps: (new-object net.webclient).DownloadFile('http://nirbheek.in/files/binaries/ninja/win32/ninja.exe', 'C:\projects\meson\ninja.exe')
# Use the x86 python only when building for x86 for the cpython tests.
# For all other archs (including, say, arm), use the x64 python.
- - ps: (new-object net.webclient).DownloadFile('https://www.dropbox.com/s/bbzvepq85hv47x1/ninja.exe?dl=1', 'C:\projects\meson\ninja.exe')
- cmd: if %arch%==x86 (set MESON_PYTHON_PATH=C:\python34) else (set MESON_PYTHON_PATH=C:\python34-x64)
+ # Set paths for BOOST dll files
+ - cmd: if %compiler%==msvc2015 ( if %arch%==x86 ( set "PATH=%PATH%;C:\Libraries\boost_1_59_0\lib32-msvc-14.0" ) else ( set "PATH=%PATH%;C:\Libraries\boost_1_59_0\lib64-msvc-14.0" ) )
+ - cmd: if %compiler%==msvc2017 ( if %arch%==x86 ( set "PATH=%PATH%;C:\Libraries\boost_1_64_0\lib32-msvc-14.1" ) else ( set "PATH=%PATH%;C:\Libraries\boost_1_64_0\lib64-msvc-14.1" ) )
+
# Set paths and config for each build type.
- cmd: if %compiler%==msvc2010 ( call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" %arch% )
- cmd: if %compiler%==msvc2015 ( call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %arch% )
@@ -73,7 +85,10 @@ install:
- cmd: if %compiler%==cygwin ( %WRAPPER% which %PYTHON% ) else ( where %PYTHON% )
# Install additional packages needed for specific builds.
- - ps: If($Env:compiler -eq 'msys2-mingw') {(new-object Net.WebClient).DownloadFile('https://bootstrap.pypa.io/get-pip.py', 'C:\projects\meson\get-pip.py')}
+ # This was originally downloaded from http://bootstrap.pypa.io/get-pip.py,
+ # but they have a broken certificate (on Windows) and an HSTS policy that
+ # forces usage of HTTPS, so we mirror our own copy.
+ - ps: If($Env:compiler -eq 'msys2-mingw') {(new-object Net.WebClient).DownloadFile('https://nirbheek.in/files/meson/get-pip.py', 'C:\projects\meson\get-pip.py')}
- cmd: if %compiler%==msys2-mingw ( %PYTHON% "C:\projects\meson\get-pip.py" )
- cmd: if %compiler%==cygwin ( call ci\appveyor-install.bat )
- ps: |
diff --git a/.travis.yml b/.travis.yml
index 5b6e022..e69cb31 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -30,14 +30,16 @@ matrix:
before_install:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi
- - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install ninja python3; fi
- - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker pull jpakkane/mesonci:zesty; fi
+ - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install python3; 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
# We need to copy the current checkout inside the Docker container,
# because it has the MR id to be tested checked out.
script:
- - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then echo FROM jpakkane/mesonci:zesty > Dockerfile; fi
+ - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then echo FROM jpakkane/mesonci:artful > Dockerfile; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then echo ADD . /root >> Dockerfile; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker build -t withgit .; fi
- |
@@ -45,6 +47,6 @@ script:
ci_env=`bash <(curl -s https://codecov.io/env)`
docker run $ci_env -v ${PWD}/.coverage:/root/.coverage \
withgit \
- /bin/sh -c "cd /root && CC=$CC CXX=$CXX OBJC=$CC OBJCXX=$CXX ./run_tests.py -- $MESON_ARGS && chmod -R a+rwX .coverage"
+ /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) OBJC=$CC OBJCXX=$CXX ./run_tests.py --backend=ninja -- $MESON_ARGS ; fi
+ - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then SDKROOT=$(xcodebuild -version -sdk macosx Path) OBJC=$CC OBJCXX=$CXX PATH=$HOME/tools:$PATH MESON_FIXED_NINJA=1 ./run_tests.py --backend=ninja -- $MESON_ARGS ; fi
diff --git a/ciimage/Dockerfile b/ciimage/Dockerfile
index 1c9e8d8..a2e3433 100644
--- a/ciimage/Dockerfile
+++ b/ciimage/Dockerfile
@@ -1,16 +1,15 @@
-FROM ubuntu:zesty
+FROM ubuntu:artful
RUN apt-get -y update && apt-get -y upgrade \
&& apt-get -y install git wget unzip \
&& apt-get -y build-dep meson \
-&& apt-get -y install qt5-default itstool clang libgtk-3-dev \
-&& apt-get -y install pkg-config-arm-linux-gnueabihf g++-6-arm-linux-gnueabihf \
-&& apt-get -y install valgrind doxygen \
-&& apt-get -y install llvm libsdl2-dev \
+&& apt-get -y install qt5-default clang \
+&& apt-get -y install pkg-config-arm-linux-gnueabihf g++-7-arm-linux-gnueabihf \
+&& apt-get -y install doxygen \
&& apt-get -y install python3-pip libxml2-dev libxslt1-dev cmake libyaml-dev \
-&& apt-get -y install openmpi-bin libopenmpi-dev \
-&& apt-get -y install libboost-log-dev \
-&& apt-get -y install libvulkan-dev libpcap-dev libcups2-dev \
+&& apt-get -y install libcups2-dev \
&& apt-get -y install gcovr lcov \
+&& apt-get -y install fpga-icestorm arachne-pnr yosys \
&& apt-get -y install gtk-sharp2 gtk-sharp2-gapi libglib2.0-cil-dev \
+&& apt-get -y install libwmf-dev \
&& python3 -m pip install hotdoc codecov
diff --git a/contributing.txt b/contributing.txt
index c4809ec..094c5e6 100644
--- a/contributing.txt
+++ b/contributing.txt
@@ -58,7 +58,7 @@ These are bad because they would make Meson's DSL Turing complete. The
second feature is a Make backend.
The FAQ has specific information why these two features will not be
-added to Meson: https://github.com/mesonbuild/meson/wiki/FAQ
+added to Meson: http://mesonbuild.com/FAQ.html
Merge requests adding either of these two features will be automatically
rejected. Please save everyone's time (especially your own) and don't start
diff --git a/cross/ubuntu-armhf.txt b/cross/ubuntu-armhf.txt
index d0fce20..367eba3 100644
--- a/cross/ubuntu-armhf.txt
+++ b/cross/ubuntu-armhf.txt
@@ -1,8 +1,8 @@
[binaries]
# we could set exe_wrapper = qemu-arm-static but to test the case
# when cross compiled binaries can't be run we don't do that
-c = '/usr/bin/arm-linux-gnueabihf-gcc-6'
-cpp = '/usr/bin/arm-linux-gnueabihf-g++-6'
+c = '/usr/bin/arm-linux-gnueabihf-gcc-7'
+cpp = '/usr/bin/arm-linux-gnueabihf-g++-7'
ar = '/usr/arm-linux-gnueabihf/bin/ar'
strip = '/usr/arm-linux-gnueabihf/bin/strip'
pkgconfig = '/usr/bin/arm-linux-gnueabihf-pkg-config'
diff --git a/data/macros.meson b/data/macros.meson
index e55f7a2..b31f77e 100644
--- a/data/macros.meson
+++ b/data/macros.meson
@@ -33,4 +33,9 @@
%ninja_install -C %{_vpath_builddir}
%meson_test \
- %ninja_test -C %{_vpath_builddir}
+ %ninja_test -C %{_vpath_builddir} || \
+ { rc=$?; \
+ echo "-----BEGIN TESTLOG-----"; \
+ cat %{_vpath_builddir}/meson-logs/testlog.txt; \
+ echo "-----END TESTLOG-----"; \
+ exit $rc; }
diff --git a/data/shell-completions/zsh/_meson b/data/shell-completions/zsh/_meson
new file mode 100644
index 0000000..877d700
--- /dev/null
+++ b/data/shell-completions/zsh/_meson
@@ -0,0 +1,213 @@
+#compdef meson mesonconf=meson-configure mesontest=meson-test mesonintrospect=meson-introspect
+
+# vim:ts=2 sw=2
+
+# Copyright (c) 2017 Arseny Maslennikov
+# All rights reserved. Individual authors, whether or not
+# specifically named, retain copyright in all changes; in what follows, they
+# are referred to as `the Meson development team'. This is for convenience
+# only and this body has no legal status. This file is distributed under
+# the following licence.
+#
+# Permission is hereby granted, without written agreement and without
+# licence or royalty fees, to use, copy, modify, and distribute this
+# software and to distribute modified versions of this software for any
+# purpose, provided that the above copyright notice and the following
+# two paragraphs appear in all copies of this software.
+#
+# In no event shall the Meson development team be liable to any party for
+# direct, indirect, special, incidental, or consequential damages arising out
+# of the use of this software and its documentation, even if the Meson
+# development team have been advised of the possibility of such damage.
+#
+# The Meson development team specifically disclaim any warranties, including,
+# but not limited to, the implied warranties of merchantability and fitness
+# for a particular purpose. The software provided hereunder is on an "as is"
+# basis, and the Meson development team have no obligation to provide
+# maintenance, support, updates, enhancements, or modifications.
+
+local curcontext="$curcontext" state line
+local -i ret
+
+local __meson_backends="(ninja xcode ${(j. .)${:-vs{,2010,2015,2017}}})"
+local __meson_build_types="(plain debug debugoptimized minsize release)"
+local __meson_wrap_modes="(WrapMode.{default,nofallback,nodownload})"
+
+local -a meson_commands=(
+'setup:set up a build directory'
+'configure:configure a project'
+'test:run tests'
+'introspect:query project properties'
+'wrap:manage source dependencies'
+)
+
+(( $+functions[__meson_is_build_dir] )) || __meson_is_build_dir() {
+ local mpd="${1:-$PWD}/meson-private"
+ [[ -f "$mpd/build.dat" && -f "$mpd/coredata.dat" ]]
+ return $?
+}
+
+# TODO: implement build option completion
+(( $+functions[__meson_build_options] )) || __meson_build_options() {}
+# TODO: implement target name completion
+(( $+functions[__meson_targets] )) || __meson_targets() {}
+# `meson introspect` currently can provide that information in JSON.
+# We can:
+# 1) pipe its output to python3 -m json.tool | grep "$alovelyregex" | cut <...>
+# 2) teach mintro.py to use a different output format
+# (or perhaps just to select the fields printed)
+
+(( $+functions[__meson_test_names] )) || __meson_test_names() {
+ local rtests
+ if rtests="$(_call_program meson meson test ${opt_args[-C]:+-C "$opt_args[-C]"} --list)";
+ then
+ local -a tests=(${(@f)rtests})
+ _describe -t "tests" "Meson tests" tests
+ else
+ _message -r "current working directory is not a build directory"
+ _message -r 'use -C $build_dir or cd $build_dir'
+ fi
+}
+
+(( $+functions[_meson_commands] )) || _meson_commands() {
+ _describe -t commands "Meson subcommands" meson_commands
+}
+
+(( $+functions[_meson-setup] )) || _meson-setup() {
+ local firstd secondd
+ if [[ -f "meson.build" ]]; then
+ # if there's no second argument on the command line
+ # cwd will implicitly be substituted:
+ # - as the source directory if it has a file with the name "meson.build";
+ # - as the build directory otherwise
+ # more info in mesonbuild/mesonmain.py
+ firstd="build"
+ secondd="source"
+ else
+ firstd="source"
+ secondd="build"
+ fi
+
+ _arguments \
+ '*-D-[set the value of a build option]:build option:__meson_build_options' \
+ '--prefix=[installation prefix]: :_directories' \
+ '--libdir=[library directory]: :_directories' \
+ '--libexecdir=[library executable directory]: :_directories' \
+ '--bindir=[executable directory]: :_directories' \
+ '--sbindir=[system executable directory]: :_directories' \
+ '--includedir=[header file directory]: :_directories' \
+ '--datadir=[data file directory]: :_directories' \
+ '--mandir=[manual page directory]: :_directories' \
+ '--infodir=[info page directory]: :_directories' \
+ '--localedir=[locale data directory]: :_directories' \
+ '--sysconfdir=[system configuration directory]: :_directories' \
+ '--localstatedir=[local state data directory]: :_directories' \
+ '--sharedstatedir=[arch-independent data directory]: :_directories' \
+ '--backend=[backend to use]:Meson backend:'"$__meson_backends" \
+ '--buildtype=[build type to use]:Meson build type:'"$__meson_build_types" \
+ '--strip[strip targets on install]' \
+ '--unity=[unity builds on/off]:whether to do unity builds:(on off subprojects)' \
+ '--werror[treat warnings as errors]' \
+ '--layout=[build directory layout]:build directory layout:(flat mirror)' \
+ '--default-library=[default library type]:default library type:(shared static)' \
+ '--warnlevel=[compiler warning level]:compiler warning level:warning level:(1 2 3)' \
+ '--stdsplit=[split stdout and stderr in test logs]' \
+ '--errorlogs=[prints the logs from failing tests]' \
+ '--cross-file=[cross-compilation environment description]:cross file:_files' \
+ '--wrap-mode=[special wrap mode]:wrap mode:'"$__meson_wrap_modes" \
+ ":$firstd directory:_directories" \
+ "::$secondd directory:_directories" \
+ #
+}
+
+(( $+functions[_meson-configure] )) || _meson-configure() {
+ local curcontext="$curcontext"
+ # TODO: implement 'mesonconf @file'
+ local -a specs=(
+ '--clearcache[clear cached state]'
+ '*-D-[set the value of a build option]:build option:__meson_build_options'
+ '::build directory:_directories'
+ )
+
+ _arguments \
+ '(: -)'{'--help','-h'}'[show a help message and quit]' \
+ "${(@)specs}"
+}
+
+(( $+functions[_meson-test] )) || _meson-test() {
+ local curcontext="$curcontext"
+
+ # TODO: complete test suites
+ local -a specs=(
+ '(--quiet -q)'{'--quiet','-q'}'[produce less output to the terminal]'
+ '(--verbose -v)'{'--verbose','-v'}'[do not redirect stdout and stderr]'
+ '(--timeout-multiplier -t)'{'--timeout-multiplier','-t'}'[a multiplier for test timeouts]:Python floating-point number: '
+ '-C[directory to cd into]: :_directories'
+ '--repeat[number of times to run the tests]:number of times to repeat: '
+ '--no-rebuild[do not rebuild before running tests]'
+ '--gdb[run tests under gdb]'
+ '--list[list available tests]'
+ '(--wrapper --wrap)'{'--wrapper=','--wrap='}'[wrapper to run tests with]:wrapper program:_path_commands'
+ '(--no-suite)--suite[only run tests from this suite]:test suite: '
+ '(--suite)--no-suite[do not run tests from this suite]:test suite: '
+ '--no-stdsplit[do not split stderr and stdout in logs]'
+ '--print-errorlogs[print logs for failing tests]'
+ '--benchmark[run benchmarks instead of tests]'
+ '--logbase[base name for log file]:filename: '
+ '--num-processes[how many threads to use]:number of processes: '
+ '--setup[which test setup to use]:test setup: '
+ '--test-args[arguments to pass to the tests]: : '
+ '*:Meson tests:__meson_test_names'
+ )
+
+ _arguments \
+ '(: -)'{'--help','-h'}'[show a help message and quit]' \
+ "${(@)specs}"
+}
+
+(( $+functions[_meson-introspect] )) || _meson-introspect() {
+ local curcontext="$curcontext"
+ local -a specs=(
+ '--targets[list top level targets]'
+ '--installed[list all installed files and directories]'
+ '--target-files[list source files for a given target]:target:__meson_targets'
+ '--buildsystem-files[list files that belong to the build system]'
+ '--buildoptions[list all build options]'
+ '--tests[list all unit tests]'
+ '--benchmarks[list all benchmarks]'
+ '--dependencies[list external dependencies]'
+ '--projectinfo[show project information]'
+ '::build directory:_directories'
+ )
+_arguments \
+ '(: -)'{'--help','-h'}'[show a help message and quit]' \
+ "${(@)specs}"
+}
+
+(( $+functions[_meson-wrap] )) || _meson-wrap() {
+ # TODO
+}
+
+if [[ $service != meson ]]; then
+ _call_function ret _$service
+ return ret
+fi
+
+_arguments -C -R \
+ '(: -)'{'--help','-h'}'[show a help message and quit]' \
+ '(: -)'{'--version','-v'}'[show version information and quit]' \
+ '(-): :_meson_commands' \
+ '*:: :->post-command' \
+#
+ret=$?
+
+[[ $ret = 300 ]] && case "$state" in
+ post-command)
+ service="meson-$words[1]"
+ curcontext=${curcontext%:*:*}:$service:
+ _call_function ret _$service
+ ;;
+esac
+
+return ret
+
diff --git a/data/meson.el b/data/syntax-highlighting/emacs/meson.el
index 36f7eb9..36f7eb9 100644
--- a/data/meson.el
+++ b/data/syntax-highlighting/emacs/meson.el
diff --git a/syntax-highlighting/vim/README b/data/syntax-highlighting/vim/README
index 1afa243..1afa243 100644
--- a/syntax-highlighting/vim/README
+++ b/data/syntax-highlighting/vim/README
diff --git a/syntax-highlighting/vim/ftdetect/meson.vim b/data/syntax-highlighting/vim/ftdetect/meson.vim
index 84db70c..84db70c 100644
--- a/syntax-highlighting/vim/ftdetect/meson.vim
+++ b/data/syntax-highlighting/vim/ftdetect/meson.vim
diff --git a/syntax-highlighting/vim/indent/meson.vim b/data/syntax-highlighting/vim/indent/meson.vim
index b00c942..8553ec0 100644
--- a/syntax-highlighting/vim/indent/meson.vim
+++ b/data/syntax-highlighting/vim/indent/meson.vim
@@ -78,7 +78,7 @@ function GetMesonIndent(lnum)
" When inside parenthesis: If at the first line below the parenthesis add
- " two 'shiftwidth', otherwise same as previous line.
+ " a 'shiftwidth', otherwise same as previous line.
" i = (a
" + b
" + c)
@@ -97,7 +97,7 @@ function GetMesonIndent(lnum)
if pp > 0
return indent(plnum) + (exists("g:pyindent_nested_paren") ? eval(g:pyindent_nested_paren) : shiftwidth())
endif
- return indent(plnum) + (exists("g:pyindent_open_paren") ? eval(g:pyindent_open_paren) : (shiftwidth() * 2))
+ return indent(plnum) + (exists("g:pyindent_open_paren") ? eval(g:pyindent_open_paren) : shiftwidth())
endif
if plnumstart == p
return indent(plnum)
diff --git a/syntax-highlighting/vim/syntax/meson.vim b/data/syntax-highlighting/vim/syntax/meson.vim
index 49921c1..49921c1 100644
--- a/syntax-highlighting/vim/syntax/meson.vim
+++ b/data/syntax-highlighting/vim/syntax/meson.vim
diff --git a/docs/images/gtksample.png b/docs/images/gtksample.png
index 1784b77..b6557c4 100644
--- a/docs/images/gtksample.png
+++ b/docs/images/gtksample.png
Binary files differ
diff --git a/docs/markdown/Build-options.md b/docs/markdown/Build-options.md
index 54905d5..cb7b19e 100644
--- a/docs/markdown/Build-options.md
+++ b/docs/markdown/Build-options.md
@@ -42,11 +42,16 @@ prefix = get_option('prefix')
```
It should be noted that you can not set option values in your Meson
-scripts. They have to be set externally with the `mesonconf` command
-line tool. Running `mesonconf` without arguments in a build dir shows
-you all options you can set. To change their values use the `-D`
+scripts. They have to be set externally with the `meson configure` command
+line tool. Running `meson configure` without arguments in a build dir shows
+you all options you can set.
+
+To change their values use the `-D`
option:
```console
-$ mesonconf -Doption=newvalue
+$ meson configure -Doption=newvalue
```
+
+
+**NOTE:** If you cannot call `meson configure` you likely have a old version of Meson. In that case you can call `mesonconf` instead, but that is deprecated in newer versions
diff --git a/docs/markdown/Comparisons.md b/docs/markdown/Comparisons.md
index 3c526ad..1deef69 100644
--- a/docs/markdown/Comparisons.md
+++ b/docs/markdown/Comparisons.md
@@ -2,7 +2,7 @@
title: Comparisons
...
-# Comparing Meson with other build systems #
+# Comparing Meson with other build systems
A common question is *Why should I choose Meson over a different build
system X?* There is no one true answer to this as it depends on the
@@ -11,37 +11,37 @@ to build medium-to-large projects so the decision is usually made on
other points. Here we list some pros and cons of various build systems
to help you do the decision yourself.
-## GNU Autotools ##
+## GNU Autotools
-### Pros ###
+### Pros
Excellent support for legacy Unix platforms, large selection of
existing modules.
-### Cons ###
+### Cons
Needlessly slow, complicated, hard to use correctly, unreliable,
painful to debug, incomprehensible for most people, poor support for
non-Unix platforms (especially Windows).
-## CMake ##
+## CMake
-### Pros ###
+### Pros
Great support for multiple backends (Visual Studio, XCode, etc).
-### Cons ###
+### Cons
The scripting language is cumbersome to work with. Some simple things
are more complicated than necessary.
-## SCons ##
+## SCons
-### Pros ###
+### Pros
Full power of Python available for defining your build.
-### Cons ###
+### Cons
Slow. Requires you to pass your configuration settings on every
invocation. That is, if you do `scons OPT1 OPT2` and then just
@@ -51,19 +51,19 @@ previous invocation.
## Bazel
-# Pros
+### Pros
Proven to scale to very large projects.
-## Cons
+### Cons
Implemented in Java. Poor Windows support. Heavily focused on Google's
way of doing things (which may be a good or a bad thing). Contributing
code requires [signing a CLA](https://bazel.build/contributing.html).
-## Meson ##
+## Meson
-### Pros ###
+### Pros
The fastest build system [see
measurements](Performance-comparison.md), user friendly, designed to
@@ -71,7 +71,7 @@ be as invisible to the developer as possible, native support for
modern tools (precompiled headers, coverage, Valgrind etc). Not Turing
complete so build definition files are easy to read and understand.
-### Cons ###
+### Cons
Relatively new so it does not have a large user base yet, and may thus
contain some unknown bugs. Visual Studio and XCode backends not as
diff --git a/docs/markdown/Compiler-properties.md b/docs/markdown/Compiler-properties.md
index 5978b5d..4def628 100644
--- a/docs/markdown/Compiler-properties.md
+++ b/docs/markdown/Compiler-properties.md
@@ -29,26 +29,9 @@ Compiler id
==
The compiler object has a method called `get_id`, which returns a
-lower case string describing the "family" of the compiler. It has one
-of the following values.
-
-| Value | Compiler family |
-| ----- | ---------------- |
-| gcc | The GNU Compiler Collection |
-| clang | The Clang compiler |
-| msvc | Microsoft Visual Studio |
-| intel | Intel compiler |
-| llvm | LLVM-based compiler (Swift, D) |
-| mono | Xamarin C# compiler |
-| dmd | D lang reference compiler |
-| rustc | Rust compiler |
-| valac | Vala compiler |
-| pathscale | The Pathscale Fortran compiler |
-| pgi | The Portland Fortran compiler |
-| sun | Sun Fortran compiler |
-| g95 | The G95 Fortran compiler |
-| open64 | The Open64 Fortran Compiler |
-| nagfor | The NAG Fortran compiler |
+lower case string describing the "family" of the compiler. See
+[reference tables](Reference-tables.md) for a list of supported
+compiler ids.
Does code compile?
==
@@ -120,12 +103,12 @@ The `result` variable encapsulates the state of the test, which can be
extracted with the following methods. The `name` keyword argument
works the same as with `compiles`.
-| Method | Return value
-| ------ | ------------
-| compiled | `True` if compilation succeeded. If `false` then all other methods return undefined values.
-| returncode | The return code of the application as an integer
-| stdout | Program's standard out as text.
-| stderr | Program's standard error as text.
+| Method | Return value |
+| ------ | ------------ |
+| compiled | `True` if compilation succeeded. If `false` then all other methods return undefined values. |
+| returncode | The return code of the application as an integer |
+| stdout | Program's standard out as text. |
+| stderr | Program's standard error as text. |
Here is an example usage:
diff --git a/docs/markdown/Configuring-a-build-directory.md b/docs/markdown/Configuring-a-build-directory.md
index edf3d97..774addf 100644
--- a/docs/markdown/Configuring-a-build-directory.md
+++ b/docs/markdown/Configuring-a-build-directory.md
@@ -9,11 +9,11 @@ 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 `mesonconf` script. You may also use the
+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.
-You invoke `mesonconf` by giving it the location of your build dir. If
+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
sample output for a simple project.
@@ -56,7 +56,7 @@ the option. To set an option you use the `-D` option. For example,
changing the installation prefix from `/usr/local` to `/tmp/testroot`
you would issue the following command.
- mesonconf -Dprefix=/tmp/testroot
+ meson configure -Dprefix=/tmp/testroot
Then you would run your build command (usually `ninja`), which would
cause Meson to detect that the build setup has changed and do all the
diff --git a/docs/markdown/Cross-compilation.md b/docs/markdown/Cross-compilation.md
index e232033..f68b1f5 100644
--- a/docs/markdown/Cross-compilation.md
+++ b/docs/markdown/Cross-compilation.md
@@ -69,6 +69,7 @@ c = '/usr/bin/i586-mingw32msvc-gcc'
cpp = '/usr/bin/i586-mingw32msvc-g++'
ar = '/usr/i586-mingw32msvc/bin/ar'
strip = '/usr/i586-mingw32msvc/bin/strip'
+pkgconfig = '/usr/bin/i586-mingw32msvc-pkg-config'
exe_wrapper = 'wine' # A command used to run generated executables.
```
diff --git a/docs/markdown/Custom-build-targets.md b/docs/markdown/Custom-build-targets.md
index 8bd31db..30a16e3 100644
--- a/docs/markdown/Custom-build-targets.md
+++ b/docs/markdown/Custom-build-targets.md
@@ -27,7 +27,7 @@ This would generate the binary `output.bin` and install it to
`${prefix}/subdir/output.bin`. Variable substitution works just like
it does for source generation.
-## Details on compiler invocations ##
+## Details on compiler invocations
Meson only permits you to specify one command to run. This is by
design as writing shell pipelines into build definition files leads to
diff --git a/docs/markdown/D.md b/docs/markdown/D.md
new file mode 100644
index 0000000..7b0d485
--- /dev/null
+++ b/docs/markdown/D.md
@@ -0,0 +1,89 @@
+---
+title: D
+short-description: Compiling D sources
+...
+
+# Compiling D applications
+
+Meson has support for compiling D programs. A minimal `meson.build` file for D looks like this:
+
+```meson
+project('myapp', 'd')
+
+executable('myapp', 'app.d')
+```
+
+## Compiling different versions
+
+If you are using the [version()](https://dlang.org/spec/version.html) feature for conditional compilation, you can use it using the `d_module_versions`
+target property:
+```meson
+project('myapp', 'd')
+executable('myapp', 'app.d', d_module_versions: ['Demo', 'FeatureA'])
+```
+
+## Using embedded unittests
+
+If you are using embedded [unittest functions](https://dlang.org/spec/unittest.html), your source code needs to be compiled twice, once in regular
+mode, and once with unittests active. This is done by setting the `d_unittest` target property to `true`.
+Meson will only ever pass the respective compiler's `-unittest` flag, and never have the compiler generate an empty main function.
+If you need that feature in a portable way, create an empty `main()` function for unittests yourself, since the GNU D compiler
+does not have this feature.
+
+This is an example for using D unittests with Meson:
+```meson
+project('myapp_tested', 'd')
+
+myapp_src = ['app.d', 'alpha.d', 'beta.d']
+executable('myapp', myapp_src)
+
+test_exe = executable('myapp_test', myapp_src, d_unittest: true)
+test('myapptest', test_exe)
+```
+
+# Compiling D libraries and installing them
+
+Building D libraries is a straightforward process, not different from how C libraries are built in Meson. You should generate a pkg-config file
+and install it, in order to make other software on the system find the dependency once it is installed.
+
+This is an example on how to build a D shared library:
+```meson
+project('mylib', 'd', version: '1.2.0')
+
+project_soversion = 0
+glib_dep = dependency('glib-2.0')
+
+my_lib = library('mylib',
+ ['src/mylib/libfunctions.d'],
+ dependencies: [glib_dep],
+ install: true,
+ version: meson.project_version(),
+ soversion: project_soversion,
+ d_module_versions: ['FeatureA', 'featureB']
+)
+pkgc.generate(name: 'mylib',
+ libraries: my_lib,
+ subdirs: 'd/mylib',
+ version: meson.project_version(),
+ description: 'A simple example D library.',
+ d_module_versions: ['FeatureA']
+)
+install_subdir('src/mylib/', install_dir: 'include/d/mylib/')
+```
+
+It is important to make the D sources install in a subdirectory in the include path, in this case `/usr/include/d/mylib/mylib`.
+All D compilers include the `/usr/include/d` directory by default, and if your library would be installed into `/usr/include/d/mylib`, there
+is a high chance that, when you compile your project again on a machine where you installed it, the compiler will prefer the old installed include over
+the new version in the source tree, leading to very confusing errors.
+
+This is an example of how to use the D library we just built and installed in an application:
+```meson
+project('myapp', 'd')
+
+mylib_dep = dependency('mylib', version: '>= 1.2.0')
+myapp_src = ['app.d', 'alpha.d', 'beta.d']
+executable('myapp', myapp_src, dependencies: [mylib_dep])
+```
+
+Please keep in mind that the library and executable would both need to be built with the exact same D compiler and D compiler version. The D ABI is not
+stable across compilers and their versions, and mixing compilers will lead to problems.
diff --git a/docs/markdown/Dependencies.md b/docs/markdown/Dependencies.md
index 187c4fe..8e780d6 100644
--- a/docs/markdown/Dependencies.md
+++ b/docs/markdown/Dependencies.md
@@ -45,13 +45,66 @@ non-found dependencies.
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.
+pkg-config files. Meson has autodetection support for some of these,
+and they are described later on this page.
-## Boost ##
+# Declaring your own
+
+You can declare your own dependency objects that can be used
+interchangeably with dependency objects obtained from the system. The
+syntax is straightforward:
+
+```meson
+my_inc = include_directories(...)
+my_lib = static_library(...)
+my_dep = declare_dependency(link_with : my_lib,
+ include_directories : my_inc)
+```
+
+This declares a dependency that adds the given include directories and
+static library to any target you use it in.
+
+# Building dependencies as subprojects
+
+Many platforms do not provide a system package manager. On these
+systems dependencies must be compiled from source. Meson's subprojects
+make it simple to use system dependencies when they are available and
+to build dependencies manually when they are not.
+
+To make this work, the dependency must have Meson build definitions
+and it must declare its own dependency like this:
+
+ foo_dep = declare_dependency(...)
+
+Then any project that wants to use it can write out the following
+declaration in their main `meson.build` file.
+
+ foo_dep = dependency('foo', fallback : ['foo', 'foo_dep'])
+
+What this declaration means is that first Meson tries to look up the
+dependency from the system (such as by using pkg-config). If it is not
+available, then it builds subproject named `foo` and from that
+extracts a variable `foo_dep`. That means that the return value of
+this function is either an external or an internal dependency
+object. Since they can be used interchangeably, the rest of the build
+definitions do not need to care which one it is. Meson will take care
+of all the work behind the scenes to make this work.
+
+# Dependencies with custom lookup functionality
+
+## Boost
Boost is not a single dependency but rather a group of different
-libraries. To use Boost with Meson, simply list which Boost modules
-you would like to use.
+libraries. To use Boost headers-only libraries, simply add Boost as a
+dependency.
+
+```meson
+boost_dep = dependency('boost')
+exe = executable('myprog', 'file.cc', dependencies : boost_dep)
+```
+
+To link against boost with Meson, simply list which libraries you would like to
+use.
```meson
boost_dep = dependency('boost', modules : ['thread', 'utility'])
@@ -65,7 +118,10 @@ If your boost headers or libraries are in non-standard locations you
can set the BOOST_ROOT, BOOST_INCLUDEDIR, and/or BOOST_LIBRARYDIR
environment variables.
-## GTest and GMock ##
+You can set the argument `threading` to `single` to use boost libraries that
+has been compiled for single-threaded use instead.
+
+## GTest and GMock
GTest and GMock come as sources that must be compiled as part of your
project. With Meson you don't have to care about the details, just
@@ -73,7 +129,7 @@ pass `gtest` or `gmock` to `dependency` and it will do everything for
you. If you want to use GMock, it is recommended to use GTest as well,
as getting it to work standalone is tricky.
-## MPI ##
+## MPI
MPI is supported for C, C++ and Fortran. Because dependencies are
language-specific, you must specify the requested language using the
@@ -89,7 +145,7 @@ are not in your path, they can be specified by setting the standard
environment variables `MPICC`, `MPICXX`, `MPIFC`, `MPIF90`, or
`MPIF77`, during configuration.
-## Qt5 ##
+## Qt5
Meson has native Qt5 support. Its usage is best demonstrated with an
example.
@@ -142,18 +198,12 @@ automatically:
cups_dep = dependency('cups', version : '>=1.4')
```
-## Declaring your own
+## LibWMF
-You can declare your own dependency objects that can be used
-interchangeably with dependency objects obtained from the system. The
-syntax is straightforward:
+The libwmf library does not ship with pkg-config at the time or writing
+but instead it has its own `libwmf-config` util. Meson will use it
+automatically:
```meson
-my_inc = include_directories(...)
-my_lib = static_library(...)
-my_dep = declare_dependency(link_with : my_lib,
- include_directories : my_inc)
+libwmf_dep = dependency('libwmf', version : '>=0.2.8')
```
-
-This declares a dependency that adds the given include directories and
-static library to any target you use it in.
diff --git a/docs/markdown/Design-rationale.md b/docs/markdown/Design-rationale.md
index 269f688..7cf67a4 100644
--- a/docs/markdown/Design-rationale.md
+++ b/docs/markdown/Design-rationale.md
@@ -67,7 +67,7 @@ need to solve? What sort of solutions would be the most appropriate?
To get things started, here is a list of requirements any modern cross-platform build system needs to provide.
-###1. Must be simple to use###
+### 1. Must be simple to use
One of the great virtues of Python is the fact that it is very
readable. It is easy to see what a given block of code does. It is
@@ -76,7 +76,7 @@ be syntactically and semantically clean. Side effects, global state
and interrelations must be kept at a minimum or, if possible,
eliminated entirely.
-###2. Must do the right thing by default###
+### 2. Must do the right thing by default
Most builds are done by developers working on the code. Therefore the
defaults must be tailored towards that use case. As an example the
@@ -85,7 +85,7 @@ information. It shall make binaries that can be run directly from the
build directory without linker tricks, shell scripts or magic
environment variables.
-###3. Must enforce established best practices###
+### 3. Must enforce established best practices
There really is no reason to compile source code without the
equivalent of `-Wall`. So enable it by default. A different kind of
@@ -94,7 +94,7 @@ directories. All build artifacts must be stored in the build
directory. Writing stray files in the source directory is not
permitted under any circumstances.
-###4. Must have native support for platforms that are in common use###
+### 4. Must have native support for platforms that are in common use
A lot of free software projects can be used on non-free platforms such
as Windows or OSX. The system must provide native support for the
@@ -102,10 +102,10 @@ tools of choice on those platforms. In practice this means native
support for Visual Studio and XCode. Having said IDEs invoke external
builder binaries does not count as native support.
-###5. Must not add complexity due to obsolete platforms###
+### 5. Must not add complexity due to obsolete platforms
-Work on this build system started during the Christmas holidays of
-2012. This provides a natural hard cutoff line of 2012/12/24. Any
+Work on this build system started during the Christmas holidays of 2012.
+This provides a natural hard cutoff line of 2012/12/24. Any
platform, tool or library that was not in active use at that time is
explicitly not supported. These include Unixes such as IRIX, SunOS,
OSF-1, Ubuntu versions older than 12/10, GCC versions older than 4.7
@@ -113,20 +113,20 @@ and so on. If these old versions happen to work, great. If they don't,
not a single line of code will be added to the system to work around
their bugs.
-###6. Must be fast###
+### 6. Must be fast
Running the configuration step on a moderate sized project must not
take more than five seconds. Running the compile command on a fully up
to date tree of 1000 source files must not take more than 0.1 seconds.
-###7. Must provide easy to use support for modern sw development features###
+### 7. Must provide easy to use support for modern sw development features
An example is precompiled headers. Currently no free software build
system provides native support for them. Other examples could include
easy integration of Valgrind and unit tests, test coverage reporting
and so on.
-###8. Must allow override of default values###
+### 8. Must allow override of default values
Sometimes you just have to compile files with only given compiler
flags and no others, or install files in weird places. The system must
diff --git a/docs/markdown/FAQ.md b/docs/markdown/FAQ.md
index 2d28137..441cd69 100644
--- a/docs/markdown/FAQ.md
+++ b/docs/markdown/FAQ.md
@@ -98,7 +98,7 @@ The only reason why one would use Make instead of Ninja is working on a platform
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? ##
+## 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?*
@@ -144,7 +144,7 @@ This defaults to `c++11` on GCC compilers. Suppose you want to use `c++14` inste
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 `mesonconf` 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.
## Does wrap download sources behind my back?
diff --git a/docs/markdown/Generating-sources.md b/docs/markdown/Generating-sources.md
index c251805..ae1302b 100644
--- a/docs/markdown/Generating-sources.md
+++ b/docs/markdown/Generating-sources.md
@@ -31,7 +31,7 @@ gen_src = custom_target('gen-output',
'--h-out', '@OUTPUT1@'])
```
-The `@INPUT@` there will be transformed to `'out.c' 'out.h'`. Just like the output, you can also refer to each input file individually by index.
+The `@INPUT@` there will be transformed to `'somefile1.c' 'file2.c'`. Just like the output, you can also refer to each input file individually by index.
Then you just put that in your program and you're done.
diff --git a/docs/markdown/Getting-meson.md b/docs/markdown/Getting-meson.md
index d654ff3..8664d61 100644
--- a/docs/markdown/Getting-meson.md
+++ b/docs/markdown/Getting-meson.md
@@ -5,7 +5,7 @@
Meson releases can be downloaded from the [GitHub release page].
Meson is also available in the [Python Package Index] and can be
-installed with <tt>pip3 install meson</tt>.
+installed with `pip3 install meson`.
The newest development code can be obtained directly from [Git]
diff --git a/docs/markdown/Gnome-module.md b/docs/markdown/Gnome-module.md
index 99a9c8e..738e2a9 100644
--- a/docs/markdown/Gnome-module.md
+++ b/docs/markdown/Gnome-module.md
@@ -30,29 +30,19 @@ file called `foobar.h`, which you can then include in your sources.
* `c_name`: passed to the resource compiler as an argument after
`--c-name`
-
* `dependencies`: extra targets to depend upon for building
-
* `export`: (*Added 0.37.0*) if true, export the symbols of the
generated sources
-
* `extra_args`: extra command line arguments to pass to the resource
-
* `gresource_bundle`: (*Added 0.37.0*) if true, output a `.gresource`
file instead of source
-
* `install`: (*Added 0.37.0*) if true, install the gresource file
-
* `install_dir`: (*Added 0.37.0*) location to install the header or
bundle depending on previous options
-
* `install_header`: (*Added 0.37.0*) if true, install the header file
-
* `source_dir`: a list of subdirectories where the resource compiler
should look up the files, relative to the location of the XML file
- compiler
-
Returns an array containing: `[c_source, header_file]` or
`[gresource_bundle]`
@@ -64,36 +54,26 @@ keyword arguments. Many of these map directly to the `g-ir-scanner`
tool so see its documentation for more information.
* `dependencies`: deps to use during introspection scanning
-
* `extra_args`: command line arguments to pass to gir compiler
-
* `export_packages`: extra packages the gir file exports
-
* `sources`: the list of sources to be scanned for gir data
-
* `nsversion`: namespace version
-
* `namespace`: the namespace for this gir object which determines
output files
-
* `identifier_prefix`: the identifier prefix for the gir object,
e.g. `Gtk`
-
* `includes`: list of gir names to be included, can also be a GirTarget
-
+* `header`: *(Added 0.43.0)* name of main c header to include for the library, e.g. `glib.h`
+* `dependencies`: deps to use during introspection scanning
* `include_directories`: extra include paths to look for gir files
-
* `install`: if true, install the generated files
-
* `install_dir_gir`: (*Added 0.35.0*) which directory to install the
gir file into
-
* `install_dir_typelib`: (*Added 0.35.0*) which directory to install
the typelib file into
-
* `link_with`: list of libraries to link with
-
-* `symbol_prefix`: the symbol prefix for the gir object, e.g. `gtk`
+* `symbol_prefix`: the symbol prefix for the gir object, e.g. `gtk`,
+ (*Since 0.43.0*) an ordered list of multiple prefixes is allowed
Returns an array of two elements which are: `[gir_target,
typelib_target]`
diff --git a/docs/markdown/IDE-integration.md b/docs/markdown/IDE-integration.md
index d2a3e9c..f7939dd 100644
--- a/docs/markdown/IDE-integration.md
+++ b/docs/markdown/IDE-integration.md
@@ -34,7 +34,7 @@ The next thing to display is the list of options that can be set. These include
mesonintrospect.py --buildoptions
-To set the options, use the `mesonconf.py` binary.
+To set the options, use the `meson configure` command.
Compilation and unit tests are done as usual by running the `ninja` and `ninja test` commands. A JSON formatted result log can be found in `workspace/project/builddir/meson-logs/testlog.json`.
diff --git a/docs/markdown/Installing.md b/docs/markdown/Installing.md
index 3454d49..2663ff4 100644
--- a/docs/markdown/Installing.md
+++ b/docs/markdown/Installing.md
@@ -44,7 +44,7 @@ giving an absolute install path.
install_data(sources : 'foo.dat', install_dir : '/etc') # -> /etc/foo.dat
```
-## Custom install behavior ##
+## Custom install behavior
Sometimes you need to do more than just install basic targets. Meson makes this easy by allowing you to specify a custom script to execute at install time. As an example, here is a script that generates an empty file in a custom directory.
@@ -65,7 +65,7 @@ meson.add_install_script('myscript.sh')
The argument is the name of the script file relative to the current subdirectory.
-## DESTDIR support ##
+## DESTDIR support
Sometimes you need to install to a different directory than the install prefix. This is most common when building rpm or deb packages. This is done with the `DESTDIR` environment variable and it is used just like with other build systems:
diff --git a/docs/markdown/Module-reference.md b/docs/markdown/Module-reference.md
index 80e3b8f..60be7bd 100644
--- a/docs/markdown/Module-reference.md
+++ b/docs/markdown/Module-reference.md
@@ -17,4 +17,4 @@ change in arbitrary ways between releases. The modules might also be removed
without warning in future releases.
* [SIMD](Simd-module.md)
- \ No newline at end of file
+
diff --git a/docs/markdown/Pkgconfig-module.md b/docs/markdown/Pkgconfig-module.md
index 5a660fd..7f767f1 100644
--- a/docs/markdown/Pkgconfig-module.md
+++ b/docs/markdown/Pkgconfig-module.md
@@ -41,3 +41,5 @@ keyword arguments.
e.g. `datadir=${prefix}/share`. The names `prefix`, `libdir` and
`installdir` are reserved and may not be used.
- `version` a string describing the version of this library
+- `d_module_versions` a list of module version flags used when compiling
+ D sources referred to by this pkg-config file
diff --git a/docs/markdown/Precompiled-headers.md b/docs/markdown/Precompiled-headers.md
index 22fd762..57b2923 100644
--- a/docs/markdown/Precompiled-headers.md
+++ b/docs/markdown/Precompiled-headers.md
@@ -40,7 +40,7 @@ Toggling the usage of precompiled headers
If you wish to compile your project without precompiled headers, you
can change the value of the pch option by passing `-Db_pch=false`
-argument to Meson at configure time or later with `mesonconf`. You can
+argument to Meson at configure time or later with `meson configure`. You can
also toggle the use of pch in a configured build directory with the
GUI tool. You don't have to do any changes to the source
code. Typically this is done to test whether your project compiles
diff --git a/docs/markdown/Qt5-module.md b/docs/markdown/Qt5-module.md
index 7082309..aea2ae1 100644
--- a/docs/markdown/Qt5-module.md
+++ b/docs/markdown/Qt5-module.md
@@ -5,17 +5,24 @@ tools and steps required for Qt. The module has one method.
## preprocess
-This method takes four keyword arguments, `moc_headers`,
-`moc_sources`, `ui_files` and `qresources` which define the files that
-require preprocessing with `moc`, `uic` and `rcc`. It returns an
-opaque object that should be passed to a main build target. A simple
-example would look like this:
+This method takes the following keyword arguments:
+ - `moc_headers`, `moc_sources`, `ui_files`, `qresources`, which define the files that require preprocessing with `moc`, `uic` and `rcc`
+ - `include_directories`, the directories to add to header search path for `moc` (optional)
+ - `moc_extra_arguments`, any additional arguments to `moc` (optional). Available since v0.44.0.
+
+It returns an opaque object that should be passed to a main build target.
+
+A simple example would look like this:
```meson
qt5 = import('qt5')
qt5_dep = dependency('qt5', modules: ['Core', 'Gui'])
-moc_files = qt5.preprocess(moc_headers : 'myclass.h')
+inc = include_directories('includes')
+moc_files = qt5.preprocess(moc_headers : 'myclass.h',
+ moc_extra_arguments: ['-DMAKES_MY_MOC_HEADER_COMPILE'],
+ include_directories: inc)
executable('myprog', 'main.cpp', 'myclass.cpp', moc_files,
+ include_directories: inc,
dependencies : qt5_dep)
```
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md
index 9d9111e..92c8a1f 100644
--- a/docs/markdown/Reference-manual.md
+++ b/docs/markdown/Reference-manual.md
@@ -95,10 +95,10 @@ the following:
- `gdb` if `true`, the tests are also run under `gdb`
- `timeout_multiplier` a number to multiply the test timeout with
-To use the test setup, run `mesontest --setup=*name*` inside the build dir.
+To use the test setup, run `meson test --setup=*name*` inside the build dir.
Note that all these options are also available while running the
-`mesontest` script for running tests instead of `ninja test` or
+`meson test` script for running tests instead of `ninja test` or
`msbuild RUN_TESTS.vcxproj`, etc depending on the backend.
### benchmark()
@@ -201,10 +201,15 @@ following.
to the target file. Note that your command argument list may not
contain `@OUTPUT@` when capture mode is active.
- `command` command to run to create outputs from inputs. The command
- may be strings or the return of `find_program()` or `executable()`
- (note: always specify commands in array form `['commandname',
+ may be strings or the return value of functions that return file-like
+ objects such as [`find_program()`](#find_program),
+ [`executable()`](#executable), [`configure_file()`](#configure_file),
+ [`files()`](#files), [`custom_target()`](#custom_target), etc.
+ Meson will automatically insert the appropriate dependencies on
+ targets and files listed in this keyword argument.
+ Note: always specify commands in array form `['commandname',
'-arg1', '-arg2']` rather than as a string `'commandname -arg1
- -arg2'` as the latter will *not* work)
+ -arg2'` as the latter will *not* work.
- `depend_files` files ([`string`](#string-object),
[`files()`](#files), or [`configure_file()`](#configure_file)) that
this target depends on but are not listed in the `command` keyword
@@ -424,6 +429,10 @@ be passed to [shared and static libraries](#library).
- `override_options` takes an array of strings in the same format as
`project`'s `default_options` overriding the values of these options
for this target only, since 0.40.0
+- `d_import_dirs` list of directories to look in for string imports used
+ in the D programmling language
+- `d_unittest`, when set to true, the D modules are compiled in debug mode
+- `d_module_versions` list of module versions set when compiling D sources
The list of `sources`, `objects`, and `dependencies` is always
flattened, which means you can freely nest and add lists while
@@ -545,6 +554,9 @@ following:
- `output` a template string (or list of template strings) defining
how an output file name is (or multiple output names are) generated
from a single source file name
+- `capture` when this argument is set to true, Meson captures `stdout`
+ of the `executable` and writes it to the target file specified as
+ `output`. Available since v0.43.0.
The returned object also has methods that are documented in the
[object methods section](#generator-object) below.
@@ -808,10 +820,19 @@ static with only one option.
The keyword arguments for this are the same as for [`executable`](#executable) with the following additions:
-- `name_prefix` the string that will be used as the suffix for the
- target by overriding the default (only used for libraries). By
- default this is `lib` on all platforms and compilers except with
- MSVC where it is omitted.
+- `name_prefix` the string that will be used as the prefix for the
+ target output filename by overriding the default (only used for
+ libraries). By default this is `lib` on all platforms and compilers
+ except with MSVC shared libraries where it is omitted to follow
+ convention.
+- `name_suffix` the string that will be used as the suffix for the
+ target output filename by overriding the default (see also:
+ [executable()](#executable)). By default, for shared libraries this
+ is `dylib` on macOS, `dll` on Windows, and `so` everywhere else.
+ For static libraries, it is `a` everywhere. By convention MSVC
+ static libraries use the `lib` suffix, but we use `a` to avoid a
+ potential name clash with shared libraries which also generate
+ `xxx.lib` import files.
- `rust_crate_type` specifies the crate type for Rust
libraries. Defaults to `dylib` for shared libraries and `rlib` for
static libraries.
@@ -826,6 +847,14 @@ The keyword arguments for this are the same as for [`executable`](#executable) w
This function prints its argument to stdout.
+### warning()
+
+``` meson
+ void warning(text)
+```
+
+This function prints its argument to stdout prefixed with WARNING:.
+
### project()
``` meson
@@ -835,7 +864,7 @@ This function prints its argument to stdout.
The first argument to this function must be a string defining the name
of this project. It is followed by programming languages that the
project uses. Supported values for languages are `c`, `cpp` (for
-`C++`), `objc`, `objcpp`, `fortran`, `java`, `cs` (for `C#`) and
+`C++`), `d`, `objc`, `objcpp`, `fortran`, `java`, `cs` (for `C#`) and
`vala`. In versions before `0.40.0` you must have at least one
language listed.
@@ -850,7 +879,7 @@ Project supports the following keyword arguments.
- `default_options` takes an array of strings. The strings are in the
form `key=value` and have the same format as options to
- `mesonconf`. For example to set the default project type you would
+ `meson configure`. For example to set the default project type you would
set this: `default_options : ['buildtype=debugoptimized']`. Note
that these settings are only used when running Meson for the first
time. Global options such as `buildtype` can only be specified in
@@ -1063,7 +1092,7 @@ arguments are the following.
for the test
Defined tests can be run in a backend-agnostic way by calling
-`mesontest` inside the build dir, or by using backend-specific
+`meson test` inside the build dir, or by using backend-specific
commands, such as `ninja test` or `msbuild RUN_TESTS.vcxproj`.
### vcs_tag()
@@ -1300,9 +1329,9 @@ the following methods:
- `get_id()` returns a string identifying the compiler. For example,
`gcc`, `msvc`, [and more](Compiler-properties.md#compiler-id).
-- `get_supported_arguments(list_of_string)` returns an array
- containing only the arguments supported by the compiler, as if
- `has_argument` were called on them individually.
+- `get_supported_arguments(list_of_string)` *(added 0.43.0)* returns
+ an array containing only the arguments supported by the compiler,
+ as if `has_argument` were called on them individually.
- `has_argument(argument_name)` returns true if the compiler accepts
the specified command line argument, that is, can compile code
@@ -1432,6 +1461,8 @@ are immutable, all operations return their results as a new string.
specified as the argument
- `strip()` removes whitespace at the beginning and end of the string
+ *(added 0.43.0)* optionally can take one positional string argument,
+ and all characters in that string will be stripped
- `to_int` returns the string converted to an integer (error if string
is not a number)
@@ -1502,7 +1533,10 @@ A build target is either an [executable](#executable),
files with custom flags. To use the object file(s) in another build
target, use the `objects:` keyword argument.
-- `full_path()` returns a full path pointing to the result target file
+- `full_path()` returns a full path pointing to the result target file.
+ NOTE: In most cases using the object itself will do the same job as
+ this and will also allow Meson to setup inter-target dependencies
+ correctly. Please file a bug if that doesn't work for you.
- `private_dir_include()` returns a opaque value that works like
`include_directories` but points to the private directory of this
@@ -1554,6 +1588,14 @@ This object is returned by [`custom_target`](#custom_target) and
contains a target with the following methods:
- `full_path()` returns a full path pointing to the result target file
+ NOTE: In most cases using the object itself will do the same job as
+ this and will also allow Meson to setup inter-target dependencies
+ correctly. Please file a bug if that doesn't work for you.
+
+- `[index]` returns an opaque object that references this target, and can be
+ used as a source in other targets. When it is used as such it will make that
+ target depend on this custom target, but the only source added will be the
+ one that corresponds to the index of the custom target's output argument.
### `dependency` object
@@ -1594,7 +1636,7 @@ during tests. It should be passed as the `env` keyword argument to
tests. It has the following methods.
- `append(varname, value)` appends the given value to the old value of
- the environment variable, e.g. `env.append'('FOO', 'BAR', separator
+ the environment variable, e.g. `env.append('FOO', 'BAR', separator
: ';')` produces `BOB;BAR` if `FOO` had the value `BOB` and plain
`BAR` if the value was not defined. If the separator is not
specified explicitly, the default path separator for the host
diff --git a/docs/markdown/Reference-tables.md b/docs/markdown/Reference-tables.md
new file mode 100644
index 0000000..b604fb6
--- /dev/null
+++ b/docs/markdown/Reference-tables.md
@@ -0,0 +1,60 @@
+# Reference tables
+
+## Compiler ids
+
+These are return values of the `get_id` method in a compiler object.
+
+| Value | Compiler family |
+| ----- | ---------------- |
+| gcc | The GNU Compiler Collection |
+| clang | The Clang compiler |
+| msvc | Microsoft Visual Studio |
+| intel | Intel compiler |
+| llvm | LLVM-based compiler (Swift, D) |
+| mono | Xamarin C# compiler |
+| dmd | D lang reference compiler |
+| rustc | Rust compiler |
+| valac | Vala compiler |
+| pathscale | The Pathscale Fortran compiler |
+| pgi | The Portland Fortran compiler |
+| sun | Sun Fortran compiler |
+| g95 | The G95 Fortran compiler |
+| open64 | The Open64 Fortran Compiler |
+| nagfor | The NAG Fortran compiler |
+
+## Script environment variables
+
+| Value | Comment |
+| ----- | ------- |
+| MESON_SOURCE_ROOT | Absolute path to the source dir |
+| MESON_BUILD_ROOT | Absolute path to the build dir |
+| MESONINTROSPECT | Command to run to run the introspection command, may be of the form `python /path/to/meson introspect`, user is responsible for splitting the path if necessary. |
+| MESON_SUBDIR | Current subdirectory, only set for `run_command` |
+
+## CPU families
+
+These are returned by the `cpu_family` method of `build_machine`,
+`host_machine` and `target_machine`. For cross compilation they are
+set in the cross file.
+
+| Value | Comment |
+| ----- | ------- |
+| x86 | 32 bit x86 processor |
+| x86_64 | 64 bit x86 processor |
+| arm | 32 bit ARM processor |
+
+Any cpu family not listed in the above list is not guaranteed to
+remain stable in future releases.
+
+## Operating system names
+
+These are provided by the `.system()` method call.
+
+| Value | Comment |
+| ----- | ------- |
+| linux | |
+| darwin | Either OSX or iOS |
+| windows | Any version of Windows |
+
+Any string not listed above is not guaranteed to remain stable in
+future releases. \ No newline at end of file
diff --git a/docs/markdown/Release-notes-for-0.43.0.md b/docs/markdown/Release-notes-for-0.43.0.md
index 0cb8cc1..3f981e8 100644
--- a/docs/markdown/Release-notes-for-0.43.0.md
+++ b/docs/markdown/Release-notes-for-0.43.0.md
@@ -3,14 +3,121 @@ title: Release 0.43
short-description: Release notes for 0.43 (preliminary)
...
-# New features
+# Portability improvements to Boost Dependency
-This page is a placeholder for the eventual release notes.
+The Boost dependency has been improved to better detect the various ways to
+install boost on multiple platforms. At the same time the `modules` semantics
+for the dependency has been changed. Previously it was allowed to specify
+header directories as `modules` but it wasn't required. Now, modules are only
+used to specify libraries that require linking.
-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:
+This is a breaking change and the fix is to remove all modules that aren't
+found.
- # Feature name
+# Generator learned capture
- A short description explaining the new feature and how it should be used.
+Generators can now be configured to capture the standard output. See
+`test cases/common/98 gen extra/meson.build` for an example.
+
+# Can index CustomTarget objects
+
+The `CustomTarget` object can now be indexed like an array. The resulting
+object can be used as a source file for other Targets, this will create a
+dependency on the original `CustomTarget`, but will only insert the generated
+file corresponding to the index value of the `CustomTarget`'s `output` keyword.
+
+```meson
+c = custom_target(
+ ...
+ output : ['out.h', 'out.c'],
+)
+lib1 = static_library(
+ 'lib1',
+ [lib1_sources, c[0]],
+ ...
+)
+exec = executable(
+ 'executable',
+ c[1],
+ link_with : lib1,
+)
+```
+
+# Can override executables in the cross file
+
+The cross file can now be used for overriding the result of
+`find_program`. As an example if you want to find the `objdump`
+command and have the following definition in your cross file:
+
+```ini
+[binaries]
+...
+objdump = '/usr/bin/arm-linux-gnueabihf-objdump-6'
+```
+
+Then issuing the command `find_program('objdump')` will return the
+version specified in the cross file. If you need the build machine's
+objdump, you can specify the `native` keyword like this:
+
+```meson
+native_objdump = find_program('objdump', native : true)
+```
+
+# Easier handling of supported compiler arguments
+
+A common pattern for handling multiple desired compiler arguments, was to
+test their presence and add them to an array one-by-one, e.g.:
+
+```meson
+warning_flags_maybe = [
+ '-Wsomething',
+ '-Wanother-thing',
+ '-Wno-the-other-thing',
+]
+warning_flags = []
+foreach flag : warning_flags_maybe
+ if cc.has_argument(flag)
+ warning_flags += flag
+ endif
+endforeach
+cc.add_project_argument(warning_flags)
+```
+
+A helper has been added for the foreach/has_argument pattern, so you can
+now simply do:
+
+```meson
+warning_flags = [ ... ]
+flags = cc.get_supported_arguments(warning_flags)
+```
+
+# Better support for shared libraries in non-system paths
+
+Meson has support for prebuilt object files and static libraries.
+This release adds feature parity to shared libraries that are either
+in non-standard system paths or shipped as part of your project. On
+systems that support rpath, Meson automatically adds rpath entries
+to built targets using manually found external libraries.
+
+This means that e.g. supporting prebuilt libraries shipped with your
+source or provided by subprojects or wrap definitions by writing a
+build file like this:
+
+```meson
+project('myprebuiltlibrary', 'c')
+
+cc = meson.get_compiler('c')
+prebuilt = cc.find_library('mylib', dirs : meson.current_source_dir())
+mydep = declare_dependency(include_directories : include_directories('.'),
+ dependencies : prebuilt)
+```
+
+Then you can use the dependency object in the same way as any other.
+
+# wrap-svn
+
+The [Wrap dependency system](Wrap-dependency-system-manual.md) now
+supports [Subversion](https://subversion.apache.org/) (svn). This
+support is rudimentary. The repository url has to point to a specific
+(sub)directory containing the `meson.build` file (typically
+`trunk/`). However, providing a `revision` is supported.
diff --git a/docs/markdown/Release-notes-for-0.44.0.md b/docs/markdown/Release-notes-for-0.44.0.md
new file mode 100644
index 0000000..0df2e97
--- /dev/null
+++ b/docs/markdown/Release-notes-for-0.44.0.md
@@ -0,0 +1,16 @@
+---
+title: Release 0.44
+short-description: Release notes for 0.44 (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 85453e3..923b6a3 100644
--- a/docs/markdown/Subprojects.md
+++ b/docs/markdown/Subprojects.md
@@ -42,7 +42,7 @@ else
l = sp.get_variable('l')
endif
exe = executable('prog', 'prog.c', include_directories : i, link_with : l,
- deps : dep, install : true)
+ dependencies : dep, install : true)
```
With this setup the system dependency is used when it is available, otherwise we fall back on the bundled version.
diff --git a/docs/markdown/Syntax.md b/docs/markdown/Syntax.md
index 02db228..88b9bbb 100644
--- a/docs/markdown/Syntax.md
+++ b/docs/markdown/Syntax.md
@@ -4,23 +4,39 @@ short-description: Syntax and structure of Meson files
# Syntax
-The syntax of Meson's specification language has been kept as simple as possible. It is *strongly typed* so no object is ever converted to another under the covers. Variables have no visible type which makes Meson *dynamically typed* (also known as *duck typed*).
-
-The main building blocks of the language are *variables*, *numbers*, *booleans*, *strings*, *arrays*, *function calls*, *method calls*, *if statements* and *includes*.
-
-Usually one Meson statement takes just one line. There is no way to have multiple statements on one line as in e.g. *C*. Function and method calls' argument lists can be split over multiple lines. Meson will autodetect this case and do the right thing. In other cases you can get multi-line statements by ending the line with a `\`. Apart from line ending whitespace has no syntactic meaning.
+The syntax of Meson's specification language has been kept as simple
+as possible. It is *strongly typed* so no object is ever converted to
+another under the covers. Variables have no visible type which makes
+Meson *dynamically typed* (also known as *duck typed*).
+
+The main building blocks of the language are *variables*, *numbers*,
+*booleans*, *strings*, *arrays*, *function calls*, *method calls*, *if
+statements* and *includes*.
+
+Usually one Meson statement takes just one line. There is no way to
+have multiple statements on one line as in e.g. *C*. Function and
+method calls' argument lists can be split over multiple lines. Meson
+will autodetect this case and do the right thing. In other cases you
+can get multi-line statements by ending the line with a `\`. Apart
+from line ending whitespace has no syntactic meaning.
Variables
--
-Variables in Meson work just like in other high level programming languages. A variable can contain a value of any type, such as an integer or a string. Variables don't need to be predeclared, you can just assign to them and they appear. Here's how you would assign values to two different variables.
+Variables in Meson work just like in other high level programming
+languages. A variable can contain a value of any type, such as an
+integer or a string. Variables don't need to be predeclared, you can
+just assign to them and they appear. Here's how you would assign
+values to two different variables.
```meson
var1 = 'hello'
var2 = 102
```
-One important difference in how variables work in Meson is that all variables are immutable. This is different from, for example, how Python works.
+One important difference in how variables work in Meson is that all
+objects are immutable. This is different from, for example, how Python
+works.
```meson
var1 = [1, 2, 3]
@@ -33,7 +49,8 @@ var2 += [4]
Numbers
--
-Meson supports only integer numbers. They are declared simply by writing them out. Basic arithmetic operations are supported.
+Meson supports only integer numbers. They are declared simply by
+writing them out. Basic arithmetic operations are supported.
```meson
x = 1 + 2
@@ -45,7 +62,7 @@ Strings can be converted to a number like this:
```meson
string_var = '42'
-num = var1.to_int()
+num = string_var.to_int()
```
Booleans
@@ -60,13 +77,15 @@ truth = true
Strings
--
-Strings in Meson are declared with single quotes. To enter a literal single quote do it like this:
+Strings in Meson are declared with single quotes. To enter a literal
+single quote do it like this:
```meson
single quote = 'contains a \' character'
```
-Similarly `\n` gets converted to a newline and `\\\\` to a single backslash.
+Similarly `\n` gets converted to a newline and `\\\\` to a single
+backslash.
#### String concatenation
@@ -80,7 +99,8 @@ combined = str1 + '_' + str2 # combined is now abc_xyz
#### Strings running over multiple lines
-Strings running over multiple lines can be declared with three single quotes, like this:
+Strings running over multiple lines can be declared with three single
+quotes, like this:
```meson
multiline_string = '''#include <foo.h>
@@ -89,7 +109,8 @@ int main (int argc, char ** argv) {
}'''
```
-This can also be combined with the string formatting functionality described below.
+This can also be combined with the string formatting functionality
+described below.
#### String formatting
@@ -101,11 +122,13 @@ res = template.format('text', 1, true)
# res now has value 'string: text, number: 1, bool: true'
```
-As can be seen, the formatting works by replacing placeholders of type `@number@` with the corresponding argument.
+As can be seen, the formatting works by replacing placeholders of type
+`@number@` with the corresponding argument.
#### String methods
-Strings also support a number of other methods that return transformed copies.
+Strings also support a number of other methods that return transformed
+copies.
**.strip()**
@@ -226,7 +249,9 @@ my_array += ['something']
my_array += 'else'
```
-Note appending to an array will always create a new array object and assign it to `my_array` instead of modifying the original since all objects in Meson are immutable.
+Note appending to an array will always create a new array object and
+assign it to `my_array` instead of modifying the original since all
+objects in Meson are immutable.
#### Array methods
@@ -239,7 +264,8 @@ The following methods are defined for all arrays:
Function calls
--
-Meson provides a set of usable functions. The most common use case is creating build objects.
+Meson provides a set of usable functions. The most common use case is
+creating build objects.
```meson
executable('progname', 'prog.c')
@@ -248,7 +274,8 @@ executable('progname', 'prog.c')
Method calls
--
-Objects can have methods, which are called with the dot operator. The exact methods it provides depends on the object.
+Objects can have methods, which are called with the dot operator. The
+exact methods it provides depends on the object.
```meson
myobj = some_function()
@@ -279,7 +306,9 @@ endif
## Foreach statements
-To do an operation on all elements of an array, use the `foreach` command. As an example, here's how you would define two executables with corresponding tests.
+To do an operation on all elements of an array, use the `foreach`
+command. As an example, here's how you would define two executables
+with corresponding tests.
```meson
progs = [['prog1', ['prog1.c', 'foo.c']],
@@ -291,7 +320,9 @@ foreach p : progs
endforeach
```
-Note that Meson variables are immutable. Trying to assign a new value to `progs` inside a foreach loop will not affect foreach's control flow.
+Note that Meson variables are immutable. Trying to assign a new value
+to `progs` inside a foreach loop will not affect foreach's control
+flow.
Logical operations
--
@@ -334,12 +365,20 @@ The ternary operator works just like in other languages.
x = condition ? true_value : false_value
```
-The only exception is that nested ternary operators are forbidden to improve legibility. If your branching needs are more complex than this you need to write an `if/else` construct.
+The only exception is that nested ternary operators are forbidden to
+improve legibility. If your branching needs are more complex than this
+you need to write an `if/else` construct.
Includes
--
-Most source trees have multiple subdirectories to process. These can be handled by Meson's `subdir` command. It changes to the given subdirectory and executes the contents of `meson.build` in that subdirectory. All state (variables etc) are passed to and from the subdirectory. The effect is roughly the same as if the contents of the subdirectory's Meson file would have been written where the include command is.
+Most source trees have multiple subdirectories to process. These can
+be handled by Meson's `subdir` command. It changes to the given
+subdirectory and executes the contents of `meson.build` in that
+subdirectory. All state (variables etc) are passed to and from the
+subdirectory. The effect is roughly the same as if the contents of the
+subdirectory's Meson file would have been written where the include
+command is.
```meson
test_data_dir = 'data'
@@ -349,4 +388,12 @@ subdir('tests')
User-defined functions and methods
--
-Meson does not currently support user-defined functions or methods. The addition of user-defined functions would make Meson Turing-complete which would make it harder to reason about and more difficult to integrate with tools like IDEs. More details about this are [in the FAQ](FAQ.md#why-is-meson-not-just-a-python-module-so-i-could-code-my-build-setup-in-python). If because of this limitation you find yourself copying and pasting code a lot you may be able to use a [`foreach` loop instead](#foreach-statements).
+Meson does not currently support user-defined functions or
+methods. The addition of user-defined functions would make Meson
+Turing-complete which would make it harder to reason about and more
+difficult to integrate with tools like IDEs. More details about this
+are [in the
+FAQ](FAQ.md#why-is-meson-not-just-a-python-module-so-i-could-code-my-build-setup-in-python). If
+because of this limitation you find yourself copying and pasting code
+a lot you may be able to use a [`foreach` loop
+instead](#foreach-statements).
diff --git a/docs/markdown/Unit-tests.md b/docs/markdown/Unit-tests.md
index 7949522..afbeaa0 100644
--- a/docs/markdown/Unit-tests.md
+++ b/docs/markdown/Unit-tests.md
@@ -57,52 +57,54 @@ Sometimes a test can only determine at runtime that it can not be run. The GNU s
## Testing tool
-In version 0.37.0 a new tool called `mesontest` was added. The goal of this tool is to provide a simple way to run tests in a variety of different ways. The tool is designed to be run in the build directory.
+The goal of the meson test tool is to provide a simple way to run tests in a variety of different ways. The tool is designed to be run in the build directory.
The simplest thing to do is just to run all tests, which is equivalent to running `ninja test`.
```console
-$ mesontest
+$ meson test
```
You can also run only a single test by giving its name:
```console
-$ mesontest testname
+$ meson test testname
```
Sometimes you need to run the tests multiple times, which is done like this:
```console
-$ mesontest --repeat=10
+$ meson test --repeat=10
```
Invoking tests via a helper executable such as Valgrind can be done with the `--wrap` argument
```console
-$ mesontest --wrap=valgrind testname
+$ meson test --wrap=valgrind testname
```
Arguments to the wrapper binary can be given like this:
```console
-$ mesontest --wrap='valgrind --tool=helgrind' testname
+$ meson test --wrap='valgrind --tool=helgrind' testname
```
Meson also supports running the tests under GDB. Just doing this:
```console
-$ mesontest --gdb testname
+$ meson test --gdb testname
```
-Mesontest will launch `gdb` all set up to run the test. Just type `run` in the GDB command prompt to start the program.
+Meson will launch `gdb` all set up to run the test. Just type `run` in the GDB command prompt to start the program.
The second use case is a test that segfaults only rarely. In this case you can invoke the following command:
```console
-$ mesontest --gdb --repeat=10000 testname
+$ meson test --gdb --repeat=10000 testname
```
-This runs the test up to 10 000 times under GDB automatically. If the program crashes, GDB will halt and the user can debug the application. Note that testing timeouts are disabled in this case so mesontest will not kill `gdb` while the developer is still debugging it. The downside is that if the test binary freezes, the test runner will wait forever.
+This runs the test up to 10 000 times under GDB automatically. If the program crashes, GDB will halt and the user can debug the application. Note that testing timeouts are disabled in this case so `meson test` will not kill `gdb` while the developer is still debugging it. The downside is that if the test binary freezes, the test runner will wait forever.
-For further information see the command line help of Mesontest by running `mesontest -h`.
+For further information see the command line help of Meson by running `meson test -h`.
+
+**NOTE:** If `meson test` does not work for you, you likely have a old version of Meson. In that case you should call `mesontest` instead. If `mesontest` doesn't work either you have a very old version prior to 0.37.0 and should upgrade.
diff --git a/docs/markdown/Users.md b/docs/markdown/Users.md
index 46c2654..c27c516 100644
--- a/docs/markdown/Users.md
+++ b/docs/markdown/Users.md
@@ -9,7 +9,7 @@ If you have a project that uses Meson that you want to add to this list, let us
- [AQEMU](https://github.com/tobimensch/aqemu), a Qt GUI for QEMU virtual machines, since version 0.9.3
- [Arduino sample project](https://github.com/jpakkane/mesonarduino)
- [Budgie Desktop](https://github.com/budgie-desktop/budgie-desktop), a desktop environment built on GNOME technologies
- - [casync](https://github.com/systemd/casync),
+ - [casync](https://github.com/systemd/casync), Content-Addressable Data Synchronization Tool
- [Emeus](https://github.com/ebassi/emeus), Constraint based layout manager for GTK+
- [Frida](https://www.frida.re/), a dynamic binary instrumentation toolkit
- [GLib](https://git.gnome.org/browse/glib/), cross-platform C library used by GTK+ and GStreamer (not the default yet)
@@ -43,4 +43,4 @@ If you have a project that uses Meson that you want to add to this list, let us
- [Wayland and Weston](https://lists.freedesktop.org/archives/wayland-devel/2016-November/031984.html), a next generation display server (not merged yet)
- [ZStandard](https://github.com/facebook/zstd/commit/4dca56ed832c6a88108a2484a8f8ff63d8d76d91) a compression algorithm developed at Facebook (not used by default)
-Note that a more up-to-date list of GNOME projects that use Meson can be found here: https://wiki.gnome.org/Initiatives/GnomeGoals/MesonPorting
+Note that a more up-to-date list of GNOME projects that use Meson can be found [here](https://wiki.gnome.org/Initiatives/GnomeGoals/MesonPorting).
diff --git a/docs/markdown/Using-multiple-build-directories.md b/docs/markdown/Using-multiple-build-directories.md
index c07b39c..2455640 100644
--- a/docs/markdown/Using-multiple-build-directories.md
+++ b/docs/markdown/Using-multiple-build-directories.md
@@ -8,7 +8,7 @@ Secondly this makes it very easy to clean your projects: just delete the build s
The true benefit comes from somewhere else, though.
-## Multiple build directories for the same source tree ##
+## Multiple build directories for the same source tree
Since a build directory is fully self contained and treats the source tree as a read-only piece of data, it follows that you can have arbitrarily many build trees for any source tree at the same time. Since all build trees can have different configuration, this is extremely powerful. Now you might be wondering why one would want to have multiple build setups at the same time. Let's examine this by setting up a hypothetical project.
@@ -36,7 +36,7 @@ The cross compilation file sets up Wine so that not only can you compile your ap
To compile any of these build types, just cd into the corresponding build directory and run `ninja` or instruct your IDE to do the same. Note that once you have set up your build directory once, you can just run Ninja and Meson will ensure that the resulting build is fully up to date according to the source. Even if you have not touched one of the directories in weeks and have done major changes to your build configuration, Meson will detect this and bring the build directory up to date (or print an error if it can't do that). This allows you to do most of your work in the default directory and use the others every now and then without having to babysit your build directories.
-## Specialized uses ##
+## Specialized uses
Separate build directories allows easy integration for various different kinds of tools. As an example, Clang comes with a static analyzer. It is meant to be run from scratch on a given source tree. The steps to run it with Meson are very simple.
diff --git a/docs/markdown/Using-wraptool.md b/docs/markdown/Using-wraptool.md
index e000695..8e5f898 100644
--- a/docs/markdown/Using-wraptool.md
+++ b/docs/markdown/Using-wraptool.md
@@ -53,7 +53,7 @@ To check if your projects are up to date you can issue the `status` command.
In this case `zlib` has a newer release available. Updating it is straightforward:
- $ wraptool.py update zlib
+ $ wraptool update zlib
Updated zlib to branch 1.2.8 revision 4
Wraptool can do other things besides these. Documentation for these can be found in the command line help, which can be accessed by `wraptool --help`.
diff --git a/docs/markdown/Vala.md b/docs/markdown/Vala.md
index e183bb0..c5d2b79 100644
--- a/docs/markdown/Vala.md
+++ b/docs/markdown/Vala.md
@@ -26,9 +26,9 @@ When dealing with libraries that are not providing Vala bindings, a `--vapidir`
```meson
project('vala app', 'c', 'vala')
-add_project_arguments(['--vapidir', join_paths(meson.current_source_dir(), 'vapi')],
+add_project_arguments(['--vapidir', join_paths(meson.current_source_dir(), 'vapi')],
language: 'vala')
-
+
glib_dep = dependency('glib-2.0')
gobject_dep = dependency('gobject-2.0')
foo_dep = dependency('foo') # 'foo.vapi' will be resolved in './vapi/foo.vapi'
@@ -36,7 +36,7 @@ foo_dep = dependency('foo') # 'foo.vapi' will be resolved in './vapi/foo.vapi'
executable('app', 'app.vala', dependencies: [glib_dep, gobject_dep, foo_dep])
```
-In this case, make sure that the VAPI name corresponds to the pkg-config file.
+In this case, make sure that the VAPI name corresponds to the pkg-config file.
If no pkg-config file is provided, you must use `find_library`. Using`declare_dependency` is cleaner because it does not require passing both dependency objects to the target.
@@ -63,9 +63,9 @@ executable('app', 'app.vala', dependencies: [glib_dep, gobject_dep, posix_dep])
If a library target is used, Meson automatically outputs the C header and the VAPI. They can be renamed by setting the `vala_header` and `vala_vapi` arguments respectively. In this case, the second and third elements of the `install_dir` array indicate the destination with `true` to indicate default directories (i.e. `include` and `share/vala/vapi`).
```meson
-foo_lib = library('foo', 'foo.vala',
+foo_lib = library('foo', 'foo.vala',
vala_header: 'foo.h',
- vala_vapi: 'foo-1.0.vapi',
+ vala_vapi: 'foo-1.0.vapi',
dependencies: [glib_dep, gobject_dep],
install: true,
install_dir: [true, true, true])
@@ -78,8 +78,8 @@ To generate GObject Introspection metadata, the `vala_gir` option has to be set
The fourth element in the `install_dir` array indicate where the GIR file will be installed. The `true` value tells Meson to use the default directory (i.e. `share/gir-1.0`).
```meson
-foo_lib = library('foo', 'foo.vala',
- vala_gir: 'Foo-1.0.gir',
+foo_lib = library('foo', 'foo.vala',
+ vala_gir: 'Foo-1.0.gir',
dependencies: [glib_dep, gobject_dep],
install: true,
install_dir: [true, true, true, true])
diff --git a/docs/markdown/Wrap-dependency-system-manual.md b/docs/markdown/Wrap-dependency-system-manual.md
index a850896..d97fc9a 100644
--- a/docs/markdown/Wrap-dependency-system-manual.md
+++ b/docs/markdown/Wrap-dependency-system-manual.md
@@ -52,7 +52,7 @@ are downloaded and automatically applied to the subproject. These
files contain a Meson build definition for the given subproject. A
wrap file with an additional patch URL would look like this.
-```
+```ini
[wrap-file]
directory = libfoobar-1.0
@@ -83,7 +83,7 @@ packaged files. Sometimes you want to check code out directly from
Git. Meson supports this natively. All you need to do is to write a
slightly different wrap file.
-```
+```ini
[wrap-git]
directory=samplesubproject
url=https://github.com/jpakkane/samplesubproject.git
diff --git a/docs/markdown/Wrap-review-guidelines.md b/docs/markdown/Wrap-review-guidelines.md
index 39acadc..512353c 100644
--- a/docs/markdown/Wrap-review-guidelines.md
+++ b/docs/markdown/Wrap-review-guidelines.md
@@ -7,7 +7,7 @@ package is rejected. What should be done will be determined on a
case-by-case basis. Similarly meeting all these requirements does not
guarantee that the package will get accepted. Use common sense.
-## Checklist ##
+## Checklist
Reviewer: copy-paste this to MR discussion box and tick all boxes that apply.
diff --git a/docs/markdown/howtox.md b/docs/markdown/howtox.md
index 2dd5ddf..c4aa9c5 100644
--- a/docs/markdown/howtox.md
+++ b/docs/markdown/howtox.md
@@ -97,12 +97,12 @@ $ ninja coverage-html (or coverage-xml)
The coverage report can be found in the meson-logs subdirectory.
-## Add some optimization to debug builds ##
+## Add some optimization to debug builds
By default the debug build does not use any optimizations. This is the desired approach most of the time. However some projects benefit from having some minor optimizations enabled. GCC even has a specific compiler flag `-Og` for this. To enable its use, just issue the following command.
```console
-$ mesonconf -Dc_args=-Og
+$ meson configure -Dc_args=-Og
```
This causes all subsequent builds to use this command line argument.
@@ -139,7 +139,7 @@ Then we need to run the program with some representative input. This step depend
Once that is done we change the compiler flags to use the generated information and rebuild.
```console
-$ mesonconf -Db_pgo=use
+$ meson configure -Db_pgo=use
$ ninja
```
diff --git a/docs/markdown/i18n-module.md b/docs/markdown/i18n-module.md
index 5e6004a..8fb650a 100644
--- a/docs/markdown/i18n-module.md
+++ b/docs/markdown/i18n-module.md
@@ -17,20 +17,18 @@ argument which is the name of the gettext module.
* `args`: list of extra arguments to pass to `xgettext` when
generating the pot file
-
* `data_dirs`: (*Added 0.36.0*) list of directories to be set for
`GETTEXTDATADIRS` env var (Requires gettext 0.19.8+), used for local
its files
-
* `languages`: list of languages that are to be generated. As of
0.37.0 this is optional and the
[LINGUAS](https://www.gnu.org/software/gettext/manual/html_node/po_002fLINGUAS.html)
file is read.
-
* `preset`: (*Added 0.37.0*) name of a preset list of arguments,
current option is `'glib'`, see
[source](https://github.com/mesonbuild/meson/blob/master/mesonbuild/modules/i18n.py)
for for their value
+* `install`: (*Added 0.43.0*) if false, do not install the built translations.
This function also defines targets for maintainers to use:
**Note**: These output to the source directory
diff --git a/docs/markdown/index.md b/docs/markdown/index.md
index 8e35a4d..81c17ff 100644
--- a/docs/markdown/index.md
+++ b/docs/markdown/index.md
@@ -13,7 +13,7 @@ The main design point of Meson is that every moment a developer spends writing o
## Features
* multiplatform support for Linux, OSX, Windows, GCC, Clang, Visual Studio and others
-* supported languages include C, C++, Fortran, Java, Rust
+* supported languages include C, C++, D, Fortran, Java, Rust
* build definitions in a very readable and user friendly non-Turing complete DSL
* cross compilation for many operating systems as well as bare metal
* optimized for extremely fast full and incremental builds without sacrificing correctness
@@ -24,10 +24,10 @@ The main design point of Meson is that every moment a developer spends writing o
There are two main methods of connecting with other Meson developers. The first one is the mailing list, which is hosted at [Google Groups](https://groups.google.com/forum/#!forum/mesonbuild).
-The second way is via IRC. The channel to use is <tt>#mesonbuild</tt> at [Freenode](https://freenode.net/).
+The second way is via IRC. The channel to use is `#mesonbuild` at [Freenode](https://freenode.net/).
## Development
-All development on Meson is done on [GitHub project](https://github.com/mesonbuild/meson). For further info look into the <tt>contributing.txt</tt> file that comes with Meson's source checkout.
+All development on Meson is done on [GitHub project](https://github.com/mesonbuild/meson). For further info look into the `contributing.txt` file that comes with Meson's source checkout.
You do not need to sign a CLA to contribute to Meson.
diff --git a/docs/markdown/snippets/add_release_note_snippets_here b/docs/markdown/snippets/add_release_note_snippets_here
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/docs/markdown/snippets/add_release_note_snippets_here
diff --git a/docs/markdown/snippets/cross_find.md b/docs/markdown/snippets/cross_find.md
deleted file mode 100644
index b16d64d..0000000
--- a/docs/markdown/snippets/cross_find.md
+++ /dev/null
@@ -1,15 +0,0 @@
-# Can override executables in the cross file
-
-The cross file can now be used for overriding the result of
-`find_program`. As an example if you want to find the `objdump`
-command and have the following definition in your cross file:
-
- [binaries]
- ...
- objdump = '/usr/bin/arm-linux-gnueabihf-objdump-6'
-
-Then issuing the command `find_program('objdump')` will return the
-version specified in the cross file. If you need the build machine's
-objdump, you can specify the `native` keyword like this:
-
- native_objdump = find_program('objdump', native : true)
diff --git a/docs/markdown/snippets/get-supported-arguments.md b/docs/markdown/snippets/get-supported-arguments.md
deleted file mode 100644
index c0cc9bf..0000000
--- a/docs/markdown/snippets/get-supported-arguments.md
+++ /dev/null
@@ -1,23 +0,0 @@
-# Easier handling of supported compiler arguments
-
-A common pattern for handling multiple desired compiler arguments, was to
-test their presence and add them to an array one-by-one, e.g.:
-
- warning_flags_maybe = [
- '-Wsomething',
- '-Wanother-thing',
- '-Wno-the-other-thing',
- ]
- warning_flags = []
- foreach flag : warning_flags_maybe
- if cc.has_argument(flag)
- warning_flags += flag
- endif
- endforeach
- cc.add_project_argument(warning_flags)
-
-A helper has been added for the foreach/has_argument pattern, so you can
-now simply do:
-
- warning_flags = [ ... ]
- flags = cc.get_supported_flags(warning_flags)
diff --git a/docs/markdown/snippets/llvm-static-linking.md b/docs/markdown/snippets/llvm-static-linking.md
new file mode 100644
index 0000000..bb72a56
--- /dev/null
+++ b/docs/markdown/snippets/llvm-static-linking.md
@@ -0,0 +1,8 @@
+# LLVM dependency supports both dynamic and static linking
+
+The LLVM dependency has been improved to consistently use dynamic linking.
+Previously recent version (>= 3.9) would link dynamically while older versions
+would link statically.
+
+Now LLVM also accepts the `static` keyword to enable statically linking to LLVM
+modules instead of dynamically linking.
diff --git a/docs/markdown/snippets/prefix-dependent-defaults.md b/docs/markdown/snippets/prefix-dependent-defaults.md
new file mode 100644
index 0000000..7cc1792
--- /dev/null
+++ b/docs/markdown/snippets/prefix-dependent-defaults.md
@@ -0,0 +1,10 @@
+# Prefix-dependent defaults for sysconfdir, localstatedir and sharedstatedir
+
+These options now default in a way consistent with
+[FHS](http://refspecs.linuxfoundation.org/fhs.shtml) and common usage.
+
+If prefix is `/usr`, default sysconfdir to `/etc`, localstatedir to `/var` and
+sharedstatedir to `/var/lib`.
+
+If prefix is `/usr/local` (the default), default localstatedir to `/var/local`
+and sharedstatedir to `/var/local/lib`.
diff --git a/docs/markdown/snippets/qt5-moc_extra_arguments.md b/docs/markdown/snippets/qt5-moc_extra_arguments.md
new file mode 100644
index 0000000..957c3c7
--- /dev/null
+++ b/docs/markdown/snippets/qt5-moc_extra_arguments.md
@@ -0,0 +1,8 @@
+# Adds support for additional Qt5-Module keyword `moc_extra_arguments`
+
+When `moc`-ing sources, the `moc` tool does not know about any
+preprocessor macros. The generated code might not match the input
+files when the linking with the moc input sources happens.
+
+This amendment allows to specify a a list of additional arguments
+passed to the `moc` tool. They are called `moc_extra_arguments`. \ No newline at end of file
diff --git a/docs/markdown/snippets/warning_function b/docs/markdown/snippets/warning_function
new file mode 100644
index 0000000..537651e
--- /dev/null
+++ b/docs/markdown/snippets/warning_function
@@ -0,0 +1,6 @@
+# Added warning function
+
+This function prints its argument to the console prefixed by "WARNING:" in
+yellow color. A simple example:
+
+warning('foo is deprecated, please use bar instead')
diff --git a/docs/sitemap.txt b/docs/sitemap.txt
index af8aede..6b155af 100644
--- a/docs/sitemap.txt
+++ b/docs/sitemap.txt
@@ -38,6 +38,7 @@ index.md
Windows-module.md
Java.md
Vala.md
+ D.md
IDE-integration.md
Custom-build-targets.md
Build-system-converters.md
@@ -47,6 +48,7 @@ index.md
Creating-OSX-packages.md
Creating-Linux-binaries.md
Reference-manual.md
+ Reference-tables.md
FAQ.md
Reproducible-builds.md
howtox.md
@@ -59,6 +61,7 @@ index.md
Shipping-prebuilt-binaries-as-wraps.md
fallback-wraptool.md
Release-notes.md
+ Release-notes-for-0.44.0.md
Release-notes-for-0.43.0.md
Release-notes-for-0.42.0.md
Release-notes-for-0.41.0.md
diff --git a/ghwt.py b/ghwt.py
index d04cd3f..bf06e19 100755
--- a/ghwt.py
+++ b/ghwt.py
@@ -14,6 +14,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+# ghwt - GitHub WrapTool
+#
+# An emergency wraptool(1) replacement downloader that downloads
+# directly from GitHub in case wrapdb.mesonbuild.com is down.
+
import urllib.request, json, sys, os, shutil, subprocess
import configparser, hashlib
diff --git a/man/meson.1 b/man/meson.1
index b453828..1333904 100644
--- a/man/meson.1
+++ b/man/meson.1
@@ -1,4 +1,4 @@
-.TH MESON "1" "August 2017" "meson 0.42.0" "User Commands"
+.TH MESON "1" "October 2017" "meson 0.43.0" "User Commands"
.SH NAME
meson - a high productivity build system
.SH DESCRIPTION
@@ -63,8 +63,9 @@ print command line help
.SH The configure command
-Mesonconf provides a way to configure a Meson
-project from the command line. Its usage is simple.
+.B meson configure
+provides a way to configure a Meson project from the command line.
+Its usage is simple:
.B meson configure [
.I build directory
@@ -74,8 +75,9 @@ project from the command line. Its usage is simple.
If build directory is omitted, the current directory is used instead.
-If no parameters are set, mesonconf will print the value of all build
-options to the console.
+If no parameters are set,
+.B meson configure
+will print the value of all build options to the console.
To set values, use the \-D command line argument like this.
@@ -113,12 +115,14 @@ print command line help
.SH The test command
-Mesontest is a helper tool for running test suites of projects using Meson.
+.B meson test
+is a helper tool for running test suites of projects using Meson.
The default way of running tests is to invoke the default build command:
\fBninja [\fR \fItest\fR \fB]\fR
-Mesontest provides a richer set of tools for invoking tests.
+.B meson test
+provides a richer set of tools for invoking tests.
.SS "options:"
.TP
diff --git a/man/mesonconf.1 b/man/mesonconf.1
index ae28e35..1ad8c4a 100644
--- a/man/mesonconf.1
+++ b/man/mesonconf.1
@@ -1,4 +1,4 @@
-.TH MESONCONF "1" "August 2017" "mesonconf 0.42.0" "User Commands"
+.TH MESONCONF "1" "October 2017" "mesonconf 0.43.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 eae7b4a..c32767c 100644
--- a/man/mesonintrospect.1
+++ b/man/mesonintrospect.1
@@ -1,4 +1,4 @@
-.TH MESONCONF "1" "August 2017" "mesonintrospect 0.42.0" "User Commands"
+.TH MESONINTROSPECT "1" "October 2017" "mesonintrospect 0.43.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 ed676dc..76e20bd 100644
--- a/man/mesontest.1
+++ b/man/mesontest.1
@@ -1,4 +1,4 @@
-.TH MESON "1" "August 2017" "meson 0.42.0" "User Commands"
+.TH MESON "1" "October 2017" "meson 0.43.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 50546d5..cca9551 100644
--- a/man/wraptool.1
+++ b/man/wraptool.1
@@ -1,4 +1,4 @@
-.TH WRAPTOOL "1" "August 2017" "meson 0.42.0" "User Commands"
+.TH WRAPTOOL "1" "October 2017" "meson 0.43.0" "User Commands"
.SH NAME
wraptool - source dependency downloader
.SH DESCRIPTION
diff --git a/manual tests/10 svn wrap/meson.build b/manual tests/10 svn wrap/meson.build
new file mode 100644
index 0000000..23ef1f1
--- /dev/null
+++ b/manual tests/10 svn wrap/meson.build
@@ -0,0 +1,10 @@
+project('Subversion outchecker', 'c')
+
+sp = subproject('samplesubproject')
+
+exe = executable('gitprog', 'prog.c',
+include_directories : sp.get_variable('subproj_inc'),
+link_with : sp.get_variable('subproj_lib'),
+)
+
+test('maintest', exe)
diff --git a/manual tests/10 svn wrap/prog.c b/manual tests/10 svn wrap/prog.c
new file mode 100644
index 0000000..df38000
--- /dev/null
+++ b/manual tests/10 svn wrap/prog.c
@@ -0,0 +1,6 @@
+#include"subproj.h"
+
+int main(int argc, char **argv) {
+ subproj_function();
+ return 0;
+}
diff --git a/manual tests/10 svn wrap/subprojects/samplesubproject.wrap b/manual tests/10 svn wrap/subprojects/samplesubproject.wrap
new file mode 100644
index 0000000..c8a687e
--- /dev/null
+++ b/manual tests/10 svn wrap/subprojects/samplesubproject.wrap
@@ -0,0 +1,4 @@
+[wrap-svn]
+directory=samplesubproject
+url=https://svn.code.sf.net/p/mesonsubproject/code/trunk
+revision=head
diff --git a/meson.py b/meson.py
index d1b629d..57cc6dc 100755
--- a/meson.py
+++ b/meson.py
@@ -24,7 +24,7 @@ def main():
# encoding, so we can just warn about it.
e = locale.getpreferredencoding()
if e.upper() != 'UTF-8' and not mesonlib.is_windows():
- print('Warning: You are using {!r} which is not a a Unicode-compatible '
+ print('Warning: You are using {!r} which is not a Unicode-compatible '
'locale.'.format(e), file=sys.stderr)
print('You might see errors if you use UTF-8 strings as '
'filenames, as strings, or as file contents.', file=sys.stderr)
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index 97959b6..61f7535 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -155,9 +155,18 @@ class Backend:
dirname = 'meson-out'
return dirname
+ def get_target_dir_relative_to(self, t, o):
+ '''Get a target dir relative to another target's directory'''
+ target_dir = os.path.join(self.environment.get_build_dir(), self.get_target_dir(t))
+ othert_dir = os.path.join(self.environment.get_build_dir(), self.get_target_dir(o))
+ return os.path.relpath(target_dir, othert_dir)
+
def get_target_source_dir(self, target):
- dirname = os.path.join(self.build_to_src, self.get_target_dir(target))
- return dirname
+ # if target dir is empty, avoid extraneous trailing / from os.path.join()
+ target_dir = self.get_target_dir(target)
+ if target_dir:
+ return os.path.join(self.build_to_src, target_dir)
+ return self.build_to_src
def get_target_private_dir(self, target):
dirname = os.path.join(self.get_target_dir(target), target.get_basename() + target.type_suffix())
@@ -174,7 +183,7 @@ class Backend:
Returns the full path of the generated source relative to the build root
"""
# CustomTarget generators output to the build dir of the CustomTarget
- if isinstance(gensrc, build.CustomTarget):
+ if isinstance(gensrc, (build.CustomTarget, build.CustomTargetIndex)):
return os.path.join(self.get_target_dir(gensrc), src)
# GeneratedList generators output to the private build directory of the
# target that the GeneratedList is used in
@@ -298,6 +307,25 @@ class Backend:
raise MesonException(m.format(target.name))
return l
+ def rpaths_for_bundled_shared_libraries(self, target):
+ paths = []
+ for dep in target.external_deps:
+ if isinstance(dep, dependencies.ExternalLibrary):
+ la = dep.link_args
+ if len(la) == 1 and os.path.isabs(la[0]):
+ # The only link argument is an absolute path to a library file.
+ libpath = la[0]
+ if libpath.startswith(('/usr/lib', '/lib')):
+ # No point in adding system paths.
+ continue
+ if os.path.splitext(libpath)[1] not in ['.dll', '.lib', '.so']:
+ continue
+ absdir = os.path.split(libpath)[0]
+ rel_to_src = absdir[len(self.environment.get_source_dir()) + 1:]
+ assert(not os.path.isabs(rel_to_src))
+ paths.append(os.path.join(self.build_to_src, rel_to_src))
+ return paths
+
def determine_rpath_dirs(self, target):
link_deps = target.get_all_link_deps()
result = []
@@ -305,6 +333,9 @@ class Backend:
prospective = self.get_target_dir(ld)
if prospective not in result:
result.append(prospective)
+ for rp in self.rpaths_for_bundled_shared_libraries(target):
+ if rp not in result:
+ result += [rp]
return result
def object_filename_from_source(self, target, source, is_unity):
@@ -513,6 +544,8 @@ class Backend:
dirseg = os.path.join(self.environment.get_build_dir(), self.get_target_dir(ld))
if dirseg not in result:
result.append(dirseg)
+ for deppath in self.rpaths_for_bundled_shared_libraries(target):
+ result.append(os.path.normpath(os.path.join(self.environment.get_build_dir(), deppath)))
return result
def write_benchmark_file(self, datafile):
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index bac984b..c633daf 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import os, pickle, re, shlex, shutil, subprocess, sys
+import os, pickle, re, shlex, subprocess, sys
from collections import OrderedDict
from . import backends
@@ -83,10 +83,9 @@ class NinjaBuildElement:
def write(self, outfile):
self.check_outputs()
- line = 'build %s: %s %s' % (
- ' '.join([ninja_quote(i) for i in self.outfilenames]),
- self.rule,
- ' '.join([ninja_quote(i) for i in self.infilenames]))
+ line = 'build %s: %s %s' % (' '.join([ninja_quote(i) for i in self.outfilenames]),
+ self.rule,
+ ' '.join([ninja_quote(i) for i in self.infilenames]))
if len(self.deps) > 0:
line += ' | ' + ' '.join([ninja_quote(x) for x in self.deps])
if len(self.orderdeps) > 0:
@@ -192,6 +191,9 @@ int dummy;
def generate(self, interp):
self.interpreter = interp
+ self.ninja_command = environment.detect_ninja(log=True)
+ if self.ninja_command is None:
+ raise MesonException('Could not detect Ninja v1.5 or newer')
outfilename = os.path.join(self.environment.get_build_dir(), self.ninja_filename)
tempfilename = outfilename + '~'
with open(tempfilename, 'w') as outfile:
@@ -225,11 +227,10 @@ int dummy;
# http://clang.llvm.org/docs/JSONCompilationDatabase.html
def generate_compdb(self):
- ninja_exe = environment.detect_ninja()
pch_compilers = ['%s_PCH' % i for i in self.build.compilers]
native_compilers = ['%s_COMPILER' % i for i in self.build.compilers]
cross_compilers = ['%s_CROSS_COMPILER' % i for i in self.build.cross_compilers]
- ninja_compdb = [ninja_exe, '-t', 'compdb'] + pch_compilers + native_compilers + cross_compilers
+ ninja_compdb = [self.ninja_command, '-t', 'compdb'] + pch_compilers + native_compilers + cross_compilers
builddir = self.environment.get_build_dir()
try:
jsondb = subprocess.check_output(ninja_compdb, cwd=builddir)
@@ -244,7 +245,7 @@ int dummy;
header_deps = []
# XXX: Why don't we add deps to CustomTarget headers here?
for genlist in target.get_generated_sources():
- if isinstance(genlist, build.CustomTarget):
+ if isinstance(genlist, (build.CustomTarget, build.CustomTargetIndex)):
continue
for src in genlist.get_outputs():
if self.environment.is_header(src):
@@ -533,7 +534,7 @@ int dummy;
elem.add_item('COMMAND', cmd)
elem.add_item('description', desc.format(target.name, cmd_type))
elem.write(outfile)
- self.processed_targets[target.name + target.type_suffix()] = True
+ self.processed_targets[target.get_id()] = True
def generate_run_target(self, target, outfile):
cmd = self.environment.get_build_command() + ['--internal', 'commandrunner']
@@ -551,7 +552,12 @@ int dummy;
arg_strings.append(os.path.join(self.environment.get_build_dir(), relfname))
else:
raise AssertionError('Unreachable code in generate_run_target: ' + str(i))
- elem = NinjaBuildElement(self.all_outputs, 'meson-' + target.name, 'CUSTOM_COMMAND', [])
+ if target.subproject != '':
+ subproject_prefix = '{}@@'.format(target.subproject)
+ else:
+ subproject_prefix = ''
+ target_name = 'meson-{}{}'.format(subproject_prefix, target.name)
+ elem = NinjaBuildElement(self.all_outputs, target_name, 'CUSTOM_COMMAND', [])
cmd += [self.environment.get_source_dir(),
self.environment.get_build_dir(),
target.subdir] + self.environment.get_build_command()
@@ -587,8 +593,8 @@ int dummy;
elem.add_item('pool', 'console')
elem.write(outfile)
# Alias that runs the target defined above with the name the user specified
- self.create_target_alias('meson-' + target.name, outfile)
- self.processed_targets[target.name + target.type_suffix()] = True
+ self.create_target_alias(target_name, outfile)
+ self.processed_targets[target.get_id()] = True
def generate_coverage_rules(self, outfile):
e = NinjaBuildElement(self.all_outputs, 'meson-coverage', 'CUSTOM_COMMAND', 'PHONY')
@@ -719,8 +725,7 @@ int dummy;
# On toolchains/platforms that use an import library for
# linking (separate from the shared library with all the
# code), we need to install that too (dll.a/.lib).
- if (isinstance(t, build.SharedLibrary) or
- isinstance(t, build.Executable)) and t.get_import_filename():
+ if (isinstance(t, build.SharedLibrary) or isinstance(t, build.Executable)) and t.get_import_filename():
if custom_install_dir:
# If the DLL is installed into a custom directory,
# install the import library into the same place so
@@ -854,8 +859,9 @@ int dummy;
self.create_target_alias('meson-test', outfile)
# And then benchmarks.
- cmd = self.environment.get_build_command(True) + ['test', '--benchmark', '--logbase',
- 'benchmarklog', '--num-processes=1', '--no-rebuild']
+ cmd = self.environment.get_build_command(True) + [
+ 'test', '--benchmark', '--logbase',
+ 'benchmarklog', '--num-processes=1', '--no-rebuild']
elem = NinjaBuildElement(self.all_outputs, 'meson-benchmark', 'CUSTOM_COMMAND', ['all', 'PHONY'])
elem.add_item('COMMAND', cmd)
elem.add_item('DESC', 'Running benchmark suite.')
@@ -1046,7 +1052,7 @@ int dummy;
if hasattr(i, 'fname'):
i = i.fname
if i.endswith('vala'):
- vapiname = dep.name + '.vapi'
+ vapiname = dep.vala_vapi
fullname = os.path.join(self.get_target_dir(dep), vapiname)
result.add(fullname)
break
@@ -1130,9 +1136,13 @@ int dummy;
# file is outside the build directory, the path components will be
# stripped and just the basename will be used.
if isinstance(gensrc, (build.CustomTarget, build.GeneratedList)) or gensrc.is_built:
- vala_c_file = os.path.splitext(vala_file)[0] + '.c'
- else:
vala_c_file = os.path.splitext(os.path.basename(vala_file))[0] + '.c'
+ else:
+ path_to_target = os.path.join(self.build_to_src, target.get_subdir())
+ if vala_file.startswith(path_to_target):
+ vala_c_file = os.path.splitext(os.path.relpath(vala_file, path_to_target))[0] + '.c'
+ else:
+ vala_c_file = os.path.splitext(os.path.basename(vala_file))[0] + '.c'
# All this will be placed inside the c_out_dir
vala_c_file = os.path.join(c_out_dir, vala_c_file)
vala_c_src.append(vala_c_file)
@@ -1143,13 +1153,14 @@ int dummy;
# Tell Valac to output everything in our private directory. Sadly this
# means it will also preserve the directory components of Vala sources
# found inside the build tree (generated sources).
- args += ['-d', c_out_dir]
+ args += ['--directory', c_out_dir]
+ args += ['--basedir', os.path.join(self.build_to_src, target.get_subdir())]
if not isinstance(target, build.Executable):
# Library name
- args += ['--library=' + target.name]
+ args += ['--library', target.name]
# Outputted header
hname = os.path.join(self.get_target_dir(target), target.vala_header)
- args += ['-H', hname]
+ args += ['--header', hname]
if self.is_unity(target):
# Without this the declarations will get duplicated in the .c
# files and cause a build failure when all of them are
@@ -1574,9 +1585,10 @@ int dummy;
def generate_swift_compile_rules(self, compiler, outfile):
rule = 'rule %s_COMPILER\n' % compiler.get_language()
full_exe = [ninja_quote(x) for x in self.environment.get_build_command()] + [
- '--internal',
- 'dirchanger',
- '$RUNDIR']
+ '--internal',
+ 'dirchanger',
+ '$RUNDIR',
+ ]
invoc = (' '.join(full_exe) + ' ' +
' '.join(ninja_quote(i) for i in compiler.get_exelist()))
command = ' command = %s $ARGS $in\n' % invoc
@@ -1759,10 +1771,11 @@ rule FORTRAN_DEP_HACK
outfile.write('\n')
def generate_generator_list_rules(self, target, outfile):
- # CustomTargets have already written their rules,
- # so write rules for GeneratedLists here
+ # CustomTargets have already written their rules and
+ # CustomTargetIndexes don't actually get generated, so write rules for
+ # GeneratedLists here
for genlist in target.get_generated_sources():
- if isinstance(genlist, build.CustomTarget):
+ if isinstance(genlist, (build.CustomTarget, build.CustomTargetIndex)):
continue
self.generate_genlist_for_target(genlist, target, outfile)
@@ -1782,7 +1795,6 @@ rule FORTRAN_DEP_HACK
exe_arr = self.exe_object_to_cmd_array(exe)
infilelist = genlist.get_inputs()
outfilelist = genlist.get_outputs()
- base_args = generator.get_arglist()
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)):
@@ -1792,6 +1804,7 @@ rule FORTRAN_DEP_HACK
sole_output = ''
curfile = infilelist[i]
infilename = curfile.rel_to_builddir(self.build_to_src)
+ base_args = generator.get_arglist(infilename)
outfiles = genlist.get_outputs_for(curfile)
outfiles = [os.path.join(self.get_target_private_dir(target), of) for of in outfiles]
if generator.depfile is None:
@@ -1811,15 +1824,28 @@ rule FORTRAN_DEP_HACK
relout = self.get_target_private_dir(target)
args = self.replace_paths(target, args)
cmdlist = exe_arr + self.replace_extra_args(args, genlist)
+ if generator.capture:
+ exe_data = self.serialize_executable(
+ cmdlist[0],
+ cmdlist[1:],
+ self.environment.get_build_dir(),
+ capture=outfiles[0]
+ )
+ cmd = self.environment.get_build_command() + ['--internal', 'exe', exe_data]
+ abs_pdir = os.path.join(self.environment.get_build_dir(), self.get_target_dir(target))
+ os.makedirs(abs_pdir, exist_ok=True)
+ else:
+ cmd = cmdlist
+
elem = NinjaBuildElement(self.all_outputs, outfiles, rulename, infilename)
if generator.depfile is not None:
elem.add_item('DEPFILE', depfile)
if len(extra_dependencies) > 0:
elem.add_dep(extra_dependencies)
- elem.add_item('DESC', 'Generating $out')
+ elem.add_item('DESC', 'Generating {!r}.'.format(sole_output))
if isinstance(exe, build.BuildTarget):
elem.add_dep(self.get_target_filename(exe))
- elem.add_item('COMMAND', cmdlist)
+ elem.add_item('COMMAND', cmd)
elem.write(outfile)
def scan_fortran_module_outputs(self, target):
@@ -2011,7 +2037,7 @@ rule FORTRAN_DEP_HACK
# Generator output goes into the target private dir which is
# already in the include paths list. Only custom targets have their
# own target build dir.
- if not isinstance(i, build.CustomTarget):
+ if not isinstance(i, (build.CustomTarget, build.CustomTargetIndex)):
continue
idir = self.get_target_dir(i)
if idir not in custom_target_include_dirs:
@@ -2525,10 +2551,11 @@ rule FORTRAN_DEP_HACK
def generate_dist(self, outfile):
elem = NinjaBuildElement(self.all_outputs, 'meson-dist', 'CUSTOM_COMMAND', 'PHONY')
elem.add_item('DESC', 'Creating source packages')
- elem.add_item('COMMAND', self.environment.get_build_command() +
- ['--internal', 'dist',
- self.environment.source_dir,
- self.environment.build_dir] + self.environment.get_build_command())
+ elem.add_item('COMMAND', self.environment.get_build_command() + [
+ '--internal', 'dist',
+ self.environment.source_dir,
+ self.environment.build_dir,
+ ] + self.environment.get_build_command())
elem.add_item('pool', 'console')
elem.write(outfile)
# Alias that runs the target defined above
@@ -2566,11 +2593,8 @@ rule FORTRAN_DEP_HACK
default = 'default all\n\n'
outfile.write(default)
- ninja_command = environment.detect_ninja()
- if ninja_command is None:
- raise MesonException('Could not detect Ninja v1.6 or newer')
elem = NinjaBuildElement(self.all_outputs, 'meson-clean', 'CUSTOM_COMMAND', 'PHONY')
- elem.add_item('COMMAND', [ninja_command, '-t', 'clean'])
+ elem.add_item('COMMAND', [self.ninja_command, '-t', 'clean'])
elem.add_item('description', 'Cleaning.')
# Alias that runs the above-defined meson-clean target
self.create_target_alias('meson-clean', outfile)
diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
index 0bbc17c..e4e9696 100644
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -22,7 +22,6 @@ from .. import build
from .. import dependencies
from .. import mlog
from .. import compilers
-from ..build import BuildTarget
from ..compilers import CompilerArgs
from ..mesonlib import MesonException, File
from ..environment import Environment
@@ -92,7 +91,7 @@ class Vs2010Backend(backends.Backend):
source_target_dir = self.get_target_source_dir(target)
down = self.target_to_build_root(target)
for genlist in target.get_generated_sources():
- if isinstance(genlist, build.CustomTarget):
+ if isinstance(genlist, (build.CustomTarget, build.CustomTargetIndex)):
for i in genlist.get_outputs():
# Path to the generated source from the current vcxproj dir via the build root
ipath = os.path.join(down, self.get_target_dir(genlist), i)
@@ -106,7 +105,6 @@ class Vs2010Backend(backends.Backend):
infilelist = genlist.get_inputs()
outfilelist = genlist.get_outputs()
exe_arr = self.exe_object_to_cmd_array(exe)
- base_args = generator.get_arglist()
idgroup = ET.SubElement(parent_node, 'ItemGroup')
for i in range(len(infilelist)):
if len(infilelist) == len(outfilelist):
@@ -115,6 +113,7 @@ class Vs2010Backend(backends.Backend):
sole_output = ''
curfile = infilelist[i]
infilename = os.path.join(down, curfile.rel_to_builddir(self.build_to_src))
+ base_args = generator.get_arglist(infilename)
outfiles_rel = genlist.get_outputs_for(curfile)
outfiles = [os.path.join(target_private_dir, of) for of in outfiles_rel]
generator_output_files += outfiles
@@ -129,6 +128,16 @@ class Vs2010Backend(backends.Backend):
.replace("@BUILD_ROOT@", self.environment.get_build_dir())
for x in args]
cmd = exe_arr + self.replace_extra_args(args, genlist)
+ if generator.capture:
+ exe_data = self.serialize_executable(
+ cmd[0],
+ cmd[1:],
+ self.environment.get_build_dir(),
+ capture=outfiles[0]
+ )
+ cmd = self.environment.get_build_command() + ['--internal', 'exe', exe_data]
+ abs_pdir = os.path.join(self.environment.get_build_dir(), self.get_target_dir(target))
+ os.makedirs(abs_pdir, exist_ok=True)
cbs = ET.SubElement(idgroup, 'CustomBuild', Include=infilename)
ET.SubElement(cbs, 'Command').text = ' '.join(self.quote_arguments(cmd))
ET.SubElement(cbs, 'Outputs').text = ';'.join(outfiles)
@@ -202,6 +211,8 @@ class Vs2010Backend(backends.Backend):
for gendep in target.get_generated_sources():
if isinstance(gendep, build.CustomTarget):
all_deps[gendep.get_id()] = gendep
+ elif isinstance(gendep, build.CustomTargetIndex):
+ all_deps[gendep.target.get_id()] = gendep.target
else:
gen_exe = gendep.generator.get_exe()
if isinstance(gen_exe, build.Executable):
@@ -333,6 +344,11 @@ class Vs2010Backend(backends.Backend):
def quote_arguments(self, arr):
return ['"%s"' % i for i in arr]
+ def add_project_reference(self, root, include, projid):
+ ig = ET.SubElement(root, 'ItemGroup')
+ pref = ET.SubElement(ig, 'ProjectReference', Include=include)
+ ET.SubElement(pref, 'Project').text = '{%s}' % projid
+
def create_basic_crap(self, target):
project_name = target.name
root = ET.Element('Project', {'DefaultTargets': "Build",
@@ -383,8 +399,7 @@ class Vs2010Backend(backends.Backend):
cmd = [sys.executable, os.path.join(self.environment.get_script_dir(), 'commandrunner.py'),
self.environment.get_build_dir(),
self.environment.get_source_dir(),
- self.get_target_dir(target)] + \
- self.environment.get_build_command()
+ self.get_target_dir(target)] + self.environment.get_build_command()
for i in cmd_raw:
if isinstance(i, build.BuildTarget):
cmd.append(os.path.join(self.environment.get_build_dir(), self.get_target_filename(i)))
@@ -527,6 +542,8 @@ class Vs2010Backend(backends.Backend):
if lpath in lpaths:
lpaths.remove(lpath)
lpaths.append(lpath)
+ elif arg.startswith(('/', '-')):
+ other.append(arg)
# It's ok if we miss libraries with non-standard extensions here.
# They will go into the general link arguments.
elif arg.endswith('.lib') or arg.endswith('.a'):
@@ -897,20 +914,26 @@ class Vs2010Backend(backends.Backend):
# *_winlibs that we want to link to are static mingw64 libraries.
extra_link_args += compiler.get_option_link_args(self.environment.coredata.compiler_options)
(additional_libpaths, additional_links, extra_link_args) = self.split_link_args(extra_link_args.to_native())
- if len(extra_link_args) > 0:
- extra_link_args.append('%(AdditionalOptions)')
- ET.SubElement(link, "AdditionalOptions").text = ' '.join(extra_link_args)
- if len(additional_libpaths) > 0:
- additional_libpaths.insert(0, '%(AdditionalLibraryDirectories)')
- ET.SubElement(link, 'AdditionalLibraryDirectories').text = ';'.join(additional_libpaths)
# Add more libraries to be linked if needed
for t in target.get_dependencies():
lobj = self.build.targets[t.get_id()]
linkname = os.path.join(down, self.get_target_filename_for_linking(lobj))
if t in target.link_whole_targets:
- linkname = compiler.get_link_whole_for(linkname)[0]
- additional_links.append(linkname)
+ # /WHOLEARCHIVE:foo must go into AdditionalOptions
+ extra_link_args += compiler.get_link_whole_for(linkname)
+ # To force Visual Studio to build this project even though it
+ # has no sources, we include a reference to the vcxproj file
+ # that builds this target. Technically we should add this only
+ # if the current target has no sources, but it doesn't hurt to
+ # have 'extra' references.
+ trelpath = self.get_target_dir_relative_to(t, target)
+ tvcxproj = os.path.join(trelpath, t.get_id() + '.vcxproj')
+ tid = self.environment.coredata.target_guids[t.get_id()]
+ self.add_project_reference(root, tvcxproj, tid)
+ else:
+ # Other libraries go into AdditionalDependencies
+ additional_links.append(linkname)
for lib in self.get_custom_target_provided_libraries(target):
additional_links.append(self.relpath(lib, self.get_target_dir(target)))
additional_objects = []
@@ -919,6 +942,13 @@ class Vs2010Backend(backends.Backend):
additional_objects.append(o)
for o in custom_objs:
additional_objects.append(o)
+
+ if len(extra_link_args) > 0:
+ extra_link_args.append('%(AdditionalOptions)')
+ ET.SubElement(link, "AdditionalOptions").text = ' '.join(extra_link_args)
+ if len(additional_libpaths) > 0:
+ additional_libpaths.insert(0, '%(AdditionalLibraryDirectories)')
+ ET.SubElement(link, 'AdditionalLibraryDirectories').text = ';'.join(additional_libpaths)
if len(additional_links) > 0:
additional_links.append('%(AdditionalDependencies)')
ET.SubElement(link, 'AdditionalDependencies').text = ';'.join(additional_links)
@@ -926,8 +956,7 @@ class Vs2010Backend(backends.Backend):
ofile.text = '$(OutDir)%s' % target.get_filename()
subsys = ET.SubElement(link, 'SubSystem')
subsys.text = subsystem
- if (isinstance(target, build.SharedLibrary) or
- isinstance(target, build.Executable)) and target.get_import_filename():
+ if (isinstance(target, build.SharedLibrary) or isinstance(target, build.Executable)) and target.get_import_filename():
# DLLs built with MSVC always have an import library except when
# they're data-only DLLs, but we don't support those yet.
ET.SubElement(link, 'ImportLibrary').text = target.get_import_filename()
@@ -1009,9 +1038,8 @@ class Vs2010Backend(backends.Backend):
ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.targets')
# Reference the regen target.
- ig = ET.SubElement(root, 'ItemGroup')
- pref = ET.SubElement(ig, 'ProjectReference', Include=os.path.join(self.environment.get_build_dir(), 'REGEN.vcxproj'))
- ET.SubElement(pref, 'Project').text = self.environment.coredata.regen_guid
+ regen_vcxproj = os.path.join(self.environment.get_build_dir(), 'REGEN.vcxproj')
+ self.add_project_reference(root, regen_vcxproj, self.environment.coredata.regen_guid)
self._prettyprint_vcxproj_xml(ET.ElementTree(root), ofname)
def gen_regenproj(self, project_name, ofname):
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index 89689d7..12f4bdb 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -19,8 +19,8 @@ import itertools
from . import environment
from . import dependencies
from . import mlog
-from .mesonlib import File, MesonException
-from .mesonlib import flatten, typeslistify, stringlistify, classify_unity_sources
+from .mesonlib import File, MesonException, listify, extract_as_list
+from .mesonlib import typeslistify, stringlistify, classify_unity_sources
from .mesonlib import get_filenames_templates_dict, substitute_values
from .environment import for_windows, for_darwin, for_cygwin
from .compilers import is_object, clike_langs, sort_clike, lang_suffixes
@@ -36,6 +36,9 @@ known_basic_kwargs = {'install': True,
'vala_args': True,
'fortran_args': True,
'd_args': True,
+ 'd_import_dirs': True,
+ 'd_unittest': True,
+ 'd_module_versions': True,
'java_args': True,
'rust_args': True,
'link_args': True,
@@ -276,7 +279,7 @@ class EnvironmentVariables:
return env
class Target:
- def __init__(self, name, subdir, build_by_default):
+ def __init__(self, name, subdir, subproject, build_by_default):
if '/' in name or '\\' in name:
# Fix failing test 53 when this becomes an error.
mlog.warning('''Target "%s" has a path separator in its name.
@@ -284,6 +287,7 @@ This is not supported, it can cause unexpected failures and will become
a hard error in the future.''' % name)
self.name = name
self.subdir = subdir
+ self.subproject = subproject
self.build_by_default = build_by_default
self.install = False
self.build_always = False
@@ -295,6 +299,15 @@ a hard error in the future.''' % name)
def get_subdir(self):
return self.subdir
+ def get_id(self):
+ # This ID must also be a valid file name on all OSs.
+ # It should also avoid shell metacharacters for obvious
+ # reasons.
+ base = self.name + self.type_suffix()
+ if self.subproject == '':
+ return base
+ return self.subproject + '@@' + base
+
def process_kwargs(self, kwargs):
if 'build_by_default' in kwargs:
self.build_by_default = kwargs['build_by_default']
@@ -317,8 +330,7 @@ a hard error in the future.''' % name)
class BuildTarget(Target):
def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
- super().__init__(name, subdir, True)
- self.subproject = subproject # Can not be calculated from subdir as subproject dirname can be changed per project.
+ super().__init__(name, subdir, subproject, True)
self.is_cross = is_cross
unity_opt = environment.coredata.get_builtin_option('unity')
self.is_unity = unity_opt == 'on' or (unity_opt == 'subprojects' and subproject != '')
@@ -351,11 +363,12 @@ class BuildTarget(Target):
# 1. Pre-existing objects provided by the user with the `objects:` kwarg
# 2. Compiled objects created by and extracted from another target
self.process_objectlist(objects)
+ self.process_compilers()
self.process_kwargs(kwargs, environment)
self.check_unknown_kwargs(kwargs)
- if not self.sources and not self.generated and not self.objects:
+ if not any([self.sources, self.generated, self.objects, self.link_whole]):
raise InvalidArguments('Build target %s has no sources.' % name)
- self.process_compilers()
+ self.process_compilers_late()
self.validate_sources()
self.validate_cross_install(environment)
@@ -370,15 +383,6 @@ class BuildTarget(Target):
if environment.is_cross_build() and not self.is_cross and self.install:
raise InvalidArguments('Tried to install a natively built target in a cross build.')
- def get_id(self):
- # This ID must also be a valid file name on all OSs.
- # It should also avoid shell metacharacters for obvious
- # reasons.
- base = self.name + self.type_suffix()
- if self.subproject == '':
- return base
- return self.subproject + '@@' + base
-
def check_unknown_kwargs(self, kwargs):
# Override this method in derived classes that have more
# keywords.
@@ -411,8 +415,7 @@ class BuildTarget(Target):
raise InvalidArguments(msg)
def process_sourcelist(self, sources):
- if not isinstance(sources, list):
- sources = [sources]
+ sources = listify(sources)
added_sources = {} # If the same source is defined multiple times, use it only once.
for s in sources:
# Holder unpacking. Ugly.
@@ -422,7 +425,7 @@ class BuildTarget(Target):
if s not in added_sources:
self.sources.append(s)
added_sources[s] = True
- elif isinstance(s, (GeneratedList, CustomTarget)):
+ elif isinstance(s, (GeneratedList, CustomTarget, CustomTargetIndex)):
self.generated.append(s)
else:
msg = 'Bad source of type {!r} in target {!r}.'.format(type(s).__name__, self.name)
@@ -437,6 +440,39 @@ class BuildTarget(Target):
removed = True
return removed
+ def process_compilers_late(self):
+ """Processes additional compilers after kwargs have been evaluated.
+
+ This can add extra compilers that might be required by keyword
+ arguments, such as link_with or dependencies. It will also try to guess
+ which compiler to use if one hasn't been selected already.
+ """
+ # Populate list of compilers
+ if self.is_cross:
+ compilers = self.environment.coredata.cross_compilers
+ else:
+ compilers = self.environment.coredata.compilers
+
+ # If this library is linked against another library we need to consider
+ # the languages of those libraries as well.
+ if self.link_targets or self.link_whole_targets:
+ extra = set()
+ for t in itertools.chain(self.link_targets, self.link_whole_targets):
+ for name, compiler in t.compilers.items():
+ if name in clike_langs:
+ extra.add((name, compiler))
+ for name, compiler in sorted(extra, key=lambda p: sort_clike(p[0])):
+ self.compilers[name] = compiler
+
+ if not self.compilers:
+ # No source files or parent targets, target consists of only object
+ # files of unknown origin. Just add the first clike compiler
+ # that we have and hope that it can link these objects
+ for lang in clike_langs:
+ if lang in compilers:
+ self.compilers[lang] = compilers[lang]
+ break
+
def process_compilers(self):
'''
Populate self.compilers, which is the list of compilers that this
@@ -485,14 +521,7 @@ class BuildTarget(Target):
# Re-sort according to clike_langs
self.compilers = OrderedDict(sorted(self.compilers.items(),
key=lambda t: sort_clike(t[0])))
- else:
- # No source files, target consists of only object files of unknown
- # origin. Just add the first clike compiler that we have and hope
- # that it can link these objects
- for lang in clike_langs:
- if lang in compilers:
- self.compilers[lang] = compilers[lang]
- break
+
# If all our sources are Vala, our target also needs the C compiler but
# it won't get added above.
if 'vala' in self.compilers and 'c' not in self.compilers:
@@ -525,8 +554,7 @@ class BuildTarget(Target):
generated twice, since the output needs to be passed to the ld_args and
link_depends.
"""
- if not isinstance(sources, list):
- sources = [sources]
+ sources = listify(sources)
for s in sources:
if hasattr(s, 'held_object'):
s = s.held_object
@@ -548,8 +576,7 @@ class BuildTarget(Target):
return self.kwargs
def unpack_holder(self, d):
- if not isinstance(d, list):
- d = [d]
+ d = listify(d)
newd = []
for i in d:
if isinstance(i, list):
@@ -607,71 +634,61 @@ class BuildTarget(Target):
self.copy_kwargs(kwargs)
kwargs.get('modules', [])
self.need_install = kwargs.get('install', self.need_install)
- llist = kwargs.get('link_with', [])
- if not isinstance(llist, list):
- llist = [llist]
+ llist = extract_as_list(kwargs, 'link_with')
for linktarget in llist:
# Sorry for this hack. Keyword targets are kept in holders
# in kwargs. Unpack here without looking at the exact type.
if hasattr(linktarget, "held_object"):
linktarget = linktarget.held_object
+ if isinstance(linktarget, dependencies.ExternalLibrary):
+ raise MesonException('''An external library was used in link_with keyword argument, which
+is reserved for libraries built as part of this project. External
+libraries must be passed using the dependencies keyword argument
+instead, because they are conceptually "external dependencies",
+just like those detected with the dependency() function.''')
self.link(linktarget)
- lwhole = kwargs.get('link_whole', [])
- if not isinstance(lwhole, list):
- lwhole = [lwhole]
+ lwhole = extract_as_list(kwargs, 'link_whole')
for linktarget in lwhole:
# Sorry for this hack. Keyword targets are kept in holders
# in kwargs. Unpack here without looking at the exact type.
if hasattr(linktarget, "held_object"):
linktarget = linktarget.held_object
self.link_whole(linktarget)
- c_pchlist = kwargs.get('c_pch', [])
- if not isinstance(c_pchlist, list):
- c_pchlist = [c_pchlist]
+
+ c_pchlist, cpp_pchlist, clist, cpplist, cslist, valalist, objclist, objcpplist, fortranlist, rustlist \
+ = extract_as_list(kwargs, 'c_pch', 'cpp_pch', 'c_args', 'cpp_args', 'cs_args', 'vala_args', 'objc_args',
+ 'objcpp_args', 'fortran_args', 'rust_args')
+
self.add_pch('c', c_pchlist)
- cpp_pchlist = kwargs.get('cpp_pch', [])
- if not isinstance(cpp_pchlist, list):
- cpp_pchlist = [cpp_pchlist]
self.add_pch('cpp', cpp_pchlist)
- clist = kwargs.get('c_args', [])
- if not isinstance(clist, list):
- clist = [clist]
- self.add_compiler_args('c', clist)
- cpplist = kwargs.get('cpp_args', [])
- if not isinstance(cpplist, list):
- cpplist = [cpplist]
- self.add_compiler_args('cpp', cpplist)
- cslist = kwargs.get('cs_args', [])
- if not isinstance(cslist, list):
- cslist = [cslist]
- self.add_compiler_args('cs', cslist)
- valalist = kwargs.get('vala_args', [])
- if not isinstance(valalist, list):
- valalist = [valalist]
- self.add_compiler_args('vala', valalist)
- objclist = kwargs.get('objc_args', [])
- if not isinstance(objclist, list):
- objclist = [objclist]
- self.add_compiler_args('objc', objclist)
- objcpplist = kwargs.get('objcpp_args', [])
- if not isinstance(objcpplist, list):
- objcpplist = [objcpplist]
- self.add_compiler_args('objcpp', objcpplist)
- fortranlist = kwargs.get('fortran_args', [])
- if not isinstance(fortranlist, list):
- fortranlist = [fortranlist]
- self.add_compiler_args('fortran', fortranlist)
- rustlist = kwargs.get('rust_args', [])
- if not isinstance(rustlist, list):
- rustlist = [rustlist]
- self.add_compiler_args('rust', rustlist)
+ compiler_args = {'c': clist, 'cpp': cpplist, 'cs': cslist, 'vala': valalist, 'objc': objclist, 'objcpp': objcpplist,
+ 'fortran': fortranlist, 'rust': rustlist
+ }
+ for key, value in compiler_args.items():
+ self.add_compiler_args(key, value)
+
if not isinstance(self, Executable):
self.vala_header = kwargs.get('vala_header', self.name + '.h')
self.vala_vapi = kwargs.get('vala_vapi', self.name + '.vapi')
self.vala_gir = kwargs.get('vala_gir', None)
+
dlist = stringlistify(kwargs.get('d_args', []))
self.add_compiler_args('d', dlist)
- self.link_args = flatten(kwargs.get('link_args', []))
+ dfeatures = dict()
+ dfeature_unittest = kwargs.get('d_unittest', False)
+ if dfeature_unittest:
+ dfeatures['unittest'] = dfeature_unittest
+ dfeature_versions = kwargs.get('d_module_versions', None)
+ if dfeature_versions:
+ dfeatures['versions'] = dfeature_versions
+ dfeature_import_dirs = kwargs.get('d_import_dirs', None)
+ if dfeature_import_dirs:
+ dfeatures['import_dirs'] = dfeature_import_dirs
+ if dfeatures:
+ if 'd' in self.compilers:
+ self.add_compiler_args('d', self.compilers['d'].get_feature_args(dfeatures))
+
+ self.link_args = extract_as_list(kwargs, 'link_args')
for i in self.link_args:
if not isinstance(i, str):
raise InvalidArguments('Link_args arguments must be strings.')
@@ -682,14 +699,10 @@ This will become a hard error in a future Meson release.''')
self.process_link_depends(kwargs.get('link_depends', []), environment)
# Target-specific include dirs must be added BEFORE include dirs from
# internal deps (added inside self.add_deps()) to override them.
- inclist = kwargs.get('include_directories', [])
- if not isinstance(inclist, list):
- inclist = [inclist]
+ inclist = extract_as_list(kwargs, 'include_directories')
self.add_include_dirs(inclist)
# Add dependencies (which also have include_directories)
- deplist = kwargs.get('dependencies', [])
- if not isinstance(deplist, list):
- deplist = [deplist]
+ deplist = extract_as_list(kwargs, 'dependencies')
self.add_deps(deplist)
# If an item in this list is False, the output corresponding to
# the list index of that item will not be installed
@@ -705,9 +718,7 @@ This will become a hard error in a future Meson release.''')
raise InvalidArguments('Argument gui_app must be boolean.')
elif 'gui_app' in kwargs:
raise InvalidArguments('Argument gui_app can only be used on executables.')
- extra_files = kwargs.get('extra_files', [])
- if not isinstance(extra_files, list):
- extra_files = [extra_files]
+ extra_files = extract_as_list(kwargs, 'extra_files')
for i in extra_files:
assert(isinstance(i, File))
trial = os.path.join(environment.get_source_dir(), i.subdir, i.fname)
@@ -720,9 +731,7 @@ This will become a hard error in a future Meson release.''')
self.build_rpath = kwargs.get('build_rpath', '')
if not isinstance(self.build_rpath, str):
raise InvalidArguments('Build_rpath is not a string.')
- resources = kwargs.get('resources', [])
- if not isinstance(resources, list):
- resources = [resources]
+ resources = extract_as_list(kwargs, 'resources')
for r in resources:
if not isinstance(r, str):
raise InvalidArguments('Resource argument is not a string.')
@@ -811,8 +820,7 @@ This will become a hard error in a future Meson release.''')
return self.include_dirs
def add_deps(self, deps):
- if not isinstance(deps, list):
- deps = [deps]
+ deps = listify(deps)
for dep in deps:
if hasattr(dep, 'held_object'):
dep = dep.held_object
@@ -854,9 +862,9 @@ You probably should put it in link_with instead.''')
return self.external_deps
def link(self, target):
- for t in flatten(target):
- if hasattr(t, 'held_object'):
- t = t.held_object
+ for t in listify(target, unholder=True):
+ if not isinstance(t, Target):
+ raise InvalidArguments('{!r} is not a target.'.format(t))
if not t.is_linkable_target():
raise InvalidArguments('Link target {!r} is not linkable.'.format(t))
if isinstance(self, SharedLibrary) and isinstance(t, StaticLibrary) and not t.pic:
@@ -868,9 +876,7 @@ You probably should put it in link_with instead.''')
self.link_targets.append(t)
def link_whole(self, target):
- for t in flatten(target):
- if hasattr(t, 'held_object'):
- t = t.held_object
+ for t in listify(target, unholder=True):
if not isinstance(t, StaticLibrary):
raise InvalidArguments('{!r} is not a static library.'.format(t))
if isinstance(self, SharedLibrary) and not t.pic:
@@ -913,7 +919,7 @@ You probably should put it in link_with instead.''')
self.include_dirs += ids
def add_compiler_args(self, language, args):
- args = flatten(args)
+ args = listify(args)
for a in args:
if not isinstance(a, (str, File)):
raise InvalidArguments('A non-string passed to compiler args.')
@@ -1017,6 +1023,7 @@ class Generator:
raise InvalidArguments('First generator argument must be an executable.')
self.exe = exe
self.depfile = None
+ self.capture = False
self.process_kwargs(kwargs)
def __repr__(self):
@@ -1040,9 +1047,7 @@ class Generator:
self.arglist = args
if 'output' not in kwargs:
raise InvalidArguments('Generator must have "output" keyword argument.')
- outputs = kwargs['output']
- if not isinstance(outputs, list):
- outputs = [outputs]
+ outputs = listify(kwargs['output'])
for rule in outputs:
if not isinstance(rule, str):
raise InvalidArguments('"output" may only contain strings.')
@@ -1062,6 +1067,11 @@ class Generator:
if os.path.split(depfile)[1] != depfile:
raise InvalidArguments('Depfile must be a plain filename without a subdirectory.')
self.depfile = depfile
+ if 'capture' in kwargs:
+ capture = kwargs['capture']
+ if not isinstance(capture, bool):
+ raise InvalidArguments('Capture must be boolean.')
+ self.capture = capture
def get_base_outnames(self, inname):
plainname = os.path.split(inname)[1]
@@ -1075,8 +1085,10 @@ class Generator:
basename = os.path.splitext(plainname)[0]
return self.depfile.replace('@BASENAME@', basename).replace('@PLAINNAME@', plainname)
- def get_arglist(self):
- return self.arglist
+ def get_arglist(self, inname):
+ plainname = os.path.split(inname)[1]
+ basename = os.path.splitext(plainname)[0]
+ return [x.replace('@BASENAME@', basename).replace('@PLAINNAME@', plainname) for x in self.arglist]
def process_files(self, name, files, state, extra_args=[]):
output = GeneratedList(self, extra_args=extra_args)
@@ -1499,8 +1511,8 @@ class CustomTarget(Target):
'override_options': True,
}
- def __init__(self, name, subdir, kwargs, absolute_paths=False):
- super().__init__(name, subdir, False)
+ def __init__(self, name, subdir, subproject, kwargs, absolute_paths=False):
+ super().__init__(name, subdir, subproject, False)
self.dependencies = []
self.extra_depends = []
self.depend_files = [] # Files that this target depends on but are not on the command line.
@@ -1538,12 +1550,9 @@ class CustomTarget(Target):
return deps
def flatten_command(self, cmd):
- if not isinstance(cmd, list):
- cmd = [cmd]
+ cmd = listify(cmd, unholder=True)
final_cmd = []
for c in cmd:
- if hasattr(c, 'held_object'):
- c = c.held_object
if isinstance(c, str):
final_cmd.append(c)
elif isinstance(c, File):
@@ -1566,17 +1575,10 @@ class CustomTarget(Target):
def process_kwargs(self, kwargs):
super().process_kwargs(kwargs)
- sources = flatten(kwargs.get('input', []))
- self.sources = []
- for s in sources:
- if hasattr(s, 'held_object'):
- s = s.held_object
- self.sources.append(s)
+ self.sources = extract_as_list(kwargs, 'input', unholder=True)
if 'output' not in kwargs:
raise InvalidArguments('Missing keyword argument "output".')
- self.outputs = kwargs['output']
- if not isinstance(self.outputs, list):
- self.outputs = [self.outputs]
+ self.outputs = listify(kwargs['output'])
# This will substitute values from the input into output and return it.
inputs = get_sources_string_names(self.sources)
values = get_filenames_templates_dict(inputs, [])
@@ -1630,18 +1632,13 @@ class CustomTarget(Target):
self.build_always = kwargs.get('build_always', False)
if not isinstance(self.build_always, bool):
raise InvalidArguments('Argument build_always must be a boolean.')
- extra_deps = kwargs.get('depends', [])
- if not isinstance(extra_deps, list):
- extra_deps = [extra_deps]
+ extra_deps, depend_files = extract_as_list(kwargs, 'depends', 'depend_files', pop = False)
for ed in extra_deps:
while hasattr(ed, 'held_object'):
ed = ed.held_object
if not isinstance(ed, (CustomTarget, BuildTarget)):
raise InvalidArguments('Can only depend on toplevel targets: custom_target or build_target (executable or a library)')
self.extra_depends.append(ed)
- depend_files = kwargs.get('depend_files', [])
- if not isinstance(depend_files, list):
- depend_files = [depend_files]
for i in depend_files:
if isinstance(i, (File, str)):
self.depend_files.append(i)
@@ -1682,9 +1679,18 @@ class CustomTarget(Target):
def type_suffix(self):
return "@cus"
+ def __getitem__(self, index):
+ return CustomTargetIndex(self, self.outputs[index])
+
+ def __setitem__(self, index, value):
+ raise NotImplementedError
+
+ def __delitem__(self, index):
+ raise NotImplementedError
+
class RunTarget(Target):
- def __init__(self, name, command, args, dependencies, subdir):
- super().__init__(name, subdir, False)
+ def __init__(self, name, command, args, dependencies, subdir, subproject):
+ super().__init__(name, subdir, subproject, False)
self.command = command
self.args = args
self.dependencies = dependencies
@@ -1696,9 +1702,6 @@ class RunTarget(Target):
repr_str = "<{0} {1}: {2}>"
return repr_str.format(self.__class__.__name__, self.get_id(), self.command)
- def get_id(self):
- return self.name + self.type_suffix()
-
def get_dependencies(self):
return self.dependencies
@@ -1741,6 +1744,29 @@ class Jar(BuildTarget):
pass
+class CustomTargetIndex:
+
+ """A special opaque object returned by indexing a CustomTaget. This object
+ exists in meson, but acts as a proxy in the backends, making targets depend
+ on the CustomTarget it's derived from, but only adding one source file to
+ the sources.
+ """
+
+ def __init__(self, target, output):
+ self.target = target
+ self.output = output
+
+ def __repr__(self):
+ return '<CustomTargetIndex: {!r}[{}]>'.format(
+ self.target, self.target.output.index(self.output))
+
+ def get_outputs(self):
+ return [self.output]
+
+ def get_subdir(self):
+ return self.target.get_subdir()
+
+
class ConfigureFile:
def __init__(self, subdir, sourcename, targetname, configuration_data):
@@ -1791,8 +1817,7 @@ class Data:
self.sources = sources
self.install_dir = install_dir
self.install_mode = install_mode
- if not isinstance(self.sources, list):
- self.sources = [self.sources]
+ self.sources = listify(self.sources)
for s in self.sources:
assert(isinstance(s, File))
diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py
index ec16134..3f9ba5c 100644
--- a/mesonbuild/compilers/c.py
+++ b/mesonbuild/compilers/c.py
@@ -16,7 +16,7 @@ import subprocess, os.path, tempfile
from .. import mlog
from .. import coredata
-from ..mesonlib import EnvironmentException, version_compare, Popen_safe
+from ..mesonlib import EnvironmentException, version_compare, Popen_safe, listify
from .compilers import (
GCC_MINGW,
@@ -172,6 +172,9 @@ class CCompiler(Compiler):
def get_linker_search_args(self, dirname):
return ['-L' + dirname]
+ def get_default_include_dirs(self):
+ return []
+
def gen_import_library_args(self, implibname):
"""
The name of the outputted import library
@@ -482,6 +485,34 @@ class CCompiler(Compiler):
# minus the extra newline at the end
return p.stdo.split(delim + '\n')[-1][:-1]
+ def get_return_value(self, fname, rtype, prefix, env, extra_args, dependencies):
+ if rtype == 'string':
+ fmt = '%s'
+ cast = '(char*)'
+ elif rtype == 'int':
+ fmt = '%lli'
+ cast = '(long long int)'
+ else:
+ raise AssertionError('BUG: Unknown return type {!r}'.format(rtype))
+ fargs = {'prefix': prefix, 'f': fname, 'cast': cast, 'fmt': fmt}
+ code = '''{prefix}
+ #include <stdio.h>
+ int main(int argc, char *argv[]) {{
+ printf ("{fmt}", {cast} {f}());
+ }}'''.format(**fargs)
+ res = self.run(code, env, extra_args, dependencies)
+ if not res.compiled:
+ m = 'Could not get return value of {}()'
+ raise EnvironmentException(m.format(fname))
+ if rtype == 'string':
+ return res.stdout
+ elif rtype == 'int':
+ try:
+ return int(res.stdout.strip())
+ except:
+ m = 'Return value of {}() is not an int'
+ raise EnvironmentException(m.format(fname))
+
@staticmethod
def _no_prototype_templ():
"""
@@ -896,6 +927,9 @@ class VisualStudioCCompiler(CCompiler):
def get_linker_search_args(self, dirname):
return ['/LIBPATH:' + dirname]
+ def get_gui_app_args(self):
+ return ['/SUBSYSTEM:WINDOWS']
+
def get_pic_args(self):
return [] # PIC is handled by the loader on Windows
@@ -1013,8 +1047,7 @@ class VisualStudioCCompiler(CCompiler):
def get_link_whole_for(self, args):
# Only since VS2015
- if not isinstance(args, list):
- args = [args]
+ args = listify(args)
return ['/WHOLEARCHIVE:' + x for x in args]
def get_instruction_set_args(self, instruction_set):
@@ -1027,4 +1060,33 @@ class VisualStudioCCompiler(CCompiler):
return None
return vs32_instruction_set_args.get(instruction_set, None)
+ def get_toolset_version(self):
+ # See boost/config/compiler/visualc.cpp for up to date mapping
+ try:
+ version = int(''.join(self.version.split('.')[0:2]))
+ except:
+ return None
+ if version < 1310:
+ return '7.0'
+ elif version < 1400:
+ return '7.1' # (Visual Studio 2003)
+ elif version < 1500:
+ return '8.0' # (Visual Studio 2005)
+ elif version < 1600:
+ return '9.0' # (Visual Studio 2008)
+ elif version < 1700:
+ return '10.0' # (Visual Studio 2010)
+ elif version < 1800:
+ return '11.0' # (Visual Studio 2012)
+ elif version < 1900:
+ return '12.0' # (Visual Studio 2013)
+ elif version < 1910:
+ return '14.0' # (Visual Studio 2015)
+ elif version < 1920:
+ return '14.1' # (Visual Studio 2017)
+ return None
+ def get_default_include_dirs(self):
+ if 'INCLUDE' not in os.environ:
+ return []
+ return os.environ['INCLUDE'].split(os.pathsep)
diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py
index c431194..5a3c8d1 100644
--- a/mesonbuild/compilers/compilers.py
+++ b/mesonbuild/compilers/compilers.py
@@ -13,6 +13,7 @@
# limitations under the License.
import contextlib, os.path, re, tempfile
+import subprocess
from ..linkers import StaticLinker
from .. import coredata
@@ -252,7 +253,7 @@ vs32_instruction_set_args = {'mmx': ['/arch:SSE'], # There does not seem to be a
'avx': ['/arch:AVX'],
'avx2': ['/arch:AVX2'],
'neon': None,
-}
+ }
# The 64 bit compiler defaults to /arch:avx.
vs64_instruction_set_args = {'mmx': ['/arch:AVX'],
@@ -272,7 +273,7 @@ def sanitizer_compile_args(value):
if value == 'none':
return []
args = ['-fsanitize=' + value]
- if value == 'address':
+ if 'address' in value: # For -fsanitize=address,undefined
args.append('-fno-omit-frame-pointer')
return args
@@ -917,6 +918,41 @@ def get_largefile_args(compiler):
# those features explicitly.
return []
+# TODO: The result from calling compiler should be cached. So that calling this
+# function multiple times don't add latency.
+def gnulike_default_include_dirs(compiler, lang):
+ if lang == 'cpp':
+ lang = 'c++'
+ env = os.environ.copy()
+ env["LC_ALL"] = 'C'
+ cmd = compiler + ['-x{}'.format(lang), '-E', '-v', '-']
+ p = subprocess.Popen(
+ cmd,
+ stdin=subprocess.DEVNULL,
+ stderr=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ env=env
+ )
+ stderr = p.stderr.read().decode('utf-8')
+ parse_state = 0
+ paths = []
+ for line in stderr.split('\n'):
+ if parse_state == 0:
+ if line == '#include "..." search starts here:':
+ parse_state = 1
+ elif parse_state == 1:
+ if line == '#include <...> search starts here:':
+ parse_state = 2
+ else:
+ paths.append(line[1:])
+ elif parse_state == 2:
+ if line == 'End of search list.':
+ break
+ else:
+ paths.append(line[1:])
+ if len(paths) == 0:
+ mlog.warning('No include directory found parsing "{cmd}" output'.format(cmd=" ".join(cmd)))
+ return paths
class GnuCompiler:
# Functionality that is common to all GNU family compilers.
@@ -998,6 +1034,9 @@ class GnuCompiler:
def get_instruction_set_args(self, instruction_set):
return gnulike_instruction_set_args.get(instruction_set, None)
+ def get_default_include_dirs(self):
+ return gnulike_default_include_dirs(self.exelist, self.language)
+
class ClangCompiler:
def __init__(self, clang_type):
@@ -1082,6 +1121,9 @@ class ClangCompiler:
def get_instruction_set_args(self, instruction_set):
return gnulike_instruction_set_args.get(instruction_set, None)
+ def get_default_include_dirs(self):
+ return gnulike_default_include_dirs(self.exelist, self.language)
+
# Tested on linux for ICC 14.0.3, 15.0.6, 16.0.4, 17.0.1
class IntelCompiler:
@@ -1132,3 +1174,6 @@ class IntelCompiler:
# if self.icc_type == ICC_OSX:
# return ['-bundle']
return ['-shared']
+
+ def get_default_include_dirs(self):
+ return gnulike_default_include_dirs(self.exelist, self.language)
diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py
index a989704..9739f28 100644
--- a/mesonbuild/compilers/d.py
+++ b/mesonbuild/compilers/d.py
@@ -27,6 +27,20 @@ from .compilers import (
CompilerArgs,
)
+d_feature_args = {'gcc': {'unittest': '-funittest',
+ 'version': '-fversion',
+ 'import_dir': '-J'
+ },
+ 'llvm': {'unittest': '-unittest',
+ 'version': '-d-version',
+ 'import_dir': '-J'
+ },
+ 'dmd': {'unittest': '-unittest',
+ 'version': '-version',
+ 'import_dir': '-J'
+ }
+ }
+
class DCompiler(Compiler):
def __init__(self, exelist, version, is_cross):
self.language = 'd'
@@ -79,8 +93,42 @@ class DCompiler(Compiler):
# FIXME: Make this work for Windows, MacOS and cross-compiling
return get_gcc_soname_args(GCC_STANDARD, prefix, shlib_name, suffix, path, soversion, is_shared_module)
- def get_unittest_args(self):
- return ['-unittest']
+ def get_feature_args(self, kwargs):
+ res = []
+ if 'unittest' in kwargs:
+ unittest = kwargs.pop('unittest')
+ unittest_arg = d_feature_args[self.id]['unittest']
+ if not unittest_arg:
+ raise EnvironmentException('D compiler %s does not support the "unittest" feature.' % self.name_string())
+ if unittest:
+ res.append(unittest_arg)
+
+ if 'versions' in kwargs:
+ versions = kwargs.pop('versions')
+ if not isinstance(versions, list):
+ versions = [versions]
+
+ version_arg = d_feature_args[self.id]['version']
+ if not version_arg:
+ raise EnvironmentException('D compiler %s does not support the "feature versions" feature.' % self.name_string())
+ for v in versions:
+ res.append('{0}={1}'.format(version_arg, v))
+
+ if 'import_dirs' in kwargs:
+ import_dirs = kwargs.pop('import_dirs')
+ if not isinstance(import_dirs, list):
+ import_dirs = [import_dirs]
+
+ import_dir_arg = d_feature_args[self.id]['import_dir']
+ if not import_dir_arg:
+ raise EnvironmentException('D compiler %s does not support the "string import directories" feature.' % self.name_string())
+ for d in import_dirs:
+ res.append('{0}{1}'.format(import_dir_arg, d))
+
+ if kwargs:
+ raise EnvironmentException('Unknown D compiler feature(s) selected: %s' % ', '.join(kwargs.keys()))
+
+ return res
def get_buildtype_linker_args(self, buildtype):
return []
@@ -217,9 +265,6 @@ class GnuDCompiler(DCompiler):
def build_rpath_args(self, build_dir, from_dir, rpath_paths, build_rpath, install_rpath):
return self.build_unix_rpath_args(build_dir, from_dir, rpath_paths, build_rpath, install_rpath)
- def get_unittest_args(self):
- return ['-funittest']
-
class LLVMDCompiler(DCompiler):
def __init__(self, exelist, version, is_cross):
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index e7c1e6d..e8b23fd 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -1,3 +1,4 @@
+
# Copyright 2012-2017 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,7 +20,7 @@ from .mesonlib import MesonException, commonpath
from .mesonlib import default_libdir, default_libexecdir, default_prefix
import ast
-version = '0.43.0.dev1'
+version = '0.44.0.dev1'
backendlist = ['ninja', 'vs', 'vs2010', 'vs2015', 'vs2017', 'xcode']
class UserOption:
@@ -29,9 +30,6 @@ class UserOption:
self.choices = choices
self.description = description
- def parse_string(self, valuestring):
- return valuestring
-
# Check that the input is a valid value and return the
# "cleaned" or "native" version. For example the Boolean
# option could take the string "true" and return True.
@@ -72,13 +70,6 @@ class UserBooleanOption(UserOption):
def set_value(self, newvalue):
self.value = self.tobool(newvalue)
- def parse_string(self, valuestring):
- if valuestring == 'false':
- return False
- if valuestring == 'true':
- return True
- raise MesonException('Value "%s" for boolean option "%s" is not a boolean.' % (valuestring, self.name))
-
def __bool__(self):
return self.value
@@ -109,9 +100,6 @@ class UserIntegerOption(UserOption):
except:
raise MesonException('Value string "%s" is not convertable to an integer.' % valuestring)
- def parse_string(self, valuestring):
- return self.toint(valuestring)
-
def validate_value(self, value):
return self.toint(value)
@@ -245,7 +233,7 @@ class CoreData:
value = self.sanitize_dir_option_value(options.prefix, key, value)
setattr(options, key, value)
else:
- value = get_builtin_option_default(key)
+ value = get_builtin_option_default(key, prefix=options.prefix)
args = [key] + builtin_options[key][1:-1] + [value]
self.builtins[key] = builtin_options[key][0](*args)
@@ -321,11 +309,19 @@ def get_builtin_option_description(optname):
else:
raise RuntimeError('Tried to get the description for an unknown builtin option \'%s\'.' % optname)
-def get_builtin_option_default(optname):
+def get_builtin_option_default(optname, prefix='', noneIfSuppress=False):
if is_builtin_option(optname):
o = builtin_options[optname]
if o[0] == UserComboOption:
return o[3]
+ if optname in builtin_dir_noprefix_options:
+ if noneIfSuppress:
+ # Return None if argparse defaulting should be suppressed for
+ # this option (so we can determine the default later based on
+ # prefix)
+ return None
+ elif prefix in builtin_dir_noprefix_options[optname]:
+ return builtin_dir_noprefix_options[optname][prefix]
return o[2]
else:
raise RuntimeError('Tried to get the default value for an unknown builtin option \'%s\'.' % optname)
@@ -344,15 +340,6 @@ builtin_options = {
'mandir': [UserStringOption, 'Manual page directory.', 'share/man'],
'infodir': [UserStringOption, 'Info page directory.', 'share/info'],
'localedir': [UserStringOption, 'Locale data directory.', 'share/locale'],
- # sysconfdir, localstatedir and sharedstatedir are a bit special. These defaults to ${prefix}/etc,
- # ${prefix}/var and ${prefix}/com but nobody uses that. Instead they always set it
- # manually to /etc, /var and /var/lib. This default values is thus pointless and not really used
- # but we set it to this for consistency with other systems.
- #
- # Projects installing to sysconfdir, localstatedir or sharedstatedir probably want
- # to set the following in project():
- #
- # default_options : ['sysconfdir=/etc', 'localstatedir=/var', 'sharedstatedir=/var/lib']
'sysconfdir': [UserStringOption, 'Sysconf data directory.', 'etc'],
'localstatedir': [UserStringOption, 'Localstate data directory.', 'var'],
'sharedstatedir': [UserStringOption, 'Architecture-independent data directory.', 'com'],
@@ -365,8 +352,13 @@ builtin_options = {
'errorlogs': [UserBooleanOption, "Whether to print the logs from failing tests.", True],
}
-# Installation directories that can reside in a path outside of the prefix
-builtin_dir_noprefix_options = {'sysconfdir', 'localstatedir', 'sharedstatedir'}
+# Special prefix-dependent defaults for installation directories that reside in
+# a path outside of the prefix in FHS and common usage.
+builtin_dir_noprefix_options = {
+ 'sysconfdir': {'/usr': '/etc'},
+ 'localstatedir': {'/usr': '/var', '/usr/local': '/var/local'},
+ 'sharedstatedir': {'/usr': '/var/lib', '/usr/local': '/var/local/lib'},
+}
forbidden_target_names = {'clean': None,
'clean-ctlist': None,
diff --git a/mesonbuild/dependencies/__init__.py b/mesonbuild/dependencies/__init__.py
index aa29190..4dc2b27 100644
--- a/mesonbuild/dependencies/__init__.py
+++ b/mesonbuild/dependencies/__init__.py
@@ -17,7 +17,7 @@ from .base import ( # noqa: F401
ExternalDependency, ExternalLibrary, ExtraFrameworkDependency, InternalDependency,
PkgConfigDependency, find_external_dependency, get_dep_identifier, packages, _packages_accept_language)
from .dev import GMockDependency, GTestDependency, LLVMDependency, ValgrindDependency
-from .misc import (BoostDependency, MPIDependency, Python3Dependency, ThreadDependency, PcapDependency, CupsDependency)
+from .misc import (BoostDependency, MPIDependency, Python3Dependency, ThreadDependency, PcapDependency, CupsDependency, LibWmfDependency)
from .platform import AppleFrameworks
from .ui import GLDependency, GnuStepDependency, Qt4Dependency, Qt5Dependency, SDL2Dependency, WxDependency, VulkanDependency
@@ -36,6 +36,7 @@ packages.update({
'threads': ThreadDependency,
'pcap': PcapDependency,
'cups': CupsDependency,
+ 'libwmf': LibWmfDependency,
# From platform:
'appleframeworks': AppleFrameworks,
diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py
index cc4837a..05170ff 100644
--- a/mesonbuild/dependencies/base.py
+++ b/mesonbuild/dependencies/base.py
@@ -23,7 +23,7 @@ from enum import Enum
from .. import mlog
from .. import mesonlib
-from ..mesonlib import MesonException, Popen_safe, flatten, version_compare_many
+from ..mesonlib import MesonException, Popen_safe, version_compare_many, listify
# These must be defined in this file to avoid cyclical references.
@@ -48,6 +48,8 @@ class DependencyMethods(Enum):
PCAPCONFIG = 'pcap-config'
# Detect using cups-config
CUPSCONFIG = 'cups-config'
+ # Detect using libwmf-config
+ LIBWMFCONFIG = 'libwmf-config'
# This is only supported on OSX - search the frameworks directory by name.
EXTRAFRAMEWORK = 'extraframework'
# Detect using the sysconfig module.
@@ -374,10 +376,7 @@ class ExternalProgram:
def __init__(self, name, command=None, silent=False, search_dir=None):
self.name = name
if command is not None:
- if not isinstance(command, list):
- self.command = [command]
- else:
- self.command = command
+ self.command = listify(command)
else:
self.command = self._search(name, search_dir)
if not silent:
@@ -589,7 +588,7 @@ class ExtraFrameworkDependency(ExternalDependency):
def get_dep_identifier(name, kwargs, want_cross):
# Need immutable objects since the identifier will be used as a dict key
- version_reqs = flatten(kwargs.get('version', []))
+ version_reqs = listify(kwargs.get('version', []))
if isinstance(version_reqs, list):
version_reqs = frozenset(version_reqs)
identifier = (name, version_reqs, want_cross)
@@ -602,7 +601,7 @@ def get_dep_identifier(name, kwargs, want_cross):
continue
# All keyword arguments are strings, ints, or lists (or lists of lists)
if isinstance(value, list):
- value = frozenset(flatten(value))
+ value = frozenset(listify(value))
identifier += (key, value)
return identifier
@@ -643,3 +642,14 @@ def find_external_dependency(name, env, kwargs):
raise pkg_exc
mlog.log('Dependency', mlog.bold(name), 'found:', mlog.red('NO'))
return pkgdep
+
+
+def strip_system_libdirs(environment, link_args):
+ """Remove -L<system path> arguments.
+
+ leaving these in will break builds where a user has a version of a library
+ in the system path, and a different version not in the system path if they
+ want to link against the non-system path version.
+ """
+ exclude = {'-L{}'.format(p) for p in environment.get_compiler_system_dirs()}
+ return [l for l in link_args if l not in exclude]
diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py
index f991d3c..257bf7a 100644
--- a/mesonbuild/dependencies/dev.py
+++ b/mesonbuild/dependencies/dev.py
@@ -16,13 +16,15 @@
# development purposes, such as testing, debugging, etc..
import os
+import re
import shlex
import shutil
from .. import mlog
from .. import mesonlib
-from ..mesonlib import version_compare, Popen_safe
+from ..mesonlib import version_compare, Popen_safe, stringlistify, extract_as_list
from .base import DependencyException, ExternalDependency, PkgConfigDependency
+from .base import strip_system_libdirs
class GTestDependency(ExternalDependency):
def __init__(self, environment, kwargs):
@@ -115,35 +117,36 @@ class LLVMDependency(ExternalDependency):
# Ordered list of llvm-config binaries to try. Start with base, then try
# newest back to oldest (3.5 is abitrary), and finally the devel version.
- # Please note that llvm-config-5.0 is a development snapshot and it should
+ # Please note that llvm-config-6.0 is a development snapshot and it should
# not be moved to the beginning of the list. The only difference between
- # llvm-config-5.0 and llvm-config-devel is that the former is used by
+ # llvm-config-6.0 and llvm-config-devel is that the former is used by
# Debian and the latter is used by FreeBSD.
llvm_config_bins = [
'llvm-config', # base
- 'llvm-config-4.0', 'llvm-config40', # latest stable release
- 'llvm-config-3.9', 'llvm-config39', # old stable releases
+ 'llvm-config-5.0', 'llvm-config50', # latest stable release
+ 'llvm-config-4.0', 'llvm-config40', # old stable releases
+ 'llvm-config-3.9', 'llvm-config39',
'llvm-config-3.8', 'llvm-config38',
'llvm-config-3.7', 'llvm-config37',
'llvm-config-3.6', 'llvm-config36',
'llvm-config-3.5', 'llvm-config35',
- 'llvm-config-5.0', 'llvm-config-devel', # development snapshot
+ 'llvm-config-6.0', 'llvm-config-devel', # development snapshot
]
- llvmconfig = None
- _llvmconfig_found = False
- __best_found = None
__cpp_blacklist = {'-DNDEBUG'}
def __init__(self, environment, kwargs):
# It's necessary for LLVM <= 3.8 to use the C++ linker. For 3.9 and 4.0
# the C linker works fine if only using the C API.
super().__init__('llvm-config', environment, 'cpp', kwargs)
- self.modules = []
+ self.provided_modules = []
+ self.required_modules = set()
+ self.llvmconfig = None
+ self.static = kwargs.get('static', False)
+ self.__best_found = None
# FIXME: Support multiple version requirements ala PkgConfigDependency
req_version = kwargs.get('version', None)
+ self.check_llvmconfig(req_version)
if self.llvmconfig is None:
- self.check_llvmconfig(req_version)
- if not self._llvmconfig_found:
if self.__best_found is not None:
mlog.log('found {!r} but need:'.format(self.__best_found),
req_version)
@@ -159,72 +162,130 @@ class LLVMDependency(ExternalDependency):
mlog.debug('stdout: {}\nstderr: {}'.format(out, err))
if self.required:
raise DependencyException('Dependency LLVM not found')
+ mlog.log('Dependency LLVM found:', mlog.red('NO'))
return
+
+ mlog.log('Dependency LLVM found:', mlog.green('YES'))
+ self.is_found = True
+
+ # Currently meson doesn't really atempt to handle pre-release versions,
+ # so strip the 'svn' off the end, since it will probably cuase problems
+ # for users who want the patch version.
+ self.version = out.strip().rstrip('svn')
+
+ p, out, err = Popen_safe([self.llvmconfig, '--components'])
+ if p.returncode != 0:
+ raise DependencyException('Could not generate modules for LLVM:\n' + err)
+ self.provided_modules = shlex.split(out)
+
+ modules = stringlistify(extract_as_list(kwargs, 'modules'))
+ self.check_components(modules)
+ opt_modules = stringlistify(extract_as_list(kwargs, 'optional_modules'))
+ self.check_components(opt_modules, required=False)
+
+ p, out, err = Popen_safe([self.llvmconfig, '--cppflags'])
+ if p.returncode != 0:
+ raise DependencyException('Could not generate includedir for LLVM:\n' + err)
+ cargs = mesonlib.OrderedSet(shlex.split(out))
+ self.compile_args = list(cargs.difference(self.__cpp_blacklist))
+
+ if version_compare(self.version, '>= 3.9'):
+ self._set_new_link_args()
else:
- self.version = out.strip()
- mlog.log('Dependency LLVM found:', mlog.green('YES'))
- self.is_found = True
+ self._set_old_link_args()
+ self.link_args = strip_system_libdirs(environment, self.link_args)
+
+ def _set_new_link_args(self):
+ """How to set linker args for LLVM versions >= 3.9"""
+ link_args = ['--link-static', '--system-libs'] if self.static else ['--link-shared']
+ p, out, err = Popen_safe(
+ [self.llvmconfig, '--libs', '--ldflags'] + link_args + list(self.required_modules))
+ if p.returncode != 0:
+ raise DependencyException('Could not generate libs for LLVM:\n' + err)
+ self.link_args = shlex.split(out)
+
+ def _set_old_link_args(self):
+ """Setting linker args for older versions of llvm.
- p, out = Popen_safe(
- [self.llvmconfig, '--libs', '--ldflags', '--system-libs'])[:2]
+ Old versions of LLVM bring an extra level of insanity with them.
+ llvm-config will provide the correct arguments for static linking, but
+ not for shared-linnking, we have to figure those out ourselves, because
+ of course we do.
+ """
+ if self.static:
+ p, out, err = Popen_safe(
+ [self.llvmconfig, '--libs', '--ldflags', '--system-libs'] + list(self.required_modules))
if p.returncode != 0:
- raise DependencyException('Could not generate libs for LLVM.')
+ raise DependencyException('Could not generate libs for LLVM:\n' + err)
self.link_args = shlex.split(out)
-
- p, out = Popen_safe([self.llvmconfig, '--cppflags'])[:2]
+ else:
+ # llvm-config will provide arguments for static linking, so we get
+ # to figure out for ourselves what to link with. We'll do that by
+ # checking in the directory provided by --libdir for a library
+ # called libLLVM-<ver>.(so|dylib|dll)
+ p, out, err = Popen_safe([self.llvmconfig, '--libdir'])
if p.returncode != 0:
- raise DependencyException('Could not generate includedir for LLVM.')
- cargs = mesonlib.OrderedSet(shlex.split(out))
- self.compile_args = list(cargs.difference(self.__cpp_blacklist))
+ raise DependencyException('Could not generate libs for LLVM:\n' + err)
+ libdir = out.strip()
- p, out = Popen_safe([self.llvmconfig, '--components'])[:2]
- if p.returncode != 0:
- raise DependencyException('Could not generate modules for LLVM.')
- self.modules = shlex.split(out)
-
- modules = mesonlib.stringlistify(kwargs.get('modules', []))
- for mod in modules:
- if mod not in self.modules:
- mlog.log('LLVM module', mod, 'found:', mlog.red('NO'))
- self.is_found = False
- if self.required:
- raise DependencyException(
- 'Could not find required LLVM Component: {}'.format(mod))
+ expected_name = 'libLLVM-{}'.format(self.version)
+ re_name = re.compile(r'{}.(so|dll|dylib)'.format(expected_name))
+
+ for file_ in os.listdir(libdir):
+ if re_name.match(file_):
+ self.link_args = ['-L{}'.format(libdir),
+ '-l{}'.format(os.path.splitext(file_.lstrip('lib'))[0])]
+ break
else:
+ raise DependencyException(
+ 'Could not find a dynamically linkable library for LLVM.')
+
+ def check_components(self, modules, required=True):
+ """Check for llvm components (modules in meson terms).
+
+ The required option is whether the module is required, not whether LLVM
+ is required.
+ """
+ for mod in sorted(set(modules)):
+ if mod not in self.provided_modules:
+ mlog.log('LLVM module', mod, 'found:', mlog.red('NO'),
+ '(optional)' if not required else '')
+ if required:
+ self.is_found = False
+ if self.required:
+ raise DependencyException(
+ 'Could not find required LLVM Component: {}'.format(mod))
+ else:
+ self.required_modules.add(mod)
mlog.log('LLVM module', mod, 'found:', mlog.green('YES'))
- @classmethod
- def check_llvmconfig(cls, version_req):
+ def check_llvmconfig(self, version_req):
"""Try to find the highest version of llvm-config."""
- for llvmconfig in cls.llvm_config_bins:
+ for llvmconfig in self.llvm_config_bins:
try:
p, out = Popen_safe([llvmconfig, '--version'])[0:2]
out = out.strip()
if p.returncode != 0:
continue
- # FIXME: As soon as some llvm-config is found, version checks
- # in further dependnecy() calls will be ignored
if version_req:
if version_compare(out, version_req, strict=True):
- if cls.__best_found and version_compare(out, '<={}'.format(cls.__best_found), strict=True):
+ if self.__best_found and version_compare(
+ out, '<={}'.format(self.__best_found), strict=True):
continue
- cls.__best_found = out
- cls.llvmconfig = llvmconfig
+ self.__best_found = out
+ self.llvmconfig = llvmconfig
else:
# If no specific version is requested use the first version
# found, since that should be the best.
- cls.__best_found = out
- cls.llvmconfig = llvmconfig
+ self.__best_found = out
+ self.llvmconfig = llvmconfig
break
except (FileNotFoundError, PermissionError):
pass
- if cls.__best_found:
+ if self.__best_found:
mlog.log('Found llvm-config:',
- mlog.bold(shutil.which(cls.llvmconfig)),
+ mlog.bold(shutil.which(self.llvmconfig)),
'({})'.format(out.strip()))
- cls._llvmconfig_found = True
- else:
- cls.llvmconfig = False
def need_threads(self):
return True
diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py
index 12e0239..c807926 100644
--- a/mesonbuild/dependencies/misc.py
+++ b/mesonbuild/dependencies/misc.py
@@ -18,89 +18,167 @@ import glob
import os
import re
import shlex
-import stat
import shutil
import sysconfig
from .. import mlog
from .. import mesonlib
-from ..mesonlib import Popen_safe
+from ..mesonlib import Popen_safe, extract_as_list
from ..environment import detect_cpu_family
from .base import DependencyException, DependencyMethods
from .base import ExternalDependency, ExternalProgram, ExtraFrameworkDependency, PkgConfigDependency
+# On windows 3 directory layouts are supported:
+# * The default layout (versioned) installed:
+# - $BOOST_ROOT/include/boost-x_x/boost/*.hpp
+# - $BOOST_ROOT/lib/*.lib
+# * The non-default layout (system) installed:
+# - $BOOST_ROOT/include/boost/*.hpp
+# - $BOOST_ROOT/lib/*.lib
+# * The pre-built binaries from sf.net:
+# - $BOOST_ROOT/boost/*.hpp
+# - $BOOST_ROOT/lib<arch>-<compiler>/*.lib where arch=32/64 and compiler=msvc-14.1
+#
+# Library names supported:
+# - libboost_<module>-<compiler>-mt-gd-x_x.lib (static)
+# - boost_<module>-<compiler>-mt-gd-x_x.lib|.dll (shared)
+# - libboost_<module>.lib (static)
+# - boost_<module>.lib|.dll (shared)
+# where compiler is vc141 for example.
+#
+# NOTE: -gb means runtime and build time debugging is on
+# -mt means threading=multi
+#
+# The `modules` argument accept library names. This is because every module that
+# has libraries to link against also has multiple options regarding how to
+# link. See for example:
+# * http://www.boost.org/doc/libs/1_65_1/libs/test/doc/html/boost_test/usage_variants.html
+# * http://www.boost.org/doc/libs/1_65_1/doc/html/stacktrace/configuration_and_build.html
+# * http://www.boost.org/doc/libs/1_65_1/libs/math/doc/html/math_toolkit/main_tr1.html
class BoostDependency(ExternalDependency):
- # Some boost libraries have different names for
- # their sources and libraries. This dict maps
- # between the two.
- name2lib = {'test': 'unit_test_framework'}
-
def __init__(self, environment, kwargs):
super().__init__('boost', environment, 'cpp', kwargs)
+ self.need_static_link = ['boost_exception', 'boost_test_exec_monitor']
+ self.is_debug = environment.cmd_line_options.buildtype.startswith('debug')
+ threading = kwargs.get("threading", "multi")
+ self.is_multithreading = threading == "multi"
+
+ self.requested_modules = self.get_requested(kwargs)
+ invalid_modules = [c for c in self.requested_modules if 'boost_' + c not in BOOST_LIBS]
+ if invalid_modules:
+ mlog.warning('Invalid Boost modules: ' + ', '.join(invalid_modules))
+ self.log_fail()
+ return
+
+ self.boost_root = None
+ self.boost_roots = []
+ self.incdir = None
self.libdir = None
- try:
+
+ if 'BOOST_ROOT' in os.environ:
self.boost_root = os.environ['BOOST_ROOT']
+ self.boost_roots = [self.boost_root]
if not os.path.isabs(self.boost_root):
raise DependencyException('BOOST_ROOT must be an absolute path.')
- except KeyError:
- self.boost_root = None
+ if 'BOOST_INCLUDEDIR' in os.environ:
+ self.incdir = os.environ['BOOST_INCLUDEDIR']
+ if 'BOOST_LIBRARYDIR' in os.environ:
+ self.libdir = os.environ['BOOST_LIBRARYDIR']
+
if self.boost_root is None:
- if self.want_cross:
- if 'BOOST_INCLUDEDIR' in os.environ:
- self.incdir = os.environ['BOOST_INCLUDEDIR']
- else:
- raise DependencyException('BOOST_ROOT or BOOST_INCLUDEDIR is needed while cross-compiling')
if mesonlib.is_windows():
- self.boost_root = self.detect_win_root()
- self.incdir = self.boost_root
+ self.boost_roots = self.detect_win_roots()
else:
- if 'BOOST_INCLUDEDIR' in os.environ:
- self.incdir = os.environ['BOOST_INCLUDEDIR']
- else:
- self.incdir = '/usr/include'
+ self.boost_roots = self.detect_nix_roots()
+
+ if self.boost_root is None and not self.boost_roots:
+ self.log_fail()
+ return
+
+ if self.incdir is None:
+ if mesonlib.is_windows():
+ self.incdir = self.detect_win_incdir()
+ else:
+ self.incdir = self.detect_nix_incdir()
+
+ if self.incdir is None:
+ self.log_fail()
+ return
+
+ mlog.debug('Boost library root dir is', mlog.bold(self.boost_root))
+ mlog.debug('Boost include directory is', mlog.bold(self.incdir))
- if 'BOOST_LIBRARYDIR' in os.environ:
- self.libdir = os.environ['BOOST_LIBRARYDIR']
- else:
- self.incdir = os.path.join(self.boost_root, 'include')
- self.boost_inc_subdir = os.path.join(self.incdir, 'boost')
- mlog.debug('Boost library root dir is', self.boost_root)
- self.src_modules = {}
self.lib_modules = {}
- self.lib_modules_mt = {}
self.detect_version()
- self.requested_modules = self.get_requested(kwargs)
- module_str = ', '.join(self.requested_modules)
if self.is_found:
- self.detect_src_modules()
self.detect_lib_modules()
+ mlog.debug('Boost library directory is', mlog.bold(self.libdir))
self.validate_requested()
- if self.boost_root is not None:
- info = self.version + ', ' + self.boost_root
- else:
- info = self.version
- mlog.log('Dependency Boost (%s) found:' % module_str, mlog.green('YES'), info)
+ self.log_success()
else:
- mlog.log("Dependency Boost (%s) found:" % module_str, mlog.red('NO'))
+ self.log_fail()
- def detect_win_root(self):
- globtext = 'c:\\local\\boost_*'
+ def log_fail(self):
+ module_str = ', '.join(self.requested_modules)
+ mlog.log("Dependency Boost (%s) found:" % module_str, mlog.red('NO'))
+
+ def log_success(self):
+ module_str = ', '.join(self.requested_modules)
+ if self.boost_root:
+ info = self.version + ', ' + self.boost_root
+ else:
+ info = self.version
+ mlog.log('Dependency Boost (%s) found:' % module_str, mlog.green('YES'), info)
+
+ def detect_nix_roots(self):
+ return [os.path.abspath(os.path.join(x, '..'))
+ for x in self.compiler.get_default_include_dirs()]
+
+ def detect_win_roots(self):
+ res = []
+ # Where boost documentation says it should be
+ globtext = 'C:\\Program Files\\boost\\boost_*'
files = glob.glob(globtext)
- if len(files) > 0:
- return files[0]
- return 'C:\\'
+ res.extend(files)
+
+ # Where boost built from source actually installs it
+ if os.path.isdir('C:\\Boost'):
+ res.append('C:\\Boost')
+
+ # Where boost prebuilt binaries are
+ globtext = 'C:\\local\\boost_*'
+ files = glob.glob(globtext)
+ res.extend(files)
+ return res
+
+ def detect_nix_incdir(self):
+ for root in self.boost_roots:
+ incdir = os.path.join(root, 'include', 'boost')
+ if os.path.isdir(incdir):
+ return os.path.join(root, 'include')
+ return None
+
+ # FIXME: Should pick a version that matches the requested version
+ # Returns the folder that contains the boost folder.
+ def detect_win_incdir(self):
+ for root in self.boost_roots:
+ globtext = os.path.join(root, 'include', 'boost-*')
+ incdirs = glob.glob(globtext)
+ if len(incdirs) > 0:
+ return incdirs[0]
+ incboostdir = os.path.join(root, 'include', 'boost')
+ if os.path.isdir(incboostdir):
+ return os.path.join(root, 'include')
+ incboostdir = os.path.join(root, 'boost')
+ if os.path.isdir(incboostdir):
+ return root
+ return None
def get_compile_args(self):
args = []
- if self.boost_root is not None:
- if mesonlib.is_windows():
- include_dir = self.boost_root
- else:
- include_dir = os.path.join(self.boost_root, 'include')
- else:
- include_dir = self.incdir
+ include_dir = self.incdir
# Use "-isystem" when including boost headers instead of "-I"
# to avoid compiler warnings/failures when "-Werror" is used
@@ -116,25 +194,12 @@ class BoostDependency(ExternalDependency):
# and http://stackoverflow.com/questions/37218953/isystem-on-a-system-include-directory-causes-errors
# for more details
- # TODO: The correct solution would probably be to ask the
- # compiler for it's default include paths (ie: "gcc -xc++ -E
- # -v -") and avoid including those with -isystem
-
- # For now, use -isystem for all includes except for some
- # typical defaults (which don't need to be included at all
- # since they are in the default include paths). These typical
- # defaults include the usual directories at the root of the
- # filesystem, but also any path that ends with those directory
- # names in order to handle cases like cross-compiling where we
- # might have a different sysroot.
- if not include_dir.endswith(('/usr/include', '/usr/local/include')):
+ if include_dir and include_dir not in self.compiler.get_default_include_dirs():
args.append("".join(self.compiler.get_include_args(include_dir, True)))
return args
def get_requested(self, kwargs):
- candidates = kwargs.get('modules', [])
- if not isinstance(candidates, list):
- candidates = [candidates]
+ candidates = extract_as_list(kwargs, 'modules')
for c in candidates:
if not isinstance(c, str):
raise DependencyException('Boost module argument is not a string.')
@@ -142,15 +207,17 @@ class BoostDependency(ExternalDependency):
def validate_requested(self):
for m in self.requested_modules:
- if m not in self.src_modules and m not in self.lib_modules and m + '-mt' not in self.lib_modules_mt:
- msg = 'Requested Boost module {!r} not found'
+ if 'boost_' + m not in self.lib_modules:
+ msg = 'Requested Boost library {!r} not found'
raise DependencyException(msg.format(m))
def detect_version(self):
try:
- ifile = open(os.path.join(self.boost_inc_subdir, 'version.hpp'))
+ ifile = open(os.path.join(self.incdir, 'boost', 'version.hpp'))
except FileNotFoundError:
return
+ except TypeError:
+ return
with ifile:
for line in ifile:
if line.startswith("#define") and 'BOOST_LIB_VERSION' in line:
@@ -160,12 +227,6 @@ class BoostDependency(ExternalDependency):
self.is_found = True
return
- def detect_src_modules(self):
- for entry in os.listdir(self.boost_inc_subdir):
- entry = os.path.join(self.boost_inc_subdir, entry)
- if stat.S_ISDIR(os.stat(entry).st_mode):
- self.src_modules[os.path.split(entry)[-1]] = True
-
def detect_lib_modules(self):
if mesonlib.is_windows():
return self.detect_lib_modules_win()
@@ -173,32 +234,79 @@ class BoostDependency(ExternalDependency):
def detect_lib_modules_win(self):
arch = detect_cpu_family(self.env.coredata.compilers)
- # Guess the libdir
- if arch == 'x86':
- gl = 'lib32*'
- elif arch == 'x86_64':
- gl = 'lib64*'
- else:
- # Does anyone do Boost cross-compiling to other archs on Windows?
- gl = None
- # See if the libdir is valid
- if gl:
- libdir = glob.glob(os.path.join(self.boost_root, gl))
- else:
- libdir = []
- # Can't find libdir, bail
- if not libdir:
+ compiler_ts = self.env.detect_cpp_compiler(self.want_cross).get_toolset_version().split('.')
+ compiler = 'vc{}{}'.format(compiler_ts[0], compiler_ts[1])
+ if not self.libdir:
+ # The libdirs in the distributed binaries
+ if arch == 'x86':
+ gl = 'lib32*'
+ elif arch == 'x86_64':
+ gl = 'lib64*'
+ else:
+ # Does anyone do Boost cross-compiling to other archs on Windows?
+ gl = None
+ if self.boost_root:
+ roots = [self.boost_root]
+ else:
+ roots = self.boost_roots
+ for root in roots:
+ # The default libdir when building
+ libdir = os.path.join(root, 'lib')
+ if os.path.isdir(libdir):
+ self.libdir = libdir
+ break
+ if gl:
+ tmp = glob.glob(os.path.join(root, gl))
+ if len(tmp) > 0:
+ # FIXME: Should pick the correct version
+ self.libdir = tmp[0]
+ break
+
+ if not self.libdir:
return
- libdir = libdir[0]
- # Don't override what was set in the environment
- if self.libdir:
- self.libdir = libdir
- globber = 'libboost_*-gd-*.lib' if self.static else 'boost_*-gd-*.lib' # FIXME
- for entry in glob.glob(os.path.join(libdir, globber)):
+
+ for name in self.need_static_link:
+ libname = "lib{}".format(name) + '-' + compiler
+ if self.is_multithreading:
+ libname = libname + '-mt'
+ if self.is_debug:
+ libname = libname + '-gd'
+ libname = libname + "-{}.lib".format(self.version.replace('.', '_'))
+ if os.path.isfile(os.path.join(self.libdir, libname)):
+ modname = libname.split('-', 1)[0][3:]
+ self.lib_modules[modname] = libname
+ else:
+ libname = "lib{}.lib".format(name)
+ if os.path.isfile(os.path.join(self.libdir, libname)):
+ self.lib_modules[name[3:]] = libname
+
+ # globber1 applies to a layout=system installation
+ # globber2 applies to a layout=versioned installation
+ globber1 = 'libboost_*' if self.static else 'boost_*'
+ globber2 = globber1 + '-' + compiler
+ if self.is_multithreading:
+ globber2 = globber2 + '-mt'
+ if self.is_debug:
+ globber2 = globber2 + '-gd'
+ globber2 = globber2 + '-{}'.format(self.version.replace('.', '_'))
+ globber2_matches = glob.glob(os.path.join(self.libdir, globber2 + '.lib'))
+ for entry in globber2_matches:
(_, fname) = os.path.split(entry)
- base = fname.split('_', 1)[1]
- modname = base.split('-', 1)[0]
- self.lib_modules_mt[modname] = fname
+ modname = fname.split('-', 1)
+ if len(modname) > 1:
+ modname = modname[0]
+ else:
+ modname = modname.split('.', 1)[0]
+ if self.static:
+ modname = modname[3:]
+ self.lib_modules[modname] = fname
+ if len(globber2_matches) == 0:
+ for entry in glob.glob(os.path.join(self.libdir, globber1 + '.lib')):
+ (_, fname) = os.path.split(entry)
+ modname = fname.split('.', 1)[0]
+ if self.static:
+ modname = modname[3:]
+ self.lib_modules[modname] = fname
def detect_lib_modules_nix(self):
if self.static:
@@ -216,25 +324,32 @@ class BoostDependency(ExternalDependency):
else:
libdirs = [os.path.join(self.boost_root, 'lib')]
for libdir in libdirs:
+ for name in self.need_static_link:
+ libname = 'lib{}.a'.format(name)
+ if os.path.isfile(os.path.join(libdir, libname)):
+ self.lib_modules[name] = libname
for entry in glob.glob(os.path.join(libdir, globber)):
lib = os.path.basename(entry)
- name = lib.split('.')[0].split('_', 1)[-1]
+ name = lib.split('.')[0][3:]
# I'm not 100% sure what to do here. Some distros
# have modules such as thread only as -mt versions.
- if entry.endswith('-mt.{}'.format(libsuffix)):
- self.lib_modules_mt[name] = True
- else:
- self.lib_modules[name] = True
+ # On debian all packages are built threading=multi
+ # but not suffixed with -mt.
+ # FIXME: implement detect_lib_modules_{debian, redhat, ...}
+ if self.is_multithreading and mesonlib.is_debianlike():
+ self.lib_modules[name] = lib
+ elif self.is_multithreading and entry.endswith('-mt.{}'.format(libsuffix)):
+ self.lib_modules[name] = lib
+ elif not entry.endswith('-mt.{}'.format(libsuffix)):
+ self.lib_modules[name] = lib
def get_win_link_args(self):
args = []
# TODO: should this check self.libdir?
- if self.boost_root:
+ if self.libdir:
args.append('-L' + self.libdir)
- for module in self.requested_modules:
- module = BoostDependency.name2lib.get(module, module)
- if module in self.lib_modules_mt:
- args.append(self.lib_modules_mt[module])
+ for lib in self.requested_modules:
+ args.append(self.lib_modules['boost_' + lib])
return args
def get_link_args(self):
@@ -245,33 +360,15 @@ class BoostDependency(ExternalDependency):
args.append('-L' + os.path.join(self.boost_root, 'lib'))
elif self.libdir:
args.append('-L' + self.libdir)
- for module in self.requested_modules:
- module = BoostDependency.name2lib.get(module, module)
- libname = 'boost_' + module
+ for lib in self.requested_modules:
# The compiler's library detector is the most reliable so use that first.
- default_detect = self.compiler.find_library(libname, self.env, [])
+ boost_lib = 'boost_' + lib
+ default_detect = self.compiler.find_library(boost_lib, self.env, [])
if default_detect is not None:
- if module == 'unit_testing_framework':
- emon_args = self.compiler.find_library('boost_test_exec_monitor')
- else:
- emon_args = None
args += default_detect
- if emon_args is not None:
- args += emon_args
- elif module in self.lib_modules or module in self.lib_modules_mt:
- linkcmd = '-l' + libname
- args.append(linkcmd)
- # FIXME a hack, but Boost's testing framework has a lot of
- # different options and it's hard to determine what to do
- # without feedback from actual users. Update this
- # as we get more bug reports.
- if module == 'unit_testing_framework':
- args.append('-lboost_test_exec_monitor')
- elif module + '-mt' in self.lib_modules_mt:
- linkcmd = '-lboost_' + module + '-mt'
+ elif boost_lib in self.lib_modules:
+ linkcmd = '-l' + boost_lib
args.append(linkcmd)
- if module == 'unit_testing_framework':
- args.append('-lboost_test_exec_monitor-mt')
return args
def get_sources(self):
@@ -577,6 +674,7 @@ class Python3Dependency(ExternalDependency):
else:
return [DependencyMethods.PKGCONFIG]
+
class PcapDependency(ExternalDependency):
def __init__(self, environment, kwargs):
super().__init__('pcap', environment, None, kwargs)
@@ -600,23 +698,12 @@ class PcapDependency(ExternalDependency):
self.compile_args = stdo.strip().split()
stdo = Popen_safe(['pcap-config', '--libs'])[1]
self.link_args = stdo.strip().split()
- self.version = '0'
+ self.version = self.get_pcap_lib_version()
self.is_found = True
mlog.log('Dependency', mlog.bold('pcap'), 'found:',
mlog.green('YES'), '(%s)' % pcapconf)
return
mlog.debug('Could not find pcap-config binary, trying next.')
- if DependencyMethods.EXTRAFRAMEWORK in self.methods:
- if mesonlib.is_osx():
- fwdep = ExtraFrameworkDependency('pcap', False, None, self.env,
- self.language, kwargs)
- if fwdep.found():
- self.is_found = True
- self.compile_args = fwdep.get_compile_args()
- self.link_args = fwdep.get_link_args()
- self.version = '2' # FIXME
- return
- mlog.log('Dependency', mlog.bold('pcap'), 'found:', mlog.red('NO'))
def get_methods(self):
if mesonlib.is_osx():
@@ -624,6 +711,11 @@ class PcapDependency(ExternalDependency):
else:
return [DependencyMethods.PKGCONFIG, DependencyMethods.PCAPCONFIG]
+ def get_pcap_lib_version(self):
+ return self.compiler.get_return_value('pcap_lib_version', 'string',
+ '#include <pcap.h>', self.env, [], [self])
+
+
class CupsDependency(ExternalDependency):
def __init__(self, environment, kwargs):
super().__init__('cups', environment, None, kwargs)
@@ -671,3 +763,121 @@ class CupsDependency(ExternalDependency):
return [DependencyMethods.PKGCONFIG, DependencyMethods.CUPSCONFIG, DependencyMethods.EXTRAFRAMEWORK]
else:
return [DependencyMethods.PKGCONFIG, DependencyMethods.CUPSCONFIG]
+
+
+class LibWmfDependency(ExternalDependency):
+ def __init__(self, environment, kwargs):
+ super().__init__('libwmf', environment, None, kwargs)
+ if DependencyMethods.PKGCONFIG in self.methods:
+ try:
+ kwargs['required'] = False
+ pcdep = PkgConfigDependency('libwmf', environment, kwargs)
+ if pcdep.found():
+ self.type_name = 'pkgconfig'
+ self.is_found = True
+ self.compile_args = pcdep.get_compile_args()
+ self.link_args = pcdep.get_link_args()
+ self.version = pcdep.get_version()
+ return
+ except Exception as e:
+ mlog.debug('LibWmf not found via pkgconfig. Trying next, error was:', str(e))
+ if DependencyMethods.LIBWMFCONFIG in self.methods:
+ libwmfconf = shutil.which('libwmf-config')
+ if libwmfconf:
+ stdo = Popen_safe(['libwmf-config', '--cflags'])[1]
+ self.compile_args = stdo.strip().split()
+ stdo = Popen_safe(['libwmf-config', '--libs'])[1]
+ self.link_args = stdo.strip().split()
+ stdo = Popen_safe(['libwmf-config', '--version'])[1]
+ self.version = stdo.strip()
+ self.is_found = True
+ mlog.log('Dependency', mlog.bold('libwmf'), 'found:',
+ mlog.green('YES'), '(%s)' % libwmfconf)
+ return
+ mlog.debug('Could not find libwmf-config binary, trying next.')
+
+ def get_methods(self):
+ if mesonlib.is_osx():
+ return [DependencyMethods.PKGCONFIG, DependencyMethods.LIBWMFCONFIG, DependencyMethods.EXTRAFRAMEWORK]
+ else:
+ return [DependencyMethods.PKGCONFIG, DependencyMethods.LIBWMFCONFIG]
+
+# Generated with boost_names.py
+BOOST_LIBS = [
+ 'boost_atomic',
+ 'boost_chrono',
+ 'boost_chrono',
+ 'boost_container',
+ 'boost_context',
+ 'boost_coroutine',
+ 'boost_date_time',
+ 'boost_exception',
+ 'boost_fiber',
+ 'boost_filesystem',
+ 'boost_graph',
+ 'boost_iostreams',
+ 'boost_locale',
+ 'boost_log',
+ 'boost_log_setup',
+ 'boost_math_tr1',
+ 'boost_math_tr1f',
+ 'boost_math_tr1l',
+ 'boost_math_c99',
+ 'boost_math_c99f',
+ 'boost_math_c99l',
+ 'boost_math_tr1',
+ 'boost_math_tr1f',
+ 'boost_math_tr1l',
+ 'boost_math_c99',
+ 'boost_math_c99f',
+ 'boost_math_c99l',
+ 'boost_math_tr1',
+ 'boost_math_tr1f',
+ 'boost_math_tr1l',
+ 'boost_math_c99',
+ 'boost_math_c99f',
+ 'boost_math_c99l',
+ 'boost_math_tr1',
+ 'boost_math_tr1f',
+ 'boost_math_tr1l',
+ 'boost_math_c99',
+ 'boost_math_c99f',
+ 'boost_math_c99l',
+ 'boost_math_tr1',
+ 'boost_math_tr1f',
+ 'boost_math_tr1l',
+ 'boost_math_c99',
+ 'boost_math_c99f',
+ 'boost_math_c99l',
+ 'boost_math_tr1',
+ 'boost_math_tr1f',
+ 'boost_math_tr1l',
+ 'boost_math_c99',
+ 'boost_math_c99f',
+ 'boost_math_c99l',
+ 'boost_mpi',
+ 'boost_program_options',
+ 'boost_python',
+ 'boost_python3',
+ 'boost_numpy',
+ 'boost_numpy3',
+ 'boost_random',
+ 'boost_regex',
+ 'boost_serialization',
+ 'boost_wserialization',
+ 'boost_signals',
+ 'boost_stacktrace_noop',
+ 'boost_stacktrace_backtrace',
+ 'boost_stacktrace_addr2line',
+ 'boost_stacktrace_basic',
+ 'boost_stacktrace_windbg',
+ 'boost_stacktrace_windbg_cached',
+ 'boost_system',
+ 'boost_prg_exec_monitor',
+ 'boost_test_exec_monitor',
+ 'boost_unit_test_framework',
+ 'boost_thread',
+ 'boost_timer',
+ 'boost_type_erasure',
+ 'boost_wave'
+]
diff --git a/mesonbuild/dependencies/ui.py b/mesonbuild/dependencies/ui.py
index 99e017b..8f183e5 100644
--- a/mesonbuild/dependencies/ui.py
+++ b/mesonbuild/dependencies/ui.py
@@ -23,7 +23,7 @@ from collections import OrderedDict
from .. import mlog
from .. import mesonlib
-from ..mesonlib import MesonException, Popen_safe, version_compare
+from ..mesonlib import MesonException, Popen_safe, version_compare, extract_as_list
from ..environment import for_windows, detect_cpu
from .base import DependencyException, DependencyMethods
@@ -468,12 +468,9 @@ class WxDependency(ExternalDependency):
self.link_args = out.split()
def get_requested(self, kwargs):
- modules = 'modules'
- if modules not in kwargs:
+ if 'modules' not in kwargs:
return []
- candidates = kwargs[modules]
- if not isinstance(candidates, list):
- candidates = [candidates]
+ candidates = extract_as_list(kwargs, 'modules')
for c in candidates:
if not isinstance(c, str):
raise DependencyException('wxwidgets module argument is not a string')
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index 0b2a159..7f07c8d 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -90,16 +90,19 @@ def find_coverage_tools():
genhtml_exe = None
return gcovr_exe, lcov_exe, genhtml_exe
-def detect_ninja(version='1.5'):
+def detect_ninja(version='1.5', log=False):
for n in ['ninja', 'ninja-build']:
try:
p, found = Popen_safe([n, '--version'])[0:2]
except (FileNotFoundError, PermissionError):
# Doesn't exist in PATH or isn't executable
continue
+ found = found.strip()
# Perhaps we should add a way for the caller to know the failure mode
# (not found or too old)
if p.returncode == 0 and mesonlib.version_compare(found, '>=' + version):
+ if log:
+ mlog.log('Found ninja-{} at {}'.format(found, shlex.quote(shutil.which(n))))
return n
def detect_native_windows_arch():
@@ -346,10 +349,9 @@ class Environment:
def is_cross_build(self):
return self.cross_info is not None
- def dump_coredata(self, mtime):
+ def dump_coredata(self):
cdf = os.path.join(self.get_build_dir(), Environment.coredata_file)
coredata.save(self.coredata, cdf)
- os.utime(cdf, times=(mtime, mtime))
return cdf
def get_script_dir(self):
@@ -884,6 +886,24 @@ class Environment:
def get_datadir(self):
return self.coredata.get_builtin_option('datadir')
+ def get_compiler_system_dirs(self):
+ for comp in self.coredata.compilers.values():
+ if isinstance(comp, compilers.ClangCompiler):
+ index = 1
+ break
+ elif isinstance(comp, compilers.GnuCompiler):
+ index = 2
+ break
+ else:
+ # This option is only supported by gcc and clang. If we don't get a
+ # GCC or Clang compiler return and empty list.
+ return []
+
+ p, out, _ = Popen_safe(comp.get_exelist() + ['-print-search-dirs'])
+ if p.returncode != 0:
+ raise mesonlib.MesonException('Could not calculate system search dirs')
+ out = out.split('\n')[index].lstrip('libraries: =').split(':')
+ return [os.path.normpath(p) for p in out]
def get_args_from_envvars(compiler):
"""
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index e0aebc1..6300f7f 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -21,7 +21,7 @@ from . import optinterpreter
from . import compilers
from .wrap import wrap, WrapMode
from . import mesonlib
-from .mesonlib import FileMode, Popen_safe
+from .mesonlib import FileMode, Popen_safe, listify, extract_as_list
from .dependencies import ExternalProgram
from .dependencies import InternalDependency, Dependency, DependencyException
from .interpreterbase import InterpreterBase
@@ -48,6 +48,14 @@ def stringifyUserArguments(args):
raise InvalidArguments('Function accepts only strings, integers, lists and lists thereof.')
+class ObjectHolder:
+ def __init__(self, obj):
+ self.held_object = obj
+
+ def __repr__(self):
+ return '<Holder: {!r}>'.format(self.held_object)
+
+
class TryRunResultHolder(InterpreterObject):
def __init__(self, res):
super().__init__()
@@ -117,17 +125,18 @@ class RunProcess(InterpreterObject):
def stderr_method(self, args, kwargs):
return self.stderr
-class ConfigureFileHolder(InterpreterObject):
+class ConfigureFileHolder(InterpreterObject, ObjectHolder):
def __init__(self, subdir, sourcename, targetname, configuration_data):
InterpreterObject.__init__(self)
- self.held_object = build.ConfigureFile(subdir, sourcename, targetname, configuration_data)
+ ObjectHolder.__init__(self, build.ConfigureFile(subdir, sourcename,
+ targetname, configuration_data))
-class EnvironmentVariablesHolder(MutableInterpreterObject):
+class EnvironmentVariablesHolder(MutableInterpreterObject, ObjectHolder):
def __init__(self):
- super().__init__()
- self.held_object = build.EnvironmentVariables()
+ MutableInterpreterObject.__init__(self)
+ ObjectHolder.__init__(self, build.EnvironmentVariables())
self.methods.update({'set': self.set_method,
'append': self.append_method,
'prepend': self.prepend_method,
@@ -158,11 +167,11 @@ class EnvironmentVariablesHolder(MutableInterpreterObject):
self.add_var(self.held_object.prepend, args, kwargs)
-class ConfigurationDataHolder(MutableInterpreterObject):
+class ConfigurationDataHolder(MutableInterpreterObject, ObjectHolder):
def __init__(self):
- super().__init__()
+ MutableInterpreterObject.__init__(self)
self.used = False # These objects become immutable after use in configure_file.
- self.held_object = build.ConfigurationData()
+ ObjectHolder.__init__(self, build.ConfigurationData())
self.methods.update({'set': self.set_method,
'set10': self.set10_method,
'set_quoted': self.set_quoted_method,
@@ -257,10 +266,10 @@ class ConfigurationDataHolder(MutableInterpreterObject):
# Interpreter objects can not be pickled so we must have
# these wrappers.
-class DependencyHolder(InterpreterObject):
+class DependencyHolder(InterpreterObject, ObjectHolder):
def __init__(self, dep):
InterpreterObject.__init__(self)
- self.held_object = dep
+ ObjectHolder.__init__(self, dep)
self.methods.update({'found': self.found_method,
'type_name': self.type_name_method,
'version': self.version_method,
@@ -279,8 +288,7 @@ class DependencyHolder(InterpreterObject):
return self.held_object.get_version()
def pkgconfig_method(self, args, kwargs):
- if not isinstance(args, list):
- args = [args]
+ args = listify(args)
if len(args) != 1:
raise InterpreterException('get_pkgconfig_variable takes exactly one argument.')
varname = args[0]
@@ -288,10 +296,10 @@ class DependencyHolder(InterpreterObject):
raise InterpreterException('Variable name must be a string.')
return self.held_object.get_pkgconfig_variable(varname)
-class InternalDependencyHolder(InterpreterObject):
+class InternalDependencyHolder(InterpreterObject, ObjectHolder):
def __init__(self, dep):
InterpreterObject.__init__(self)
- self.held_object = dep
+ ObjectHolder.__init__(self, dep)
self.methods.update({'found': self.found_method,
'version': self.version_method,
})
@@ -302,10 +310,10 @@ class InternalDependencyHolder(InterpreterObject):
def version_method(self, args, kwargs):
return self.held_object.get_version()
-class ExternalProgramHolder(InterpreterObject):
+class ExternalProgramHolder(InterpreterObject, ObjectHolder):
def __init__(self, ep):
InterpreterObject.__init__(self)
- self.held_object = ep
+ ObjectHolder.__init__(self, ep)
self.methods.update({'found': self.found_method,
'path': self.path_method})
@@ -324,10 +332,10 @@ class ExternalProgramHolder(InterpreterObject):
def get_name(self):
return self.held_object.get_name()
-class ExternalLibraryHolder(InterpreterObject):
+class ExternalLibraryHolder(InterpreterObject, ObjectHolder):
def __init__(self, el):
InterpreterObject.__init__(self)
- self.held_object = el
+ ObjectHolder.__init__(self, el)
self.methods.update({'found': self.found_method})
def found(self):
@@ -348,11 +356,11 @@ class ExternalLibraryHolder(InterpreterObject):
def get_exe_args(self):
return self.held_object.get_exe_args()
-class GeneratorHolder(InterpreterObject):
+class GeneratorHolder(InterpreterObject, ObjectHolder):
def __init__(self, interpreter, args, kwargs):
- super().__init__()
+ InterpreterObject.__init__(self)
self.interpreter = interpreter
- self.held_object = build.Generator(args, kwargs)
+ ObjectHolder.__init__(self, build.Generator(args, kwargs))
self.methods.update({'process': self.process_method})
def process_method(self, args, kwargs):
@@ -361,13 +369,13 @@ class GeneratorHolder(InterpreterObject):
return GeneratedListHolder(gl)
-class GeneratedListHolder(InterpreterObject):
+class GeneratedListHolder(InterpreterObject, ObjectHolder):
def __init__(self, arg1, extra_args=[]):
- super().__init__()
+ InterpreterObject.__init__(self)
if isinstance(arg1, GeneratorHolder):
- self.held_object = build.GeneratedList(arg1.held_object, extra_args)
+ ObjectHolder.__init__(self, build.GeneratedList(arg1.held_object, extra_args))
else:
- self.held_object = arg1
+ ObjectHolder.__init__(self, arg1)
def __repr__(self):
r = '<{}: {!r}>'
@@ -376,14 +384,15 @@ class GeneratedListHolder(InterpreterObject):
def add_file(self, a):
self.held_object.add_file(a)
-class BuildMachine(InterpreterObject):
+class BuildMachine(InterpreterObject, ObjectHolder):
def __init__(self, compilers):
self.compilers = compilers
InterpreterObject.__init__(self)
- self.held_object = environment.MachineInfo(environment.detect_system(),
- environment.detect_cpu_family(self.compilers),
- environment.detect_cpu(self.compilers),
- sys.byteorder)
+ held_object = environment.MachineInfo(environment.detect_system(),
+ environment.detect_cpu_family(self.compilers),
+ environment.detect_cpu(self.compilers),
+ sys.byteorder)
+ ObjectHolder.__init__(self, held_object)
self.methods.update({'system': self.system_method,
'cpu_family': self.cpu_family_method,
'cpu': self.cpu_method,
@@ -404,7 +413,7 @@ class BuildMachine(InterpreterObject):
# This class will provide both host_machine and
# target_machine
-class CrossMachineInfo(InterpreterObject):
+class CrossMachineInfo(InterpreterObject, ObjectHolder):
def __init__(self, cross_info):
InterpreterObject.__init__(self)
minimum_cross_info = {'cpu', 'cpu_family', 'endian', 'system'}
@@ -413,10 +422,11 @@ class CrossMachineInfo(InterpreterObject):
'Machine info is currently {}\n'.format(cross_info) +
'but is missing {}.'.format(minimum_cross_info - set(cross_info)))
self.info = cross_info
- self.held_object = environment.MachineInfo(cross_info['system'],
- cross_info['cpu_family'],
- cross_info['cpu'],
- cross_info['endian'])
+ minfo = environment.MachineInfo(cross_info['system'],
+ cross_info['cpu_family'],
+ cross_info['cpu'],
+ cross_info['endian'])
+ ObjectHolder.__init__(self, minfo)
self.methods.update({'system': self.system_method,
'cpu': self.cpu_method,
'cpu_family': self.cpu_family_method,
@@ -435,10 +445,10 @@ class CrossMachineInfo(InterpreterObject):
def endian_method(self, args, kwargs):
return self.held_object.endian
-class IncludeDirsHolder(InterpreterObject):
+class IncludeDirsHolder(InterpreterObject, ObjectHolder):
def __init__(self, idobj):
- super().__init__()
- self.held_object = idobj
+ InterpreterObject.__init__(self)
+ ObjectHolder.__init__(self, idobj)
class Headers(InterpreterObject):
@@ -463,10 +473,10 @@ class Headers(InterpreterObject):
def get_custom_install_dir(self):
return self.custom_install_dir
-class DataHolder(InterpreterObject):
+class DataHolder(InterpreterObject, ObjectHolder):
def __init__(self, data):
- super().__init__()
- self.held_object = data
+ InterpreterObject.__init__(self)
+ ObjectHolder.__init__(self, data)
def get_source_subdir(self):
return self.held_object.source_subdir
@@ -511,20 +521,20 @@ class Man(InterpreterObject):
def get_sources(self):
return self.sources
-class GeneratedObjectsHolder(InterpreterObject):
+class GeneratedObjectsHolder(InterpreterObject, ObjectHolder):
def __init__(self, held_object):
- super().__init__()
- self.held_object = held_object
+ InterpreterObject.__init__(self)
+ ObjectHolder.__init__(self, held_object)
-class TargetHolder(InterpreterObject):
- def __init__(self):
- super().__init__()
+class TargetHolder(InterpreterObject, ObjectHolder):
+ def __init__(self, target, interp):
+ InterpreterObject.__init__(self)
+ ObjectHolder.__init__(self, target)
+ self.interpreter = interp
class BuildTargetHolder(TargetHolder):
def __init__(self, target, interp):
- super().__init__()
- self.held_object = target
- self.interpreter = interp
+ super().__init__(target, interp)
self.methods.update({'extract_objects': self.extract_objects_method,
'extract_all_objects': self.extract_all_objects_method,
'get_id': self.get_id_method,
@@ -582,11 +592,14 @@ class JarHolder(BuildTargetHolder):
def __init__(self, target, interp):
super().__init__(target, interp)
+class CustomTargetIndexHolder(InterpreterObject, ObjectHolder):
+ def __init__(self, object_to_hold):
+ InterpreterObject.__init__(self)
+ ObjectHolder.__init__(self, object_to_hold)
+
class CustomTargetHolder(TargetHolder):
- def __init__(self, object_to_hold, interp):
- super().__init__()
- self.held_object = object_to_hold
- self.interpreter = interp
+ def __init__(self, target, interp):
+ super().__init__(target, interp)
self.methods.update({'full_path': self.full_path_method,
})
@@ -598,10 +611,19 @@ class CustomTargetHolder(TargetHolder):
def full_path_method(self, args, kwargs):
return self.interpreter.backend.get_target_filename_abs(self.held_object)
-class RunTargetHolder(InterpreterObject):
- def __init__(self, name, command, args, dependencies, subdir):
- super().__init__()
- self.held_object = build.RunTarget(name, command, args, dependencies, subdir)
+ def __getitem__(self, index):
+ return CustomTargetIndexHolder(self.held_object[index])
+
+ def __setitem__(self, index, value):
+ raise InterpreterException('Cannot set a member of a CustomTarget')
+
+ def __delitem__(self, index):
+ raise InterpreterException('Cannot delete a member of a CustomTarget')
+
+class RunTargetHolder(InterpreterObject, ObjectHolder):
+ def __init__(self, name, command, args, dependencies, subdir, subproject):
+ InterpreterObject.__init__(self)
+ ObjectHolder.__init__(self, build.RunTarget(name, command, args, dependencies, subdir, subproject))
def __repr__(self):
r = '<{} {}: {}>'
@@ -627,11 +649,11 @@ class Test(InterpreterObject):
def get_name(self):
return self.name
-class SubprojectHolder(InterpreterObject):
+class SubprojectHolder(InterpreterObject, ObjectHolder):
def __init__(self, subinterpreter):
- super().__init__()
- self.held_object = subinterpreter
+ InterpreterObject.__init__(self)
+ ObjectHolder.__init__(self, subinterpreter)
self.methods.update({'get_variable': self.get_variable_method,
})
@@ -684,14 +706,13 @@ class CompilerHolder(InterpreterObject):
if not isinstance(nobuiltins, bool):
raise InterpreterException('Type of no_builtin_args not a boolean.')
args = []
- incdirs = kwargs.get('include_directories', [])
- if not isinstance(incdirs, list):
- incdirs = [incdirs]
+ incdirs = extract_as_list(kwargs, 'include_directories')
for i in incdirs:
if not isinstance(i, IncludeDirsHolder):
raise InterpreterException('Include directories argument must be an include_directories object.')
for idir in i.held_object.get_incdirs():
- idir = os.path.join(self.environment.get_source_dir(), idir)
+ idir = os.path.join(self.environment.get_source_dir(),
+ i.held_object.get_curdir(), idir)
args += self.compiler.get_include_args(idir, False)
if not nobuiltins:
opts = self.environment.coredata.compiler_options
@@ -703,8 +724,7 @@ class CompilerHolder(InterpreterObject):
def determine_dependencies(self, kwargs):
deps = kwargs.get('dependencies', None)
if deps is not None:
- if not isinstance(deps, list):
- deps = [deps]
+ deps = listify(deps)
final_deps = []
for d in deps:
try:
@@ -767,10 +787,13 @@ class CompilerHolder(InterpreterObject):
return self.compiler.symbols_have_underscore_prefix(self.environment)
def unittest_args_method(self, args, kwargs):
- # At time, only D compilers have this feature.
- if not hasattr(self.compiler, 'get_unittest_args'):
- raise InterpreterException('This {} compiler has no unittest arguments.'.format(self.compiler.get_display_language()))
- return self.compiler.get_unittest_args()
+ '''
+ This function is deprecated and should not be used.
+ It can be removed in a future version of Meson.
+ '''
+ if not hasattr(self.compiler, 'get_feature_args'):
+ raise InterpreterException('This {} compiler has no feature arguments.'.format(self.compiler.get_display_language()))
+ return self.compiler.get_feature_args({'unittest': 'true'})
def has_member_method(self, args, kwargs):
if len(args) != 2:
@@ -897,7 +920,7 @@ class CompilerHolder(InterpreterObject):
extra_args = self.determine_args(kwargs)
deps = self.determine_dependencies(kwargs)
value = self.compiler.get_define(element, prefix, self.environment, extra_args, deps)
- mlog.log('Checking for value of define "%s": %s' % (element, value))
+ mlog.log('Fetching value of define "%s": %s' % (element, value))
return value
def compiles_method(self, args, kwargs):
@@ -1044,7 +1067,6 @@ class CompilerHolder(InterpreterObject):
h)
return result
-
def first_supported_argument_method(self, args, kwargs):
for i in mesonlib.stringlistify(args):
if self.compiler.has_argument(i, self.environment):
@@ -1054,16 +1076,16 @@ class CompilerHolder(InterpreterObject):
return []
ModuleState = namedtuple('ModuleState', [
- 'build_to_src', 'subdir', 'current_lineno', 'environment', 'project_name',
- 'project_version', 'backend', 'compilers', 'targets', 'data', 'headers',
- 'man', 'global_args', 'project_args', 'build_machine', 'host_machine',
- 'target_machine'])
+ 'build_to_src', 'subproject', 'subdir', 'current_lineno', 'environment',
+ 'project_name', 'project_version', 'backend', 'compilers', 'targets',
+ 'data', 'headers', 'man', 'global_args', 'project_args', 'build_machine',
+ 'host_machine', 'target_machine'])
-class ModuleHolder(InterpreterObject):
+class ModuleHolder(InterpreterObject, ObjectHolder):
def __init__(self, modname, module, interpreter):
InterpreterObject.__init__(self)
+ ObjectHolder.__init__(self, module)
self.modname = modname
- self.held_object = module
self.interpreter = interpreter
def method_call(self, method_name, args, kwargs):
@@ -1079,6 +1101,7 @@ class ModuleHolder(InterpreterObject):
state = ModuleState(
build_to_src=os.path.relpath(self.interpreter.environment.get_source_dir(),
self.interpreter.environment.get_build_dir()),
+ subproject=self.interpreter.subproject,
subdir=self.interpreter.subdir,
current_lineno=self.interpreter.current_lineno,
environment=self.interpreter.environment,
@@ -1261,45 +1284,50 @@ class MesonMain(InterpreterObject):
pch_kwargs = set(['c_pch', 'cpp_pch'])
-lang_arg_kwargs = set(['c_args',
- 'cpp_args',
- 'd_args',
- 'fortran_args',
- 'java_args',
- 'objc_args',
- 'objcpp_args',
- 'rust_args',
- 'vala_args',
- 'cs_args',
- ])
+lang_arg_kwargs = set([
+ 'c_args',
+ 'cpp_args',
+ 'd_args',
+ 'd_import_dirs',
+ 'd_unittest',
+ 'd_module_versions',
+ 'fortran_args',
+ 'java_args',
+ 'objc_args',
+ 'objcpp_args',
+ 'rust_args',
+ 'vala_args',
+ 'cs_args',
+])
vala_kwargs = set(['vala_header', 'vala_gir', 'vala_vapi'])
rust_kwargs = set(['rust_crate_type'])
-cs_kwargs = set(['resources'])
-
-buildtarget_kwargs = set(['build_by_default',
- 'build_rpath',
- 'dependencies',
- 'extra_files',
- 'gui_app',
- 'link_with',
- 'link_whole',
- 'link_args',
- 'link_depends',
- 'implicit_include_directories',
- 'include_directories',
- 'install',
- 'install_rpath',
- 'install_dir',
- 'name_prefix',
- 'name_suffix',
- 'native',
- 'objects',
- 'override_options',
- 'pic',
- 'sources',
- 'vs_module_defs',
- ])
+cs_kwargs = set(['resources', 'cs_args'])
+
+buildtarget_kwargs = set([
+ 'build_by_default',
+ 'build_rpath',
+ 'dependencies',
+ 'extra_files',
+ 'gui_app',
+ 'link_with',
+ 'link_whole',
+ 'link_args',
+ 'link_depends',
+ 'implicit_include_directories',
+ 'include_directories',
+ 'install',
+ 'install_rpath',
+ 'install_dir',
+ 'name_prefix',
+ 'name_suffix',
+ 'native',
+ 'objects',
+ 'override_options',
+ 'pic',
+ 'sources',
+ 'vs_module_defs',
+])
build_target_common_kwargs = (
buildtarget_kwargs |
@@ -1333,7 +1361,7 @@ permitted_kwargs = {'add_global_arguments': {'language'},
'declare_dependency': {'include_directories', 'link_with', 'sources', 'dependencies', 'compile_args', 'link_args', 'version'},
'executable': exe_kwargs,
'find_program': {'required', 'native'},
- 'generator': {'arguments', 'output', 'depfile'},
+ 'generator': {'arguments', 'output', 'depfile', 'capture'},
'include_directories': {'is_system'},
'install_data': {'install_dir', 'install_mode', 'sources'},
'install_headers': {'install_dir', 'subdir'},
@@ -1362,6 +1390,9 @@ class Interpreter(InterpreterBase):
self.coredata = self.environment.get_coredata()
self.backend = backend
self.subproject = subproject
+ # Subproject directory is usually the name of the subproject, but can
+ # be different for dependencies provided by wrap files.
+ self.subproject_directory_name = subdir.split(os.path.sep)[-1]
self.subproject_dir = subproject_dir
self.option_file = os.path.join(self.source_root, self.subdir, 'meson_options.txt')
self.load_root_meson_file()
@@ -1375,6 +1406,8 @@ class Interpreter(InterpreterBase):
self.subproject_stack = []
self.default_project_options = default_project_options[:] # Passed from the outside, only used in subprojects.
self.build_func_dict()
+ # build_def_files needs to be defined before parse_project is called
+ self.build_def_files = [os.path.join(self.subdir, environment.build_filename)]
self.parse_project()
self.builtin['build_machine'] = BuildMachine(self.coredata.compilers)
if not self.build.environment.is_cross_build():
@@ -1390,7 +1423,6 @@ class Interpreter(InterpreterBase):
self.builtin['target_machine'] = CrossMachineInfo(cross_info.config['target_machine'])
else:
self.builtin['target_machine'] = self.builtin['host_machine']
- self.build_def_files = [os.path.join(self.subdir, environment.build_filename)]
def build_func_dict(self):
self.funcs.update({'add_global_arguments': self.func_add_global_arguments,
@@ -1428,6 +1460,7 @@ class Interpreter(InterpreterBase):
'join_paths': self.func_join_paths,
'library': self.func_library,
'message': self.func_message,
+ 'warning': self.func_warning,
'option': self.func_option,
'project': self.func_project,
'run_target': self.func_run_target,
@@ -1469,8 +1502,7 @@ class Interpreter(InterpreterBase):
raise InterpreterException('Module returned a value of unknown type.')
def process_new_values(self, invalues):
- if not isinstance(invalues, list):
- invalues = [invalues]
+ invalues = listify(invalues)
for v in invalues:
if isinstance(v, (build.BuildTarget, build.CustomTarget, build.RunTarget)):
self.add_target(v.name, v)
@@ -1550,19 +1582,11 @@ class Interpreter(InterpreterBase):
version = kwargs.get('version', self.project_version)
if not isinstance(version, str):
raise InterpreterException('Version must be a string.')
- incs = kwargs.get('include_directories', [])
- if not isinstance(incs, list):
- incs = [incs]
- libs = kwargs.get('link_with', [])
- if not isinstance(libs, list):
- libs = [libs]
- sources = kwargs.get('sources', [])
- if not isinstance(sources, list):
- sources = [sources]
- sources = self.source_strings_to_files(self.flatten(sources))
- deps = self.flatten(kwargs.get('dependencies', []))
- if not isinstance(deps, list):
- deps = [deps]
+ incs = extract_as_list(kwargs, 'include_directories', unholder=True)
+ libs = extract_as_list(kwargs, 'link_with', 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)
compile_args = mesonlib.stringlistify(kwargs.get('compile_args', []))
link_args = mesonlib.stringlistify(kwargs.get('link_args', []))
final_deps = []
@@ -1574,13 +1598,12 @@ class Interpreter(InterpreterBase):
if not isinstance(d, (dependencies.Dependency, dependencies.ExternalLibrary, dependencies.InternalDependency)):
raise InterpreterException('Dependencies must be external deps')
final_deps.append(d)
- dep = dependencies.InternalDependency(version,
- mesonlib.unholder_array(incs),
- compile_args,
- link_args,
- mesonlib.unholder_array(libs),
- mesonlib.unholder_array(sources),
- final_deps)
+ for l in libs:
+ if isinstance(l, dependencies.Dependency):
+ 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)
return DependencyHolder(dep)
@noKwargs
@@ -1634,8 +1657,11 @@ class Interpreter(InterpreterBase):
raise InterpreterException('Program or command {!r} not found'
'or not executable'.format(cmd))
cmd = prog
+ cmd_path = os.path.relpath(cmd.get_path(), start=srcdir)
+ if not cmd_path.startswith('..') and cmd_path not in self.build_def_files:
+ self.build_def_files.append(cmd_path)
expanded_args = []
- for a in mesonlib.flatten(cargs):
+ for a in listify(cargs):
if isinstance(a, str):
expanded_args.append(a)
elif isinstance(a, mesonlib.File):
@@ -1644,6 +1670,14 @@ class Interpreter(InterpreterBase):
expanded_args.append(a.held_object.get_path())
else:
raise InterpreterException('Arguments ' + m.format(a))
+ for a in expanded_args:
+ if not os.path.isabs(a):
+ a = os.path.join(builddir if in_builddir else srcdir, self.subdir, a)
+ if os.path.exists(a):
+ a = os.path.relpath(a, start=srcdir)
+ if not a.startswith('..'):
+ if a not in self.build_def_files:
+ self.build_def_files.append(a)
return RunProcess(cmd, expanded_args, srcdir, builddir, self.subdir,
self.environment.get_build_command() + ['introspect'], in_builddir)
@@ -1663,6 +1697,8 @@ class Interpreter(InterpreterBase):
return self.do_subproject(dirname, kwargs)
def do_subproject(self, dirname, kwargs):
+ if '/' in dirname or '\\' in dirname:
+ raise InterpreterException('Subproject name must not contain a path separator.')
if dirname in self.subproject_stack:
fullstack = self.subproject_stack + [dirname]
incpath = ' => '.join(fullstack)
@@ -1706,12 +1742,15 @@ class Interpreter(InterpreterBase):
if len(args) != 1:
raise InterpreterException('Argument required for get_option.')
optname = args[0]
+ if ':' in optname:
+ raise InterpreterException('''Having a colon in option name is forbidden, projects are not allowed
+to directly access options of other subprojects.''')
try:
- return compilers.base_options[optname].value
+ return self.environment.get_coredata().base_options[optname].value
except KeyError:
pass
try:
- return self.environment.get_coredata().get_builtin_option(optname)
+ return self.environment.coredata.get_builtin_option(optname)
except RuntimeError:
pass
try:
@@ -1736,6 +1775,11 @@ class Interpreter(InterpreterBase):
return self.coredata.external_args[lang]
except KeyError:
pass
+ # Some base options are not defined in some environments, return the default value.
+ try:
+ return compilers.base_options[optname].value
+ except KeyError:
+ pass
raise InterpreterException('Tried to access unknown option "%s".' % optname)
@noKwargs
@@ -1745,8 +1789,7 @@ class Interpreter(InterpreterBase):
return ConfigurationDataHolder()
def parse_default_options(self, default_options):
- if not isinstance(default_options, list):
- default_options = [default_options]
+ default_options = listify(default_options)
for option in default_options:
if not isinstance(option, str):
mlog.debug(option)
@@ -1817,7 +1860,12 @@ class Interpreter(InterpreterBase):
if self.subproject in self.build.projects:
raise InvalidCode('Second call to project().')
if not self.is_subproject() and 'subproject_dir' in kwargs:
- self.subproject_dir = kwargs['subproject_dir']
+ spdirname = kwargs['subproject_dir']
+ if '/' in spdirname or '\\' in spdirname:
+ raise InterpreterException('Subproject_dir must not contain a path segment.')
+ if spdirname.startswith('.'):
+ raise InterpreterException('Subproject_dir must not begin with a period.')
+ self.subproject_dir = spdirname
if 'meson_version' in kwargs:
cv = coredata.version
@@ -1839,8 +1887,7 @@ class Interpreter(InterpreterBase):
def func_add_languages(self, node, args, kwargs):
return self.add_languages(args, kwargs.get('required', True))
- @noKwargs
- def func_message(self, node, args, kwargs):
+ def get_message_string_arg(self, node):
# reduce arguments again to avoid flattening posargs
(posargs, _) = self.reduce_arguments(node.args)
if len(posargs) != 1:
@@ -1856,9 +1903,19 @@ class Interpreter(InterpreterBase):
else:
raise InvalidArguments('Function accepts only strings, integers, lists and lists thereof.')
+ return argstr
+
+ @noKwargs
+ def func_message(self, node, args, kwargs):
+ argstr = self.get_message_string_arg(node)
mlog.log(mlog.bold('Message:'), argstr)
@noKwargs
+ def func_warning(self, node, args, kwargs):
+ argstr = self.get_message_string_arg(node)
+ mlog.warning(argstr)
+
+ @noKwargs
def func_error(self, node, args, kwargs):
self.validate_arguments(args, 1, [str])
raise InterpreterException('Error encountered: ' + args[0])
@@ -2030,11 +2087,11 @@ class Interpreter(InterpreterBase):
if not isinstance(use_native, bool):
raise InvalidArguments('Argument to "native" must be a boolean.')
if not use_native:
- progobj = self.program_from_cross_file(args)
+ progobj = self.program_from_cross_file(args)
if progobj is None:
progobj = self.program_from_system(args)
if required and (progobj is None or not progobj.found()):
- raise InvalidArguments('Program "%s" not found or not executable' % exename)
+ raise InvalidArguments('Program "%s" not found or not executable' % args[0])
if progobj is None:
return ExternalProgramHolder(dependencies.ExternalProgram('nonexistingprogram'))
return progobj
@@ -2274,7 +2331,7 @@ class Interpreter(InterpreterBase):
if len(args) != 1:
raise InterpreterException('custom_target: Only one positional argument is allowed, and it must be a string name')
name = args[0]
- tg = CustomTargetHolder(build.CustomTarget(name, self.subdir, kwargs), self)
+ tg = CustomTargetHolder(build.CustomTarget(name, self.subdir, self.subproject, kwargs), self)
self.add_target(name, tg.held_object)
return tg
@@ -2292,21 +2349,13 @@ class Interpreter(InterpreterBase):
elif len(args) == 1:
if 'command' not in kwargs:
raise InterpreterException('Missing "command" keyword argument')
- all_args = kwargs['command']
- if not isinstance(all_args, list):
- all_args = [all_args]
- deps = kwargs.get('depends', [])
- if not isinstance(deps, list):
- deps = [deps]
+ all_args = extract_as_list(kwargs, 'command')
+ deps = extract_as_list(kwargs, 'depends')
else:
raise InterpreterException('Run_target needs at least one positional argument.')
cleaned_args = []
- for i in mesonlib.flatten(all_args):
- try:
- i = i.held_object
- except AttributeError:
- pass
+ for i in listify(all_args, unholder=True):
if not isinstance(i, (str, build.BuildTarget, build.CustomTarget, dependencies.ExternalProgram, mesonlib.File)):
mlog.debug('Wrong type:', str(i))
raise InterpreterException('Invalid argument to run_target.')
@@ -2325,7 +2374,7 @@ class Interpreter(InterpreterBase):
cleaned_deps.append(d)
command = cleaned_args[0]
cmd_args = cleaned_args[1:]
- tg = RunTargetHolder(name, command, cmd_args, cleaned_deps, self.subdir)
+ tg = RunTargetHolder(name, command, cmd_args, cleaned_deps, self.subdir, self.subproject)
self.add_target(name, tg.held_object)
return tg
@@ -2348,8 +2397,7 @@ class Interpreter(InterpreterBase):
if isinstance(envlist, EnvironmentVariablesHolder):
env = envlist.held_object
else:
- if not isinstance(envlist, list):
- envlist = [envlist]
+ envlist = listify(envlist)
# Convert from array to environment object
env = EnvironmentVariablesHolder()
for e in envlist:
@@ -2378,13 +2426,10 @@ class Interpreter(InterpreterBase):
par = kwargs.get('is_parallel', True)
if not isinstance(par, bool):
raise InterpreterException('Keyword argument is_parallel must be a boolean.')
- cmd_args = kwargs.get('args', [])
- if not isinstance(cmd_args, list):
- cmd_args = [cmd_args]
+ cmd_args = extract_as_list(kwargs, 'args', unholder=True)
for i in cmd_args:
- if not isinstance(i, (str, mesonlib.File, TargetHolder)):
+ if not isinstance(i, (str, mesonlib.File, build.Target)):
raise InterpreterException('Command line arguments must be strings, files or targets.')
- cmd_args = mesonlib.unholder_array(cmd_args)
env = self.unpack_env_kwarg(kwargs)
should_fail = kwargs.get('should_fail', False)
if not isinstance(should_fail, bool):
@@ -2519,9 +2564,7 @@ class Interpreter(InterpreterBase):
if not isinstance(install_dir, str):
raise InvalidArguments('Keyword argument install_dir not a string.')
if 'exclude_files' in kwargs:
- exclude = kwargs['exclude_files']
- if not isinstance(exclude, list):
- exclude = [exclude]
+ exclude = extract_as_list(kwargs, 'exclude_files')
for f in exclude:
if not isinstance(f, str):
raise InvalidArguments('Exclude argument not a string.')
@@ -2531,9 +2574,7 @@ class Interpreter(InterpreterBase):
else:
exclude_files = set()
if 'exclude_directories' in kwargs:
- exclude = kwargs['exclude_directories']
- if not isinstance(exclude, list):
- exclude = [exclude]
+ exclude = extract_as_list(kwargs, 'exclude_directories')
for d in exclude:
if not isinstance(d, str):
raise InvalidArguments('Exclude argument not a string.')
@@ -2577,12 +2618,10 @@ class Interpreter(InterpreterBase):
if not isinstance(inputfile, (str, mesonlib.File)):
raise InterpreterException('Input must be a string or a file')
if isinstance(inputfile, str):
- inputfile = os.path.join(self.subdir, inputfile)
- ifile_abs = os.path.join(self.environment.source_dir, inputfile)
- else:
- ifile_abs = inputfile.absolute_path(self.environment.source_dir,
- self.environment.build_dir)
- inputfile = inputfile.relative_name()
+ inputfile = mesonlib.File.from_source_file(self.environment.source_dir,
+ self.subdir, inputfile)
+ ifile_abs = inputfile.absolute_path(self.environment.source_dir,
+ self.environment.build_dir)
elif 'command' in kwargs and '@INPUT@' in kwargs['command']:
raise InterpreterException('@INPUT@ used as command argument, but no input file specified.')
# Validate output
@@ -2603,18 +2642,13 @@ class Interpreter(InterpreterBase):
raise InterpreterException('Argument "configuration" is not of type configuration_data')
mlog.log('Configuring', mlog.bold(output), 'using configuration')
if inputfile is not None:
- # Normalize the path of the conffile to avoid duplicates
- # This is especially important to convert '/' to '\' on Windows
- conffile = os.path.normpath(inputfile)
- if conffile not in self.build_def_files:
- self.build_def_files.append(conffile)
os.makedirs(os.path.join(self.environment.build_dir, self.subdir), exist_ok=True)
missing_variables = mesonlib.do_conf_file(ifile_abs, ofile_abs,
conf.held_object)
if missing_variables:
var_list = ", ".join(map(repr, sorted(missing_variables)))
mlog.warning(
- "The variable(s) %s in the input file %r are not "
+ "The variable(s) %s in the input file %s are not "
"present in the given configuration data" % (
var_list, inputfile))
else:
@@ -2644,6 +2678,17 @@ class Interpreter(InterpreterBase):
mesonlib.replace_if_different(ofile_abs, dst_tmp)
else:
raise InterpreterException('Configure_file must have either "configuration" or "command".')
+ # If the input is a source file, add it to the list of files that we
+ # need to reconfigure on when they change. FIXME: Do the same for
+ # files() objects in the command: kwarg.
+ if inputfile and not inputfile.is_built:
+ # Normalize the path of the conffile (relative to the
+ # source root) to avoid duplicates. This is especially
+ # important to convert '/' to '\' on Windows
+ conffile = os.path.normpath(inputfile.relative_name())
+ if conffile not in self.build_def_files:
+ self.build_def_files.append(conffile)
+ # Install file if requested
idir = kwargs.get('install_dir', None)
if isinstance(idir, str):
cfile = mesonlib.File.from_built_file(ofile_path, ofile_fname)
@@ -2696,9 +2741,7 @@ different subdirectory.
if re.fullmatch('[_a-zA-Z][_0-9a-zA-Z]*', setup_name) is None:
raise InterpreterException('Setup name may only contain alphanumeric characters.')
try:
- inp = kwargs.get('exe_wrapper', [])
- if not isinstance(inp, list):
- inp = [inp]
+ inp = extract_as_list(kwargs, 'exe_wrapper')
exe_wrapper = []
for i in inp:
if hasattr(i, 'held_object'):
@@ -2795,16 +2838,60 @@ different subdirectory.
super().run()
mlog.log('Build targets in project:', mlog.bold(str(len(self.build.targets))))
+ def evaluate_subproject_info(self, path_from_source_root, subproject_dirname):
+ depth = 0
+ subproj_name = ''
+ segs = path_from_source_root.split(os.path.sep)
+ while segs and segs[0] == subproject_dirname:
+ depth += 1
+ subproj_name = segs[1]
+ segs = segs[2:]
+ return (depth, subproj_name)
+
+ # Check that the indicated file is within the same subproject
+ # as we currently are. This is to stop people doing
+ # nasty things like:
+ #
+ # f = files('../../master_src/file.c')
+ #
+ # Note that this is validated only when the file
+ # object is generated. The result can be used in a different
+ # subproject than it is defined in (due to e.g. a
+ # declare_dependency).
+ def validate_within_subproject(self, subdir, fname):
+ norm = os.path.normpath(os.path.join(subdir, fname))
+ if os.path.isabs(norm):
+ if not norm.startswith(self.environment.source_dir):
+ # Grabbing files outside the source tree is ok.
+ # This is for vendor stuff like:
+ #
+ # /opt/vendorsdk/src/file_with_license_restrictions.c
+ return
+ norm = os.path.relpath(norm, self.environment.source_dir)
+ assert(not os.path.isabs(norm))
+ (num_sps, sproj_name) = self.evaluate_subproject_info(norm, self.subproject_dir)
+ plain_filename = os.path.split(norm)[-1]
+ if num_sps == 0:
+ if self.subproject == '':
+ return
+ raise InterpreterException('Sandbox violation: Tried to grab file %s from a different subproject.' % plain_filename)
+ if num_sps > 1:
+ raise InterpreterException('Sandbox violation: Tried to grab file %s from a nested subproject.' % plain_filename)
+ if sproj_name != self.subproject_directory_name:
+ raise InterpreterException('Sandbox violation: Tried to grab file %s from a different subproject.' % plain_filename)
+
def source_strings_to_files(self, sources):
results = []
for s in sources:
if isinstance(s, (mesonlib.File, GeneratedListHolder,
- CustomTargetHolder)):
+ CustomTargetHolder, CustomTargetIndexHolder)):
pass
elif isinstance(s, str):
+ self.validate_within_subproject(self.subdir, s)
s = mesonlib.File.from_source_file(self.environment.source_dir, self.subdir, s)
else:
- raise InterpreterException("Source item is not string or File-type object.")
+ raise InterpreterException('Source item is {!r} instead of '
+ 'string or File-type object'.format(s))
results.append(s)
return results
@@ -2830,7 +2917,7 @@ different subdirectory.
if not args:
raise InterpreterException('Target does not have a name.')
name = args[0]
- sources = args[1:]
+ sources = listify(args[1:])
if self.environment.is_cross_build():
if kwargs.get('native', False):
is_cross = False
@@ -2838,23 +2925,14 @@ different subdirectory.
is_cross = True
else:
is_cross = False
- try:
- kw_src = self.flatten(kwargs['sources'])
- if not isinstance(kw_src, list):
- kw_src = [kw_src]
- except KeyError:
- kw_src = []
- sources += kw_src
+ if 'sources' in kwargs:
+ sources += listify(kwargs['sources'])
sources = self.source_strings_to_files(sources)
- objs = self.flatten(kwargs.get('objects', []))
- kwargs['dependencies'] = self.flatten(kwargs.get('dependencies', []))
+ objs = extract_as_list(kwargs, 'objects')
+ kwargs['dependencies'] = extract_as_list(kwargs, 'dependencies')
if 'extra_files' in kwargs:
- ef = kwargs['extra_files']
- if not isinstance(ef, list):
- ef = [ef]
+ ef = extract_as_list(kwargs, 'extra_files')
kwargs['extra_files'] = self.source_strings_to_files(ef)
- if not isinstance(objs, list):
- objs = [objs]
self.check_sources_exist(os.path.join(self.source_root, self.subdir), sources)
if targetholder is ExecutableHolder:
targetclass = build.Executable
diff --git a/mesonbuild/interpreterbase.py b/mesonbuild/interpreterbase.py
index d2e2ab3..cb82e56 100644
--- a/mesonbuild/interpreterbase.py
+++ b/mesonbuild/interpreterbase.py
@@ -369,14 +369,16 @@ class InterpreterBase:
def evaluate_indexing(self, node):
assert(isinstance(node, mparser.IndexNode))
iobject = self.evaluate_statement(node.iobject)
- if not isinstance(iobject, list):
- raise InterpreterException('Tried to index a non-array object.')
+ if not hasattr(iobject, '__getitem__'):
+ raise InterpreterException(
+ 'Tried to index an object that doesn\'t support indexing.')
index = self.evaluate_statement(node.index)
if not isinstance(index, int):
raise InterpreterException('Index value is not an integer.')
- if index < -len(iobject) or index >= len(iobject):
+ try:
+ return iobject[index]
+ except IndexError:
raise InterpreterException('Index %d out of bounds of array of size %d.' % (index, len(iobject)))
- return iobject[index]
def function_call(self, node):
func_name = node.func_name
@@ -450,9 +452,25 @@ class InterpreterBase:
else:
raise InterpreterException('Unknown method "%s" for an integer.' % method_name)
+ @staticmethod
+ def _get_one_string_posarg(posargs, method_name):
+ if len(posargs) > 1:
+ m = '{}() must have zero or one arguments'
+ raise InterpreterException(m.format(method_name))
+ elif len(posargs) == 1:
+ s = posargs[0]
+ if not isinstance(s, str):
+ m = '{}() argument must be a string'
+ raise InterpreterException(m.format(method_name))
+ return s
+ return None
+
def string_method_call(self, obj, method_name, args):
(posargs, _) = self.reduce_arguments(args)
if method_name == 'strip':
+ s = self._get_one_string_posarg(posargs, 'strip')
+ if s is not None:
+ return obj.strip(s)
return obj.strip()
elif method_name == 'format':
return self.format_string(obj, args)
@@ -463,15 +481,10 @@ class InterpreterBase:
elif method_name == 'underscorify':
return re.sub(r'[^a-zA-Z0-9]', '_', obj)
elif method_name == 'split':
- if len(posargs) > 1:
- raise InterpreterException('Split() must have at most one argument.')
- elif len(posargs) == 1:
- s = posargs[0]
- if not isinstance(s, str):
- raise InterpreterException('Split() argument must be a string')
+ s = self._get_one_string_posarg(posargs, 'split')
+ if s is not None:
return obj.split(s)
- else:
- return obj.split()
+ return obj.split()
elif method_name == 'startswith' or method_name == 'contains' or method_name == 'endswith':
s = posargs[0]
if not isinstance(s, str):
diff --git a/mesonbuild/mconf.py b/mesonbuild/mconf.py
index ee4dbf8..09b0f12 100644
--- a/mesonbuild/mconf.py
+++ b/mesonbuild/mconf.py
@@ -17,7 +17,7 @@ import pickle
import argparse
from . import coredata, mesonlib
-parser = argparse.ArgumentParser()
+parser = argparse.ArgumentParser(prog='meson configure')
parser.add_argument('-D', action='append', default=[], dest='sets',
help='Set an option to the given value.')
diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py
index d03e5a2..5c4c374 100644
--- a/mesonbuild/mesonlib.py
+++ b/mesonbuild/mesonlib.py
@@ -14,6 +14,7 @@
"""A library of random helper functionality."""
+import sys
import stat
import time
import platform, subprocess, operator, os, shutil, re
@@ -198,17 +199,6 @@ def classify_unity_sources(compilers, sources):
compsrclist[comp].append(src)
return compsrclist
-def flatten(item):
- if not isinstance(item, list):
- return [item]
- result = []
- for i in item:
- if isinstance(i, list):
- result += flatten(i)
- else:
- result.append(i)
- return result
-
def is_osx():
return platform.system().lower() == 'darwin'
@@ -473,6 +463,47 @@ def replace_if_different(dst, dst_tmp):
else:
os.unlink(dst_tmp)
+def listify(item, flatten=True, unholder=False):
+ '''
+ Returns a list with all args embedded in a list if they are not a list.
+ This function preserves order.
+ @flatten: Convert lists of lists to a flat list
+ @unholder: Replace each item with the object it holds, if required
+
+ Note: unholding only works recursively when flattening
+ '''
+ if not isinstance(item, list):
+ if unholder and hasattr(item, 'held_object'):
+ item = item.held_object
+ return [item]
+ result = []
+ for i in item:
+ if unholder and hasattr(i, 'held_object'):
+ i = i.held_object
+ if flatten and isinstance(i, list):
+ result += listify(i, flatten=True, unholder=unholder)
+ else:
+ result.append(i)
+ return result
+
+
+def extract_as_list(dict_object, *keys, pop=False, **kwargs):
+ '''
+ Extracts all values from given dict_object and listifies them.
+ '''
+ result = []
+ fetch = dict_object.get
+ if pop:
+ fetch = dict_object.pop
+ # If there's only one key, we don't return a list with one element
+ if len(keys) == 1:
+ return listify(fetch(keys[0], []), **kwargs)
+ # Return a list of values corresponding to *keys
+ for key in keys:
+ result.append(listify(fetch(key, []), **kwargs))
+ return result
+
+
def typeslistify(item, types):
'''
Ensure that type(@item) is one of @types or a
@@ -509,6 +540,8 @@ def expand_arguments(args):
return expended_args
def Popen_safe(args, write=None, stderr=subprocess.PIPE, **kwargs):
+ if sys.version_info < (3, 6) or not sys.stdout.encoding:
+ return Popen_safe_legacy(args, write=write, stderr=stderr, **kwargs)
p = subprocess.Popen(args, universal_newlines=True,
close_fds=False,
stdout=subprocess.PIPE,
@@ -516,6 +549,25 @@ def Popen_safe(args, write=None, stderr=subprocess.PIPE, **kwargs):
o, e = p.communicate(write)
return p, o, e
+def Popen_safe_legacy(args, write=None, stderr=subprocess.PIPE, **kwargs):
+ p = subprocess.Popen(args, universal_newlines=False,
+ stdout=subprocess.PIPE,
+ stderr=stderr, **kwargs)
+ if write is not None:
+ write = write.encode('utf-8')
+ o, e = p.communicate(write)
+ if o is not None:
+ if sys.stdout.encoding:
+ o = o.decode(encoding=sys.stdout.encoding, errors='replace').replace('\r\n', '\n')
+ else:
+ o = o.decode(errors='replace').replace('\r\n', '\n')
+ if e is not None:
+ if sys.stderr.encoding:
+ e = e.decode(encoding=sys.stderr.encoding, errors='replace').replace('\r\n', '\n')
+ else:
+ e = e.decode(errors='replace').replace('\r\n', '\n')
+ return p, o, e
+
def commonpath(paths):
'''
For use on Python 3.4 where os.path.commonpath is not available.
@@ -708,15 +760,6 @@ def windows_proof_rmtree(f):
# Try one last time and throw if it fails.
shutil.rmtree(f)
-def unholder_array(entries):
- result = []
- entries = flatten(entries)
- for e in entries:
- if hasattr(e, 'held_object'):
- e = e.held_object
- result.append(e)
- return result
-
class OrderedSet(collections.MutableSet):
"""A set that preserves the order in which items are added, by first
insertion.
diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py
index 1657ddd..8d5fb85 100644
--- a/mesonbuild/mesonmain.py
+++ b/mesonbuild/mesonmain.py
@@ -24,7 +24,7 @@ from .mesonlib import MesonException
from .wrap import WrapMode, wraptool
-parser = argparse.ArgumentParser()
+parser = argparse.ArgumentParser(prog='meson')
default_warning = '1'
@@ -37,7 +37,12 @@ def add_builtin_argument(name, **kwargs):
h = h.rstrip('.') + ' (default: %s).' % coredata.get_builtin_option_default(k)
if c and not b:
kwargs['choices'] = c
- parser.add_argument('--' + name, default=coredata.get_builtin_option_default(k), help=h, **kwargs)
+ default = coredata.get_builtin_option_default(k, noneIfSuppress=True)
+ if default is not None:
+ kwargs['default'] = default
+ else:
+ kwargs['default'] = argparse.SUPPRESS
+ parser.add_argument('--' + name, help=h, **kwargs)
add_builtin_argument('prefix')
add_builtin_argument('libdir')
@@ -122,11 +127,11 @@ class MesonApp:
if os.path.exists(priv_dir):
if not handshake:
print('Directory already configured, exiting Meson. Just run your build command\n'
- '(e.g. ninja) and Meson will regenerate as necessary. If ninja fails, run ninja\n'
- 'reconfigure to force Meson to regenerate.\n'
- '\nIf build failures persist, manually wipe your build directory to clear any\n'
- 'stored system data.\n'
- '\nTo change option values, run meson configure instead.')
+ '(e.g. ninja) and Meson will regenerate as necessary. If ninja fails, run ninja\n'
+ 'reconfigure to force Meson to regenerate.\n'
+ '\nIf build failures persist, manually wipe your build directory to clear any\n'
+ 'stored system data.\n'
+ '\nTo change option values, run meson configure instead.')
sys.exit(0)
else:
if handshake:
@@ -193,23 +198,19 @@ class MesonApp:
mlog.log('Build machine cpu family:', mlog.bold(intr.builtin['build_machine'].cpu_family_method([], {})))
mlog.log('Build machine cpu:', mlog.bold(intr.builtin['build_machine'].cpu_method([], {})))
intr.run()
- coredata_mtime = time.time()
- g.generate(intr)
- dumpfile = os.path.join(env.get_scratch_dir(), 'build.dat')
- with open(dumpfile, 'wb') as f:
- pickle.dump(b, f)
- # Write this as late as possible since we use the existence of this
- # file to check if we generated the build file successfully, so we
- # don't want an error that pops up during generation, etc to cause us to
- # incorrectly signal a successful meson run which will cause an error
- # about an already-configured build directory when the user tries again.
- #
- # However, we set the mtime to an earlier value to ensure that doing an
- # mtime comparison between the coredata dump and other build files
- # shows the build files to be newer, not older.
- cdf = env.dump_coredata(coredata_mtime)
- # Post-conf scripts must be run after writing coredata or else introspection fails.
try:
+ # 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
+ # to various kernel caches, we cannot guarantee that any time in Python is exactly in
+ # sync with the time that gets applied to any files. Thus, we dump this file as late as
+ # 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)
+ # Post-conf scripts must be run after writing coredata or else introspection fails.
g.run_postconf_scripts()
except:
os.unlink(cdf)
diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py
index 7356175..568bdfc 100644
--- a/mesonbuild/mintro.py
+++ b/mesonbuild/mintro.py
@@ -25,7 +25,7 @@ import argparse
import sys, os
import pathlib
-parser = argparse.ArgumentParser()
+parser = argparse.ArgumentParser(prog='meson introspect')
parser.add_argument('--targets', action='store_true', dest='list_targets', default=False,
help='List top level targets.')
parser.add_argument('--installed', action='store_true', dest='list_installed', default=False,
@@ -104,6 +104,7 @@ def list_targets(coredata, builddata, installdata):
t['install_filename'] = determine_installed_path(target, installdata)
else:
t['installed'] = False
+ t['build_by_default'] = target.build_by_default
tlist.append(t)
print(json.dumps(tlist))
diff --git a/mesonbuild/modules/__init__.py b/mesonbuild/modules/__init__.py
index 8b5b210..bf513fd 100644
--- a/mesonbuild/modules/__init__.py
+++ b/mesonbuild/modules/__init__.py
@@ -4,7 +4,6 @@ from .. import build
from .. import dependencies
from .. import mlog
from ..mesonlib import MesonException
-from ..interpreterbase import permittedKwargs, noKwargs
class permittedSnippetKwargs:
@@ -79,21 +78,21 @@ class ModuleReturnValue:
self.new_objects = new_objects
class GResourceTarget(build.CustomTarget):
- def __init__(self, name, subdir, kwargs):
- super().__init__(name, subdir, kwargs)
+ def __init__(self, name, subdir, subproject, kwargs):
+ super().__init__(name, subdir, subproject, kwargs)
class GResourceHeaderTarget(build.CustomTarget):
- def __init__(self, name, subdir, kwargs):
- super().__init__(name, subdir, kwargs)
+ def __init__(self, name, subdir, subproject, kwargs):
+ super().__init__(name, subdir, subproject, kwargs)
class GirTarget(build.CustomTarget):
- def __init__(self, name, subdir, kwargs):
- super().__init__(name, subdir, kwargs)
+ def __init__(self, name, subdir, subproject, kwargs):
+ super().__init__(name, subdir, subproject, kwargs)
class TypelibTarget(build.CustomTarget):
- def __init__(self, name, subdir, kwargs):
- super().__init__(name, subdir, kwargs)
+ def __init__(self, name, subdir, subproject, kwargs):
+ super().__init__(name, subdir, subproject, kwargs)
class VapiTarget(build.CustomTarget):
- def __init__(self, name, subdir, kwargs):
- super().__init__(name, subdir, kwargs)
+ def __init__(self, name, subdir, subproject, kwargs):
+ super().__init__(name, subdir, subproject, kwargs)
diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py
index fcdd193..7e61242 100644
--- a/mesonbuild/modules/gnome.py
+++ b/mesonbuild/modules/gnome.py
@@ -17,11 +17,10 @@ functionality such as gobject-introspection, gresources and gtk-doc'''
from .. import build
import os
-import sys
import copy
import subprocess
from . import ModuleReturnValue
-from ..mesonlib import MesonException, OrderedSet, Popen_safe
+from ..mesonlib import MesonException, OrderedSet, Popen_safe, extract_as_list
from ..dependencies import Dependency, PkgConfigDependency, InternalDependency
from .. import mlog
from .. import mesonlib
@@ -30,7 +29,7 @@ from .. import interpreter
from . import GResourceTarget, GResourceHeaderTarget, GirTarget, TypelibTarget, VapiTarget
from . import find_program, get_include_args
from . import ExtensionModule
-from . import noKwargs, permittedKwargs
+from ..interpreterbase import noKwargs, permittedKwargs
# gresource compilation is broken due to the way
# the resource compiler and Ninja clash about it
@@ -98,27 +97,22 @@ class GnomeModule(ExtensionModule):
cmd = ['glib-compile-resources', '@INPUT@']
- source_dirs = kwargs.pop('source_dir', [])
- if not isinstance(source_dirs, list):
- source_dirs = [source_dirs]
+ source_dirs, dependencies = mesonlib.extract_as_list(kwargs, 'source_dir', 'dependencies', pop=True)
if len(args) < 2:
raise MesonException('Not enough arguments; the name of the resource '
'and the path to the XML file are required')
- dependencies = kwargs.pop('dependencies', [])
- if not isinstance(dependencies, list):
- dependencies = [dependencies]
# Validate dependencies
for (ii, dep) in enumerate(dependencies):
if hasattr(dep, 'held_object'):
dependencies[ii] = dep = dep.held_object
- if not isinstance(dep, (mesonlib.File, build.CustomTarget)):
+ if not isinstance(dep, (mesonlib.File, build.CustomTarget, build.CustomTargetIndex)):
m = 'Unexpected dependency type {!r} for gnome.compile_resources() ' \
'"dependencies" argument.\nPlease pass the return value of ' \
'custom_target() or configure_file()'
raise MesonException(m.format(dep))
- if isinstance(dep, build.CustomTarget):
+ if isinstance(dep, (build.CustomTarget, build.CustomTargetIndex)):
if not mesonlib.version_compare(glib_version, gresource_dep_needed_version):
m = 'The "dependencies" argument of gnome.compile_resources() can not\n' \
'be used with the current version of glib-compile-resources due to\n' \
@@ -137,6 +131,7 @@ class GnomeModule(ExtensionModule):
elif isinstance(ifile, str):
ifile = os.path.join(state.subdir, ifile)
elif isinstance(ifile, (interpreter.CustomTargetHolder,
+ interpreter.CustomTargetIndexHolder,
interpreter.GeneratedObjectsHolder)):
m = 'Resource xml files generated at build-time cannot be used ' \
'with gnome.compile_resources() because we need to scan ' \
@@ -197,7 +192,7 @@ class GnomeModule(ExtensionModule):
depfile = kwargs['output'] + '.d'
kwargs['depfile'] = depfile
kwargs['command'] = copy.copy(cmd) + ['--dependency-file', '@DEPFILE@']
- target_c = GResourceTarget(name, state.subdir, kwargs)
+ target_c = GResourceTarget(name, state.subdir, state.subproject, kwargs)
if gresource: # Only one target for .gresource files
return ModuleReturnValue(target_c, [target_c])
@@ -215,7 +210,7 @@ class GnomeModule(ExtensionModule):
h_kwargs['install'] = install_header
h_kwargs['install_dir'] = kwargs.get('install_dir',
state.environment.coredata.get_builtin_option('includedir'))
- target_h = GResourceHeaderTarget(args[0] + '_h', state.subdir, h_kwargs)
+ target_h = GResourceHeaderTarget(args[0] + '_h', state.subdir, state.subproject, h_kwargs)
rv = [target_c, target_h]
return ModuleReturnValue(rv, rv)
@@ -267,7 +262,7 @@ class GnomeModule(ExtensionModule):
dep_files.append(dep)
subdirs.append(dep.subdir)
break
- elif isinstance(dep, build.CustomTarget):
+ elif isinstance(dep, (build.CustomTarget, build.CustomTargetIndex)):
fname = None
outputs = {(o, os.path.basename(o)) for o in dep.get_outputs()}
for o, baseo in outputs:
@@ -328,12 +323,9 @@ class GnomeModule(ExtensionModule):
cflags = OrderedSet()
ldflags = OrderedSet()
gi_includes = OrderedSet()
- if not isinstance(deps, list):
- deps = [deps]
+ deps = mesonlib.listify(deps, unholder=True)
for dep in deps:
- if hasattr(dep, 'held_object'):
- dep = dep.held_object
if isinstance(dep, InternalDependency):
cflags.update(get_include_args(dep.include_directories))
for lib in dep.libraries:
@@ -384,7 +376,7 @@ class GnomeModule(ExtensionModule):
elif isinstance(dep, (build.StaticLibrary, build.SharedLibrary)):
cflags.update(get_include_args(dep.get_include_dirs()))
else:
- mlog.log('dependency %s not handled to build gir files' % dep)
+ mlog.log('dependency {!r} not handled to build gir files'.format(dep))
continue
if gir_has_extra_lib_arg() and use_gir_args:
@@ -400,7 +392,7 @@ class GnomeModule(ExtensionModule):
@permittedKwargs({'sources', 'nsversion', 'namespace', 'symbol_prefix', 'identifier_prefix',
'export_packages', 'includes', 'dependencies', 'link_with', 'include_directories',
'install', 'install_dir_gir', 'install_dir_typelib', 'extra_args',
- 'packages', 'build_by_default'})
+ 'packages', 'header', 'build_by_default'})
def generate_gir(self, state, args, kwargs):
if len(args) != 1:
raise MesonException('Gir takes one argument')
@@ -423,7 +415,7 @@ class GnomeModule(ExtensionModule):
raise MesonException('gobject-introspection dependency was not found, gir cannot be generated.')
ns = kwargs.pop('namespace')
nsversion = kwargs.pop('nsversion')
- libsources = mesonlib.flatten(kwargs.pop('sources'))
+ libsources = mesonlib.extract_as_list(kwargs, 'sources', pop=True)
girfile = '%s-%s.gir' % (ns, nsversion)
srcdir = os.path.join(state.environment.get_source_dir(), state.subdir)
builddir = os.path.join(state.environment.get_build_dir(), state.subdir)
@@ -435,6 +427,12 @@ class GnomeModule(ExtensionModule):
scan_command += ['--no-libtool', '--namespace=' + ns, '--nsversion=' + nsversion, '--warn-all',
'--output', '@OUTPUT@']
+ header = kwargs.pop('header', None)
+ if header:
+ if not isinstance(header, str):
+ raise MesonException('header must be a string')
+ scan_command += ['--c-include=' + header]
+
extra_args = mesonlib.stringlistify(kwargs.pop('extra_args', []))
scan_command += extra_args
scan_command += ['-I' + srcdir,
@@ -450,7 +448,7 @@ class GnomeModule(ExtensionModule):
for s in libsources:
if hasattr(s, 'held_object'):
s = s.held_object
- if isinstance(s, build.CustomTarget):
+ if isinstance(s, (build.CustomTarget, build.CustomTargetIndex)):
gir_filelist.write(os.path.join(state.environment.get_build_dir(),
state.backend.get_target_dir(s),
s.get_outputs()[0]) + '\n')
@@ -464,17 +462,14 @@ class GnomeModule(ExtensionModule):
scan_command += ['--filelist=' + gir_filelist_filename]
if 'link_with' in kwargs:
- link_with = kwargs.pop('link_with')
- if not isinstance(link_with, list):
- link_with = [link_with]
+ link_with = mesonlib.extract_as_list(kwargs, 'link_with', pop = True)
+
for link in link_with:
scan_command += self._get_link_args(state, link.held_object, depends,
use_gir_args=True)
if 'includes' in kwargs:
- includes = kwargs.pop('includes')
- if not isinstance(includes, list):
- includes = [includes]
+ includes = mesonlib.extract_as_list(kwargs, 'includes', pop = True)
for inc in includes:
if hasattr(inc, 'held_object'):
inc = inc.held_object
@@ -515,17 +510,15 @@ class GnomeModule(ExtensionModule):
# FIXME: Linking directly to libasan is not recommended but g-ir-scanner
# does not understand -f LDFLAGS. https://bugzilla.gnome.org/show_bug.cgi?id=783892
# ldflags += compilers.sanitizer_link_args(sanitize)
- if kwargs.get('symbol_prefix'):
- sym_prefix = kwargs.pop('symbol_prefix')
- if not isinstance(sym_prefix, str):
- raise MesonException('Gir symbol prefix must be str')
- scan_command += ['--symbol-prefix=%s' % sym_prefix]
- if kwargs.get('identifier_prefix'):
+ if 'symbol_prefix' in kwargs:
+ sym_prefixes = mesonlib.stringlistify(kwargs.pop('symbol_prefix', []))
+ scan_command += ['--symbol-prefix=%s' % sym_prefix for sym_prefix in sym_prefixes]
+ if 'identifier_prefix' in kwargs:
identifier_prefix = kwargs.pop('identifier_prefix')
if not isinstance(identifier_prefix, str):
raise MesonException('Gir identifier prefix must be str')
scan_command += ['--identifier-prefix=%s' % identifier_prefix]
- if kwargs.get('export_packages'):
+ if 'export_packages' in kwargs:
pkgs = kwargs.pop('export_packages')
if isinstance(pkgs, str):
scan_command += ['--pkg-export=%s' % pkgs]
@@ -534,11 +527,8 @@ class GnomeModule(ExtensionModule):
else:
raise MesonException('Gir export packages must be str or list')
- deps = kwargs.pop('dependencies', [])
- if not isinstance(deps, list):
- deps = [deps]
deps = (girtarget.get_all_link_deps() + girtarget.get_external_deps() +
- deps)
+ extract_as_list(kwargs, 'dependencies', pop=True, unholder=True))
# Need to recursively add deps on GirTarget sources from our
# dependencies and also find the include directories needed for the
# typelib generation custom target below.
@@ -593,9 +583,7 @@ class GnomeModule(ExtensionModule):
for i in gi_includes:
scan_command += ['--add-include-path=%s' % i]
- inc_dirs = kwargs.pop('include_directories', [])
- if not isinstance(inc_dirs, list):
- inc_dirs = [inc_dirs]
+ inc_dirs = mesonlib.extract_as_list(kwargs, 'include_directories', pop = True)
for incd in inc_dirs:
if not isinstance(incd.held_object, (str, build.IncludeDirs)):
raise MesonException(
@@ -618,13 +606,13 @@ class GnomeModule(ExtensionModule):
scankwargs = {'output': girfile,
'command': scan_command,
'depends': depends}
- if kwargs.get('install'):
+ if 'install' in kwargs:
scankwargs['install'] = kwargs['install']
scankwargs['install_dir'] = kwargs.get('install_dir_gir',
os.path.join(state.environment.get_datadir(), 'gir-1.0'))
if 'build_by_default' in kwargs:
scankwargs['build_by_default'] = kwargs['build_by_default']
- scan_target = GirTarget(girfile, state.subdir, scankwargs)
+ scan_target = GirTarget(girfile, state.subdir, state.subproject, scankwargs)
typelib_output = '%s-%s.typelib' % (ns, nsversion)
typelib_cmd = [gicompiler, scan_target, '--output', '@OUTPUT@']
@@ -636,13 +624,13 @@ class GnomeModule(ExtensionModule):
'output': typelib_output,
'command': typelib_cmd,
}
- if kwargs.get('install'):
+ if 'install' in kwargs:
typelib_kwargs['install'] = kwargs['install']
typelib_kwargs['install_dir'] = kwargs.get('install_dir_typelib',
os.path.join(state.environment.get_libdir(), 'girepository-1.0'))
if 'build_by_default' in kwargs:
typelib_kwargs['build_by_default'] = kwargs['build_by_default']
- typelib_target = TypelibTarget(typelib_output, state.subdir, typelib_kwargs)
+ typelib_target = TypelibTarget(typelib_output, state.subdir, state.subproject, typelib_kwargs)
rv = [scan_target, typelib_target]
return ModuleReturnValue(rv, rv)
@@ -661,8 +649,8 @@ class GnomeModule(ExtensionModule):
if state.subdir == '':
targetname = 'gsettings-compile'
else:
- targetname = 'gsettings-compile-' + state.subdir
- target_g = build.CustomTarget(targetname, state.subdir, kwargs)
+ targetname = 'gsettings-compile-' + state.subdir.replace('/', '_')
+ target_g = build.CustomTarget(targetname, state.subdir, state.subproject, kwargs)
return ModuleReturnValue(target_g, [target_g])
@permittedKwargs({'sources', 'media', 'symlink_media', 'languages'})
@@ -710,20 +698,24 @@ This will become a hard error in the future.''')
args.append('--langs=' + '@@'.join(langs))
inscript = build.RunScript(script, args)
- potargs = state.environment.get_build_command() + ['--internal', 'yelphelper', 'pot',
- '--subdir=' + state.subdir,
- '--id=' + project_id,
- '--sources=' + source_str]
+ potargs = state.environment.get_build_command() + [
+ '--internal', 'yelphelper', 'pot',
+ '--subdir=' + state.subdir,
+ '--id=' + project_id,
+ '--sources=' + source_str,
+ ]
pottarget = build.RunTarget('help-' + project_id + '-pot', potargs[0],
- potargs[1:], [], state.subdir)
-
- poargs = state.environment.get_build_command() + ['--internal', 'yelphelper', 'update-po',
- '--subdir=' + state.subdir,
- '--id=' + project_id,
- '--sources=' + source_str,
- '--langs=' + '@@'.join(langs)]
+ potargs[1:], [], state.subdir, state.subproject)
+
+ poargs = state.environment.get_build_command() + [
+ '--internal', 'yelphelper', 'update-po',
+ '--subdir=' + state.subdir,
+ '--id=' + project_id,
+ '--sources=' + source_str,
+ '--langs=' + '@@'.join(langs),
+ ]
potarget = build.RunTarget('help-' + project_id + '-update-po', poargs[0],
- poargs[1:], [], state.subdir)
+ poargs[1:], [], state.subdir, state.subproject)
rv = [inscript, pottarget, potarget]
return ModuleReturnValue(None, rv)
@@ -731,7 +723,7 @@ This will become a hard error in the future.''')
@permittedKwargs({'main_xml', 'main_sgml', 'src_dir', 'dependencies', 'install',
'install_dir', 'scan_args', 'scanobjs_args', 'gobject_typesfile',
'fixxref_args', 'html_args', 'html_assets', 'content_files',
- 'mkdb_args', 'ignore_headers'})
+ 'mkdb_args', 'ignore_headers', 'include_directories'})
def gtkdoc(self, state, args, kwargs):
if len(args) != 1:
raise MesonException('Gtkdoc must have one positional argument.')
@@ -759,9 +751,7 @@ This will become a hard error in the future.''')
if mode not in VALID_MODES:
raise MesonException('gtkdoc: Mode {} is not a valid mode: {}'.format(mode, VALID_MODES))
- src_dirs = kwargs['src_dir']
- if not isinstance(src_dirs, list):
- src_dirs = [src_dirs]
+ src_dirs = mesonlib.extract_as_list(kwargs, 'src_dir')
header_dirs = []
for src_dir in src_dirs:
if hasattr(src_dir, 'held_object'):
@@ -798,17 +788,16 @@ This will become a hard error in the future.''')
args += self._unpack_args('--ignore-headers=', 'ignore_headers', kwargs)
args += self._unpack_args('--installdir=', 'install_dir', kwargs, state)
args += self._get_build_args(kwargs, state)
- res = [build.RunTarget(targetname, command[0], command[1:] + args, [], state.subdir)]
+ res = [build.RunTarget(targetname, command[0], command[1:] + args, [], state.subdir, state.subproject)]
if kwargs.get('install', True):
res.append(build.RunScript(command, args))
return ModuleReturnValue(None, res)
def _get_build_args(self, kwargs, state):
args = []
- cflags, ldflags, gi_includes = self._get_dependencies_flags(kwargs.get('dependencies', []), state, include_rpath=True)
- inc_dirs = kwargs.get('include_directories', [])
- if not isinstance(inc_dirs, list):
- inc_dirs = [inc_dirs]
+ deps = extract_as_list(kwargs, 'dependencies', unholder=True)
+ cflags, ldflags, gi_includes = self._get_dependencies_flags(deps, state, include_rpath=True)
+ inc_dirs = mesonlib.extract_as_list(kwargs, 'include_directories')
for incd in inc_dirs:
if not isinstance(incd.held_object, (str, build.IncludeDirs)):
raise MesonException(
@@ -839,13 +828,11 @@ This will become a hard error in the future.''')
if kwarg_name not in kwargs:
return []
- new_args = kwargs[kwarg_name]
- if not isinstance(new_args, list):
- new_args = [new_args]
+ new_args = mesonlib.extract_as_list(kwargs, kwarg_name)
args = []
for i in new_args:
if expend_file_state and isinstance(i, mesonlib.File):
- i = os.path.join(expend_file_state.environment.get_build_dir(), i.subdir, i.fname)
+ i = i.absolute_path(expend_file_state.environment.get_source_dir(), expend_file_state.environment.get_build_dir())
elif not isinstance(i, str):
raise MesonException(kwarg_name + ' values must be strings.')
args.append(i)
@@ -898,7 +885,7 @@ This will become a hard error in the future.''')
}
if 'build_by_default' in kwargs:
custom_kwargs['build_by_default'] = kwargs['build_by_default']
- ct = build.CustomTarget(target_name, state.subdir, custom_kwargs)
+ ct = build.CustomTarget(target_name, state.subdir, state.subproject, custom_kwargs)
return ModuleReturnValue(ct, [ct])
@permittedKwargs({'sources', 'c_template', 'h_template', 'install_header', 'install_dir',
@@ -1114,7 +1101,7 @@ G_END_DECLS'''
'command': cmd
}
custom_kwargs.update(kwargs)
- return build.CustomTarget(output, state.subdir, custom_kwargs,
+ return build.CustomTarget(output, state.subdir, state.subproject, custom_kwargs,
# https://github.com/mesonbuild/meson/issues/973
absolute_paths=True)
@@ -1184,7 +1171,7 @@ G_END_DECLS'''
# Silence any warnings about missing prototypes
custom_kwargs['command'] += ['--include-header', header_file]
custom_kwargs['output'] = output + '.c'
- body = build.CustomTarget(output + '_c', state.subdir, custom_kwargs)
+ body = build.CustomTarget(output + '_c', state.subdir, state.subproject, custom_kwargs)
custom_kwargs['install'] = install_header
if install_dir is not None:
@@ -1193,19 +1180,15 @@ G_END_DECLS'''
cmd += ['--pragma-once']
custom_kwargs['command'] = cmd + ['--header', '@INPUT@']
custom_kwargs['output'] = header_file
- header = build.CustomTarget(output + '_h', state.subdir, custom_kwargs)
+ header = build.CustomTarget(output + '_h', state.subdir, state.subproject, custom_kwargs)
rv = [body, header]
return ModuleReturnValue(rv, rv)
@staticmethod
def _vapi_args_to_command(prefix, variable, kwargs, accept_vapi=False):
- arg_list = kwargs.get(variable)
- if not arg_list:
- return []
+ arg_list = mesonlib.extract_as_list(kwargs, variable)
ret = []
- if not isinstance(arg_list, list):
- arg_list = [arg_list]
for arg in arg_list:
if not isinstance(arg, str):
types = 'strings' + ' or InternalDependencys' if accept_vapi else ''
@@ -1224,9 +1207,7 @@ G_END_DECLS'''
arg_list = kwargs.get('packages')
if not arg_list:
return [], [], [], []
- if not isinstance(arg_list, list):
- arg_list = [arg_list]
-
+ arg_list = mesonlib.listify(arg_list)
vapi_depends = []
vapi_packages = []
vapi_includes = []
@@ -1300,12 +1281,10 @@ G_END_DECLS'''
cmd += pkg_cmd
cmd += ['--metadatadir=' + source_dir]
- inputs = kwargs.get('sources')
- if not inputs:
+ if 'sources' not in kwargs:
raise MesonException('sources are required to generate the vapi file')
- if not isinstance(inputs, list):
- inputs = [inputs]
+ inputs = mesonlib.extract_as_list(kwargs, 'sources')
link_with = []
for i in inputs:
@@ -1337,7 +1316,7 @@ G_END_DECLS'''
# We shouldn't need this locally but we install it
deps_target = self._generate_deps(state, library, vapi_packages, install_dir)
created_values.append(deps_target)
- vapi_target = VapiTarget(vapi_output, state.subdir, custom_kwargs)
+ vapi_target = VapiTarget(vapi_output, state.subdir, state.subproject, custom_kwargs)
# So to try our best to get this to just work we need:
# - link with with the correct library
diff --git a/mesonbuild/modules/i18n.py b/mesonbuild/modules/i18n.py
index 2af09de..6c02fbb 100644
--- a/mesonbuild/modules/i18n.py
+++ b/mesonbuild/modules/i18n.py
@@ -12,7 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import sys
import shutil
from os import path
@@ -20,7 +19,7 @@ from .. import coredata, mesonlib, build
from ..mesonlib import MesonException
from . import ModuleReturnValue
from . import ExtensionModule
-from . import permittedKwargs
+from ..interpreterbase import permittedKwargs
PRESET_ARGS = {
'glib': [
@@ -72,16 +71,18 @@ class I18nModule(ExtensionModule):
datadirs = self._get_data_dirs(state, mesonlib.stringlistify(kwargs.pop('data_dirs', [])))
datadirs = '--datadirs=' + ':'.join(datadirs) if datadirs else None
- command = state.environment.get_build_command() + ['--internal', 'msgfmthelper',
- '@INPUT@', '@OUTPUT@', file_type, podir]
+ command = state.environment.get_build_command() + [
+ '--internal', 'msgfmthelper',
+ '@INPUT@', '@OUTPUT@', file_type, podir
+ ]
if datadirs:
command.append(datadirs)
kwargs['command'] = command
- ct = build.CustomTarget(kwargs['output'] + '_merge', state.subdir, kwargs)
+ ct = build.CustomTarget(kwargs['output'] + '_merge', state.subdir, state.subproject, kwargs)
return ModuleReturnValue(ct, [ct])
- @permittedKwargs({'po_dir', 'data_dirs', 'type', 'languages', 'args', 'preset'})
+ @permittedKwargs({'po_dir', 'data_dirs', 'type', 'languages', 'args', 'preset', 'install'})
def gettext(self, state, args, kwargs):
if len(args) != 1:
raise coredata.MesonException('Gettext requires one positional argument (package name).')
@@ -110,12 +111,12 @@ class I18nModule(ExtensionModule):
potargs.append(datadirs)
if extra_args:
potargs.append(extra_args)
- pottarget = build.RunTarget(packagename + '-pot', potargs[0], potargs[1:], [], state.subdir)
+ pottarget = build.RunTarget(packagename + '-pot', potargs[0], potargs[1:], [], state.subdir, state.subproject)
gmoargs = state.environment.get_build_command() + ['--internal', 'gettext', 'gen_gmo']
if lang_arg:
gmoargs.append(lang_arg)
- gmotarget = build.RunTarget(packagename + '-gmo', gmoargs[0], gmoargs[1:], [], state.subdir)
+ gmotarget = build.RunTarget(packagename + '-gmo', gmoargs[0], gmoargs[1:], [], state.subdir, state.subproject)
updatepoargs = state.environment.get_build_command() + ['--internal', 'gettext', 'update_po', pkg_arg]
if lang_arg:
@@ -124,18 +125,23 @@ class I18nModule(ExtensionModule):
updatepoargs.append(datadirs)
if extra_args:
updatepoargs.append(extra_args)
- updatepotarget = build.RunTarget(packagename + '-update-po', updatepoargs[0], updatepoargs[1:], [], state.subdir)
-
- script = state.environment.get_build_command()
- args = ['--internal', 'gettext', 'install',
- '--subdir=' + state.subdir,
- '--localedir=' + state.environment.coredata.get_builtin_option('localedir'),
- pkg_arg]
- if lang_arg:
- args.append(lang_arg)
- iscript = build.RunScript(script, args)
-
- return ModuleReturnValue(None, [pottarget, gmotarget, iscript, updatepotarget])
+ updatepotarget = build.RunTarget(packagename + '-update-po', updatepoargs[0], updatepoargs[1:], [], state.subdir, state.subproject)
+
+ targets = [pottarget, gmotarget, updatepotarget]
+
+ install = kwargs.get('install', True)
+ if install:
+ script = state.environment.get_build_command()
+ args = ['--internal', 'gettext', 'install',
+ '--subdir=' + state.subdir,
+ '--localedir=' + state.environment.coredata.get_builtin_option('localedir'),
+ pkg_arg]
+ if lang_arg:
+ args.append(lang_arg)
+ iscript = build.RunScript(script, args)
+ targets.append(iscript)
+
+ return ModuleReturnValue(None, targets)
def initialize():
return I18nModule()
diff --git a/mesonbuild/modules/modtest.py b/mesonbuild/modules/modtest.py
index dd2f215..758eeae 100644
--- a/mesonbuild/modules/modtest.py
+++ b/mesonbuild/modules/modtest.py
@@ -14,7 +14,7 @@
from . import ModuleReturnValue
from . import ExtensionModule
-from . import noKwargs
+from ..interpreterbase import noKwargs
class TestModule(ExtensionModule):
diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py
index 0a0498c..8383a3a 100644
--- a/mesonbuild/modules/pkgconfig.py
+++ b/mesonbuild/modules/pkgconfig.py
@@ -19,7 +19,7 @@ from .. import mesonlib
from .. import mlog
from . import ModuleReturnValue
from . import ExtensionModule
-from . import permittedKwargs
+from ..interpreterbase import permittedKwargs
class PkgConfigModule(ExtensionModule):
@@ -80,9 +80,11 @@ class PkgConfigModule(ExtensionModule):
yield l
else:
install_dir = l.get_custom_install_dir()[0]
- if install_dir:
+ if install_dir is False:
+ continue
+ if isinstance(install_dir, str):
yield '-L${prefix}/%s ' % install_dir
- else:
+ else: # install_dir is True
yield '-L${libdir}'
lname = self._get_lname(l, msg, pcfile)
# If using a custom suffix, the compiler may not be able to
@@ -108,8 +110,7 @@ class PkgConfigModule(ExtensionModule):
ofile.write('\n')
def process_libs(self, libs):
- if not isinstance(libs, list):
- libs = [libs]
+ libs = mesonlib.listify(libs)
processed_libs = []
for l in libs:
if hasattr(l, 'held_object'):
@@ -121,7 +122,7 @@ class PkgConfigModule(ExtensionModule):
@permittedKwargs({'libraries', 'version', 'name', 'description', 'filebase',
'subdirs', 'requires', 'requires_private', 'libraries_private',
- 'install_dir', 'extra_cflags', 'variables', 'url'})
+ 'install_dir', 'extra_cflags', 'variables', 'url', 'd_module_versions'})
def generate(self, state, args, kwargs):
if len(args) > 0:
raise mesonlib.MesonException('Pkgconfig_gen takes no positional arguments.')
@@ -148,6 +149,12 @@ class PkgConfigModule(ExtensionModule):
conflicts = mesonlib.stringlistify(kwargs.get('conflicts', []))
extra_cflags = mesonlib.stringlistify(kwargs.get('extra_cflags', []))
+ dversions = kwargs.get('d_module_versions', None)
+ if dversions:
+ compiler = state.environment.coredata.compilers.get('d')
+ if compiler:
+ extra_cflags.extend(compiler.get_feature_args({'versions': dversions}))
+
def parse_variable_list(stringlist):
reserved = ['prefix', 'libdir', 'includedir']
variables = []
diff --git a/mesonbuild/modules/python3.py b/mesonbuild/modules/python3.py
index 94db75c..4fae88b 100644
--- a/mesonbuild/modules/python3.py
+++ b/mesonbuild/modules/python3.py
@@ -18,7 +18,8 @@ from .. import mesonlib, dependencies
from . import ExtensionModule
from mesonbuild.modules import ModuleReturnValue
-from . import noKwargs, permittedSnippetKwargs
+from . import permittedSnippetKwargs
+from ..interpreterbase import noKwargs
from ..interpreter import shlib_kwargs
mod_kwargs = set()
diff --git a/mesonbuild/modules/qt.py b/mesonbuild/modules/qt.py
new file mode 100644
index 0000000..285169b
--- /dev/null
+++ b/mesonbuild/modules/qt.py
@@ -0,0 +1,146 @@
+# Copyright 2015 The Meson development team
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+from .. import mlog
+from .. import build
+from ..mesonlib import MesonException, Popen_safe, extract_as_list
+from ..dependencies import Qt4Dependency, Qt5Dependency
+import xml.etree.ElementTree as ET
+from . import ModuleReturnValue, get_include_args
+from ..interpreterbase import permittedKwargs
+
+_QT_DEPS_LUT = {
+ 4: Qt4Dependency,
+ 5: Qt5Dependency
+}
+
+
+class QtBaseModule:
+ tools_detected = False
+
+ def __init__(self, qt_version=5):
+ self.qt_version = qt_version
+
+ def _detect_tools(self, env, method):
+ if self.tools_detected:
+ return
+ mlog.log('Detecting Qt{version} tools'.format(version=self.qt_version))
+ # FIXME: We currently require QtX to exist while importing the module.
+ # We should make it gracefully degrade and not create any targets if
+ # the import is marked as 'optional' (not implemented yet)
+ kwargs = {'required': 'true', 'modules': 'Core', 'silent': 'true', 'method': method}
+ qt = _QT_DEPS_LUT[self.qt_version](env, kwargs)
+ # Get all tools and then make sure that they are the right version
+ self.moc, self.uic, self.rcc = qt.compilers_detect()
+ # Moc, uic and rcc write their version strings to stderr.
+ # Moc and rcc return a non-zero result when doing so.
+ # What kind of an idiot thought that was a good idea?
+ for compiler, compiler_name in ((self.moc, "Moc"), (self.uic, "Uic"), (self.rcc, "Rcc")):
+ if compiler.found():
+ stdout, stderr = Popen_safe(compiler.get_command() + ['-v'])[1:3]
+ stdout = stdout.strip()
+ stderr = stderr.strip()
+ if 'Qt {}'.format(self.qt_version) in stderr:
+ compiler_ver = stderr
+ elif 'version {}.'.format(self.qt_version) in stderr:
+ compiler_ver = stderr
+ elif ' {}.'.format(self.qt_version) in stdout:
+ compiler_ver = stdout
+ else:
+ raise MesonException('{name} preprocessor is not for Qt {version}. Output:\n{stdo}\n{stderr}'.format(
+ name=compiler_name, version=self.qt_version, stdo=stdout, stderr=stderr))
+ mlog.log(' {}:'.format(compiler_name.lower()), mlog.green('YES'), '({path}, {version})'.format(
+ path=self.moc.get_path(), version=compiler_ver.split()[-1]))
+ else:
+ mlog.log(' {}:'.format(compiler_name.lower()), mlog.red('NO'))
+ self.tools_detected = True
+
+ def parse_qrc(self, state, fname):
+ abspath = os.path.join(state.environment.source_dir, state.subdir, fname)
+ relative_part = os.path.split(fname)[0]
+ try:
+ tree = ET.parse(abspath)
+ root = tree.getroot()
+ result = []
+ for child in root[0]:
+ if child.tag != 'file':
+ mlog.warning("malformed rcc file: ", os.path.join(state.subdir, fname))
+ break
+ else:
+ result.append(os.path.join(state.subdir, relative_part, child.text))
+ return result
+ except Exception:
+ return []
+
+ @permittedKwargs({'moc_headers', 'moc_sources', 'moc_extra_arguments', 'include_directories', 'ui_files', 'qresources', 'method'})
+ def preprocess(self, state, args, kwargs):
+ rcc_files, ui_files, moc_headers, moc_sources, moc_extra_arguments, sources, include_directories \
+ = extract_as_list(kwargs, 'qresources', 'ui_files', 'moc_headers', 'moc_sources', 'moc_extra_arguments', 'sources', 'include_directories', pop = True)
+ sources += args[1:]
+ method = kwargs.get('method', 'auto')
+ self._detect_tools(state.environment, method)
+ err_msg = "{0} sources specified and couldn't find {1}, " \
+ "please check your qt{2} installation"
+ if len(moc_headers) + len(moc_sources) > 0 and not self.moc.found():
+ raise MesonException(err_msg.format('MOC', 'moc-qt{}'.format(self.qt_version), self.qt_version))
+ if len(rcc_files) > 0:
+ if not self.rcc.found():
+ raise MesonException(err_msg.format('RCC', 'rcc-qt{}'.format(self.qt_version), self.qt_version))
+ qrc_deps = []
+ for i in rcc_files:
+ qrc_deps += self.parse_qrc(state, i)
+ # custom output name set? -> one output file, multiple otherwise
+ if len(args) > 0:
+ name = args[0]
+ rcc_kwargs = {'input': rcc_files,
+ 'output': name + '.cpp',
+ 'command': [self.rcc, '-name', name, '-o', '@OUTPUT@', '@INPUT@'],
+ 'depend_files': qrc_deps}
+ res_target = build.CustomTarget(name, state.subdir, state.subproject, rcc_kwargs)
+ sources.append(res_target)
+ else:
+ for rcc_file in rcc_files:
+ basename = os.path.split(rcc_file)[1]
+ name = 'qt' + str(self.qt_version) + '-' + basename.replace('.', '_')
+ rcc_kwargs = {'input': rcc_file,
+ 'output': name + '.cpp',
+ 'command': [self.rcc, '-name', '@BASENAME@', '-o', '@OUTPUT@', '@INPUT@'],
+ 'depend_files': qrc_deps}
+ res_target = build.CustomTarget(name, state.subdir, state.subproject, rcc_kwargs)
+ sources.append(res_target)
+ if len(ui_files) > 0:
+ if not self.uic.found():
+ raise MesonException(err_msg.format('UIC', 'uic-qt' + self.qt_version))
+ ui_kwargs = {'output': 'ui_@BASENAME@.h',
+ 'arguments': ['-o', '@OUTPUT@', '@INPUT@']}
+ ui_gen = build.Generator([self.uic], ui_kwargs)
+ ui_output = ui_gen.process_files('Qt{} ui'.format(self.qt_version), ui_files, state)
+ sources.append(ui_output)
+ inc = get_include_args(include_dirs=include_directories)
+ if len(moc_headers) > 0:
+ arguments = moc_extra_arguments + inc + ['@INPUT@', '-o', '@OUTPUT@']
+ moc_kwargs = {'output': 'moc_@BASENAME@.cpp',
+ 'arguments': arguments}
+ moc_gen = build.Generator([self.moc], moc_kwargs)
+ moc_output = moc_gen.process_files('Qt{} moc header'.format(self.qt_version), moc_headers, state)
+ sources.append(moc_output)
+ if len(moc_sources) > 0:
+ arguments = moc_extra_arguments + ['@INPUT@', '-o', '@OUTPUT@']
+ moc_kwargs = {'output': '@BASENAME@.moc',
+ 'arguments': arguments}
+ moc_gen = build.Generator([self.moc], moc_kwargs)
+ moc_output = moc_gen.process_files('Qt{} moc source'.format(self.qt_version), moc_sources, state)
+ sources.append(moc_output)
+ return ModuleReturnValue(sources, sources)
diff --git a/mesonbuild/modules/qt4.py b/mesonbuild/modules/qt4.py
index 4056b6d..3011de7 100644
--- a/mesonbuild/modules/qt4.py
+++ b/mesonbuild/modules/qt4.py
@@ -12,153 +12,16 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import os
from .. import mlog
-from .. import build
-from ..mesonlib import MesonException, Popen_safe
-from ..dependencies import Qt4Dependency
+from .qt import QtBaseModule
from . import ExtensionModule
-import xml.etree.ElementTree as ET
-from . import ModuleReturnValue
-from . import permittedKwargs
-class Qt4Module(ExtensionModule):
- tools_detected = False
- def _detect_tools(self, env, method):
- if self.tools_detected:
- return
- mlog.log('Detecting Qt4 tools')
- # FIXME: We currently require Qt4 to exist while importing the module.
- # We should make it gracefully degrade and not create any targets if
- # the import is marked as 'optional' (not implemented yet)
- kwargs = {'required': 'true', 'modules': 'Core', 'silent': 'true', 'method': method}
- qt4 = Qt4Dependency(env, kwargs)
- # Get all tools and then make sure that they are the right version
- self.moc, self.uic, self.rcc = qt4.compilers_detect()
- # Moc, uic and rcc write their version strings to stderr.
- # Moc and rcc return a non-zero result when doing so.
- # What kind of an idiot thought that was a good idea?
- if self.moc.found():
- stdout, stderr = Popen_safe(self.moc.get_command() + ['-v'])[1:3]
- stdout = stdout.strip()
- stderr = stderr.strip()
- if 'Qt Meta' in stderr:
- moc_ver = stderr
- else:
- raise MesonException('Moc preprocessor is not for Qt 4. Output:\n%s\n%s' %
- (stdout, stderr))
- mlog.log(' moc:', mlog.green('YES'), '(%s, %s)' %
- (self.moc.get_path(), moc_ver.split()[-1]))
- else:
- mlog.log(' moc:', mlog.red('NO'))
- if self.uic.found():
- stdout, stderr = Popen_safe(self.uic.get_command() + ['-v'])[1:3]
- stdout = stdout.strip()
- stderr = stderr.strip()
- if 'version 4.' in stderr:
- uic_ver = stderr
- else:
- raise MesonException('Uic compiler is not for Qt4. Output:\n%s\n%s' %
- (stdout, stderr))
- mlog.log(' uic:', mlog.green('YES'), '(%s, %s)' %
- (self.uic.get_path(), uic_ver.split()[-1]))
- else:
- mlog.log(' uic:', mlog.red('NO'))
- if self.rcc.found():
- stdout, stderr = Popen_safe(self.rcc.get_command() + ['-v'])[1:3]
- stdout = stdout.strip()
- stderr = stderr.strip()
- if 'version 4.' in stderr:
- rcc_ver = stderr
- else:
- raise MesonException('Rcc compiler is not for Qt 4. Output:\n%s\n%s' %
- (stdout, stderr))
- mlog.log(' rcc:', mlog.green('YES'), '(%s, %s)'
- % (self.rcc.get_path(), rcc_ver.split()[-1]))
- else:
- mlog.log(' rcc:', mlog.red('NO'))
- self.tools_detected = True
+class Qt4Module(ExtensionModule, QtBaseModule):
- def parse_qrc(self, state, fname):
- abspath = os.path.join(state.environment.source_dir, state.subdir, fname)
- relative_part = os.path.split(fname)[0]
- try:
- tree = ET.parse(abspath)
- root = tree.getroot()
- result = []
- for child in root[0]:
- if child.tag != 'file':
- mlog.warning("malformed rcc file: ", os.path.join(state.subdir, fname))
- break
- else:
- result.append(os.path.join(state.subdir, relative_part, child.text))
- return result
- except Exception:
- return []
-
- @permittedKwargs({'moc_headers', 'moc_sources', 'ui_files', 'qresources', 'method'})
- def preprocess(self, state, args, kwargs):
- rcc_files = kwargs.pop('qresources', [])
- if not isinstance(rcc_files, list):
- rcc_files = [rcc_files]
- ui_files = kwargs.pop('ui_files', [])
- if not isinstance(ui_files, list):
- ui_files = [ui_files]
- moc_headers = kwargs.pop('moc_headers', [])
- if not isinstance(moc_headers, list):
- moc_headers = [moc_headers]
- moc_sources = kwargs.pop('moc_sources', [])
- if not isinstance(moc_sources, list):
- moc_sources = [moc_sources]
- sources = kwargs.pop('sources', [])
- if not isinstance(sources, list):
- sources = [sources]
- sources += args[1:]
- method = kwargs.get('method', 'auto')
- self._detect_tools(state.environment, method)
- err_msg = "{0} sources specified and couldn't find {1}, " \
- "please check your qt4 installation"
- if len(moc_headers) + len(moc_sources) > 0 and not self.moc.found():
- raise MesonException(err_msg.format('MOC', 'moc-qt4'))
- if len(rcc_files) > 0:
- if not self.rcc.found():
- raise MesonException(err_msg.format('RCC', 'rcc-qt4'))
- qrc_deps = []
- for i in rcc_files:
- qrc_deps += self.parse_qrc(state, i)
- if len(args) > 0:
- name = args[0]
- else:
- basename = os.path.split(rcc_files[0])[1]
- name = 'qt4-' + basename.replace('.', '_')
- rcc_kwargs = {'input': rcc_files,
- 'output': name + '.cpp',
- 'command': [self.rcc, '-o', '@OUTPUT@', '@INPUT@'],
- 'depend_files': qrc_deps}
- res_target = build.CustomTarget(name, state.subdir, rcc_kwargs)
- sources.append(res_target)
- if len(ui_files) > 0:
- if not self.uic.found():
- raise MesonException(err_msg.format('UIC', 'uic-qt4'))
- ui_kwargs = {'output': 'ui_@BASENAME@.h',
- 'arguments': ['-o', '@OUTPUT@', '@INPUT@']}
- ui_gen = build.Generator([self.uic], ui_kwargs)
- ui_output = ui_gen.process_files('Qt4 ui', ui_files, state)
- sources.append(ui_output)
- if len(moc_headers) > 0:
- moc_kwargs = {'output': 'moc_@BASENAME@.cpp',
- 'arguments': ['@INPUT@', '-o', '@OUTPUT@']}
- moc_gen = build.Generator([self.moc], moc_kwargs)
- moc_output = moc_gen.process_files('Qt4 moc header', moc_headers, state)
- sources.append(moc_output)
- if len(moc_sources) > 0:
- moc_kwargs = {'output': '@BASENAME@.moc',
- 'arguments': ['@INPUT@', '-o', '@OUTPUT@']}
- moc_gen = build.Generator([self.moc], moc_kwargs)
- moc_output = moc_gen.process_files('Qt4 moc source', moc_sources, state)
- sources.append(moc_output)
- return ModuleReturnValue(sources, sources)
+ def __init__(self):
+ QtBaseModule.__init__(self, qt_version=4)
+ ExtensionModule.__init__(self)
def initialize():
mlog.warning('rcc dependencies will not work properly until this upstream issue is fixed:',
diff --git a/mesonbuild/modules/qt5.py b/mesonbuild/modules/qt5.py
index 6194a23..7b7acbb 100644
--- a/mesonbuild/modules/qt5.py
+++ b/mesonbuild/modules/qt5.py
@@ -12,159 +12,16 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import os
from .. import mlog
-from .. import build
-from ..mesonlib import MesonException, Popen_safe
-from ..dependencies import Qt5Dependency
+from .qt import QtBaseModule
from . import ExtensionModule
-import xml.etree.ElementTree as ET
-from . import ModuleReturnValue
-from . import permittedKwargs
-class Qt5Module(ExtensionModule):
- tools_detected = False
- def _detect_tools(self, env, method):
- if self.tools_detected:
- return
- mlog.log('Detecting Qt5 tools')
- # FIXME: We currently require Qt5 to exist while importing the module.
- # We should make it gracefully degrade and not create any targets if
- # the import is marked as 'optional' (not implemented yet)
- kwargs = {'required': 'true', 'modules': 'Core', 'silent': 'true', 'method': method}
- qt5 = Qt5Dependency(env, kwargs)
- # Get all tools and then make sure that they are the right version
- self.moc, self.uic, self.rcc = qt5.compilers_detect()
- # Moc, uic and rcc write their version strings to stderr.
- # Moc and rcc return a non-zero result when doing so.
- # What kind of an idiot thought that was a good idea?
- if self.moc.found():
- stdout, stderr = Popen_safe(self.moc.get_command() + ['-v'])[1:3]
- stdout = stdout.strip()
- stderr = stderr.strip()
- if 'Qt 5' in stderr:
- moc_ver = stderr
- elif '5.' in stdout:
- moc_ver = stdout
- else:
- raise MesonException('Moc preprocessor is not for Qt 5. Output:\n%s\n%s' %
- (stdout, stderr))
- mlog.log(' moc:', mlog.green('YES'), '(%s, %s)' %
- (self.moc.get_path(), moc_ver.split()[-1]))
- else:
- mlog.log(' moc:', mlog.red('NO'))
- if self.uic.found():
- stdout, stderr = Popen_safe(self.uic.get_command() + ['-v'])[1:3]
- stdout = stdout.strip()
- stderr = stderr.strip()
- if 'version 5.' in stderr:
- uic_ver = stderr
- elif '5.' in stdout:
- uic_ver = stdout
- else:
- raise MesonException('Uic compiler is not for Qt 5. Output:\n%s\n%s' %
- (stdout, stderr))
- mlog.log(' uic:', mlog.green('YES'), '(%s, %s)' %
- (self.uic.get_path(), uic_ver.split()[-1]))
- else:
- mlog.log(' uic:', mlog.red('NO'))
- if self.rcc.found():
- stdout, stderr = Popen_safe(self.rcc.get_command() + ['-v'])[1:3]
- stdout = stdout.strip()
- stderr = stderr.strip()
- if 'version 5.' in stderr:
- rcc_ver = stderr
- elif '5.' in stdout:
- rcc_ver = stdout
- else:
- raise MesonException('Rcc compiler is not for Qt 5. Output:\n%s\n%s' %
- (stdout, stderr))
- mlog.log(' rcc:', mlog.green('YES'), '(%s, %s)'
- % (self.rcc.get_path(), rcc_ver.split()[-1]))
- else:
- mlog.log(' rcc:', mlog.red('NO'))
- self.tools_detected = True
+class Qt5Module(ExtensionModule, QtBaseModule):
- def parse_qrc(self, state, fname):
- abspath = os.path.join(state.environment.source_dir, state.subdir, fname)
- relative_part = os.path.split(fname)[0]
- try:
- tree = ET.parse(abspath)
- root = tree.getroot()
- result = []
- for child in root[0]:
- if child.tag != 'file':
- mlog.warning("malformed rcc file: ", os.path.join(state.subdir, fname))
- break
- else:
- result.append(os.path.join(state.subdir, relative_part, child.text))
- return result
- except Exception:
- return []
-
- @permittedKwargs({'moc_headers', 'moc_sources', 'ui_files', 'qresources', 'method'})
- def preprocess(self, state, args, kwargs):
- rcc_files = kwargs.pop('qresources', [])
- if not isinstance(rcc_files, list):
- rcc_files = [rcc_files]
- ui_files = kwargs.pop('ui_files', [])
- if not isinstance(ui_files, list):
- ui_files = [ui_files]
- moc_headers = kwargs.pop('moc_headers', [])
- if not isinstance(moc_headers, list):
- moc_headers = [moc_headers]
- moc_sources = kwargs.pop('moc_sources', [])
- if not isinstance(moc_sources, list):
- moc_sources = [moc_sources]
- sources = kwargs.pop('sources', [])
- if not isinstance(sources, list):
- sources = [sources]
- sources += args[1:]
- method = kwargs.get('method', 'auto')
- self._detect_tools(state.environment, method)
- err_msg = "{0} sources specified and couldn't find {1}, " \
- "please check your qt5 installation"
- if len(moc_headers) + len(moc_sources) > 0 and not self.moc.found():
- raise MesonException(err_msg.format('MOC', 'moc-qt5'))
- if len(rcc_files) > 0:
- if not self.rcc.found():
- raise MesonException(err_msg.format('RCC', 'rcc-qt5'))
- qrc_deps = []
- for i in rcc_files:
- qrc_deps += self.parse_qrc(state, i)
- if len(args) > 0:
- name = args[0]
- else:
- basename = os.path.split(rcc_files[0])[1]
- name = 'qt5-' + basename.replace('.', '_')
- rcc_kwargs = {'input': rcc_files,
- 'output': name + '.cpp',
- 'command': [self.rcc, '-o', '@OUTPUT@', '@INPUT@'],
- 'depend_files': qrc_deps}
- res_target = build.CustomTarget(name, state.subdir, rcc_kwargs)
- sources.append(res_target)
- if len(ui_files) > 0:
- if not self.uic.found():
- raise MesonException(err_msg.format('UIC', 'uic-qt5'))
- ui_kwargs = {'output': 'ui_@BASENAME@.h',
- 'arguments': ['-o', '@OUTPUT@', '@INPUT@']}
- ui_gen = build.Generator([self.uic], ui_kwargs)
- ui_output = ui_gen.process_files('Qt5 ui', ui_files, state)
- sources.append(ui_output)
- if len(moc_headers) > 0:
- moc_kwargs = {'output': 'moc_@BASENAME@.cpp',
- 'arguments': ['@INPUT@', '-o', '@OUTPUT@']}
- moc_gen = build.Generator([self.moc], moc_kwargs)
- moc_output = moc_gen.process_files('Qt5 moc header', moc_headers, state)
- sources.append(moc_output)
- if len(moc_sources) > 0:
- moc_kwargs = {'output': '@BASENAME@.moc',
- 'arguments': ['@INPUT@', '-o', '@OUTPUT@']}
- moc_gen = build.Generator([self.moc], moc_kwargs)
- moc_output = moc_gen.process_files('Qt5 moc source', moc_sources, state)
- sources.append(moc_output)
- return ModuleReturnValue(sources, sources)
+ def __init__(self):
+ QtBaseModule.__init__(self, qt_version=5)
+ ExtensionModule.__init__(self)
def initialize():
mlog.warning('rcc dependencies will not work reliably until this upstream issue is fixed:',
diff --git a/mesonbuild/modules/rpm.py b/mesonbuild/modules/rpm.py
index b0a8db9..dbb01f7 100644
--- a/mesonbuild/modules/rpm.py
+++ b/mesonbuild/modules/rpm.py
@@ -22,7 +22,7 @@ from .. import mlog
from . import GirTarget, TypelibTarget
from . import ModuleReturnValue
from . import ExtensionModule
-from . import noKwargs
+from ..interpreterbase import noKwargs
import os
diff --git a/mesonbuild/modules/unstable_simd.py b/mesonbuild/modules/unstable_simd.py
index 828afec..b774cff 100644
--- a/mesonbuild/modules/unstable_simd.py
+++ b/mesonbuild/modules/unstable_simd.py
@@ -73,9 +73,7 @@ class SimdModule(ExtensionModule):
}
lib_kwargs.update(basic_kwargs)
langarg_key = compiler.get_language() + '_args'
- old_lang_args = lib_kwargs.get(langarg_key, [])
- if not isinstance(old_lang_args, list):
- old_lang_args = [old_lang_args]
+ old_lang_args = mesonlib.extract_as_list(lib_kwargs, langarg_key)
all_lang_args = old_lang_args + args
lib_kwargs[langarg_key] = all_lang_args
result.append(interpreter.func_static_lib(None, [libname], lib_kwargs))
diff --git a/mesonbuild/modules/windows.py b/mesonbuild/modules/windows.py
index 6fef5bb..c16d7a8 100644
--- a/mesonbuild/modules/windows.py
+++ b/mesonbuild/modules/windows.py
@@ -16,11 +16,11 @@ import os
from .. import mlog
from .. import mesonlib, dependencies, build
-from ..mesonlib import MesonException
+from ..mesonlib import MesonException, extract_as_list
from . import get_include_args
from . import ModuleReturnValue
from . import ExtensionModule
-from . import permittedKwargs
+from ..interpreterbase import permittedKwargs
class WindowsModule(ExtensionModule):
@@ -35,9 +35,7 @@ class WindowsModule(ExtensionModule):
comp = self.detect_compiler(state.compilers)
extra_args = mesonlib.stringlistify(kwargs.get('args', []))
- inc_dirs = kwargs.pop('include_directories', [])
- if not isinstance(inc_dirs, list):
- inc_dirs = [inc_dirs]
+ inc_dirs = extract_as_list(kwargs, 'include_directories', pop = True)
for incd in inc_dirs:
if not isinstance(incd.held_object, (str, build.IncludeDirs)):
raise MesonException('Resource include dirs should be include_directories().')
diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py
index 4e049a8..267e130 100644
--- a/mesonbuild/mtest.py
+++ b/mesonbuild/mtest.py
@@ -58,7 +58,7 @@ def determine_worker_count():
num_workers = 1
return num_workers
-parser = argparse.ArgumentParser()
+parser = argparse.ArgumentParser(prog='meson test')
parser.add_argument('--repeat', default=1, dest='repeat', type=int,
help='Number of times to run the tests.')
parser.add_argument('--no-rebuild', default=False, action='store_true',
@@ -619,6 +619,6 @@ def run(args):
return th.doit()
return th.run_special()
except TestException as e:
- print('Mesontest encountered an error:\n')
+ print('Meson test encountered an error:\n')
print(e)
return 1
diff --git a/mesonbuild/optinterpreter.py b/mesonbuild/optinterpreter.py
index ac27269..01dd036 100644
--- a/mesonbuild/optinterpreter.py
+++ b/mesonbuild/optinterpreter.py
@@ -12,10 +12,13 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import os, re
+import functools
+
from . import mparser
from . import coredata
from . import mesonlib
-import os, re
+
forbidden_option_names = coredata.get_builtin_options()
forbidden_prefixes = {'c_',
@@ -43,15 +46,33 @@ def is_invalid_name(name):
class OptionException(mesonlib.MesonException):
pass
+
+def permitted_kwargs(permitted):
+ """Function that validates kwargs for options."""
+ def _wraps(func):
+ @functools.wraps(func)
+ def _inner(name, description, kwargs):
+ bad = [a for a in kwargs.keys() if a not in permitted]
+ if bad:
+ raise OptionException('Invalid kwargs for option "{}": "{}"'.format(
+ name, ' '.join(bad)))
+ return func(name, description, kwargs)
+ return _inner
+ return _wraps
+
+
optname_regex = re.compile('[^a-zA-Z0-9_-]')
+@permitted_kwargs({'value'})
def StringParser(name, description, kwargs):
return coredata.UserStringOption(name, description,
kwargs.get('value', ''), kwargs.get('choices', []))
+@permitted_kwargs({'value'})
def BooleanParser(name, description, kwargs):
return coredata.UserBooleanOption(name, description, kwargs.get('value', True))
+@permitted_kwargs({'value', 'choices'})
def ComboParser(name, description, kwargs):
if 'choices' not in kwargs:
raise OptionException('Combo option missing "choices" keyword.')
@@ -141,7 +162,7 @@ class OptionInterpreter:
(posargs, kwargs) = self.reduce_arguments(node.args)
if 'type' not in kwargs:
raise OptionException('Option call missing mandatory "type" keyword argument')
- opt_type = kwargs['type']
+ opt_type = kwargs.pop('type')
if opt_type not in option_types:
raise OptionException('Unknown type %s.' % opt_type)
if len(posargs) != 1:
@@ -155,9 +176,9 @@ class OptionInterpreter:
raise OptionException('Option name %s is reserved.' % opt_name)
if self.subproject != '':
opt_name = self.subproject + ':' + opt_name
- opt = option_types[opt_type](opt_name, kwargs.get('description', ''), kwargs)
+ opt = option_types[opt_type](opt_name, kwargs.pop('description', ''), kwargs)
if opt.description == '':
opt.description = opt_name
if opt_name in self.cmd_line_options:
- opt.set_value(opt.parse_string(self.cmd_line_options[opt_name]))
+ opt.set_value(self.cmd_line_options[opt_name])
self.options[opt_name] = opt
diff --git a/mesonbuild/rewriter.py b/mesonbuild/rewriter.py
index b88c5ef..0191c30 100755..100644
--- a/mesonbuild/rewriter.py
+++ b/mesonbuild/rewriter.py
@@ -29,7 +29,7 @@ from mesonbuild import mlog
import sys, traceback
import argparse
-parser = argparse.ArgumentParser()
+parser = argparse.ArgumentParser(prog='meson rewrite')
parser.add_argument('--sourcedir', default='.',
help='Path to source directory.')
diff --git a/mesonbuild/scripts/gettext.py b/mesonbuild/scripts/gettext.py
index ef4f42a..30ac54c 100644
--- a/mesonbuild/scripts/gettext.py
+++ b/mesonbuild/scripts/gettext.py
@@ -70,7 +70,10 @@ def update_po(src_sub, pkgname, langs):
potfile = os.path.join(src_sub, pkgname + '.pot')
for l in langs:
pofile = os.path.join(src_sub, l + '.po')
- subprocess.check_call(['msgmerge', '-q', '-o', pofile, pofile, potfile])
+ if os.path.exists(pofile):
+ subprocess.check_call(['msgmerge', '-q', '-o', pofile, pofile, potfile])
+ else:
+ subprocess.check_call(['msginit', '--input', potfile, '--output-file', pofile, '--locale', l, '--no-translator'])
return 0
def do_install(src_sub, bld_sub, dest, pkgname, langs):
diff --git a/mesonbuild/scripts/gtkdochelper.py b/mesonbuild/scripts/gtkdochelper.py
index 45ed96b..4406b28 100644
--- a/mesonbuild/scripts/gtkdochelper.py
+++ b/mesonbuild/scripts/gtkdochelper.py
@@ -112,7 +112,8 @@ def build_gtkdoc(source_root, build_root, doc_subdir, src_subdirs,
scanobjs_cmd = ['gtkdoc-scangobj'] + scanobjs_args + ['--types=' + gobject_typesfile,
'--module=' + module,
'--cflags=' + cflags,
- '--ldflags=' + ldflags]
+ '--ldflags=' + ldflags,
+ '--ld=' + ld]
gtkdoc_run_check(scanobjs_cmd, abs_out)
diff --git a/mesonbuild/scripts/meson_install.py b/mesonbuild/scripts/meson_install.py
index f978be4..9485967 100644
--- a/mesonbuild/scripts/meson_install.py
+++ b/mesonbuild/scripts/meson_install.py
@@ -20,7 +20,7 @@ from . import destdir_join
from ..mesonlib import is_windows, Popen_safe
install_log_file = None
-use_selinux = True
+selinux_updates = []
class DirMaker:
def __init__(self):
@@ -84,27 +84,24 @@ def set_mode(path, mode):
msg = '{!r}: Unable to set permissions {!r}: {}, ignoring...'
print(msg.format(path, mode.perms_s, e.strerror))
-def restore_selinux_context(to_file):
+def restore_selinux_contexts():
'''
- Restores the SELinux context for @to_file
+ Restores the SELinux context for files in @selinux_updates
'''
- global use_selinux
-
- if not use_selinux:
- return
-
try:
subprocess.check_call(['selinuxenabled'])
- try:
- subprocess.check_call(['restorecon', '-F', to_file], stderr=subprocess.DEVNULL)
- except subprocess.CalledProcessError as e:
- use_selinux = False
- msg = "{!r}: Failed to restore SELinux context, ignoring SELinux context for all remaining files..."
- print(msg.format(to_file, e.returncode))
except (FileNotFoundError, PermissionError, subprocess.CalledProcessError) as e:
# If we don't have selinux or selinuxenabled returned 1, failure
# is ignored quietly.
- use_selinux = False
+ return
+
+ with subprocess.Popen(['restorecon', '-F', '-f-', '-0'],
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as proc:
+ out, err = proc.communicate(input=b'\0'.join(os.fsencode(f) for f in selinux_updates) + b'\0')
+ if proc.returncode != 0:
+ print('Failed to restore SELinux context of installed files...',
+ 'Standard output:', out.decode(),
+ 'Standard error:', err.decode(), sep='\n')
def append_to_log(line):
install_log_file.write(line)
@@ -126,7 +123,7 @@ def do_copyfile(from_file, to_file):
os.unlink(to_file)
shutil.copyfile(from_file, to_file)
shutil.copystat(from_file, to_file)
- restore_selinux_context(to_file)
+ selinux_updates.append(to_file)
append_to_log(to_file)
def do_copydir(data, src_prefix, src_dir, dst_dir, exclude):
@@ -192,6 +189,7 @@ def do_install(datafilename):
install_headers(d)
install_man(d)
install_data(d)
+ restore_selinux_contexts()
run_install_script(d)
def install_subdirs(d):
@@ -227,7 +225,9 @@ def install_man(d):
if outfilename.endswith('.gz') and not full_source_filename.endswith('.gz'):
with open(outfilename, 'wb') as of:
with open(full_source_filename, 'rb') as sf:
- of.write(gzip.compress(sf.read()))
+ # Set mtime and filename for reproducibility.
+ with gzip.GzipFile(fileobj=of, mode='wb', filename='', mtime=0) as gz:
+ gz.write(sf.read())
shutil.copystat(full_source_filename, outfilename)
append_to_log(outfilename)
else:
diff --git a/mesonbuild/scripts/regen_checker.py b/mesonbuild/scripts/regen_checker.py
index 4125f40..53c5428 100644
--- a/mesonbuild/scripts/regen_checker.py
+++ b/mesonbuild/scripts/regen_checker.py
@@ -32,9 +32,11 @@ def need_regen(regeninfo, regen_timestamp):
return False
def regen(regeninfo, mesonscript, backend):
- cmd = [sys.executable,
- mesonscript,
- '--internal',
+ if sys.executable.lower().endswith('meson.exe'):
+ cmd_exe = [sys.executable]
+ else:
+ cmd_exe = [sys.executable, mesonscript]
+ cmd = cmd_exe + ['--internal',
'regenerate',
regeninfo.build_dir,
regeninfo.source_dir,
diff --git a/mesonbuild/wrap/wrap.py b/mesonbuild/wrap/wrap.py
index ac84d0e..26a3489 100644
--- a/mesonbuild/wrap/wrap.py
+++ b/mesonbuild/wrap/wrap.py
@@ -14,11 +14,12 @@
from .. import mlog
import contextlib
-import urllib.request, os, hashlib, shutil
+import urllib.request, os, hashlib, shutil, tempfile, stat
import subprocess
import sys
from pathlib import Path
from . import WrapMode
+from ..mesonlib import Popen_safe
try:
import ssl
@@ -78,6 +79,8 @@ class PackageDefinition:
self.type = 'git'
elif first == '[wrap-hg]':
self.type = 'hg'
+ elif first == '[wrap-svn]':
+ self.type = 'svn'
else:
raise RuntimeError('Invalid format of package file')
for line in ifile:
@@ -145,6 +148,8 @@ class Resolver:
self.get_git(p)
elif p.type == "hg":
self.get_hg(p)
+ elif p.type == "svn":
+ self.get_svn(p)
else:
raise AssertionError('Unreachable code.')
return p.get('directory')
@@ -228,8 +233,31 @@ class Resolver:
subprocess.check_call(['hg', 'checkout', revno],
cwd=checkoutdir)
+ def get_svn(self, p):
+ checkoutdir = os.path.join(self.subdir_root, p.get('directory'))
+ revno = p.get('revision')
+ is_there = os.path.isdir(checkoutdir)
+ if is_there:
+ p, out = Popen_safe(['svn', 'info', '--show-item', 'revision', checkoutdir])
+ current_revno = out
+ if current_revno == revno:
+ return
+
+ if revno.lower() == 'head':
+ # Failure to do pull is not a fatal error,
+ # because otherwise you can't develop without
+ # a working net connection.
+ subprocess.call(['svn', 'update'], cwd=checkoutdir)
+ else:
+ subprocess.check_call(['svn', 'update', '-r', revno], cwd=checkoutdir)
+ else:
+ subprocess.check_call(['svn', 'checkout', '-r', revno, p.get('url'),
+ p.get('directory')], cwd=self.subdir_root)
+
def get_data(self, url):
blocksize = 10 * 1024
+ h = hashlib.sha256()
+ tmpfile = tempfile.NamedTemporaryFile(mode='wb', dir=self.cachedir, delete=False)
if url.startswith('https://wrapdb.mesonbuild.com'):
resp = open_wrapdburl(url)
else:
@@ -241,26 +269,34 @@ class Resolver:
dlsize = None
if dlsize is None:
print('Downloading file of unknown size.')
- return resp.read()
+ while True:
+ block = resp.read(blocksize)
+ if block == b'':
+ break
+ h.update(block)
+ tmpfile.write(block)
+ hashvalue = h.hexdigest()
+ return hashvalue, tmpfile.name
print('Download size:', dlsize)
print('Downloading: ', end='')
sys.stdout.flush()
printed_dots = 0
- blocks = []
downloaded = 0
while True:
block = resp.read(blocksize)
if block == b'':
break
downloaded += len(block)
- blocks.append(block)
+ h.update(block)
+ tmpfile.write(block)
ratio = int(downloaded / dlsize * 10)
while printed_dots < ratio:
print('.', end='')
sys.stdout.flush()
printed_dots += 1
print('')
- return b''.join(blocks)
+ hashvalue = h.hexdigest()
+ return hashvalue, tmpfile.name
def get_hash(self, data):
h = hashlib.sha256()
@@ -272,34 +308,55 @@ class Resolver:
ofname = os.path.join(self.cachedir, p.get('source_filename'))
if os.path.exists(ofname):
mlog.log('Using', mlog.bold(packagename), 'from cache.')
- return
- srcurl = p.get('source_url')
- mlog.log('Downloading', mlog.bold(packagename), 'from', mlog.bold(srcurl))
- srcdata = self.get_data(srcurl)
- dhash = self.get_hash(srcdata)
- expected = p.get('source_hash')
- if dhash != expected:
- raise RuntimeError('Incorrect hash for source %s:\n %s expected\n %s actual.' % (packagename, expected, dhash))
- with open(ofname, 'wb') as f:
- f.write(srcdata)
+ else:
+ srcurl = p.get('source_url')
+ mlog.log('Downloading', mlog.bold(packagename), 'from', mlog.bold(srcurl))
+ dhash, tmpfile = self.get_data(srcurl)
+ expected = p.get('source_hash')
+ if dhash != expected:
+ os.remove(tmpfile)
+ raise RuntimeError('Incorrect hash for source %s:\n %s expected\n %s actual.' % (packagename, expected, dhash))
+ os.rename(tmpfile, ofname)
if p.has_patch():
- purl = p.get('patch_url')
- mlog.log('Downloading patch from', mlog.bold(purl))
- pdata = self.get_data(purl)
- phash = self.get_hash(pdata)
- expected = p.get('patch_hash')
- if phash != expected:
- raise RuntimeError('Incorrect hash for patch %s:\n %s expected\n %s actual' % (packagename, expected, phash))
- filename = os.path.join(self.cachedir, p.get('patch_filename'))
- with open(filename, 'wb') as f:
- f.write(pdata)
+ patch_filename = p.get('patch_filename')
+ filename = os.path.join(self.cachedir, patch_filename)
+ if os.path.exists(filename):
+ mlog.log('Using', mlog.bold(patch_filename), 'from cache.')
+ else:
+ purl = p.get('patch_url')
+ mlog.log('Downloading patch from', mlog.bold(purl))
+ phash, tmpfile = self.get_data(purl)
+ expected = p.get('patch_hash')
+ if phash != expected:
+ os.remove(tmpfile)
+ raise RuntimeError('Incorrect hash for patch %s:\n %s expected\n %s actual' % (packagename, expected, phash))
+ os.rename(tmpfile, filename)
else:
mlog.log('Package does not require patch.')
+ def copy_tree(self, root_src_dir, root_dst_dir):
+ """
+ Copy directory tree. Overwrites also read only files.
+ """
+ for src_dir, dirs, files in os.walk(root_src_dir):
+ dst_dir = src_dir.replace(root_src_dir, root_dst_dir, 1)
+ if not os.path.exists(dst_dir):
+ os.makedirs(dst_dir)
+ for file_ in files:
+ src_file = os.path.join(src_dir, file_)
+ dst_file = os.path.join(dst_dir, file_)
+ if os.path.exists(dst_file):
+ try:
+ os.remove(dst_file)
+ except PermissionError as exc:
+ os.chmod(dst_file, stat.S_IWUSR)
+ os.remove(dst_file)
+ shutil.copy2(src_file, dst_dir)
+
def extract_package(self, package):
if sys.version_info < (3, 5):
try:
- import lzma
+ import lzma # noqa: F401
del lzma
except ImportError:
pass
@@ -322,4 +379,9 @@ class Resolver:
pass
shutil.unpack_archive(os.path.join(self.cachedir, package.get('source_filename')), extract_dir)
if package.has_patch():
- shutil.unpack_archive(os.path.join(self.cachedir, package.get('patch_filename')), self.subdir_root)
+ try:
+ shutil.unpack_archive(os.path.join(self.cachedir, package.get('patch_filename')), self.subdir_root)
+ except Exception:
+ with tempfile.TemporaryDirectory() as workdir:
+ shutil.unpack_archive(os.path.join(self.cachedir, package.get('patch_filename')), workdir)
+ self.copy_tree(workdir, self.subdir_root)
diff --git a/mesonrewriter.py b/mesonrewriter.py
index 426d878..e6f2637 100755
--- a/mesonrewriter.py
+++ b/mesonrewriter.py
@@ -23,11 +23,10 @@
# - move targets
# - reindent?
-from mesonbuild import mesonmain, mlog
+from mesonbuild import mesonmain
import sys
if __name__ == '__main__':
print('Warning: This executable is deprecated. Use "meson rewrite" instead.',
file=sys.stderr)
sys.exit(mesonmain.run(['rewrite'] + sys.argv[1:]))
-
diff --git a/msi/License.rtf b/msi/License.rtf
index 9b58df9..9b58df9 100755..100644
--- a/msi/License.rtf
+++ b/msi/License.rtf
diff --git a/msi/createmsi.py b/msi/createmsi.py
index 13b4081..7f165d8 100755
--- a/msi/createmsi.py
+++ b/msi/createmsi.py
@@ -43,12 +43,17 @@ class PackageGenerator:
self.main_xml = 'meson.wxs'
self.main_o = 'meson.wixobj'
self.bytesize = 32 if '32' in platform.architecture()[0] else 64
+ # rely on the environment variable since python architecture may not be the same as system architecture
+ if 'PROGRAMFILES(X86)' in os.environ:
+ self.bytesize = 64
self.final_output = 'meson-%s-%d.msi' % (self.version, self.bytesize)
self.staging_dirs = ['dist', 'dist2']
if self.bytesize == 64:
self.progfile_dir = 'ProgramFiles64Folder'
+ self.redist_path = 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\VC\\Redist\\MSVC\\14.11.25325\\MergeModules\\Microsoft_VC141_CRT_x64.msm'
else:
self.progfile_dir = 'ProgramFilesFolder'
+ self.redist_path = 'C:\\Program Files\\Microsoft Visual Studio\\2017\\Community\\VC\\Redist\\MSVC\\14.11.25325\\MergeModules\\Microsoft_VC141_CRT_x86.msm'
self.component_num = 0
self.feature_properties = {
self.staging_dirs[0]: {
@@ -56,7 +61,7 @@ class PackageGenerator:
'Title': 'Meson',
'Description': 'Meson executables',
'Level': '1',
- 'Absent': 'disallow',
+ 'Absent': 'disallow',
},
self.staging_dirs[1]: {
'Id': 'NinjaProgram',
@@ -109,7 +114,7 @@ class PackageGenerator:
'Language': '1033',
'Codepage': '1252',
'Version': self.version,
- })
+ })
package = ET.SubElement(product, 'Package', {
'Id': '*',
@@ -121,7 +126,7 @@ class PackageGenerator:
'Languages': '1033',
'Compressed': 'yes',
'SummaryCodepage': '1252',
- })
+ })
if self.bytesize == 64:
package.set('Platform', 'x64')
@@ -129,25 +134,32 @@ class PackageGenerator:
'Id': '1',
'Cabinet': 'meson.cab',
'EmbedCab': 'yes',
- })
+ })
targetdir = ET.SubElement(product, 'Directory', {
'Id': 'TARGETDIR',
'Name': 'SourceDir',
- })
+ })
progfiledir = ET.SubElement(targetdir, 'Directory', {
- 'Id' : self.progfile_dir,
- })
+ 'Id': self.progfile_dir,
+ })
installdir = ET.SubElement(progfiledir, 'Directory', {
'Id': 'INSTALLDIR',
- 'Name': 'Meson'})
+ 'Name': 'Meson',
+ })
+ ET.SubElement(installdir, 'Merge', {
+ 'Id': 'VCRedist',
+ 'SourceFile': self.redist_path,
+ 'DiskId': '1',
+ 'Language': '0',
+ })
ET.SubElement(product, 'Property', {
'Id': 'WIXUI_INSTALLDIR',
'Value': 'INSTALLDIR',
- })
+ })
ET.SubElement(product, 'UIRef', {
'Id': 'WixUI_FeatureTree',
- })
+ })
for sd in self.staging_dirs:
assert(os.path.isdir(sd))
top_feature = ET.SubElement(product, 'Feature', {
@@ -157,7 +169,7 @@ class PackageGenerator:
'Display': 'expand',
'Level': '1',
'ConfigurableDirectory': 'INSTALLDIR',
- })
+ })
for sd in self.staging_dirs:
nodes = {}
for root, dirs, files in os.walk(sd):
@@ -165,7 +177,15 @@ class PackageGenerator:
nodes[root] = cur_node
self.create_xml(nodes, sd, installdir, sd)
self.build_features(nodes, top_feature, sd)
- ET.ElementTree(self.root).write(self.main_xml, encoding='utf-8',xml_declaration=True)
+ vcredist_feature = ET.SubElement(top_feature, 'Feature', {
+ 'Id': 'VCRedist',
+ 'Title': 'Visual C++ runtime',
+ '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
import xml.dom.minidom
doc = xml.dom.minidom.parse(self.main_xml)
@@ -177,8 +197,7 @@ class PackageGenerator:
for component_id in self.feature_components[staging_dir]:
ET.SubElement(feature, 'ComponentRef', {
'Id': component_id,
- })
-
+ })
def create_xml(self, nodes, current_dir, parent_xml_node, staging_dir):
cur_node = nodes[current_dir]
@@ -187,7 +206,7 @@ class PackageGenerator:
comp_xml_node = ET.SubElement(parent_xml_node, 'Component', {
'Id': component_id,
'Guid': gen_guid(),
- })
+ })
self.feature_components[staging_dir].append(component_id)
if self.bytesize == 64:
comp_xml_node.set('Win64', 'yes')
@@ -208,14 +227,14 @@ class PackageGenerator:
'Id': file_id,
'Name': f,
'Source': os.path.join(current_dir, f),
- })
+ })
for dirname in cur_node.dirs:
dir_id = os.path.join(current_dir, dirname).replace('\\', '_').replace('/', '_')
dir_node = ET.SubElement(parent_xml_node, 'Directory', {
'Id': dir_id,
'Name': dirname,
- })
+ })
self.create_xml(nodes, os.path.join(current_dir, dirname), dir_node, staging_dir)
def build_package(self):
diff --git a/run_project_tests.py b/run_project_tests.py
index 71770f3..17e095b 100755
--- a/run_project_tests.py
+++ b/run_project_tests.py
@@ -124,6 +124,8 @@ print_debug = 'MESON_PRINT_TEST_OUTPUT' in os.environ
do_debug = not {'MESON_PRINT_TEST_OUTPUT', 'TRAVIS', 'APPVEYOR'}.isdisjoint(os.environ)
no_meson_log_msg = 'No meson-log.txt found.'
+system_compiler = None
+
meson_command = os.path.join(os.getcwd(), 'meson')
if not os.path.exists(meson_command):
meson_command += '.py'
@@ -141,9 +143,6 @@ def stop_handler(signal, frame):
signal.signal(signal.SIGINT, stop_handler)
signal.signal(signal.SIGTERM, stop_handler)
-# Needed when running cross tests because we don't generate prebuilt files
-compiler = None
-
def setup_commands(optbackend):
global do_debug, backend, backend_flags
global compile_commands, clean_commands, test_commands, install_commands, uninstall_commands
@@ -451,7 +450,6 @@ def detect_tests_to_run():
('failing-meson', 'failing', False),
('failing-build', 'failing build', False),
('failing-tests', 'failing tests', False),
- ('prebuilt', 'prebuilt', False),
('platform-osx', 'osx', not mesonlib.is_osx()),
('platform-windows', 'windows', not mesonlib.is_windows() and not mesonlib.is_cygwin()),
@@ -485,7 +483,7 @@ def run_tests(all_tests, log_name_base, extra_args):
return _run_tests(all_tests, log_name_base, extra_args)
def _run_tests(all_tests, log_name_base, extra_args):
- global stop, executor, futures
+ global stop, executor, futures, system_compiler
xmlname = log_name_base + '.xml'
junit_root = ET.Element('testsuites')
conf_time = 0
@@ -532,7 +530,7 @@ def _run_tests(all_tests, log_name_base, extra_args):
should_fail = False
if name.startswith('failing'):
should_fail = name.split('failing-')[1]
- result = executor.submit(run_test, skipped, t, extra_args, compiler, backend, backend_flags, commands, should_fail)
+ result = executor.submit(run_test, skipped, t, extra_args, system_compiler, backend, backend_flags, commands, should_fail)
futures.append((testname, t, result))
for (testname, t, result) in futures:
sys.stdout.flush()
@@ -585,7 +583,7 @@ def check_file(fname):
with open(fname, 'rb') as f:
lines = f.readlines()
for line in lines:
- if b'\t' in line:
+ if line.startswith(b'\t'):
print("File %s contains a literal tab on line %d. Only spaces are permitted." % (fname, linenum))
sys.exit(1)
if b'\r' in line:
@@ -600,52 +598,6 @@ def check_format():
fullname = os.path.join(root, file)
check_file(fullname)
-def pbcompile(compiler, source, objectfile):
- if compiler == 'cl':
- cmd = [compiler, '/nologo', '/Fo' + objectfile, '/c', source]
- else:
- cmd = [compiler, '-c', source, '-o', objectfile]
- subprocess.check_call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
-
-def generate_pb_object(compiler, object_suffix):
- source = 'test cases/prebuilt/1 object/source.c'
- objectfile = 'test cases/prebuilt/1 object/prebuilt.' + object_suffix
- pbcompile(compiler, source, objectfile)
- return objectfile
-
-def generate_pb_static(compiler, object_suffix, static_suffix):
- source = 'test cases/prebuilt/2 static/libdir/best.c'
- objectfile = 'test cases/prebuilt/2 static/libdir/best.' + object_suffix
- stlibfile = 'test cases/prebuilt/2 static/libdir/libbest.' + static_suffix
- pbcompile(compiler, source, objectfile)
- if compiler == 'cl':
- linker = ['lib', '/NOLOGO', '/OUT:' + stlibfile, objectfile]
- else:
- linker = ['ar', 'csr', stlibfile, objectfile]
- subprocess.check_call(linker)
- os.unlink(objectfile)
- return stlibfile
-
-def generate_prebuilt():
- global compiler
- static_suffix = 'a'
- if shutil.which('cl'):
- compiler = 'cl'
- static_suffix = 'lib'
- elif shutil.which('cc'):
- compiler = 'cc'
- elif shutil.which('gcc'):
- compiler = 'gcc'
- else:
- raise RuntimeError("Could not find C compiler.")
- if mesonlib.is_windows():
- object_suffix = 'obj'
- else:
- object_suffix = 'o'
- objectfile = generate_pb_object(compiler, object_suffix)
- stlibfile = generate_pb_static(compiler, object_suffix, static_suffix)
- return objectfile, stlibfile
-
def check_meson_commands_work():
global backend, meson_command, compile_commands, test_commands, install_commands
testdir = 'test cases/common/1 trivial'
@@ -670,6 +622,18 @@ def check_meson_commands_work():
if pc.returncode != 0:
raise RuntimeError('Failed to install {!r}:\n{}\n{}'.format(testdir, e, o))
+
+def detect_system_compiler():
+ global system_compiler
+ if shutil.which('cl'):
+ system_compiler = 'cl'
+ elif shutil.which('cc'):
+ system_compiler = 'cc'
+ elif shutil.which('gcc'):
+ system_compiler = 'gcc'
+ else:
+ raise RuntimeError("Could not find C compiler.")
+
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Run the test suite of Meson.")
parser.add_argument('extra_args', nargs='*',
@@ -679,19 +643,17 @@ if __name__ == '__main__':
options = parser.parse_args()
setup_commands(options.backend)
+ detect_system_compiler()
script_dir = os.path.split(__file__)[0]
if script_dir != '':
os.chdir(script_dir)
check_format()
check_meson_commands_work()
- pbfiles = generate_prebuilt()
try:
all_tests = detect_tests_to_run()
(passing_tests, failing_tests, skipped_tests) = run_tests(all_tests, 'meson-test-run', options.extra_args)
except StopException:
pass
- for f in pbfiles:
- os.unlink(f)
print('\nTotal passed tests:', green(str(passing_tests)))
print('Total failed tests:', red(str(failing_tests)))
print('Total skipped tests:', yellow(str(skipped_tests)))
diff --git a/run_tests.py b/run_tests.py
index a00898d..79c9639 100755
--- a/run_tests.py
+++ b/run_tests.py
@@ -90,7 +90,7 @@ def get_backend_commands(backend, debug=False):
test_cmd = cmd + ['-target', 'RUN_TESTS']
elif backend is Backend.ninja:
# We need at least 1.6 because of -w dupbuild=err
- cmd = [detect_ninja('1.6'), '-w', 'dupbuild=err']
+ cmd = [detect_ninja('1.6'), '-w', 'dupbuild=err', '-d', 'explain']
if cmd[0] is None:
raise RuntimeError('Could not find Ninja v1.6 or newer')
if debug:
@@ -104,6 +104,12 @@ def get_backend_commands(backend, debug=False):
return cmd, clean_cmd, test_cmd, install_cmd, uninstall_cmd
def ensure_backend_detects_changes(backend):
+ # We're using a ninja with QuLogic's patch for sub-1s resolution timestamps
+ # and not running on HFS+ which only stores dates in seconds:
+ # https://developer.apple.com/legacy/library/technotes/tn/tn1150.html#HFSPlusDates
+ # FIXME: Upgrade Travis image to Apple FS when that becomes available
+ if 'MESON_FIXED_NINJA' in os.environ and not mesonlib.is_osx():
+ return
# This is needed to increase the difference between build.ninja's
# timestamp and the timestamp of whatever you changed due to a Ninja
# bug: https://github.com/ninja-build/ninja/issues/371
@@ -119,7 +125,7 @@ def get_fake_options(prefix):
return opts
def should_run_linux_cross_tests():
- return shutil.which('arm-linux-gnueabihf-gcc-6') and not platform.machine().lower().startswith('arm')
+ return shutil.which('arm-linux-gnueabihf-gcc-7') and not platform.machine().lower().startswith('arm')
def run_configure_inprocess(commandlist):
old_stdout = sys.stdout
diff --git a/run_unittests.py b/run_unittests.py
index 6487496..ce1bf06 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -1,3 +1,4 @@
+
#!/usr/bin/env python3
# Copyright 2016-2017 The Meson development team
@@ -31,6 +32,7 @@ import mesonbuild.compilers
import mesonbuild.environment
import mesonbuild.mesonlib
import mesonbuild.coredata
+from mesonbuild.interpreter import ObjectHolder
from mesonbuild.mesonlib import is_linux, is_windows, is_osx, is_cygwin, windows_proof_rmtree
from mesonbuild.environment import Environment
from mesonbuild.dependencies import DependencyException
@@ -62,7 +64,6 @@ def get_soname(fname):
def get_rpath(fname):
return get_dynamic_section_entry(fname, r'(?:rpath|runpath)')
-
class InternalTests(unittest.TestCase):
def test_version_number(self):
@@ -398,6 +399,49 @@ class InternalTests(unittest.TestCase):
self.assertEqual(forced_value, desired_value)
+ def test_listify(self):
+ listify = mesonbuild.mesonlib.listify
+ # Test sanity
+ self.assertEqual([1], listify(1))
+ self.assertEqual([], listify([]))
+ self.assertEqual([1], listify([1]))
+ # Test flattening
+ self.assertEqual([1, 2, 3], listify([1, [2, 3]]))
+ self.assertEqual([1, 2, 3], listify([1, [2, [3]]]))
+ self.assertEqual([1, [2, [3]]], listify([1, [2, [3]]], flatten=False))
+ # Test flattening and unholdering
+ holder1 = ObjectHolder(1)
+ holder3 = ObjectHolder(3)
+ self.assertEqual([holder1], listify(holder1))
+ self.assertEqual([holder1], listify([holder1]))
+ self.assertEqual([holder1, 2], listify([holder1, 2]))
+ self.assertEqual([holder1, 2, 3], listify([holder1, 2, [3]]))
+ self.assertEqual([1], listify(holder1, unholder=True))
+ self.assertEqual([1], listify([holder1], unholder=True))
+ self.assertEqual([1, 2], listify([holder1, 2], unholder=True))
+ self.assertEqual([1, 2, 3], listify([holder1, 2, [holder3]], unholder=True))
+ # Unholding doesn't work recursively when not flattening
+ self.assertEqual([1, [2], [holder3]], listify([holder1, [2], [holder3]], unholder=True, flatten=False))
+
+ def test_extract_as_list(self):
+ extract = mesonbuild.mesonlib.extract_as_list
+ # Test sanity
+ kwargs = {'sources': [1, 2, 3]}
+ self.assertEqual([1, 2, 3], extract(kwargs, 'sources'))
+ self.assertEqual(kwargs, {'sources': [1, 2, 3]})
+ self.assertEqual([1, 2, 3], extract(kwargs, 'sources', pop=True))
+ self.assertEqual(kwargs, {})
+ # Test unholding
+ holder3 = ObjectHolder(3)
+ kwargs = {'sources': [1, 2, holder3]}
+ self.assertEqual([1, 2, 3], extract(kwargs, 'sources', unholder=True))
+ self.assertEqual(kwargs, {'sources': [1, 2, holder3]})
+ self.assertEqual([1, 2, 3], extract(kwargs, 'sources', unholder=True, pop=True))
+ self.assertEqual(kwargs, {})
+ # Test listification
+ kwargs = {'sources': [1, 2, 3], 'pch_sources': [4, 5, 6]}
+ self.assertEqual([[1, 2, 3], [4, 5, 6]], extract(kwargs, 'sources', 'pch_sources'))
+
class BasePlatformTests(unittest.TestCase):
def setUp(self):
@@ -447,7 +491,10 @@ class BasePlatformTests(unittest.TestCase):
print(f.read())
def tearDown(self):
- windows_proof_rmtree(self.builddir)
+ try:
+ windows_proof_rmtree(self.builddir)
+ except FileNotFoundError:
+ pass
os.environ = self.orig_env
super().tearDown()
@@ -696,6 +743,49 @@ class AllPlatformTests(BasePlatformTests):
self.init(testdir)
self.assertRaises(subprocess.CalledProcessError, self.setconf, '-Dlibdir=/opt', False)
+ def test_prefix_dependent_defaults(self):
+ '''
+ Tests that configured directory paths are set to prefix dependent
+ defaults.
+ '''
+ testdir = os.path.join(self.common_test_dir, '1 trivial')
+ expected = {
+ '/opt': {'prefix': '/opt',
+ 'bindir': 'bin', 'datadir': 'share', 'includedir': 'include',
+ 'infodir': 'share/info',
+ 'libexecdir': 'libexec', 'localedir': 'share/locale',
+ 'localstatedir': 'var', 'mandir': 'share/man',
+ 'sbindir': 'sbin', 'sharedstatedir': 'com',
+ 'sysconfdir': 'etc'},
+ '/usr': {'prefix': '/usr',
+ 'bindir': 'bin', 'datadir': 'share', 'includedir': 'include',
+ 'infodir': 'share/info',
+ 'libexecdir': 'libexec', 'localedir': 'share/locale',
+ 'localstatedir': '/var', 'mandir': 'share/man',
+ 'sbindir': 'sbin', 'sharedstatedir': '/var/lib',
+ 'sysconfdir': '/etc'},
+ '/usr/local': {'prefix': '/usr/local',
+ 'bindir': 'bin', 'datadir': 'share',
+ 'includedir': 'include', 'infodir': 'share/info',
+ 'libexecdir': 'libexec',
+ 'localedir': 'share/locale',
+ 'localstatedir': '/var/local', 'mandir': 'share/man',
+ 'sbindir': 'sbin', 'sharedstatedir': '/var/local/lib',
+ 'sysconfdir': 'etc'},
+ # N.B. We don't check 'libdir' as it's platform dependent, see
+ # default_libdir():
+ }
+ for prefix in expected:
+ args = ['--prefix', prefix]
+ self.init(testdir, args, default_args=False)
+ opts = self.introspect('--buildoptions')
+ for opt in opts:
+ name = opt['name']
+ value = opt['value']
+ if name in expected[prefix]:
+ self.assertEqual(value, expected[prefix][name])
+ self.wipe()
+
def test_static_library_overwrite(self):
'''
Tests that static libraries are never appended to, always overwritten.
@@ -1298,6 +1388,100 @@ int main(int argc, char **argv) {
for i in targets:
self.assertPathExists(os.path.join(testdir, i))
+ def detect_prebuild_env(self):
+ if mesonbuild.mesonlib.is_windows():
+ object_suffix = 'obj'
+ else:
+ object_suffix = 'o'
+ static_suffix = 'a'
+ shared_suffix = 'so'
+ if shutil.which('cl'):
+ compiler = 'cl'
+ static_suffix = 'lib'
+ shared_suffix = 'dll'
+ elif shutil.which('cc'):
+ compiler = 'cc'
+ elif shutil.which('gcc'):
+ compiler = 'gcc'
+ else:
+ raise RuntimeError("Could not find C compiler.")
+ return (compiler, object_suffix, static_suffix, shared_suffix)
+
+ def pbcompile(self, compiler, source, objectfile, extra_args=[]):
+ if compiler == 'cl':
+ cmd = [compiler, '/nologo', '/Fo' + objectfile, '/c', source] + extra_args
+ else:
+ cmd = [compiler, '-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')
+ source = os.path.join(tdir, 'source.c')
+ objectfile = os.path.join(tdir, 'prebuilt.' + object_suffix)
+ self.pbcompile(compiler, source, objectfile)
+ try:
+ self.init(tdir)
+ self.build()
+ self.run_tests()
+ finally:
+ os.unlink(objectfile)
+
+ def test_prebuilt_static_lib(self):
+ (compiler, object_suffix, static_suffix, _) = self.detect_prebuild_env()
+ tdir = os.path.join(self.unit_test_dir, '15 prebuilt static')
+ source = os.path.join(tdir, 'libdir/best.c')
+ objectfile = os.path.join(tdir, 'libdir/best.' + object_suffix)
+ stlibfile = os.path.join(tdir, 'libdir/libbest.' + static_suffix)
+ if compiler == 'cl':
+ link_cmd = ['lib', '/NOLOGO', '/OUT:' + stlibfile, objectfile]
+ else:
+ link_cmd = ['ar', 'csr', stlibfile, objectfile]
+ self.pbcompile(compiler, source, objectfile)
+ try:
+ subprocess.check_call(link_cmd)
+ finally:
+ os.unlink(objectfile)
+ try:
+ self.init(tdir)
+ self.build()
+ self.run_tests()
+ finally:
+ os.unlink(stlibfile)
+
+ def test_prebuilt_shared_lib(self):
+ (compiler, object_suffix, _, shared_suffix) = self.detect_prebuild_env()
+ tdir = os.path.join(self.unit_test_dir, '16 prebuilt shared')
+ source = os.path.join(tdir, 'alexandria.c')
+ objectfile = os.path.join(tdir, 'alexandria.' + object_suffix)
+ if compiler == 'cl':
+ extra_args = []
+ shlibfile = os.path.join(tdir, 'alexandria.' + shared_suffix)
+ link_cmd = ['link', '/NOLOGO','/DLL', '/DEBUG', '/IMPLIB:' + os.path.join(tdir, 'alexandria.lib'), '/OUT:' + shlibfile, objectfile]
+ else:
+ extra_args = ['-fPIC']
+ shlibfile = os.path.join(tdir, 'libalexandria.' + shared_suffix)
+ link_cmd = [compiler, '-shared', '-o', shlibfile, objectfile]
+ if not mesonbuild.mesonlib.is_osx():
+ link_cmd += ['-Wl,-soname=libalexandria.so']
+ self.pbcompile(compiler, source, objectfile, extra_args=extra_args)
+ try:
+ subprocess.check_call(link_cmd)
+ finally:
+ os.unlink(objectfile)
+ try:
+ self.init(tdir)
+ self.build()
+ self.run_tests()
+ finally:
+ os.unlink(shlibfile)
+ if mesonbuild.mesonlib.is_windows():
+ # Clean up all the garbage MSVC writes in the
+ # source tree.
+ for fname in glob(os.path.join(tdir, 'alexandria.*')):
+ if os.path.splitext(fname)[1] not in ['.c', '.h']:
+ os.unlink(fname)
class FailureTests(BasePlatformTests):
'''
@@ -1946,7 +2130,12 @@ cpu = 'armv7' # Not sure if correct.
endian = 'little'
''' % os.path.join(testdir, 'some_cross_tool.py'))
crossfile.flush()
- self.init(testdir, ['--cross-file='+crossfile.name])
+ self.init(testdir, ['--cross-file=' + crossfile.name])
+
+ def test_reconfigure(self):
+ testdir = os.path.join(self.unit_test_dir, '13 reconfigure')
+ self.init(testdir, ['-Db_lto=true'], default_args=False)
+ self.build('reconfigure')
class LinuxArmCrossCompileTests(BasePlatformTests):
diff --git a/setup.cfg b/setup.cfg
index b3adc59..edcf3c5 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -14,8 +14,10 @@ ignore =
E305,
# E401: multiple imports on one line
E401,
- # too many leading '#' for block comment
+ # E266: too many leading '#' for block comment
E266,
- # module level import not at top of file
- E402
+ # E402: module level import not at top of file
+ E402,
+ # E731: do not assign a lambda expression, use a def (too many false positives)
+ E731
max-line-length = 120
diff --git a/test cases/common/114 multiple dir configure file/meson.build b/test cases/common/114 multiple dir configure file/meson.build
index 180227c..c76c6b4 100644
--- a/test cases/common/114 multiple dir configure file/meson.build
+++ b/test cases/common/114 multiple dir configure file/meson.build
@@ -5,3 +5,7 @@ subdir('subdir')
configure_file(input : 'subdir/someinput.in',
output : 'outputhere',
configuration : configuration_data())
+
+configure_file(input : cfile1,
+ output : '@BASENAME@',
+ configuration : configuration_data())
diff --git a/test cases/common/114 multiple dir configure file/subdir/foo.txt b/test cases/common/114 multiple dir configure file/subdir/foo.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test cases/common/114 multiple dir configure file/subdir/foo.txt
diff --git a/test cases/common/114 multiple dir configure file/subdir/meson.build b/test cases/common/114 multiple dir configure file/subdir/meson.build
index a8f731d..9c72bf9 100644
--- a/test cases/common/114 multiple dir configure file/subdir/meson.build
+++ b/test cases/common/114 multiple dir configure file/subdir/meson.build
@@ -2,3 +2,10 @@ configure_file(input : 'someinput.in',
output : 'outputsubdir',
install : false,
configuration : configuration_data())
+
+py3 = import('python3').find_python()
+
+cfile1 = configure_file(input : 'foo.txt',
+ output : 'foo.h.in',
+ capture : true,
+ command : [py3, '-c', 'print("#mesondefine FOO_BAR")'])
diff --git a/test cases/common/140 get define/meson_options.txt b/test cases/common/140 get define/meson_options.txt
index a88cecd..7d34a2e 100644
--- a/test cases/common/140 get define/meson_options.txt
+++ b/test cases/common/140 get define/meson_options.txt
@@ -1 +1 @@
-option('MESON_TEST_DEFINE_VALUE', type : 'string', default : '')
+option('MESON_TEST_DEFINE_VALUE', type : 'string', value : '')
diff --git a/test cases/common/145 whole archive/allofme/meson.build b/test cases/common/145 whole archive/allofme/meson.build
new file mode 100644
index 0000000..f5c2027
--- /dev/null
+++ b/test cases/common/145 whole archive/allofme/meson.build
@@ -0,0 +1 @@
+stlib = static_library('allofme', '../libfile.c')
diff --git a/test cases/common/145 whole archive/exe/meson.build b/test cases/common/145 whole archive/exe/meson.build
new file mode 100644
index 0000000..f47a246
--- /dev/null
+++ b/test cases/common/145 whole archive/exe/meson.build
@@ -0,0 +1,2 @@
+exe = executable('prog', '../prog.c',
+ link_with : dylib)
diff --git a/test cases/common/145 whole archive/exe2/meson.build b/test cases/common/145 whole archive/exe2/meson.build
new file mode 100644
index 0000000..5365f03
--- /dev/null
+++ b/test cases/common/145 whole archive/exe2/meson.build
@@ -0,0 +1 @@
+exe2 = executable('prog2', '../prog.c', link_with : dylib2)
diff --git a/test cases/common/145 whole archive/meson.build b/test cases/common/145 whole archive/meson.build
index eadebf8..617ae03 100644
--- a/test cases/common/145 whole archive/meson.build
+++ b/test cases/common/145 whole archive/meson.build
@@ -1,5 +1,7 @@
project('whole archive', 'c')
+add_project_arguments('-I' + meson.source_root(), language : 'c')
+
cc = meson.get_compiler('c')
if cc.get_id() == 'msvc'
@@ -8,15 +10,15 @@ if cc.get_id() == 'msvc'
endif
endif
-stlib = static_library('allofme', 'libfile.c')
-
-# Nothing in dylib.c uses func1, so the linker would throw it
-# away and thus linking the exe would fail.
-dylib = shared_library('shlib', 'dylib.c',
- link_whole : stlib)
-
-exe = executable('prog', 'prog.c',
- link_with : dylib)
+subdir('allofme')
+subdir('shlib')
+subdir('exe')
test('prog', exe)
+# link_whole only
+subdir('stlib')
+subdir('wholeshlib')
+subdir('exe2')
+
+test('prog2', exe2)
diff --git a/test cases/common/145 whole archive/shlib/meson.build b/test cases/common/145 whole archive/shlib/meson.build
new file mode 100644
index 0000000..34a1b78
--- /dev/null
+++ b/test cases/common/145 whole archive/shlib/meson.build
@@ -0,0 +1,4 @@
+# Nothing in dylib.c uses func1, so the linker would throw it
+# away and thus linking the exe would fail.
+dylib = shared_library('shlib', '../dylib.c',
+ link_whole : stlib)
diff --git a/test cases/common/145 whole archive/stlib/meson.build b/test cases/common/145 whole archive/stlib/meson.build
new file mode 100644
index 0000000..07a434e
--- /dev/null
+++ b/test cases/common/145 whole archive/stlib/meson.build
@@ -0,0 +1 @@
+static = static_library('static', '../dylib.c')
diff --git a/test cases/common/145 whole archive/wholeshlib/meson.build b/test cases/common/145 whole archive/wholeshlib/meson.build
new file mode 100644
index 0000000..69a1995
--- /dev/null
+++ b/test cases/common/145 whole archive/wholeshlib/meson.build
@@ -0,0 +1 @@
+dylib2 = shared_library('link_whole', link_whole : [stlib, static])
diff --git a/test cases/common/146 C and CPP link/dummy.c b/test cases/common/146 C and CPP link/dummy.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test cases/common/146 C and CPP link/dummy.c
diff --git a/test cases/common/146 C and CPP link/meson.build b/test cases/common/146 C and CPP link/meson.build
index db84445..2dd3364 100644
--- a/test cases/common/146 C and CPP link/meson.build
+++ b/test cases/common/146 C and CPP link/meson.build
@@ -65,10 +65,44 @@ libfoo = shared_library(
#
# VS2010 lacks the /WHOLEARCHIVE option that later versions of MSVC support, so
# don't run this tests on that backend.
-if meson.backend() != 'vs2010'
+if not (cxx.get_id() == 'msvc' and cxx.version().version_compare('<19'))
libfoowhole = shared_library(
'foowhole',
['foobar.c', 'foobar.h'],
link_whole : [libc, libcpp],
)
endif
+
+# Test sublinking (linking C and C++, then linking that to C)
+libfoo_static = static_library(
+ 'foo_static',
+ ['foobar.c', 'foobar.h'],
+ link_with : [libc, libcpp],
+)
+
+libsub = shared_library(
+ 'sub',
+ ['sub.c', 'sub.h'],
+ link_with : libfoo_static,
+)
+
+if not (cxx.get_id() == 'msvc' and cxx.version().version_compare('<19'))
+ libsubwhole = shared_library(
+ 'subwhole',
+ ['sub.c', 'sub.h'],
+ link_whole : libfoo_static,
+ )
+endif
+
+# Test that it really is recursive
+libsub_static = static_library(
+ 'sub_static',
+ ['sub.c', 'sub.h'],
+ link_with : libfoo_static,
+)
+
+libsubsub = shared_library(
+ 'subsub',
+ ['dummy.c'],
+ link_with : libsub_static,
+)
diff --git a/test cases/common/146 C and CPP link/sub.c b/test cases/common/146 C and CPP link/sub.c
new file mode 100644
index 0000000..7c078f8
--- /dev/null
+++ b/test cases/common/146 C and CPP link/sub.c
@@ -0,0 +1,19 @@
+/* Copyright © 2017 Dylan Baker
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "sub.h"
+
+float a_half(void) {
+ return .5;
+}
diff --git a/test cases/common/146 C and CPP link/sub.h b/test cases/common/146 C and CPP link/sub.h
new file mode 100644
index 0000000..5b02e17
--- /dev/null
+++ b/test cases/common/146 C and CPP link/sub.h
@@ -0,0 +1,16 @@
+/* Copyright © 2017 Dylan Baker
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+float a_half(void);
diff --git a/test cases/common/147 mesonintrospect from scripts/check_env.py b/test cases/common/147 mesonintrospect from scripts/check_env.py
index 9bd64d7..2d46d88 100644
--- a/test cases/common/147 mesonintrospect from scripts/check_env.py
+++ b/test cases/common/147 mesonintrospect from scripts/check_env.py
@@ -16,8 +16,8 @@ mesonintrospect = os.environ['MESONINTROSPECT']
introspect_arr = shlex.split(mesonintrospect)
-#print(mesonintrospect)
-#print(introspect_arr)
+# print(mesonintrospect)
+# print(introspect_arr)
some_executable = introspect_arr[0]
diff --git a/test cases/common/159 reserved targets/meson.build b/test cases/common/159 reserved targets/meson.build
index 26572c0..24fd937 100644
--- a/test cases/common/159 reserved targets/meson.build
+++ b/test cases/common/159 reserved targets/meson.build
@@ -26,6 +26,9 @@ subdir('uninstall')
subdir('runtarget')
+py3 = import('python3').find_python()
+
custom_target('ctlist-test', output : 'out.txt',
- command : ['echo'], capture : true,
+ command : [py3, '-c', 'print("")'],
+ capture : true,
build_by_default : true)
diff --git a/test cases/common/161 index customtarget/gen_sources.py b/test cases/common/161 index customtarget/gen_sources.py
new file mode 100644
index 0000000..0bdb529
--- /dev/null
+++ b/test cases/common/161 index customtarget/gen_sources.py
@@ -0,0 +1,49 @@
+# Copyright © 2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import argparse
+import textwrap
+
+HEADER = textwrap.dedent('''\
+ void stringify(int foo, char * buffer);
+ ''')
+
+CODE = textwrap.dedent('''\
+ #include <stdio.h>
+
+ #ifndef WORKS
+ # error "This shouldn't have been included"
+ #endif
+
+ void stringify(int foo, char * buffer) {
+ sprintf(buffer, "%i", foo);
+ }
+ ''')
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--header')
+ parser.add_argument('--code')
+ args = parser.parse_args()
+
+ with open(args.header, 'w') as f:
+ f.write(HEADER)
+
+ with open(args.code, 'w') as f:
+ f.write(CODE)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test cases/common/161 index customtarget/lib.c b/test cases/common/161 index customtarget/lib.c
new file mode 100644
index 0000000..17117d5
--- /dev/null
+++ b/test cases/common/161 index customtarget/lib.c
@@ -0,0 +1,20 @@
+/* Copyright © 2017 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gen.h"
+
+void func(char * buffer) {
+ stringify(1, buffer);
+}
diff --git a/test cases/common/161 index customtarget/meson.build b/test cases/common/161 index customtarget/meson.build
new file mode 100644
index 0000000..11cb214
--- /dev/null
+++ b/test cases/common/161 index customtarget/meson.build
@@ -0,0 +1,32 @@
+# Copyright © 2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+project('custom_target_index', 'c', default_options : 'c_std=c89')
+
+py_mod = import('python3')
+prog_python = py_mod.find_python()
+
+gen = custom_target(
+ 'gen.[ch]',
+ input : 'gen_sources.py',
+ output : ['gen.c', 'gen.h'],
+ command : [prog_python, '@INPUT@', '--header', '@OUTPUT1@', '--code', '@OUTPUT0@'],
+)
+
+lib = static_library(
+ 'libfoo',
+ ['lib.c', gen[1]],
+)
+
+subdir('subdir')
diff --git a/test cases/common/161 index customtarget/subdir/foo.c b/test cases/common/161 index customtarget/subdir/foo.c
new file mode 100644
index 0000000..c620a11
--- /dev/null
+++ b/test cases/common/161 index customtarget/subdir/foo.c
@@ -0,0 +1,22 @@
+/* Copyright © 2017 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gen.h"
+
+int main(void) {
+ char buf[50];
+ stringify(10, buf);
+ return 0;
+}
diff --git a/test cases/common/161 index customtarget/subdir/meson.build b/test cases/common/161 index customtarget/subdir/meson.build
new file mode 100644
index 0000000..47bcd32
--- /dev/null
+++ b/test cases/common/161 index customtarget/subdir/meson.build
@@ -0,0 +1,19 @@
+# Copyright © 2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+foo = executable(
+ 'foo',
+ ['foo.c', gen[0], gen[1]],
+ c_args : '-DWORKS',
+)
diff --git a/test cases/common/162 wrap file should not failed/meson.build b/test cases/common/162 wrap file should not failed/meson.build
new file mode 100644
index 0000000..9cf4e9a
--- /dev/null
+++ b/test cases/common/162 wrap file should not failed/meson.build
@@ -0,0 +1,7 @@
+project('mainproj', 'c')
+
+subproject('zlib')
+
+executable('grabprog', files('src/subprojects/prog.c'))
+executable('grabprog2', files('src/subprojects/foo/prog2.c'))
+subdir('src')
diff --git a/test cases/common/162 wrap file should not failed/src/meson.build b/test cases/common/162 wrap file should not failed/src/meson.build
new file mode 100644
index 0000000..69f666d
--- /dev/null
+++ b/test cases/common/162 wrap file should not failed/src/meson.build
@@ -0,0 +1,2 @@
+executable('grabprog3', files('subprojects/prog.c'))
+executable('grabprog4', files('subprojects/foo/prog2.c'))
diff --git a/test cases/common/162 wrap file should not failed/src/subprojects/foo/prog2.c b/test cases/common/162 wrap file should not failed/src/subprojects/foo/prog2.c
new file mode 100644
index 0000000..56f61a8
--- /dev/null
+++ b/test cases/common/162 wrap file should not failed/src/subprojects/foo/prog2.c
@@ -0,0 +1,7 @@
+#include<stdio.h>
+
+int main(int argc, char **argv) {
+ printf("Do not have a file layout like this in your own projects.\n");
+ printf("This is only to test that this works.\n");
+ return 0;
+}
diff --git a/test cases/common/162 wrap file should not failed/src/subprojects/prog.c b/test cases/common/162 wrap file should not failed/src/subprojects/prog.c
new file mode 100644
index 0000000..56f61a8
--- /dev/null
+++ b/test cases/common/162 wrap file should not failed/src/subprojects/prog.c
@@ -0,0 +1,7 @@
+#include<stdio.h>
+
+int main(int argc, char **argv) {
+ printf("Do not have a file layout like this in your own projects.\n");
+ printf("This is only to test that this works.\n");
+ return 0;
+}
diff --git a/test cases/common/162 wrap file should not failed/subprojects/packagecache/zlib-1.2.8-8-wrap.zip b/test cases/common/162 wrap file should not failed/subprojects/packagecache/zlib-1.2.8-8-wrap.zip
new file mode 100644
index 0000000..421376d
--- /dev/null
+++ b/test cases/common/162 wrap file should not failed/subprojects/packagecache/zlib-1.2.8-8-wrap.zip
@@ -0,0 +1 @@
+dummy
diff --git a/test cases/common/162 wrap file should not failed/subprojects/packagecache/zlib-1.2.8.tar.gz b/test cases/common/162 wrap file should not failed/subprojects/packagecache/zlib-1.2.8.tar.gz
new file mode 100644
index 0000000..421376d
--- /dev/null
+++ b/test cases/common/162 wrap file should not failed/subprojects/packagecache/zlib-1.2.8.tar.gz
@@ -0,0 +1 @@
+dummy
diff --git a/test cases/common/162 wrap file should not failed/subprojects/zlib-1.2.8/foo.c b/test cases/common/162 wrap file should not failed/subprojects/zlib-1.2.8/foo.c
new file mode 100644
index 0000000..019f2ba
--- /dev/null
+++ b/test cases/common/162 wrap file should not failed/subprojects/zlib-1.2.8/foo.c
@@ -0,0 +1,3 @@
+int dummy_func() {
+ return 42;
+}
diff --git a/test cases/common/162 wrap file should not failed/subprojects/zlib-1.2.8/meson.build b/test cases/common/162 wrap file should not failed/subprojects/zlib-1.2.8/meson.build
new file mode 100644
index 0000000..8d8008e
--- /dev/null
+++ b/test cases/common/162 wrap file should not failed/subprojects/zlib-1.2.8/meson.build
@@ -0,0 +1,2 @@
+project('shared lib', 'c')
+shared_library('foo', 'foo.c')
diff --git a/test cases/common/162 wrap file should not failed/subprojects/zlib.wrap b/test cases/common/162 wrap file should not failed/subprojects/zlib.wrap
new file mode 100644
index 0000000..6d5896f
--- /dev/null
+++ b/test cases/common/162 wrap file should not failed/subprojects/zlib.wrap
@@ -0,0 +1,10 @@
+[wrap-file]
+directory = zlib-1.2.8
+
+source_url = http://zlib.net/fossils/zlib-1.2.8.tar.gz
+source_filename = zlib-1.2.8.tar.gz
+source_hash = 36658cb768a54c1d4dec43c3116c27ed893e88b02ecfcb44f2166f9c0b7f2a0d
+
+patch_url = https://wrapdb.mesonbuild.com/v1/projects/zlib/1.2.8/8/get_zip
+patch_filename = zlib-1.2.8-8-wrap.zip
+patch_hash = 17c52a0e0c59ce926d3959005d5cd8178c6c7e2c9a4a1304279a8320c955ac60
diff --git a/test cases/common/163 includedir subproj/meson.build b/test cases/common/163 includedir subproj/meson.build
new file mode 100644
index 0000000..b3de5af
--- /dev/null
+++ b/test cases/common/163 includedir subproj/meson.build
@@ -0,0 +1,9 @@
+project('include dir in subproj test', 'c')
+
+
+subproject('inctest')
+
+
+exe = executable('prog', 'prog.c')
+
+test('dummy', exe)
diff --git a/test cases/common/163 includedir subproj/prog.c b/test cases/common/163 includedir subproj/prog.c
new file mode 100644
index 0000000..772681e
--- /dev/null
+++ b/test cases/common/163 includedir subproj/prog.c
@@ -0,0 +1,4 @@
+
+int main(int argc, char **argv) {
+ return 0;
+}
diff --git a/test cases/common/163 includedir subproj/subprojects/inctest/include/incfile.h b/test cases/common/163 includedir subproj/subprojects/inctest/include/incfile.h
new file mode 100644
index 0000000..ec740da
--- /dev/null
+++ b/test cases/common/163 includedir subproj/subprojects/inctest/include/incfile.h
@@ -0,0 +1,2 @@
+
+/* file which is used in the subproject */
diff --git a/test cases/common/163 includedir subproj/subprojects/inctest/meson.build b/test cases/common/163 includedir subproj/subprojects/inctest/meson.build
new file mode 100644
index 0000000..74aabcb
--- /dev/null
+++ b/test cases/common/163 includedir subproj/subprojects/inctest/meson.build
@@ -0,0 +1,13 @@
+
+project('subproj with includedir', 'c')
+
+
+
+compile_check = '''
+#include "incfile.h"
+'''
+
+if not meson.get_compiler('c').compiles(compile_check, name : 'include in subproj',
+ include_directories: include_directories('include'))
+ error('failed')
+endif
diff --git a/test cases/common/163 subproject dir name collision/a.c b/test cases/common/163 subproject dir name collision/a.c
new file mode 100644
index 0000000..6ed96fa
--- /dev/null
+++ b/test cases/common/163 subproject dir name collision/a.c
@@ -0,0 +1,13 @@
+#include<assert.h>
+char func_b();
+char func_c();
+
+int main(int argc, char **argv) {
+ if(func_b() != 'b') {
+ return 1;
+ }
+ if(func_c() != 'c') {
+ return 2;
+ }
+ return 0;
+}
diff --git a/test cases/common/163 subproject dir name collision/custom_subproject_dir/B/b.c b/test cases/common/163 subproject dir name collision/custom_subproject_dir/B/b.c
new file mode 100644
index 0000000..4c94ee9
--- /dev/null
+++ b/test cases/common/163 subproject dir name collision/custom_subproject_dir/B/b.c
@@ -0,0 +1,20 @@
+#include<stdlib.h>
+char func_c();
+
+#if defined _WIN32 || defined __CYGWIN__
+#define DLL_PUBLIC __declspec(dllexport)
+#else
+ #if defined __GNUC__
+ #define DLL_PUBLIC __attribute__ ((visibility("default")))
+ #else
+ #pragma message ("Compiler does not support symbol visibility.")
+ #define DLL_PUBLIC
+ #endif
+#endif
+
+char DLL_PUBLIC func_b() {
+ if(func_c() != 'c') {
+ exit(3);
+ }
+ return 'b';
+}
diff --git a/test cases/common/163 subproject dir name collision/custom_subproject_dir/B/meson.build b/test cases/common/163 subproject dir name collision/custom_subproject_dir/B/meson.build
new file mode 100644
index 0000000..280c60c
--- /dev/null
+++ b/test cases/common/163 subproject dir name collision/custom_subproject_dir/B/meson.build
@@ -0,0 +1,4 @@
+project('B', 'c')
+C = subproject('C')
+c = C.get_variable('c')
+b = shared_library('b', 'b.c', link_with : c)
diff --git a/test cases/common/163 subproject dir name collision/custom_subproject_dir/C/c.c b/test cases/common/163 subproject dir name collision/custom_subproject_dir/C/c.c
new file mode 100644
index 0000000..eebfb9f
--- /dev/null
+++ b/test cases/common/163 subproject dir name collision/custom_subproject_dir/C/c.c
@@ -0,0 +1,14 @@
+#if defined _WIN32 || defined __CYGWIN__
+#define DLL_PUBLIC __declspec(dllexport)
+#else
+ #if defined __GNUC__
+ #define DLL_PUBLIC __attribute__ ((visibility("default")))
+ #else
+ #pragma message ("Compiler does not support symbol visibility.")
+ #define DLL_PUBLIC
+ #endif
+#endif
+
+char DLL_PUBLIC func_c() {
+ return 'c';
+}
diff --git a/test cases/common/163 subproject dir name collision/custom_subproject_dir/C/meson.build b/test cases/common/163 subproject dir name collision/custom_subproject_dir/C/meson.build
new file mode 100644
index 0000000..abf0b1e
--- /dev/null
+++ b/test cases/common/163 subproject dir name collision/custom_subproject_dir/C/meson.build
@@ -0,0 +1,2 @@
+project('C', 'c')
+c = shared_library('c', 'c.c')
diff --git a/test cases/common/163 subproject dir name collision/meson.build b/test cases/common/163 subproject dir name collision/meson.build
new file mode 100644
index 0000000..5531217
--- /dev/null
+++ b/test cases/common/163 subproject dir name collision/meson.build
@@ -0,0 +1,12 @@
+project('A', 'c', subproject_dir:'custom_subproject_dir')
+
+B = subproject('B')
+b = B.get_variable('b')
+
+C = subproject('C')
+c = C.get_variable('c')
+
+subdir('other_subdir')
+
+a = executable('a', 'a.c', link_with : [b, c])
+test('a test', a)
diff --git a/test cases/common/163 subproject dir name collision/other_subdir/custom_subproject_dir/other.c b/test cases/common/163 subproject dir name collision/other_subdir/custom_subproject_dir/other.c
new file mode 100644
index 0000000..0c27f84
--- /dev/null
+++ b/test cases/common/163 subproject dir name collision/other_subdir/custom_subproject_dir/other.c
@@ -0,0 +1,19 @@
+#include<stdlib.h>
+
+#if defined _WIN32 || defined __CYGWIN__
+#define DLL_PUBLIC __declspec(dllexport)
+#else
+ #if defined __GNUC__
+ #define DLL_PUBLIC __attribute__ ((visibility("default")))
+ #else
+ #pragma message ("Compiler does not support symbol visibility.")
+ #define DLL_PUBLIC
+ #endif
+#endif
+
+char DLL_PUBLIC func_b() {
+ if('c' != 'c') {
+ exit(3);
+ }
+ return 'b';
+}
diff --git a/test cases/common/163 subproject dir name collision/other_subdir/meson.build b/test cases/common/163 subproject dir name collision/other_subdir/meson.build
new file mode 100644
index 0000000..90cb67a
--- /dev/null
+++ b/test cases/common/163 subproject dir name collision/other_subdir/meson.build
@@ -0,0 +1 @@
+other = shared_library('other', 'custom_subproject_dir/other.c')
diff --git a/test cases/common/42 string operations/meson.build b/test cases/common/42 string operations/meson.build
index 5d7a73d..d9f8130 100644
--- a/test cases/common/42 string operations/meson.build
+++ b/test cases/common/42 string operations/meson.build
@@ -67,3 +67,10 @@ assert(not version_number.version_compare('!=1.2.8'), 'Version_compare neq broke
assert(version_number.version_compare('<2.0'), 'Version_compare major less broken')
assert(version_number.version_compare('>0.9'), 'Version_compare major greater broken')
+
+assert(' spaces tabs '.strip() == 'spaces tabs', 'Spaces and tabs badly stripped')
+assert('''
+multiline string '''.strip() == '''multiline string''', 'Newlines badly stripped')
+assert('"1.1.20"'.strip('"') == '1.1.20', '" badly stripped')
+assert('"1.1.20"'.strip('".') == '1.1.20', '". badly stripped')
+assert('"1.1.20" '.strip('" ') == '1.1.20', '". badly stripped')
diff --git a/test cases/common/47 options/meson.build b/test cases/common/47 options/meson.build
index 4058748..2a764f0 100644
--- a/test cases/common/47 options/meson.build
+++ b/test cases/common/47 options/meson.build
@@ -12,6 +12,7 @@ if get_option('combo_opt') != 'combo'
error('Incorrect value to combo option.')
endif
+# If the default changes, update test cases/unit/13 reconfigure
if get_option('b_lto') != false
error('Incorrect value in base option.')
endif
diff --git a/test cases/common/90 identical target name in subproject/meson.build b/test cases/common/90 identical target name in subproject/meson.build
index ddb5caf..98e4891 100644
--- a/test cases/common/90 identical target name in subproject/meson.build
+++ b/test cases/common/90 identical target name in subproject/meson.build
@@ -3,3 +3,4 @@ project('toplevel bar', 'c')
subproject('foo')
executable('bar', 'bar.c')
+run_target('nop', 'true')
diff --git a/test cases/common/90 identical target name in subproject/subprojects/foo/meson.build b/test cases/common/90 identical target name in subproject/subprojects/foo/meson.build
index 03dd9f3..a7a31b1 100644
--- a/test cases/common/90 identical target name in subproject/subprojects/foo/meson.build
+++ b/test cases/common/90 identical target name in subproject/subprojects/foo/meson.build
@@ -1,3 +1,4 @@
project('subfoo', 'c')
executable('bar', 'bar.c')
+run_target('nop', 'true')
diff --git a/test cases/common/98 gen extra/meson.build b/test cases/common/98 gen extra/meson.build
index 52ed847..cbbdceb 100644
--- a/test cases/common/98 gen extra/meson.build
+++ b/test cases/common/98 gen extra/meson.build
@@ -11,3 +11,30 @@ g2 = gen.process('name.dat', extra_args: '--upper')
test('basic', executable('basic', 'plain.c', g1))
test('upper', executable('upper', 'upper.c', g2))
+
+prog2 = find_program('srcgen2.py')
+basename_gen = generator(prog2,
+ output : ['@BASENAME@.tab.c', '@BASENAME@.tab.h'],
+ arguments : ['@BUILD_DIR@', '@BASENAME@', '@INPUT@'])
+
+basename_src = basename_gen.process('name.l')
+
+test('basename', executable('basename', basename_src))
+
+plainname_gen = generator(prog2,
+ output : ['@PLAINNAME@.tab.c', '@PLAINNAME@.tab.h'],
+ arguments : ['@BUILD_DIR@', '@PLAINNAME@', '@INPUT@'])
+
+plainname_src = plainname_gen.process('name.l')
+
+test('plainname', executable('plainname', plainname_src))
+
+prog3 = find_program('srcgen3.py')
+capture_gen = generator(prog3,
+ output : ['@BASENAME@.yy.c'],
+ arguments : ['@INPUT@'],
+ capture : true)
+
+capture_src = capture_gen.process('name.l')
+
+test('capture', executable('capture', capture_src))
diff --git a/test cases/common/98 gen extra/name.l b/test cases/common/98 gen extra/name.l
new file mode 100644
index 0000000..3adda4f
--- /dev/null
+++ b/test cases/common/98 gen extra/name.l
@@ -0,0 +1,3 @@
+int main() {
+return 0;
+}
diff --git a/test cases/common/98 gen extra/srcgen2.py b/test cases/common/98 gen extra/srcgen2.py
new file mode 100644
index 0000000..9cdf12d
--- /dev/null
+++ b/test cases/common/98 gen extra/srcgen2.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python3
+
+import os
+import sys
+import argparse
+
+parser = argparse.ArgumentParser()
+parser.add_argument('target_dir',
+ help='the target dir')
+parser.add_argument('stem',
+ help='the stem')
+parser.add_argument('input',
+ help='the input file')
+
+options = parser.parse_args(sys.argv[1:])
+
+with open(options.input) as f:
+ content = f.read()
+
+
+output_c = os.path.join(options.target_dir, options.stem + ".tab.c")
+with open(output_c, 'w') as f:
+ f.write(content)
+
+
+output_h = os.path.join(options.target_dir, options.stem + ".tab.h")
+h_content = '''#pragma once
+
+int myfun(void);
+'''
+with open(output_h, 'w') as f:
+ f.write(h_content)
diff --git a/test cases/common/98 gen extra/srcgen3.py b/test cases/common/98 gen extra/srcgen3.py
new file mode 100644
index 0000000..ad0a5cb
--- /dev/null
+++ b/test cases/common/98 gen extra/srcgen3.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python3
+
+import os
+import sys
+import argparse
+
+parser = argparse.ArgumentParser()
+parser.add_argument('input',
+ help='the input file')
+
+options = parser.parse_args(sys.argv[1:])
+
+with open(options.input) as f:
+ content = f.read().strip()
+
+print(content)
diff --git a/test cases/d/3 shared library/meson.build b/test cases/d/3 shared library/meson.build
index 4ca3137..78ad766 100644
--- a/test cases/d/3 shared library/meson.build
+++ b/test cases/d/3 shared library/meson.build
@@ -2,8 +2,8 @@ project('D Shared Library', 'd')
dc = meson.get_compiler('d')
if dc.get_id() == 'gcc'
- if dc.version().version_compare('< 7')
- error('MESON_SKIP_TEST: GDC < 7.0 can not build shared libraries')
+ if dc.version().version_compare('< 8')
+ error('MESON_SKIP_TEST: GDC < 8.0 can not build shared libraries')
endif
endif
diff --git a/test cases/d/4 library versions/meson.build b/test cases/d/4 library versions/meson.build
index cba1458..c745b92 100644
--- a/test cases/d/4 library versions/meson.build
+++ b/test cases/d/4 library versions/meson.build
@@ -2,8 +2,8 @@ project('D library versions', 'd')
dc = meson.get_compiler('d')
if dc.get_id() == 'gcc'
- if dc.version().version_compare('< 7')
- error('MESON_SKIP_TEST: GDC < 7.0 can not build shared libraries')
+ if dc.version().version_compare('< 8')
+ error('MESON_SKIP_TEST: GDC < 8.0 can not build shared libraries')
endif
endif
diff --git a/test cases/d/7 multilib/meson.build b/test cases/d/7 multilib/meson.build
index 1d9a070..1879c08 100644
--- a/test cases/d/7 multilib/meson.build
+++ b/test cases/d/7 multilib/meson.build
@@ -2,8 +2,8 @@ project('D Multiple Versioned Shared Libraries', 'd')
dc = meson.get_compiler('d')
if dc.get_id() == 'gcc'
- if dc.version().version_compare('< 7')
- error('MESON_SKIP_TEST: GDC < 7.0 can not build shared libraries')
+ if dc.version().version_compare('< 8')
+ error('MESON_SKIP_TEST: GDC < 8.0 can not build shared libraries')
endif
endif
diff --git a/test cases/d/9 features/app.d b/test cases/d/9 features/app.d
new file mode 100644
index 0000000..37cc1dd
--- /dev/null
+++ b/test cases/d/9 features/app.d
@@ -0,0 +1,51 @@
+
+import std.stdio;
+import std.array : split;
+import std.string : strip;
+
+auto getMenu ()
+{
+ auto foods = import ("food.txt").strip.split ("\n");
+ return foods;
+}
+
+auto getPeople ()
+{
+ return import ("people.txt").strip.split ("\n");
+}
+
+void main (string[] args)
+{
+ import std.array : join;
+ import core.stdc.stdlib : exit;
+
+ immutable request = args[1];
+ if (request == "menu") {
+ version (No_Menu) {
+ } else {
+ writeln ("On the menu: ", getMenu.join (", "));
+ exit (0);
+ }
+ }
+
+ version (With_People) {
+ if (request == "people") {
+ writeln ("People: ", getPeople.join (", "));
+ exit (0);
+ }
+ }
+
+ // we fail here
+ exit (1);
+}
+
+unittest
+{
+ writeln ("TEST");
+ import core.stdc.stdlib : exit;
+
+ writeln(getMenu);
+ assert (getMenu () == ["Spam", "Eggs", "Spam", "Baked Beans", "Spam", "Spam"]);
+
+ exit (0);
+}
diff --git a/test cases/d/9 features/data/food.txt b/test cases/d/9 features/data/food.txt
new file mode 100644
index 0000000..8275dd0
--- /dev/null
+++ b/test cases/d/9 features/data/food.txt
@@ -0,0 +1,6 @@
+Spam
+Eggs
+Spam
+Baked Beans
+Spam
+Spam
diff --git a/test cases/d/9 features/data/people.txt b/test cases/d/9 features/data/people.txt
new file mode 100644
index 0000000..abbae06
--- /dev/null
+++ b/test cases/d/9 features/data/people.txt
@@ -0,0 +1,5 @@
+Rick
+Morty
+Summer
+Beth
+Jerry
diff --git a/test cases/d/9 features/meson.build b/test cases/d/9 features/meson.build
new file mode 100644
index 0000000..9e63710
--- /dev/null
+++ b/test cases/d/9 features/meson.build
@@ -0,0 +1,29 @@
+project('D Features', 'd')
+
+# directory for data
+data_dir = join_paths(meson.current_source_dir(), 'data')
+
+e_plain = executable('dapp_menu',
+ 'app.d',
+ d_import_dirs: [data_dir]
+)
+test('dapp_menu_t_fail', e_plain, should_fail: true)
+test('dapp_menu_t', e_plain, args: ['menu'])
+
+# test feature versions and string imports
+e_versions = executable('dapp_versions',
+ 'app.d',
+ d_import_dirs: [data_dir],
+ d_module_versions: ['No_Menu', 'With_People']
+)
+test('dapp_versions_t_fail', e_versions, args: ['menu'], should_fail: true)
+test('dapp_versions_t', e_versions, args: ['people'])
+
+# test everything and unittests
+e_test = executable('dapp_test',
+ 'app.d',
+ d_import_dirs: [data_dir],
+ d_module_versions: ['No_Menu', 'With_People'],
+ d_unittest: true
+)
+test('dapp_test', e_test)
diff --git a/test cases/failing/60 assign custom target index/meson.build b/test cases/failing/60 assign custom target index/meson.build
new file mode 100644
index 0000000..7f2a820
--- /dev/null
+++ b/test cases/failing/60 assign custom target index/meson.build
@@ -0,0 +1,24 @@
+# Copyright © 2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+prog_python = import('python3').find_python()
+
+target = custom_target(
+ 'target',
+ output : ['1', '2'],
+ command : [prog_python, '-c',
+ 'with open("1", "w") as f: f.write("foo"); with open("2", "w") as f: f.write("foo")'],
+)
+
+target[0] = 'foo'
diff --git a/test cases/failing/61 getoption prefix/meson.build b/test cases/failing/61 getoption prefix/meson.build
new file mode 100644
index 0000000..8f85cff
--- /dev/null
+++ b/test cases/failing/61 getoption prefix/meson.build
@@ -0,0 +1,5 @@
+project('getopt prefix')
+
+subproject('abc')
+
+get_option('abc:foo')
diff --git a/test cases/failing/61 getoption prefix/subprojects/abc/meson.build b/test cases/failing/61 getoption prefix/subprojects/abc/meson.build
new file mode 100644
index 0000000..aa9c3df
--- /dev/null
+++ b/test cases/failing/61 getoption prefix/subprojects/abc/meson.build
@@ -0,0 +1 @@
+project('abc', 'c')
diff --git a/test cases/failing/61 getoption prefix/subprojects/abc/meson_options.txt b/test cases/failing/61 getoption prefix/subprojects/abc/meson_options.txt
new file mode 100644
index 0000000..89e624e
--- /dev/null
+++ b/test cases/failing/61 getoption prefix/subprojects/abc/meson_options.txt
@@ -0,0 +1 @@
+option('foo', type : 'boolean')
diff --git a/test cases/failing/62 bad option argument/meson.build b/test cases/failing/62 bad option argument/meson.build
new file mode 100644
index 0000000..5219cfb
--- /dev/null
+++ b/test cases/failing/62 bad option argument/meson.build
@@ -0,0 +1,3 @@
+project('bad option')
+
+get_option('name')
diff --git a/test cases/failing/62 bad option argument/meson_options.txt b/test cases/failing/62 bad option argument/meson_options.txt
new file mode 100644
index 0000000..de1fff6
--- /dev/null
+++ b/test cases/failing/62 bad option argument/meson_options.txt
@@ -0,0 +1 @@
+option('name', type : 'string', vaule : 'foo')
diff --git a/test cases/failing/63 subproj filegrab/meson.build b/test cases/failing/63 subproj filegrab/meson.build
new file mode 100644
index 0000000..f38d6c7
--- /dev/null
+++ b/test cases/failing/63 subproj filegrab/meson.build
@@ -0,0 +1,5 @@
+project('mainproj', 'c')
+
+# Try to grab a file from a parent project.
+
+subproject('a')
diff --git a/test cases/failing/63 subproj filegrab/prog.c b/test cases/failing/63 subproj filegrab/prog.c
new file mode 100644
index 0000000..0314ff1
--- /dev/null
+++ b/test cases/failing/63 subproj filegrab/prog.c
@@ -0,0 +1 @@
+int main(int argc, char **argv) { return 0; }
diff --git a/test cases/failing/63 subproj filegrab/subprojects/a/meson.build b/test cases/failing/63 subproj filegrab/subprojects/a/meson.build
new file mode 100644
index 0000000..80b9888
--- /dev/null
+++ b/test cases/failing/63 subproj filegrab/subprojects/a/meson.build
@@ -0,0 +1,3 @@
+project('a', 'c')
+
+executable('prog', '../../prog.c')
diff --git a/test cases/failing/64 grab subproj/meson.build b/test cases/failing/64 grab subproj/meson.build
new file mode 100644
index 0000000..30fc690
--- /dev/null
+++ b/test cases/failing/64 grab subproj/meson.build
@@ -0,0 +1,7 @@
+project('grabber', 'c')
+
+# Try to grab a file from a child subproject.
+
+subproject('foo')
+
+executable('foo', 'subprojects/foo/sub.c')
diff --git a/test cases/failing/64 grab subproj/subprojects/foo/meson.build b/test cases/failing/64 grab subproj/subprojects/foo/meson.build
new file mode 100644
index 0000000..b346f6d
--- /dev/null
+++ b/test cases/failing/64 grab subproj/subprojects/foo/meson.build
@@ -0,0 +1,3 @@
+project('foo', 'c')
+
+message('I do nothing.')
diff --git a/test cases/failing/64 grab subproj/subprojects/foo/sub.c b/test cases/failing/64 grab subproj/subprojects/foo/sub.c
new file mode 100644
index 0000000..a94b1f5
--- /dev/null
+++ b/test cases/failing/64 grab subproj/subprojects/foo/sub.c
@@ -0,0 +1,6 @@
+#include<stdio.h>
+
+int main(int argc, char **argv) {
+ printf("I am a subproject executable file.\n");
+ return 0;
+}
diff --git a/test cases/failing/65 grab sibling/meson.build b/test cases/failing/65 grab sibling/meson.build
new file mode 100644
index 0000000..60b926a
--- /dev/null
+++ b/test cases/failing/65 grab sibling/meson.build
@@ -0,0 +1,3 @@
+project('master', 'c')
+
+subproject('a')
diff --git a/test cases/failing/65 grab sibling/subprojects/a/meson.build b/test cases/failing/65 grab sibling/subprojects/a/meson.build
new file mode 100644
index 0000000..6dd9f61
--- /dev/null
+++ b/test cases/failing/65 grab sibling/subprojects/a/meson.build
@@ -0,0 +1,3 @@
+project('a', 'c')
+
+executable('sneaky', '../b/sneaky.c')
diff --git a/test cases/failing/65 grab sibling/subprojects/b/meson.build b/test cases/failing/65 grab sibling/subprojects/b/meson.build
new file mode 100644
index 0000000..7c70fe5
--- /dev/null
+++ b/test cases/failing/65 grab sibling/subprojects/b/meson.build
@@ -0,0 +1,3 @@
+projecT('b', 'c')
+
+message('I do nothing.')
diff --git a/test cases/failing/65 grab sibling/subprojects/b/sneaky.c b/test cases/failing/65 grab sibling/subprojects/b/sneaky.c
new file mode 100644
index 0000000..f1cb916
--- /dev/null
+++ b/test cases/failing/65 grab sibling/subprojects/b/sneaky.c
@@ -0,0 +1,6 @@
+#include<stdio.h>
+
+int main(int argc, char **argv) {
+ printf("I can only come into existance via trickery.\n");
+ return 0;
+}
diff --git a/test cases/failing/66 string as link target/meson.build b/test cases/failing/66 string as link target/meson.build
new file mode 100644
index 0000000..cb83fff
--- /dev/null
+++ b/test cases/failing/66 string as link target/meson.build
@@ -0,0 +1,2 @@
+project('string as link argument', 'c')
+executable('myprog', 'prog.c', link_with: [ '' ])
diff --git a/test cases/failing/66 string as link target/prog.c b/test cases/failing/66 string as link target/prog.c
new file mode 100644
index 0000000..0314ff1
--- /dev/null
+++ b/test cases/failing/66 string as link target/prog.c
@@ -0,0 +1 @@
+int main(int argc, char **argv) { return 0; }
diff --git a/test cases/frameworks/1 boost/meson.build b/test cases/frameworks/1 boost/meson.build
index 6f25f8b..b73f93a 100644
--- a/test cases/frameworks/1 boost/meson.build
+++ b/test cases/frameworks/1 boost/meson.build
@@ -9,21 +9,18 @@ add_project_arguments(['-DBOOST_LOG_DYN_LINK'],
# within one project. The need to be independent of each other.
# Use one without a library dependency and one with it.
-nolinkdep = dependency('boost', modules: 'utility')
linkdep = dependency('boost', modules : ['thread', 'system'])
staticdep = dependency('boost', modules : ['thread', 'system'], static : true)
-testdep = dependency('boost', modules : 'test')
+testdep = dependency('boost', modules : ['unit_test_framework'])
nomoddep = dependency('boost')
extralibdep = dependency('boost', modules : ['thread', 'system', 'log_setup', 'log'])
-nolinkexe = executable('nolinkedexe', 'nolinkexe.cc', dependencies : nolinkdep)
linkexe = executable('linkedexe', 'linkexe.cc', dependencies : linkdep)
staticexe = executable('staticlinkedexe', 'linkexe.cc', dependencies : staticdep)
unitexe = executable('utf', 'unit_test.cpp', dependencies: testdep)
nomodexe = executable('nomod', 'nomod.cpp', dependencies : nomoddep)
extralibexe = executable('extralibexe', 'extralib.cpp', dependencies : extralibdep)
-test('Boost nolinktest', nolinkexe)
test('Boost linktest', linkexe)
test('Boost statictest', staticexe)
test('Boost UTF test', unitexe)
diff --git a/test cases/frameworks/1 boost/nolinkexe.cc b/test cases/frameworks/1 boost/nolinkexe.cc
deleted file mode 100644
index 7b6c6d9..0000000
--- a/test cases/frameworks/1 boost/nolinkexe.cc
+++ /dev/null
@@ -1,12 +0,0 @@
-#include<boost/utility.hpp>
-
-class MyClass : boost::noncopyable {
-public:
- MyClass() {};
- ~MyClass() {};
-};
-
-int main(int argc, char **argv) {
- MyClass obj;
- return 0;
-}
diff --git a/test cases/frameworks/15 llvm/meson.build b/test cases/frameworks/15 llvm/meson.build
index af7f8c6..5211006 100644
--- a/test cases/frameworks/15 llvm/meson.build
+++ b/test cases/frameworks/15 llvm/meson.build
@@ -1,17 +1,36 @@
project('llvmtest', ['c', 'cpp'], default_options : ['c_std=c99'])
-llvm_dep = dependency(
- 'llvm',
- modules : ['bitwriter', 'asmprinter', 'executionengine', 'target',
- 'mcjit', 'nativecodegen'],
- required : true,
-)
-
d = dependency('llvm', modules : 'not-found', required : false)
assert(d.found() == false, 'not-found llvm module found')
-# XXX: Version checks are broken, see FIXME in LLVMDependency
-#d = dependency('llvm', version : '<0.1', required : false)
-#assert(d.found() == false, 'ancient llvm module found')
+d = dependency('llvm', version : '<0.1', required : false)
+assert(d.found() == false, 'ancient llvm module found')
+
+d = dependency('llvm', optional_modules : 'not-found', required : false)
+assert(d.found() == true, 'optional module stopped llvm from being found.')
+
+dep_tinfo = dependency('tinfo', required : false)
+if not dep_tinfo.found()
+ cpp = meson.get_compiler('cpp')
+ dep_tinfo = cpp.find_library('tinfo')
+endif
-executable('sum', 'sum.c', dependencies : llvm_dep)
+foreach static : [true, false]
+ llvm_dep = dependency(
+ 'llvm',
+ modules : ['bitwriter', 'asmprinter', 'executionengine', 'target',
+ 'mcjit', 'nativecodegen'],
+ required : true,
+ static : static,
+ )
+ name = static ? 'static' : 'dynamic'
+ executable(
+ 'sum-@0@'.format(name),
+ 'sum.c',
+ dependencies : [
+ llvm_dep, dep_tinfo,
+ dependency('zlib'),
+ meson.get_compiler('c').find_library('dl', required : false),
+ ]
+ )
+endforeach
diff --git a/test cases/frameworks/17 mpi/is_artful.py b/test cases/frameworks/17 mpi/is_artful.py
new file mode 100755
index 0000000..9d4512d
--- /dev/null
+++ b/test cases/frameworks/17 mpi/is_artful.py
@@ -0,0 +1,9 @@
+#!/usr/bin/env python3
+
+# Any exception causes return value to be not zero, which is sufficient.
+
+import sys
+
+fc = open('/etc/apt/sources.list').read()
+if 'artful' not in fc:
+ sys.exit(1)
diff --git a/test cases/frameworks/17 mpi/meson.build b/test cases/frameworks/17 mpi/meson.build
index 5e9bc56..17acd71 100644
--- a/test cases/frameworks/17 mpi/meson.build
+++ b/test cases/frameworks/17 mpi/meson.build
@@ -23,7 +23,15 @@ if build_machine.system() != 'windows'
test('MPI C++', execpp)
endif
-if add_languages('fortran', required : false)
+# OpenMPI is broken with Fortran on Ubuntu Artful.
+# Remove this once the following bug has been fixed:
+#
+# https://bugs.launchpad.net/ubuntu/+source/gcc-defaults/+bug/1727474
+
+ubudetector = find_program('is_artful.py')
+uburesult = run_command(ubudetector)
+
+if uburesult.returncode() != 0 and add_languages('fortran', required : false)
mpifort = dependency('mpi', language : 'fortran')
exef = executable('exef',
'main.f90',
diff --git a/test cases/frameworks/19 pcap/meson.build b/test cases/frameworks/19 pcap/meson.build
index 909d7cd..c505960 100644
--- a/test cases/frameworks/19 pcap/meson.build
+++ b/test cases/frameworks/19 pcap/meson.build
@@ -2,6 +2,9 @@ project('pcap test', 'c')
pcap_dep = dependency('pcap', version : '>=1.0')
+pcap_ver = pcap_dep.version()
+assert(pcap_ver.split('.').length() > 1, 'pcap version is "@0@"'.format(pcap_ver))
+
e = executable('pcap_prog', 'pcap_prog.c', dependencies : pcap_dep)
test('pcaptest', e)
diff --git a/test cases/frameworks/21 libwmf/libwmf_prog.c b/test cases/frameworks/21 libwmf/libwmf_prog.c
new file mode 100644
index 0000000..4e6294c
--- /dev/null
+++ b/test cases/frameworks/21 libwmf/libwmf_prog.c
@@ -0,0 +1,8 @@
+#include <libwmf/api.h>
+
+int
+main()
+{
+ wmf_help();
+ return 0;
+}
diff --git a/test cases/frameworks/21 libwmf/meson.build b/test cases/frameworks/21 libwmf/meson.build
new file mode 100644
index 0000000..a7d9263
--- /dev/null
+++ b/test cases/frameworks/21 libwmf/meson.build
@@ -0,0 +1,9 @@
+project('libwmf test', 'c')
+
+libwmf_dep = dependency('libwmf', version : '>=3.0')
+libwmf_ver = libwmf_dep.version()
+assert(libwmf_ver.split('.').length() > 1, 'libwmf version is "@0@"'.format(libwmf_ver))
+message('libwmf version is "@0@"'.format(libwmf_ver))
+e = executable('libwmf_prog', 'libwmf_prog.c', dependencies : libwmf_dep)
+
+test('libwmftest', e)
diff --git a/test cases/frameworks/4 qt/main.cpp b/test cases/frameworks/4 qt/main.cpp
index 4c257a4..388467e 100644
--- a/test cases/frameworks/4 qt/main.cpp
+++ b/test cases/frameworks/4 qt/main.cpp
@@ -2,6 +2,10 @@
#include "mainWindow.h"
int main(int argc, char **argv) {
+ #ifndef UNITY_BUILD
+ Q_INIT_RESOURCE(stuff);
+ Q_INIT_RESOURCE(stuff2);
+ #endif
QApplication app(argc, argv);
MainWindow *win = new MainWindow();
QImage qi(":/thing.png");
@@ -13,7 +17,20 @@ int main(int argc, char **argv) {
return 1;
}
win->setWindowTitle("Meson Qt5 build test");
-
+ QLabel *label_stuff = win->findChild<QLabel *>("label_stuff");
+ if(label_stuff == nullptr) {
+ return 1;
+ }
+ int w = label_stuff->width();
+ int h = label_stuff->height();
+ label_stuff->setPixmap(QPixmap::fromImage(qi).scaled(w,h,Qt::KeepAspectRatio));
+ QLabel *label_stuff2 = win->findChild<QLabel *>("label_stuff2");
+ if(label_stuff2 == nullptr) {
+ return 1;
+ }
+ w = label_stuff2->width();
+ h = label_stuff2->height();
+ label_stuff2->setPixmap(QPixmap::fromImage(qi2).scaled(w,h,Qt::KeepAspectRatio));
win->show();
return app.exec();
return 0;
diff --git a/test cases/frameworks/4 qt/mainWindow.ui b/test cases/frameworks/4 qt/mainWindow.ui
index 2eb226a..c01b8bf 100644
--- a/test cases/frameworks/4 qt/mainWindow.ui
+++ b/test cases/frameworks/4 qt/mainWindow.ui
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>270</width>
- <height>115</height>
+ <width>260</width>
+ <height>313</height>
</rect>
</property>
<property name="windowTitle">
@@ -27,6 +27,26 @@
<string>I am a button</string>
</property>
</widget>
+ <widget class="QLabel" name="label_stuff">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>112</y>
+ <width>241</width>
+ <height>91</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QLabel" name="label_stuff2">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>212</y>
+ <width>241</width>
+ <height>91</height>
+ </rect>
+ </property>
+ </widget>
</widget>
</widget>
<resources/>
diff --git a/test cases/frameworks/4 qt/manualinclude.cpp b/test cases/frameworks/4 qt/manualinclude.cpp
index 0602882..6c1ac2f 100644
--- a/test cases/frameworks/4 qt/manualinclude.cpp
+++ b/test cases/frameworks/4 qt/manualinclude.cpp
@@ -6,6 +6,10 @@
ManualInclude::ManualInclude() {
}
+void ManualInclude::myslot(void) {
+ ;
+}
+
class MocClass : public QObject {
Q_OBJECT
};
@@ -13,6 +17,9 @@ class MocClass : public QObject {
int main(int argc, char **argv) {
ManualInclude mi;
MocClass mc;
+ QObject::connect(&mi, SIGNAL(mysignal(void)),
+ &mi, SLOT(myslot(void)));
+ emit mi.mysignal();
return 0;
}
diff --git a/test cases/frameworks/4 qt/manualinclude.h b/test cases/frameworks/4 qt/manualinclude.h
index 4a00b6c..44bb7a7 100644
--- a/test cases/frameworks/4 qt/manualinclude.h
+++ b/test cases/frameworks/4 qt/manualinclude.h
@@ -8,8 +8,14 @@ class ManualInclude : public QObject {
public:
ManualInclude();
+#if defined(MOC_EXTRA_FLAG)
+public slots:
+#endif
+ void myslot(void);
+#if defined(MOC_EXTRA_FLAG)
signals:
+#endif
int mysignal();
};
diff --git a/test cases/frameworks/4 qt/meson.build b/test cases/frameworks/4 qt/meson.build
index d9cab6f..374707a 100644
--- a/test cases/frameworks/4 qt/meson.build
+++ b/test cases/frameworks/4 qt/meson.build
@@ -35,17 +35,26 @@ foreach qt : ['qt4', 'qt5']
prep = qtmodule.preprocess(
moc_headers : ['mainWindow.h'], # These need to be fed through the moc tool before use.
ui_files : 'mainWindow.ui', # XML files that need to be compiled with the uic tol.
- qresources : ['stuff.qrc', 'stuff2.qrc'], # Resource file for rcc compiler.
method : get_option('method')
)
+ # Resource file(s) for rcc compiler
+ extra_cpp_args = []
+ if meson.is_unity()
+ extra_cpp_args += '-DUNITY_BUILD'
+ prep_rcc = qtmodule.preprocess(qt + '_unity_ressource', qresources : ['stuff.qrc', 'stuff2.qrc'], method : get_option('method'))
+ else
+ prep_rcc = qtmodule.preprocess(qresources : ['stuff.qrc', 'stuff2.qrc'], method : get_option('method'))
+ endif
+
# Test that setting a unique name with a positional argument works
- qtmodule.preprocess(qt + 'teststuff', qresources : ['stuff.qrc'], method : get_option('method'))
+ qtmodule.preprocess(qt + 'teststuff', qresources : ['stuff.qrc', 'stuff2.qrc'], method : get_option('method'))
qexe = executable(qt + 'app',
sources : ['main.cpp', 'mainWindow.cpp', # Sources that don't need preprocessing.
- prep],
- dependencies : qtdep)
+ prep, prep_rcc],
+ dependencies : qtdep,
+ cpp_args: extra_cpp_args)
# We need a console test application because some test environments
# do not have an X server.
@@ -61,6 +70,7 @@ foreach qt : ['qt4', 'qt5']
# headers but the user must manually include moc
# files from sources.
manpreprocessed = qtmodule.preprocess(
+ moc_extra_arguments : ['-DMOC_EXTRA_FLAG'], # This is just a random macro to test `moc_extra_arguments`
moc_sources : 'manualinclude.cpp',
moc_headers : 'manualinclude.h',
method : get_option('method'))
@@ -70,5 +80,15 @@ foreach qt : ['qt4', 'qt5']
dependencies : qtcore)
test(qt + 'maninclude', qtmaninclude)
+
+ # building Qt plugins implies to give include path to moc
+ plugin_includes = include_directories('pluginInterface', 'plugin')
+ pluginpreprocess = qtmodule.preprocess(
+ moc_headers : 'plugin/plugin.h',
+ include_directories : plugin_includes
+ )
+ plugin = library(qt + 'plugin', 'plugin/plugin.cpp', pluginpreprocess,
+ include_directories : plugin_includes,
+ dependencies : qtcore)
endif
endforeach
diff --git a/test cases/frameworks/4 qt/plugin/plugin.cpp b/test cases/frameworks/4 qt/plugin/plugin.cpp
new file mode 100644
index 0000000..2c013fe
--- /dev/null
+++ b/test cases/frameworks/4 qt/plugin/plugin.cpp
@@ -0,0 +1,12 @@
+#include "plugin.h"
+#include <QFile>
+
+QString plugin1::getResource()
+{
+ return "hello world";
+}
+
+
+#if QT_VERSION < 0x050000
+ Q_EXPORT_PLUGIN2(Plugin1, plugin1)
+#endif \ No newline at end of file
diff --git a/test cases/frameworks/4 qt/plugin/plugin.h b/test cases/frameworks/4 qt/plugin/plugin.h
new file mode 100644
index 0000000..c8e14e4
--- /dev/null
+++ b/test cases/frameworks/4 qt/plugin/plugin.h
@@ -0,0 +1,14 @@
+#pragma once
+#include <plugin_if.h>
+
+class plugin1:public QObject,public PluginInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(PluginInterface)
+#if QT_VERSION >= 0x050000
+ Q_PLUGIN_METADATA(IID "demo.PluginInterface" FILE "plugin.json")
+#endif
+
+public:
+ QString getResource() override;
+};
diff --git a/test cases/frameworks/4 qt/plugin/plugin.json b/test cases/frameworks/4 qt/plugin/plugin.json
new file mode 100644
index 0000000..6c6a011
--- /dev/null
+++ b/test cases/frameworks/4 qt/plugin/plugin.json
@@ -0,0 +1,3 @@
+{
+ "name" : "Plugin1"
+}
diff --git a/test cases/frameworks/4 qt/pluginInterface/plugin_if.h b/test cases/frameworks/4 qt/pluginInterface/plugin_if.h
new file mode 100644
index 0000000..97d2800
--- /dev/null
+++ b/test cases/frameworks/4 qt/pluginInterface/plugin_if.h
@@ -0,0 +1,21 @@
+#ifndef PLUGIN_IF_H
+#define PLUGIN_IF_H
+
+#include <QString>
+#include <QtPlugin>
+
+/**
+ * @brief Interface for a plugin
+ */
+class PluginInterface
+{
+public:
+ virtual ~PluginInterface() = default;
+
+ /// Initializes the plugin
+ virtual QString getResource() = 0;
+};
+
+Q_DECLARE_INTERFACE(PluginInterface, "demo.PluginInterface")
+
+#endif
diff --git a/test cases/frameworks/7 gnome/gir/dep1/meson.build b/test cases/frameworks/7 gnome/gir/dep1/meson.build
index 75dd731..baa0b1d 100644
--- a/test cases/frameworks/7 gnome/gir/dep1/meson.build
+++ b/test cases/frameworks/7 gnome/gir/dep1/meson.build
@@ -19,6 +19,7 @@ dep1gir = gnome.generate_gir(
namespace : 'MesonDep1',
symbol_prefix : 'meson',
identifier_prefix : 'Meson',
+ header: 'dep1.h',
includes : ['GObject-2.0', 'MesonDep2-1.0'],
dependencies : [dep2_dep],
install : true
diff --git a/test cases/frameworks/7 gnome/gir/meson.build b/test cases/frameworks/7 gnome/gir/meson.build
index 3598b66..a91cb97 100644
--- a/test cases/frameworks/7 gnome/gir/meson.build
+++ b/test cases/frameworks/7 gnome/gir/meson.build
@@ -27,7 +27,7 @@ gnome.generate_gir(
identifier_prefix : 'Meson',
includes : ['GObject-2.0', 'MesonDep1-1.0'],
# dep1_dep pulls in dep2_dep for us
- dependencies : [fake_dep, dep1_dep],
+ dependencies : [[fake_dep, dep1_dep]],
install : true,
build_by_default : true,
# Test that unknown kwargs do not crash the parser.
diff --git a/test cases/unit/13 reconfigure/meson.build b/test cases/unit/13 reconfigure/meson.build
new file mode 100644
index 0000000..102180e
--- /dev/null
+++ b/test cases/unit/13 reconfigure/meson.build
@@ -0,0 +1,5 @@
+project('reconfigure test', ['c'])
+
+if get_option('b_lto') != true
+ error('b_lto not set')
+endif
diff --git a/test cases/prebuilt/1 object/main.c b/test cases/unit/14 prebuilt object/main.c
index 480bda5..480bda5 100644
--- a/test cases/prebuilt/1 object/main.c
+++ b/test cases/unit/14 prebuilt object/main.c
diff --git a/test cases/prebuilt/1 object/meson.build b/test cases/unit/14 prebuilt object/meson.build
index 92f966b..92f966b 100644
--- a/test cases/prebuilt/1 object/meson.build
+++ b/test cases/unit/14 prebuilt object/meson.build
diff --git a/test cases/prebuilt/1 object/source.c b/test cases/unit/14 prebuilt object/source.c
index f39b4f3..f39b4f3 100644
--- a/test cases/prebuilt/1 object/source.c
+++ b/test cases/unit/14 prebuilt object/source.c
diff --git a/test cases/prebuilt/2 static/libdir/best.c b/test cases/unit/15 prebuilt static/libdir/best.c
index ab774e1..ab774e1 100644
--- a/test cases/prebuilt/2 static/libdir/best.c
+++ b/test cases/unit/15 prebuilt static/libdir/best.c
diff --git a/test cases/prebuilt/2 static/libdir/best.h b/test cases/unit/15 prebuilt static/libdir/best.h
index 063017f..063017f 100644
--- a/test cases/prebuilt/2 static/libdir/best.h
+++ b/test cases/unit/15 prebuilt static/libdir/best.h
diff --git a/test cases/prebuilt/2 static/libdir/meson.build b/test cases/unit/15 prebuilt static/libdir/meson.build
index 8d74ccf..8d74ccf 100644
--- a/test cases/prebuilt/2 static/libdir/meson.build
+++ b/test cases/unit/15 prebuilt static/libdir/meson.build
diff --git a/test cases/prebuilt/2 static/main.c b/test cases/unit/15 prebuilt static/main.c
index d172625..d172625 100644
--- a/test cases/prebuilt/2 static/main.c
+++ b/test cases/unit/15 prebuilt static/main.c
diff --git a/test cases/prebuilt/2 static/meson.build b/test cases/unit/15 prebuilt static/meson.build
index 9ea1d0d..9ea1d0d 100644
--- a/test cases/prebuilt/2 static/meson.build
+++ b/test cases/unit/15 prebuilt static/meson.build
diff --git a/test cases/unit/16 prebuilt shared/alexandria.c b/test cases/unit/16 prebuilt shared/alexandria.c
new file mode 100644
index 0000000..2d6b848
--- /dev/null
+++ b/test cases/unit/16 prebuilt shared/alexandria.c
@@ -0,0 +1,6 @@
+#include"alexandria.h"
+#include<stdio.h>
+
+void alexandria_visit() {
+ printf("You are surrounded by wisdom and knowledge. You feel enlightened.\n");
+}
diff --git a/test cases/unit/16 prebuilt shared/alexandria.h b/test cases/unit/16 prebuilt shared/alexandria.h
new file mode 100644
index 0000000..6e507c5
--- /dev/null
+++ b/test cases/unit/16 prebuilt shared/alexandria.h
@@ -0,0 +1,20 @@
+#pragma once
+
+/* Both funcs here for simplicity. */
+
+#if defined _WIN32 || defined __CYGWIN__
+#if defined BUILDING_DLL
+ #define DLL_PUBLIC __declspec(dllexport)
+#else
+ #define DLL_PUBLIC __declspec(dllimport)
+#endif
+#else
+ #if defined __GNUC__
+ #define DLL_PUBLIC __attribute__ ((visibility("default")))
+ #else
+ #pragma message ("Compiler does not support symbol visibility.")
+ #define DLL_PUBLIC
+ #endif
+#endif
+
+void DLL_PUBLIC alexandria_visit();
diff --git a/test cases/unit/16 prebuilt shared/another_visitor.c b/test cases/unit/16 prebuilt shared/another_visitor.c
new file mode 100644
index 0000000..18e5f15
--- /dev/null
+++ b/test cases/unit/16 prebuilt shared/another_visitor.c
@@ -0,0 +1,10 @@
+#include<alexandria.h>
+#include<stdio.h>
+
+int main(int argc, char **argv) {
+ printf("Ahh, another visitor. Stay a while.\n");
+ printf("You enter the library.\n\n");
+ alexandria_visit();
+ printf("\nYou decided not to stay forever.\n");
+ return 0;
+}
diff --git a/test cases/unit/16 prebuilt shared/meson.build b/test cases/unit/16 prebuilt shared/meson.build
new file mode 100644
index 0000000..41c11c6
--- /dev/null
+++ b/test cases/unit/16 prebuilt shared/meson.build
@@ -0,0 +1,14 @@
+project('prebuilt shared library', 'c')
+
+cc = meson.get_compiler('c')
+shlib = cc.find_library('alexandria', dirs : meson.current_source_dir())
+
+exe = executable('patron', 'patron.c', dependencies : shlib)
+test('visitation', exe)
+
+d = declare_dependency(dependencies : shlib)
+
+exe2 = executable('another_visitor', 'another_visitor.c',
+ dependencies : d)
+test('another', exe2)
+
diff --git a/test cases/unit/16 prebuilt shared/patron.c b/test cases/unit/16 prebuilt shared/patron.c
new file mode 100644
index 0000000..82d9678
--- /dev/null
+++ b/test cases/unit/16 prebuilt shared/patron.c
@@ -0,0 +1,8 @@
+#include<alexandria.h>
+#include<stdio.h>
+
+int main(int argc, char **argv) {
+ printf("You are standing outside the Great Library of Alexandria.\n");
+ printf("You decide to go inside.\n\n");
+ alexandria_visit();
+}
diff --git a/test cases/vala/12 custom output/bar.vala b/test cases/vala/12 custom output/bar.vala
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test cases/vala/12 custom output/bar.vala
diff --git a/test cases/vala/12 custom output/meson.build b/test cases/vala/12 custom output/meson.build
index ef6dbb5..c328959 100644
--- a/test cases/vala/12 custom output/meson.build
+++ b/test cases/vala/12 custom output/meson.build
@@ -3,7 +3,11 @@ project('valatest', 'c', 'vala')
glib = dependency('glib-2.0')
gobject = dependency('gobject-2.0')
-library('foo-1.0', 'foo.vala',
- vala_header: 'foo.h',
- vala_vapi: 'foo.vapi',
+foo_lib = library('foo-1.0', 'foo.vala',
+ vala_header: 'foo.h',
+ vala_vapi: 'foo.vapi',
+ dependencies: [glib, gobject])
+
+library('bar', 'bar.vala',
+ link_with: [foo_lib],
dependencies: [glib, gobject])
diff --git a/test cases/vala/22 same target in directories/Subdir/Subdir2/Test.vala b/test cases/vala/22 same target in directories/Subdir/Subdir2/Test.vala
new file mode 100644
index 0000000..94e5cbc
--- /dev/null
+++ b/test cases/vala/22 same target in directories/Subdir/Subdir2/Test.vala
@@ -0,0 +1,5 @@
+public class Subdir.Subdir2.Test : GLib.Object {
+ construct {
+ stdout.printf("Test from Subdir/Subdir2/\n");
+ }
+}
diff --git a/test cases/vala/22 same target in directories/Subdir/Test.vala b/test cases/vala/22 same target in directories/Subdir/Test.vala
new file mode 100644
index 0000000..02143c4
--- /dev/null
+++ b/test cases/vala/22 same target in directories/Subdir/Test.vala
@@ -0,0 +1,5 @@
+public class Subdir.Test : GLib.Object {
+ construct {
+ stdout.printf("Test from Subdir/\n");
+ }
+}
diff --git a/test cases/vala/22 same target in directories/Subdir2/Test.vala b/test cases/vala/22 same target in directories/Subdir2/Test.vala
new file mode 100644
index 0000000..4a2d61f
--- /dev/null
+++ b/test cases/vala/22 same target in directories/Subdir2/Test.vala
@@ -0,0 +1,5 @@
+public class Subdir2.Test : GLib.Object {
+ construct {
+ stdout.printf("Test from Subdir2/\n");
+ }
+}
diff --git a/test cases/vala/22 same target in directories/Test.vala b/test cases/vala/22 same target in directories/Test.vala
new file mode 100644
index 0000000..9154e22
--- /dev/null
+++ b/test cases/vala/22 same target in directories/Test.vala
@@ -0,0 +1,5 @@
+public class Test : GLib.Object {
+ construct {
+ stdout.printf("Test from main directory\n");
+ }
+}
diff --git a/test cases/vala/22 same target in directories/meson.build b/test cases/vala/22 same target in directories/meson.build
new file mode 100644
index 0000000..6785f73
--- /dev/null
+++ b/test cases/vala/22 same target in directories/meson.build
@@ -0,0 +1,13 @@
+project('valatest', 'vala', 'c')
+
+valadeps = [dependency('glib-2.0'), dependency('gobject-2.0')]
+valafiles = files(
+ 'prog.vala',
+ 'Test.vala',
+ 'Subdir/Test.vala',
+ 'Subdir/Subdir2/Test.vala',
+ 'Subdir2/Test.vala',
+)
+
+e = executable('multidir_prog', valafiles, dependencies : valadeps)
+test('valatest', e)
diff --git a/test cases/vala/22 same target in directories/prog.vala b/test cases/vala/22 same target in directories/prog.vala
new file mode 100644
index 0000000..37cbf7a
--- /dev/null
+++ b/test cases/vala/22 same target in directories/prog.vala
@@ -0,0 +1,8 @@
+int main() {
+ var test1 = new Test ();
+ var test2 = new Subdir.Test ();
+ var test3 = new Subdir2.Test ();
+ var test4 = new Subdir.Subdir2.Test ();
+ stdout.printf("Vala is working.\n");
+ return 0;
+}
diff --git a/tools/boost_names.py b/tools/boost_names.py
new file mode 100755
index 0000000..d381162
--- /dev/null
+++ b/tools/boost_names.py
@@ -0,0 +1,187 @@
+#!/usr/bin/env python3
+
+# Copyright 2017 Niklas Claesson
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""This is two implementations for how to get module names from the boost
+sources. One relies on json metadata files in the sources, the other relies on
+the folder names.
+
+Run the tool in the boost directory and append the stdout to the misc.py:
+
+boost/$ path/to/meson/tools/boost_names.py >> path/to/meson/dependencies/misc.py
+"""
+
+import sys
+import os
+import collections
+import pprint
+import json
+import re
+
+Module = collections.namedtuple('Module', ['dirname', 'name', 'libnames'])
+Module.__repr__ = lambda self: str((self.dirname, self.name, self.libnames))
+
+LIBS = 'libs'
+
+manual_map = {
+ 'callable_traits': 'Call Traits',
+ 'crc': 'CRC',
+ 'dll': 'DLL',
+ 'gil': 'GIL',
+ 'graph_parallel': 'GraphParallel',
+ 'icl': 'ICL',
+ 'io': 'IO State Savers',
+ 'msm': 'Meta State Machine',
+ 'mpi': 'MPI',
+ 'mpl': 'MPL',
+ 'multi_array': 'Multi-Array',
+ 'multi_index': 'Multi-Index',
+ 'numeric': 'Numeric Conversion',
+ 'ptr_container': 'Pointer Container',
+ 'poly_collection': 'PolyCollection',
+ 'qvm': 'QVM',
+ 'throw_exception': 'ThrowException',
+ 'tti': 'TTI',
+ 'vmd': 'VMD',
+}
+
+extra = [
+ Module('utility', 'Compressed Pair', []),
+ Module('core', 'Enable If', []),
+ Module('functional', 'Functional/Factory', []),
+ Module('functional', 'Functional/Forward', []),
+ Module('functional', 'Functional/Hash', []),
+ Module('functional', 'Functional/Overloaded Function', []),
+ Module('utility', 'Identity Type', []),
+ Module('utility', 'In Place Factory, Typed In Place Factory', []),
+ Module('numeric', 'Interval', []),
+ Module('math', 'Math Common Factor', []),
+ Module('math', 'Math Octonion', []),
+ Module('math', 'Math Quaternion', []),
+ Module('math', 'Math/Special Functions', []),
+ Module('math', 'Math/Statistical Distributions', []),
+ Module('bind', 'Member Function', []),
+ Module('algorithm', 'Min-Max', []),
+ Module('numeric', 'Odeint', []),
+ Module('utility', 'Operators', []),
+ Module('core', 'Ref', []),
+ Module('utility', 'Result Of', []),
+ Module('algorithm', 'String Algo', []),
+ Module('core', 'Swap', []),
+ Module('', 'Tribool', []),
+ Module('numeric', 'uBLAS', []),
+ Module('utility', 'Value Initialized', []),
+]
+
+# Cannot find the following modules in the documentation of boost
+not_modules = ['beast', 'logic', 'mp11', 'winapi']
+
+def eprint(message):
+ print(message, file=sys.stderr)
+
+def get_library_names(jamfile):
+ libs = []
+ with open(jamfile) as jamfh:
+ jam = jamfh.read()
+ res = re.finditer(r'^lib[\s]+([A-Za-z0-9_]+)([^;]*);', jam, re.MULTILINE | re.DOTALL)
+ for matches in res:
+ if ':' in matches.group(2):
+ libs.append(matches.group(1))
+ res = re.finditer(r'^boost-lib[\s]+([A-Za-z0-9_]+)([^;]*);', jam, re.MULTILINE | re.DOTALL)
+ for matches in res:
+ if ':' in matches.group(2):
+ libs.append('boost_{}'.format(matches.group(1)))
+ return libs
+
+def exists(modules, module):
+ return len([x for x in modules if x.dirname == module.dirname]) != 0
+
+def get_modules(init=extra):
+ modules = init
+ for directory in os.listdir(LIBS):
+ if not os.path.isdir(os.path.join(LIBS, directory)):
+ continue
+ if directory in not_modules:
+ continue
+ jamfile = os.path.join(LIBS, directory, 'build', 'Jamfile.v2')
+ if os.path.isfile(jamfile):
+ libs = get_library_names(jamfile)
+ else:
+ libs = []
+ if directory in manual_map.keys():
+ modname = manual_map[directory]
+ else:
+ modname = directory.replace('_', ' ').title()
+ modules.append(Module(directory, modname, libs))
+ return modules
+
+def get_modules_2():
+ modules = []
+ # The python module uses an older build system format and is not easily parseable.
+ # We add the python module libraries manually.
+ modules.append(Module('python', 'Python', ['boost_python', 'boost_python3', 'boost_numpy', 'boost_numpy3']))
+ for (root, dirs, files) in os.walk(LIBS):
+ for f in files:
+ if f == "libraries.json":
+ projectdir = os.path.dirname(root)
+
+ jamfile = os.path.join(projectdir, 'build', 'Jamfile.v2')
+ if os.path.isfile(jamfile):
+ libs = get_library_names(jamfile)
+ else:
+ libs = []
+
+ # Get metadata for module
+ jsonfile = os.path.join(root, f)
+ with open(jsonfile) as jsonfh:
+ boost_modules = json.loads(jsonfh.read())
+ if(isinstance(boost_modules, dict)):
+ boost_modules = [boost_modules]
+ for boost_module in boost_modules:
+ modules.append(Module(boost_module['key'], boost_module['name'], libs))
+
+ # Some subprojects do not have meta directory with json file. Find those
+ jsonless_modules = [x for x in get_modules([]) if not exists(modules, x)]
+ for module in jsonless_modules:
+ eprint("WARNING: {} does not have meta/libraries.json. Will guess pretty name '{}'".format(module.dirname, module.name))
+ modules.extend(jsonless_modules)
+
+ return modules
+
+def main(args):
+ if not os.path.isdir(LIBS):
+ eprint("ERROR: script must be run in boost source directory")
+
+ # It will pick jsonless algorithm if 1 is given as argument
+ impl = 0
+ if len(args) > 1:
+ if args[1] == '1':
+ impl = 1
+
+ if impl == 1:
+ modules = get_modules()
+ else:
+ modules = get_modules_2()
+
+ sorted_modules = sorted(modules, key=lambda module: module.name.lower())
+ sorted_modules = [x[2] for x in sorted_modules if x[2]]
+ sorted_modules = sum(sorted_modules, [])
+ sorted_modules = [x for x in sorted_modules if x.startswith('boost')]
+
+ pp = pprint.PrettyPrinter()
+ pp.pprint(sorted_modules)
+
+if __name__ == '__main__':
+ main(sys.argv)