diff options
161 files changed, 2574 insertions, 542 deletions
diff --git a/.appveyor.yml b/.appveyor.yml index 2ef722f..56a123a 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -68,7 +68,7 @@ install: - 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. - - cmd: if %arch%==x86 (set MESON_PYTHON_PATH=C:\python34) else (set MESON_PYTHON_PATH=C:\python34-x64) + - cmd: if %arch%==x86 (set MESON_PYTHON_PATH=C:\python35) else (set MESON_PYTHON_PATH=C:\python35-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" ) ) diff --git a/.travis.yml b/.travis.yml index e69cb31..f077c9c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -49,4 +49,4 @@ script: withgit \ /bin/sh -c "cd /root && mkdir -p tools; wget -c http://nirbheek.in/files/binaries/ninja/linux-amd64/ninja -O /root/tools/ninja; chmod +x /root/tools/ninja; CC=$CC CXX=$CXX OBJC=$CC OBJCXX=$CXX PATH=/root/tools:$PATH MESON_FIXED_NINJA=1 ./run_tests.py -- $MESON_ARGS && chmod -R a+rwX .coverage" fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then SDKROOT=$(xcodebuild -version -sdk macosx Path) OBJC=$CC OBJCXX=$CXX PATH=$HOME/tools:$PATH MESON_FIXED_NINJA=1 ./run_tests.py --backend=ninja -- $MESON_ARGS ; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then SDKROOT=$(xcodebuild -version -sdk macosx Path) CPPFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib OBJC=$CC OBJCXX=$CXX PATH=$HOME/tools:$PATH MESON_FIXED_NINJA=1 ./run_tests.py --backend=ninja -- $MESON_ARGS ; fi diff --git a/ci/appveyor-install.bat b/ci/appveyor-install.bat index becc80a..1e60179 100644..100755 --- a/ci/appveyor-install.bat +++ b/ci/appveyor-install.bat @@ -1,5 +1,5 @@ set CACHE=C:\cache -set CYGWIN_MIRROR="http://cygwin.mirror.constant.com" +set CYGWIN_MIRROR=http://cygwin.mirror.constant.com if _%arch%_ == _x64_ set SETUP=setup-x86_64.exe && set CYGWIN_ROOT=C:\cygwin64 if _%arch%_ == _x86_ set SETUP=setup-x86.exe && set CYGWIN_ROOT=C:\cygwin @@ -7,5 +7,16 @@ if _%arch%_ == _x86_ set SETUP=setup-x86.exe && set CYGWIN_ROOT=C:\cygwin if not exist %CACHE% mkdir %CACHE% echo Updating Cygwin and installing ninja and test prerequisites -%CYGWIN_ROOT%\%SETUP% -qnNdO -R "%CYGWIN_ROOT%" -s "%CYGWIN_MIRROR%" -l "%CACHE%" -g -P "ninja,gcc-objc,gcc-objc++,libglib2.0-devel,zlib-devel,python3-pip" +%CYGWIN_ROOT%\%SETUP% -qnNdO -R "%CYGWIN_ROOT%" -s "%CYGWIN_MIRROR%" -l "%CACHE%" -g -P ^ +gcc-objc++,^ +gcc-objc,^ +gobject-introspection,^ +libboost-devel,^ +libglib2.0-devel,^ +libgtk3-devel,^ +ninja,^ +python3-pip,^ +vala,^ +zlib-devel + echo Install done diff --git a/contributing.txt b/contributing.txt index 094c5e6..b1c015c 100644 --- a/contributing.txt +++ b/contributing.txt @@ -1,70 +1,4 @@ Contributing to the Meson build system -There are two simple ways to submit your patches. The preferred way is -to send a github pull request. Small changes can also be sent as -patches as emails to the Meson mailing list. - - -Python Coding style - -Meson follows the basic Python coding style. Additional rules are the -following: - -- indent 4 spaces, no tabs ever -- indent meson.build files with two spaces -- try to keep the code as simple as possible -- contact the mailing list before embarking on large scale projects - to avoid wasted effort -- all new features must come with a test (or several if it is - a big feature) - -Meson uses Flake8 for style guide enforcement. The Flake8 options for -the project are contained in setup.cfg. - -To run Flake8 on your local clone of Meson: - - $ python3 -m pip install flake8 - $ cd meson - $ flake8 - -C/C++ coding style - -Meson has a bunch of test code in several languages. The rules for -those are simple. - -- indent 4 spaces, no tabs ever -- brace always on the same line as if/for/else/function definition - - -External dependencies - -The goal of Meson is to be as easily usable as possible. The user -experience should be "get Python3 and Ninja, run", even on -Windows. Unfortunately this means that we can't have dependencies on -projects outside of Python's standard library. This applies only to -core functionality, though. For additional helper programs etc the use -of external dependencies may be ok. If you feel that you are dealing -with this kind of case, please raise the issue on the mailing list -first. - - -What not to contribute? - -There are a few things that people seem to want to add to Meson but which -are not there by design and will not be added either. - -The first one is defining your own functions or a generalized for loop. -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: 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 -working on these features. - - -Do I need to sign a CLA? - -No. All contributions are welcome. +Contribution instructions can be found [on the +website](http://mesonbuild.com/Contributing.html). diff --git a/data/macros.meson b/data/macros.meson index b31f77e..732b68d 100644 --- a/data/macros.meson +++ b/data/macros.meson @@ -34,8 +34,8 @@ %meson_test \ %ninja_test -C %{_vpath_builddir} || \ - { rc=$?; \ + ( rc=$?; \ echo "-----BEGIN TESTLOG-----"; \ cat %{_vpath_builddir}/meson-logs/testlog.txt; \ echo "-----END TESTLOG-----"; \ - exit $rc; } + exit $rc; ) diff --git a/data/syntax-highlighting/vim/syntax/meson.vim b/data/syntax-highlighting/vim/syntax/meson.vim index 49921c1..e06b2df 100644 --- a/data/syntax-highlighting/vim/syntax/meson.vim +++ b/data/syntax-highlighting/vim/syntax/meson.vim @@ -112,6 +112,7 @@ syn keyword mesonBuiltin \ target_machine \ test \ vcs_tag + \ warning if exists("meson_space_error_highlight") " trailing whitespace diff --git a/docs/markdown/Contributing.md b/docs/markdown/Contributing.md new file mode 100644 index 0000000..169bf4c --- /dev/null +++ b/docs/markdown/Contributing.md @@ -0,0 +1,175 @@ +--- +short-description: Contributing to Meson +... + +# Contributing to Meson + +A large fraction of Meson is contributed by people outside the core +team. This documentation explains some of the design rationales of +Meson as well as how to create and submit your patches for inclusion +to Meson. + +Thank you for your interest in participating to the development. + +## Submitting patches + +All changes must be submitted as [pull requests to +Github](https://github.com/mesonbuild/meson/pulls). This causes them +to be run through the CI system. All submissions must pass a full CI +test run before they are even considered for submission. + +## Tests + +All new features must come with automatic tests that throughly prove +that the feature is working as expected. Similarly bug fixes must come +with a unit test that demonstrates the bug, proves that it has been +fixed and prevents the feature from breaking in the future. + +Sometimes it is difficult to create a unit test for a given bug. If +this is the case, note this in your pull request. We may permit bug +fix merge requests in these cases. This is done on a case by case +basis. Sometimes it may be easier to write the test than convince the +maintainers that one is not needed. Exercise judgment and ask for help +in problematic cases. + +The tests are split into two different parts: unit tests and full +project tests. To run all tests, execute `./run_tests.py`. Unit tests +can be run with `./run_unittests.py` and project tests with +`./run_project_tests.py`. + +Each project test is a standalone project that can be compiled on its +own. They are all in `test cases` subdirectory. The simplest way to +run a single project test is to do something like `./meson.py test\ +cases/common/1\ trivial builddir`. The one exception to this is `test +cases/unit` directory discussed below. + +The test cases in the `common` subdirectory are meant to be run always +for all backends. They should only depend on C and C++, without any +external dependencies such as libraries. Tests that require those are +in the `test cases/frameworks` directory. If there is a need for an +external program in the common directory, such as a code generator, it +should be implemented as a Python script. The goal of test projects is +also to provide sample projects that end users can use as a base for +their own projects. + +All project tests follow the same pattern: they are compiled, tests +are run and finally install is run. Passing means that building and +tests succeed and installed files match the `installed_files.txt` file +in the test's source root. Any tests that require more thorough +analysis, such as checking that certain compiler arguments can be +found in the command line or that the generated pkg-config files +actually work should be done with a unit test. + +Projects needed by unit tests are in the `test cases/unit` +subdirectory. They are not run as part of `./run_project_tests.py`. + +## Documentation + +The `docs` directory contains the full documentation that will be used +to generate [the Meson web site](http://mesonbuild.com). Every change +in functionality must change the documentation pages. In most cases +this means updating the reference documentation page but bigger +changes might need changes in other documentation, too. + +All new functionality needs to have a mention in the release +notes. These features should be written in standalone files in the +`docs/markdown/snippets` directory. The release manager will combine +them into one page when doing the release. + +## Python Coding style + +Meson follows the basic Python coding style. Additional rules are the +following: + +- indent 4 spaces, no tabs ever +- indent meson.build files with two spaces +- try to keep the code as simple as possible +- contact the mailing list before embarking on large scale projects + to avoid wasted effort + +Meson uses Flake8 for style guide enforcement. The Flake8 options for +the project are contained in setup.cfg. + +To run Flake8 on your local clone of Meson: + +```console +$ python3 -m pip install flake8 +$ cd meson +$ flake8 +``` + +## C/C++ coding style + +Meson has a bunch of test code in several languages. The rules for +those are simple. + +- indent 4 spaces, no tabs ever +- brace always on the same line as if/for/else/function definition + + + +## External dependencies + +The goal of Meson is to be as easily usable as possible. The user +experience should be "get Python3 and Ninja, run", even on +Windows. Unfortunately this means that we can't have dependencies on +projects outside of Python's standard library. This applies only to +core functionality, though. For additional helper programs etc the use +of external dependencies may be ok. If you feel that you are dealing +with this kind of case, please contact the developers first with your +use case. + +## Turing completeness + +The main design principle of Meson is that the definition language is +not Turing complete. Any change that would make Meson Turing complete +is automatically rejected. In practice this means that defining your +own functions inside `meson.build` files and generalised loops will +not be added to the language. + +## Do I need to sign a CLA in order to contribute? + +No you don't. All contributions are welcome. + +## No lingering state + +Meson operates in much the same way as functional programming +languages. It has inputs, which include `meson.build` files, values of +options, compilers and so on. These are passed to a function, which +generates output build definition. This function is pure, which means that: + + - for any given input the output is always the same + - running Meson twice in a row _always_ produce the same output in both runs + +The latter one is important, because it enforces that there is no way +for "secret state" to pass between consecutive invocations of +Meson. This is the reason why, for example, there is no `set_option` +function even though there is a `get_option` one. + +If this were not the case, we could never know if the build output is +"stable". For example suppose there were a `set_option` function and a +boolean variable `flipflop`. Then you could do this: + +```meson +set_option('flipflop', not get_option('flipflop')) +``` + +This piece of code would never converge. Every Meson run would change +the value of the option and thus the output you get out of this build +definition would be random. + +Meson does not permit this by forbidding these sorts of covert channels. + +There is one exception to this rule. Users can call into external +commands with `run_command`. If the output of that command does not +behave like a pure function, this problem arises. Meson does not try +to guard against this case, it is the responsibility of the user to +make sure the commands they run behave like pure functions. + +## Environment variables + +Environment variables are like global variables, except that they are +also hidden by default. Envvars should be avoided whenever possible, +all functionality should be exposed in better ways such as command +line switches. + diff --git a/docs/markdown/Dependencies.md b/docs/markdown/Dependencies.md index bae3edc..b36d275 100644 --- a/docs/markdown/Dependencies.md +++ b/docs/markdown/Dependencies.md @@ -43,6 +43,21 @@ You can pass the `opt_dep` variable to target construction functions whether the actual dependency was found or not. Meson will ignore non-found dependencies. +Meson also allows to get variables that are defined in the +`pkg-config` file. This can be done by using the +`get_pkgconfig_variable` function. + +```meson +zdep_prefix = zdep.get_pkgconfig_variable('prefix') +``` + +These variables can also be redefined by passing the `define_variable` +parameter, which might be useful in certain situations: + +```meson +zdep_prefix = zdep.get_pkgconfig_variable('libdir', define_variable: ['prefix', '/tmp']) +``` + 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, diff --git a/docs/markdown/Disabler.md b/docs/markdown/Disabler.md index 2d50c5c..81417f6 100644 --- a/docs/markdown/Disabler.md +++ b/docs/markdown/Disabler.md @@ -45,7 +45,8 @@ object then ```meson d2 = some_func(d) # value of d2 will be disabler -d3 = true or d2 # value of d3 will be disabler +d3 = true or d2 # value of d3 will be true because of short-circuiting +d4 = false or d2 # value of d4 will be disabler if d # neither branch is evaluated ``` @@ -62,4 +63,4 @@ endif This concentrates the handling of this option in one place and other build definition files do not need to be sprinkled with `if` -statements.
\ No newline at end of file +statements. diff --git a/docs/markdown/Gnome-module.md b/docs/markdown/Gnome-module.md index 738e2a9..b33009d 100644 --- a/docs/markdown/Gnome-module.md +++ b/docs/markdown/Gnome-module.md @@ -196,6 +196,13 @@ When called, this method will compile the gschemas in the current directory. Note that this is not for installing schemas and is only useful when running the application locally for example during tests. +* `build_by_default`: causes, when set to true, to have this target be + built by default, that is, when invoking plain `ninja`, the default + value is true for all built target types +* `depend_files`: files ([`string`](#string-object), + [`files()`](#files), or [`configure_file()`](#configure_file)) of + schema source XML files that should trigger a re-compile if changed. + ### gnome.gdbus_codegen() Compiles the given XML schema into gdbus source code. Takes two diff --git a/docs/markdown/Pkgconfig-module.md b/docs/markdown/Pkgconfig-module.md index 7f767f1..cbe01b4 100644 --- a/docs/markdown/Pkgconfig-module.md +++ b/docs/markdown/Pkgconfig-module.md @@ -23,9 +23,16 @@ keyword arguments. - `install_dir` the directory to install to, defaults to the value of option `libdir` followed by `/pkgconfig` - `libraries` a list of built libraries (usually results of - shared_library) that the user needs to link against -- `libraries_private` list of strings to put in the - `Libraries.private` field + shared_library) that the user needs to link against. Arbitraty strings can + also be provided and they will be added into the `Libs` field. Since 0.45.0 + dependencies of built libraries will be automatically added to `Libs.private` + field. If a dependency is provided by pkg-config then it will be added in + `Requires.private` instead. Other type of dependency objects can also be passed + and will result in their `link_args` and `compile_args` to be added to `Libs` + and `Cflags` fields. +- `libraries_private` list of built libraries or strings to put in the + `Libs.private` field. Since 0.45.0 it can also contain dependency objects, + their `link_args` will be added to `Libs.private`. - `name` the name of this library - `subdirs` which subdirs of `include` should be added to the header search path, for example if you install headers into diff --git a/docs/markdown/Project-templates.md b/docs/markdown/Project-templates.md new file mode 100644 index 0000000..d8459c6 --- /dev/null +++ b/docs/markdown/Project-templates.md @@ -0,0 +1,30 @@ +--- +short-description: Project templates +... + +# Project templates + +To make it easier for new developers to start working, Meson ships a +tool to generate the basic setup of different kinds of projects. This +functionality can be accessed with the `meson init` command. A typical +project setup would go like this: + +```console +$ mkdir project_name +$ cd project_name +$ meson init --language=c --name=myproject --version=0.1 +``` + +This would create the build definitions for a helloworld type +project. The result can be compiled as usual. For example compiling it +with Ninja could be done like this: + +``` +$ meson builddir +$ ninja -C builddir +``` + +The generator has many different projects and settings. They can all +be listed by invoking the command `meson test --help`. + +This feature is available since Meson version 0.45.0. diff --git a/docs/markdown/Python-3-module.md b/docs/markdown/Python-3-module.md index fa1d78e..dc6f571 100644 --- a/docs/markdown/Python-3-module.md +++ b/docs/markdown/Python-3-module.md @@ -7,7 +7,7 @@ following methods. This is a cross platform way of finding the Python 3 executable, which may have a different name on different operating systems. Returns an -external program object. +[external program](Reference-manual.html#external-program-object) object. *Added 0.38.0* diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index 7e8f7ee..a3e1ef0 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -328,7 +328,7 @@ The returned object also has methods that are documented in the ### disabler() -Returns a [disabler object]((#disabler-object)). Added in 0.44.0. +Returns a [disabler object](#disabler-object). Added in 0.44.0. ### error() @@ -403,7 +403,7 @@ be passed to [shared and static libraries](#library). flags here for all platforms. - `link_depends` strings, files, or custom targets the link step depends on such as a symbol visibility map. The purpose is to - automaticallytrigger a re-link (but not a re-compile) of the target + automatically trigger a re-link (but not a re-compile) of the target when this file changes. - `link_whole` links all contents of the given static libraries whether they are used by not, equivalent to the @@ -412,13 +412,18 @@ be passed to [shared and static libraries](#library). - `link_with`, one or more shared or static libraries (built by this project) that this target should be linked with, If passed a list this list will be flattened as of 0.41.0. +- `export_dynamic` when set to true causes the target's symbols to be + dynamically exported, allowing modules built using the + [`shared_module`](#shared_module) function to refer to functions, + variables and other symbols defined in the executable itself. Implies + the `implib` argument. Since 0.44.0 - `implib` when set to true, an import library is generated for the executable (the name of the import library is based on *exe_name*). Alternatively, when set to a string, that gives the base name for the import library. The import library is used when the returned build target object appears in `link_with:` elsewhere. Only has any - effect on platforms where that is meaningful (e.g. Windows). Since - 0.42.0 + effect on platforms where that is meaningful (e.g. Windows). Implies + the `export_dynamic` argument. Since 0.42.0 - `implicit_include_directories` is a boolean telling whether Meson adds the current source and build directories to the include path, defaults to `true`, since 0.42.0 @@ -483,7 +488,7 @@ Keyword arguments are the following: then use the `.found()` method on the returned object to check whether it was found or not. -- `native` defines how this executable should be searched. By default +- `native` *(since 0.43)* defines how this executable should be searched. By default it is set to `false`, which causes Meson to first look for the executable in the cross file (when cross building) and if it is not defined there, then from the system. If set to `true`, the cross @@ -606,6 +611,11 @@ installed, and so on, use a [`custom_target`](#custom_target) instead. Obtains the value of the [project build option](Build-options.md) specified in the positional argument. +Note that the value returned for built-in options that end in `dir` such as +`bindir` and `libdir` is always a path relative to (and inside) the `prefix`. +The only exceptions are: `sysconfdir`, `localstatedir`, and `sharedstatedir` +which will return the value passed during configuration as-is. + ### get_variable() ``` meson @@ -1005,6 +1015,11 @@ This is useful for building modules that will be `dlopen()`ed and hence may contain undefined symbols that will be provided by the library that is loading it. +If you want the shared module to be able to refer to functions and +variables defined in the [`executable`](#executable) it is loaded by, +you will need to set the `export_dynamic` argument of the executable to +`true`. + *Added 0.37.0* ### static_library() @@ -1618,7 +1633,9 @@ an external dependency with the following methods: - `get_pkgconfig_variable(varname)` (*Added 0.36.0*) will get the pkg-config variable specified, or, if invoked on a non pkg-config - dependency, error out + dependency, error out. (*Added 0.44.0*) You can also redefine a + variable by passing a list to the `define_variable` parameter + that can affect the retrieved variable: `['prefix', '/'])`. - `get_configtool_variable(varname)` (*Added 0.44.0*) will get the command line argument from the config tool (with `--` prepended), or, diff --git a/docs/markdown/Reference-tables.md b/docs/markdown/Reference-tables.md index 8e048dc..ee3b8c2 100644 --- a/docs/markdown/Reference-tables.md +++ b/docs/markdown/Reference-tables.md @@ -57,6 +57,9 @@ These are provided by the `.system()` method call. | windows | Any version of Windows | | cygwin | The Cygwin environment for Windows | | haiku | | +| freebsd | FreeBSD and it's derivatives | +| dragonfly | DragonFly BSD | +| netbsd | | Any string not listed above is not guaranteed to remain stable in future releases. diff --git a/docs/markdown/Release-notes-for-0.43.0.md b/docs/markdown/Release-notes-for-0.43.0.md index 3f981e8..7702f3c 100644 --- a/docs/markdown/Release-notes-for-0.43.0.md +++ b/docs/markdown/Release-notes-for-0.43.0.md @@ -1,6 +1,6 @@ --- title: Release 0.43 -short-description: Release notes for 0.43 (preliminary) +short-description: Release notes for 0.43 ... # Portability improvements to Boost Dependency diff --git a/docs/markdown/Release-notes-for-0.44.0.md b/docs/markdown/Release-notes-for-0.44.0.md index 93e224d..56956d7 100644 --- a/docs/markdown/Release-notes-for-0.44.0.md +++ b/docs/markdown/Release-notes-for-0.44.0.md @@ -71,10 +71,12 @@ Added a new keyword argument to the `subdir` command. It is given a list of dependency objects and the function will only recurse in the subdirectory if they are all found. Typical usage goes like this. - d1 = dependency('foo') # This is found - d2 = dependency('bar') # This is not found +```meson +d1 = dependency('foo') # This is found +d2 = dependency('bar') # This is not found - subdir('somedir', if_found : [d1, d2]) +subdir('somedir', if_found : [d1, d2]) +``` In this case the subdirectory would not be entered since `d2` could not be found. @@ -138,6 +140,8 @@ Meson now ships an internal version of Python in the MSI installer packages. This means that it can run Python scripts that are part of your build transparently. That is, if you do the following: - myprog = find_program('myscript.py') +```meson +myprog = find_program('myscript.py') +``` Then Meson will run the script with its internal Python version if necessary. diff --git a/docs/markdown/Users.md b/docs/markdown/Users.md index c27c516..616fdc5 100644 --- a/docs/markdown/Users.md +++ b/docs/markdown/Users.md @@ -12,6 +12,7 @@ If you have a project that uses Meson that you want to add to this list, let us - [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 + - [Geary](https://wiki.gnome.org/Apps/Geary), an email application built around conversations, for the GNOME 3 desktop. - [GLib](https://git.gnome.org/browse/glib/), cross-platform C library used by GTK+ and GStreamer (not the default yet) - [Gnome Builder](https://git.gnome.org/browse/gnome-builder/), an IDE for the Gnome platform - [Gnome MPV](https://github.com/gnome-mpv/gnome-mpv), Gnome frontend to the mpv video player @@ -25,6 +26,7 @@ If you have a project that uses Meson that you want to add to this list, let us - [GtkDApp](https://gitlab.com/csoriano/GtkDApp), an application template for developing Flatpak apps with Gtk+ and D - [HexChat](https://github.com/hexchat/hexchat), a cross-platform IRC client in C - [Json-glib](https://git.gnome.org/browse/json-glib), GLib-based JSON manipulation library + - [Ksh](https://github.com/att/ast), a Korn Shell - [Libepoxy](https://github.com/anholt/libepoxy/), a library for handling OpenGL function pointer management - [Libgit2-glib](https://git.gnome.org/browse/libgit2-glib/), a GLib wrapper for libgit2 - [Libhttpseverywhere](https://github.com/grindhold/libhttpseverywhere), a library to enable httpseverywhere on any desktop app @@ -37,7 +39,7 @@ If you have a project that uses Meson that you want to add to this list, let us - [Pitivi](http://pitivi.org/), a nonlinear video editor - [Polari](https://git.gnome.org/browse/polari), an IRC client - [Sysprof](https://wiki.gnome.org/Apps/Sysprof), a profiling tool - - [systemd](https://github.com/systemd/systemd/pull/5704), the init system (not the default yet) + - [systemd](https://github.com/systemd/systemd), the init system - [Xorg](https://cgit.freedesktop.org/xorg/xserver/) the X.org display server (not the default yet) - [Valum](https://github.com/valum-framework/valum), a micro web framework written in Vala - [Wayland and Weston](https://lists.freedesktop.org/archives/wayland-devel/2016-November/031984.html), a next generation display server (not merged yet) diff --git a/docs/markdown/Using-wraptool.md b/docs/markdown/Using-wraptool.md index 8e5f898..08b1bfa 100644 --- a/docs/markdown/Using-wraptool.md +++ b/docs/markdown/Using-wraptool.md @@ -1,12 +1,20 @@ # Using wraptool -Wraptool is a helper tool that allows you to manage your source dependencies using the WrapDB database. It gives you all things you would expect, such as installing and updating dependencies. The wrap tool works on all platforms, the only limitation is that the wrap definition works on your target platform. If you find some Wraps that don't work, please file bugs or, even better, patches. +Wraptool is a helper tool that allows you to manage your source +dependencies using the WrapDB database. It gives you all things you +would expect, such as installing and updating dependencies. The wrap +tool works on all platforms, the only limitation is that the wrap +definition works on your target platform. If you find some Wraps that +don't work, please file bugs or, even better, patches. -All code examples here assume that you are running the commands in your top level source directory. Lines that start with the `$` mark are commands to type. +All code examples here assume that you are running the commands in +your top level source directory. Lines that start with the `$` mark +are commands to type. ## Simple querying -The simplest operation to do is to query the list of packages available. To list them all issue the following command: +The simplest operation to do is to query the list of packages +available. To list them all issue the following command: $ wraptool list box2d @@ -22,27 +30,35 @@ The simplest operation to do is to query the list of packages available. To list vorbis zlib -Usually you want to search for a specific package. This can be done with the `search` command: +Usually you want to search for a specific package. This can be done +with the `search` command: $ wraptool search jpeg libjpeg -To determine which versions of libjpeg are available to install, issue the `info` command: +To determine which versions of libjpeg are available to install, issue +the `info` command: $ wraptool info libjpeg Available versions of libjpeg: 9a 2 -The first number is the upstream release version, in this case `9a`. The second number is the Wrap revision number. They don't relate to anything in particular, but larger numbers imply newer releases. You should always use the newest available release. +The first number is the upstream release version, in this case +`9a`. The second number is the Wrap revision number. They don't relate +to anything in particular, but larger numbers imply newer +releases. You should always use the newest available release. ## Installing dependencies -Installing dependencies is just as straightforward. First just create the `subprojects` directory at the top of your source tree and issue the install command. +Installing dependencies is just as straightforward. First just create +the `subprojects` directory at the top of your source tree and issue +the install command. $ wraptool install libjpeg Installed libjpeg branch 9a revision 2 -Now you can issue a `subproject('libjpeg')` in your `meson.build` file to use it. +Now you can issue a `subproject('libjpeg')` in your `meson.build` file +to use it. To check if your projects are up to date you can issue the `status` command. @@ -51,9 +67,33 @@ To check if your projects are up to date you can issue the `status` command. libjpeg up to date. Branch 9a, revision 2. zlib not up to date. Have 1.2.8 2, but 1.2.8 4 is available. -In this case `zlib` has a newer release available. Updating it is straightforward: +In this case `zlib` has a newer release available. Updating it is +straightforward: $ 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`. +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`. + +## Promoting dependencies + +Meson will only search for subprojects from the top level +`subprojects` directory. If you have subprojects that themselves have +subprojects, you must transfer them to the top level. This can be done +by going to your source root and issuing a promotion command. + + meson wrap promote projname + +This will cause Meson to go through your entire project tree, find an +embedded subproject and copy it to the top level. + +If there are multiple embedded copies of a subproject, Meson will not +try to guess which one you want. Instead it will print all the +possibilities. You can then manually select which one to promote by +writing it out fully. + + meson wrap promote subprojects/s1/subprojects/projname + +This functionality was added in Meson release 0.45.0. diff --git a/docs/markdown/index.md b/docs/markdown/index.md index 81c17ff..6893564 100644 --- a/docs/markdown/index.md +++ b/docs/markdown/index.md @@ -6,13 +6,17 @@ render-subpages: false ## Overview -Meson is an open source build system meant to be both extremely fast, and, even more importantly, as user friendly as possible. +Meson is an open source build system meant to be both extremely fast, +and, even more importantly, as user friendly as possible. -The main design point of Meson is that every moment a developer spends writing or debugging build definitions is a second wasted. So is every second spent waiting for the build system to actually start compiling code. +The main design point of Meson is that every moment a developer spends +writing or debugging build definitions is a second wasted. So is every +second spent waiting for the build system to actually start compiling +code. ## Features -* multiplatform support for Linux, OSX, Windows, GCC, Clang, Visual Studio and others +* multiplatform support for Linux, macOS, Windows, GCC, Clang, Visual Studio and others * 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 @@ -22,12 +26,18 @@ The main design point of Meson is that every moment a developer spends writing o ## Community -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). +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 `#mesonbuild` 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 `contributing.txt` file that comes with Meson's source checkout. +All development on Meson is done on the [GitHub +project](https://github.com/mesonbuild/meson). Instructions for +contributing can be found on the [contribution page](Contributing.md). + You do not need to sign a CLA to contribute to Meson. diff --git a/docs/markdown/snippets/if-release.md b/docs/markdown/snippets/if-release.md new file mode 100644 index 0000000..96e12ef --- /dev/null +++ b/docs/markdown/snippets/if-release.md @@ -0,0 +1,7 @@ +## b_ndebug : if-release + +The value `if-release` can be given for the `b_ndebug` project option. + +This will make the `NDEBUG` pre-compiler macro to be defined for release +type builds as if the `b_ndebug` project option had had the value `true` +defined for it. diff --git a/docs/markdown/snippets/templates.md b/docs/markdown/snippets/templates.md new file mode 100644 index 0000000..6f0474d --- /dev/null +++ b/docs/markdown/snippets/templates.md @@ -0,0 +1,8 @@ +## Project templates + +Meson ships with predefined project templates. To start a new project from +scratch, simply go to an empty directory and type: + +```meson +meson init --name=myproject --type=executable --language=c +``` diff --git a/docs/markdown/snippets/wrap_promote.md b/docs/markdown/snippets/wrap_promote.md new file mode 100644 index 0000000..20fee47 --- /dev/null +++ b/docs/markdown/snippets/wrap_promote.md @@ -0,0 +1,11 @@ +# Can promote dependencies with wrap command + +The `promote` command makes it easy to copy nested dependencies to the top level. + + meson wrap promote scommon + +This will search the project tree for a subproject called `scommon` and copy it to the top level. + +If there are many embedded subprojects with the same name, you have to specify which one to promote manually like this: + + meson wrap promote subprojects/s1/subprojects/scommon diff --git a/docs/sitemap.txt b/docs/sitemap.txt index 77a4e6f..87a5eb5 100644 --- a/docs/sitemap.txt +++ b/docs/sitemap.txt @@ -48,6 +48,7 @@ index.md Creating-releases.md Creating-OSX-packages.md Creating-Linux-binaries.md + Project-templates.md Reference-manual.md Reference-tables.md FAQ.md @@ -90,5 +91,6 @@ index.md Use-of-Python.md Users.md Using-multiple-build-directories.md + Contributing.md legal.md Videos.md @@ -18,17 +18,6 @@ from mesonbuild import mesonmain, mesonlib import sys, os, locale def main(): - # Warn if the locale is not UTF-8. This can cause various unfixable issues - # such as os.stat not being able to decode filenames with unicode in them. - # There is no way to reset both the preferred encoding and the filesystem - # 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 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) - print('Please switch to a UTF-8 locale for your platform.', file=sys.stderr) # Always resolve the command path so Ninja can find it for regen, tests, etc. launcher = os.path.realpath(sys.argv[0]) return mesonmain.run(sys.argv[1:], launcher) diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 3f1e4ce..5a5db22 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -346,6 +346,11 @@ class Backend: assert isinstance(source, mesonlib.File) build_dir = self.environment.get_build_dir() rel_src = source.rel_to_builddir(self.build_to_src) + + if (not self.environment.is_source(rel_src) or + self.environment.is_header(rel_src)) and not is_unity: + return None + # foo.vala files compile down to foo.c and then foo.c.o, not foo.vala.o if rel_src.endswith(('.vala', '.gs')): # See description in generate_vala_compile for this logic. @@ -393,8 +398,9 @@ class Backend: return [objpath] for osrc in extobj.srclist: objname = self.object_filename_from_source(extobj.target, osrc, False) - objpath = os.path.join(proj_dir_to_build_root, targetdir, objname) - result.append(objpath) + if objname: + objpath = os.path.join(proj_dir_to_build_root, targetdir, objname) + result.append(objpath) return result def get_pch_include_args(self, compiler, target): diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index c020458..77c7d50 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -42,8 +42,12 @@ def ninja_quote(text): for char in ('$', ' ', ':'): text = text.replace(char, '$' + char) if '\n' in text: - raise MesonException('Ninja does not support newlines in rules. ' - 'Please report this error with a test case to the Meson bug tracker.') + errmsg = '''Ninja does not support newlines in rules. The content was: + +%s + +Please report this error with a test case to the Meson bug tracker.''' % text + raise MesonException(errmsg) return text @@ -2259,7 +2263,7 @@ rule FORTRAN_DEP_HACK def generate_msvc_pch_command(self, target, compiler, pch): if len(pch) != 2: - raise RuntimeError('MSVC requires one header and one source to produce precompiled headers.') + raise MesonException('MSVC requires one header and one source to produce precompiled headers.') header = pch[0] source = pch[1] pchname = compiler.get_pch_name(header) @@ -2342,6 +2346,9 @@ rule FORTRAN_DEP_HACK # If gui_app, and that's significant on this platform if target.gui_app and hasattr(linker, 'get_gui_app_args'): commands += linker.get_gui_app_args() + # If export_dynamic, add the appropriate linker arguments + if target.export_dynamic: + commands += linker.gen_export_dynamic_link_args(self.environment) # If implib, and that's significant on this platform (i.e. Windows using either GCC or Visual Studio) if target.import_filename: commands += linker.gen_import_library_args(os.path.join(self.get_target_dir(target), target.import_filename)) diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py index b53bd17..1722db7 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -29,10 +29,9 @@ from ..environment import Environment def autodetect_vs_version(build): vs_version = os.getenv('VisualStudioVersion', None) vs_install_dir = os.getenv('VSINSTALLDIR', None) - if not vs_version and not vs_install_dir: - raise MesonException('Could not detect Visual Studio: VisualStudioVersion and VSINSTALLDIR are unset!\n' - 'Are we inside a Visual Studio build environment? ' - 'You can also try specifying the exact backend to use.') + if not vs_install_dir: + raise MesonException('Could not detect Visual Studio: Environment variable VSINSTALLDIR is not set!\n' + 'Are you running meson from the Visual Studio Developer Command Prompt?') # VisualStudioVersion is set since Visual Studio 12.0, but sometimes # vcvarsall.bat doesn't set it, so also use VSINSTALLDIR if vs_version == '14.0' or 'Visual Studio 14' in vs_install_dir: @@ -863,7 +862,14 @@ class Vs2010Backend(backends.Backend): if not pch: continue pch_node.text = 'Use' - pch_sources[lang] = [pch[0], pch[1], lang] + if compiler.id == 'msvc': + if len(pch) != 2: + raise MesonException('MSVC requires one header and one source to produce precompiled headers.') + pch_sources[lang] = [pch[0], pch[1], lang] + else: + # I don't know whether its relevant but let's handle other compilers + # used with a vs backend + pch_sources[lang] = [pch[0], None, lang] if len(pch_sources) == 1: # If there is only 1 language with precompiled headers, we can use it for the entire project, which # is cleaner than specifying it for each source file. @@ -1018,19 +1024,20 @@ class Vs2010Backend(backends.Backend): self.add_include_dirs(lang, inc_cl, file_inc_dirs) for lang in pch_sources: header, impl, suffix = pch_sources[lang] - relpath = os.path.join(proj_to_src_dir, impl) - inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=relpath) - pch = ET.SubElement(inc_cl, 'PrecompiledHeader') - pch.text = 'Create' - pch_out = ET.SubElement(inc_cl, 'PrecompiledHeaderOutputFile') - pch_out.text = '$(IntDir)$(TargetName)-%s.pch' % suffix - pch_file = ET.SubElement(inc_cl, 'PrecompiledHeaderFile') - # MSBuild searches for the header relative from the implementation, so we have to use - # just the file name instead of the relative path to the file. - pch_file.text = os.path.split(header)[1] - self.add_additional_options(lang, inc_cl, file_args) - self.add_preprocessor_defines(lang, inc_cl, file_defines) - self.add_include_dirs(lang, inc_cl, file_inc_dirs) + if impl: + relpath = os.path.join(proj_to_src_dir, impl) + inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=relpath) + pch = ET.SubElement(inc_cl, 'PrecompiledHeader') + pch.text = 'Create' + pch_out = ET.SubElement(inc_cl, 'PrecompiledHeaderOutputFile') + pch_out.text = '$(IntDir)$(TargetName)-%s.pch' % suffix + pch_file = ET.SubElement(inc_cl, 'PrecompiledHeaderFile') + # MSBuild searches for the header relative from the implementation, so we have to use + # just the file name instead of the relative path to the file. + pch_file.text = os.path.split(header)[1] + self.add_additional_options(lang, inc_cl, file_args) + self.add_preprocessor_defines(lang, inc_cl, file_defines) + self.add_include_dirs(lang, inc_cl, file_inc_dirs) if self.has_objects(objects, additional_objects, gen_objs): inc_objs = ET.SubElement(root, 'ItemGroup') diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 974643d..5eab794 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -82,6 +82,7 @@ known_lib_kwargs.update({'version': True, # Only for shared libs known_exe_kwargs = known_basic_kwargs.copy() known_exe_kwargs.update({'implib': True, + 'export_dynamic': True }) class InvalidArguments(MesonException): @@ -839,7 +840,7 @@ This will become a hard error in a future Meson release.''') self.external_deps.append(extpart) # Deps of deps. self.add_deps(dep.ext_deps) - elif isinstance(dep, dependencies.ExternalDependency): + elif isinstance(dep, dependencies.Dependency): self.external_deps.append(dep) self.process_sourcelist(dep.get_sources()) elif isinstance(dep, BuildTarget): @@ -1183,23 +1184,33 @@ class Executable(BuildTarget): # The import library that GCC would generate (and prefer) self.gcc_import_filename = None - # if implib appears, this target is linkwith:-able, but that only means - # something on Windows platforms. - self.is_linkwithable = False - if 'implib' in kwargs and kwargs['implib']: + # Check for export_dynamic + self.export_dynamic = False + if kwargs.get('export_dynamic'): + if not isinstance(kwargs['export_dynamic'], bool): + raise InvalidArguments('"export_dynamic" keyword argument must be a boolean') + self.export_dynamic = True + if kwargs.get('implib'): + self.export_dynamic = True + if self.export_dynamic and kwargs.get('implib') is False: + raise InvalidArguments('"implib" keyword argument must not be false for if "export_dynamic" is true') + + # If using export_dynamic, set the import library name + if self.export_dynamic: implib_basename = self.name + '.exe' - if not isinstance(kwargs['implib'], bool): + if not isinstance(kwargs.get('implib', False), bool): implib_basename = kwargs['implib'] - self.is_linkwithable = True if for_windows(is_cross, environment) or for_cygwin(is_cross, environment): self.vs_import_filename = '{0}.lib'.format(implib_basename) self.gcc_import_filename = 'lib{0}.a'.format(implib_basename) - if self.get_using_msvc(): self.import_filename = self.vs_import_filename else: self.import_filename = self.gcc_import_filename + # Only linkwithable if using export_dynamic + self.is_linkwithable = self.export_dynamic + def type_suffix(self): return "@exe" @@ -1799,7 +1810,7 @@ class CustomTargetIndex: def __repr__(self): return '<CustomTargetIndex: {!r}[{}]>'.format( - self.target, self.target.output.index(self.output)) + self.target, self.target.get_outputs().index(self.output)) def get_outputs(self): return [self.output] diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index 9c1d1fc..4c6e3a2 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -42,11 +42,11 @@ from .compilers import ( class CCompiler(Compiler): - def __init__(self, exelist, version, is_cross, exe_wrapper=None): + def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwargs): # If a child ObjC or CPP class has already set it, don't set it ourselves if not hasattr(self, 'language'): self.language = 'c' - super().__init__(exelist, version) + super().__init__(exelist, version, **kwargs) self.id = 'unknown' self.is_cross = is_cross self.can_compile_suffixes.add('h') @@ -97,7 +97,7 @@ class CCompiler(Compiler): return self.build_unix_rpath_args(build_dir, from_dir, rpath_paths, build_rpath, install_rpath) def get_dependency_gen_args(self, outtarget, outfile): - return ['-MMD', '-MQ', outtarget, '-MF', outfile] + return ['-MD', '-MQ', outtarget, '-MF', outfile] def depfile_for_object(self, objfile): return objfile + '.' + self.get_depfile_suffix() @@ -156,7 +156,9 @@ class CCompiler(Compiler): return ['-shared'] def get_library_dirs(self): - stdo = Popen_safe(self.exelist + ['--print-search-dirs'])[1] + env = os.environ.copy() + env['LC_ALL'] = 'C' + stdo = Popen_safe(self.exelist + ['--print-search-dirs'], env=env)[1] for line in stdo.split('\n'): if line.startswith('libraries:'): libstr = line.split('=', 1)[1] @@ -181,6 +183,14 @@ class CCompiler(Compiler): def get_default_include_dirs(self): return [] + def gen_export_dynamic_link_args(self, env): + if for_windows(env.is_cross_build(), env): + return ['-Wl,--export-all-symbols'] + elif for_darwin(env.is_cross_build(), env): + return [] + else: + return ['-Wl,-export-dynamic'] + def gen_import_library_args(self, implibname): """ The name of the outputted import library @@ -798,8 +808,8 @@ class CCompiler(Compiler): class ClangCCompiler(ClangCompiler, CCompiler): - def __init__(self, exelist, version, clang_type, is_cross, exe_wrapper=None): - CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) + def __init__(self, exelist, version, clang_type, is_cross, exe_wrapper=None, **kwargs): + CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwargs) ClangCompiler.__init__(self, clang_type) default_warn_args = ['-Wall', '-Winvalid-pch'] self.warn_args = {'1': default_warn_args, @@ -830,8 +840,8 @@ class ClangCCompiler(ClangCompiler, CCompiler): class GnuCCompiler(GnuCompiler, CCompiler): - def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None, defines=None): - CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) + def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None, defines=None, **kwargs): + CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwargs) GnuCompiler.__init__(self, gcc_type, defines) default_warn_args = ['-Wall', '-Winvalid-pch'] self.warn_args = {'1': default_warn_args, @@ -869,8 +879,8 @@ class GnuCCompiler(GnuCompiler, CCompiler): class IntelCCompiler(IntelCompiler, CCompiler): - def __init__(self, exelist, version, icc_type, is_cross, exe_wrapper=None): - CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) + def __init__(self, exelist, version, icc_type, is_cross, exe_wrapper=None, **kwargs): + CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwargs) IntelCompiler.__init__(self, icc_type) self.lang_header = 'c-header' default_warn_args = ['-Wall', '-w3', '-diag-disable:remark', '-Wpch-messages'] diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 011c222..2602d14 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -49,7 +49,7 @@ cpp_suffixes = lang_suffixes['cpp'] + ('h',) c_suffixes = lang_suffixes['c'] + ('h',) # List of languages that can be linked with C code directly by the linker # used in build.py:process_compilers() and build.py:get_dynamic_linker() -clike_langs = ('objcpp', 'objc', 'd', 'cpp', 'c', 'fortran',) +clike_langs = ('d', 'objcpp', 'cpp', 'objc', 'c', 'fortran',) clike_suffixes = () for _l in clike_langs: clike_suffixes += lang_suffixes[_l] @@ -224,9 +224,8 @@ base_options = {'b_pch': coredata.UserBooleanOption('b_pch', 'Use precompiled he 'b_colorout': coredata.UserComboOption('b_colorout', 'Use colored output', ['auto', 'always', 'never'], 'always'), - 'b_ndebug': coredata.UserBooleanOption('b_ndebug', - 'Disable asserts', - False), + 'b_ndebug': coredata.UserComboOption('b_ndebug', 'Disable asserts', + ['true', 'false', 'if-release'], 'false'), 'b_staticpic': coredata.UserBooleanOption('b_staticpic', 'Build static libraries as position independent', True), @@ -313,7 +312,7 @@ def get_base_compile_args(options, compiler): except KeyError: pass try: - if options['b_ndebug'].value: + if options['b_ndebug'].value == 'true' or (options['b_ndebug'].value == 'if-release' and options['buildtype'] == 'release'): args += ['-DNDEBUG'] except KeyError: pass @@ -598,7 +597,7 @@ class Compiler: # compiler or the C library. Currently only used for MSVC. ignore_libs = () - def __init__(self, exelist, version): + def __init__(self, exelist, version, **kwargs): if isinstance(exelist, str): self.exelist = [exelist] elif isinstance(exelist, list): @@ -612,6 +611,10 @@ class Compiler: self.can_compile_suffixes = set(self.file_suffixes) self.default_suffix = self.file_suffixes[0] self.version = version + if 'full_version' in kwargs: + self.full_version = kwargs['full_version'] + else: + self.full_version = None self.base_options = [] def __repr__(self): @@ -852,7 +855,15 @@ class Compiler: paths = padding else: paths = paths + ':' + padding - args = ['-Wl,-rpath,' + paths] + args = [] + if mesonlib.is_dragonflybsd(): + # This argument instructs the compiler to record the value of + # ORIGIN in the .dynamic section of the elf. On Linux this is done + # by default, but is not on dragonfly for some reason. Without this + # $ORIGIN in the runtime path will be undefined and any binaries + # linked against local libraries will fail to resolve them. + args.append('-Wl,-z,origin') + args.append('-Wl,-rpath,' + paths) if get_compiler_is_linuxlike(self): # Rpaths to use while linking must be absolute. These are not # written to the binary. Needed only with GNU ld: @@ -860,9 +871,17 @@ class Compiler: # Not needed on Windows or other platforms that don't use RPATH # https://github.com/mesonbuild/meson/issues/1897 lpaths = ':'.join([os.path.join(build_dir, p) for p in rpath_paths]) - args += ['-Wl,-rpath-link,' + lpaths] + + # clang expands '-Wl,rpath-link,' to ['-rpath-link'] instead of ['-rpath-link',''] + # This eats the next argument, which happens to be 'ldstdc++', causing link failures. + # We can dodge this problem by not adding any rpath_paths if the argument is empty. + if lpaths.strip() != '': + args += ['-Wl,-rpath-link,' + lpaths] return args + def thread_flags(self, env): + return [] + GCC_STANDARD = 0 GCC_OSX = 1 diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index cb4b055..5e32ace 100644 --- a/mesonbuild/compilers/cpp.py +++ b/mesonbuild/compilers/cpp.py @@ -28,11 +28,11 @@ from .compilers import ( ) class CPPCompiler(CCompiler): - def __init__(self, exelist, version, is_cross, exe_wrap): + def __init__(self, exelist, version, is_cross, exe_wrap, **kwargs): # If a child ObjCPP class has already set it, don't set it ourselves if not hasattr(self, 'language'): self.language = 'cpp' - CCompiler.__init__(self, exelist, version, is_cross, exe_wrap) + CCompiler.__init__(self, exelist, version, is_cross, exe_wrap, **kwargs) def get_display_language(self): return 'C++' @@ -66,8 +66,8 @@ class CPPCompiler(CCompiler): class ClangCPPCompiler(ClangCompiler, CPPCompiler): - def __init__(self, exelist, version, cltype, is_cross, exe_wrapper=None): - CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) + def __init__(self, exelist, version, cltype, is_cross, exe_wrapper=None, **kwargs): + CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwargs) ClangCompiler.__init__(self, cltype) default_warn_args = ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor'] self.warn_args = {'1': default_warn_args, @@ -92,8 +92,8 @@ class ClangCPPCompiler(ClangCompiler, CPPCompiler): class GnuCPPCompiler(GnuCompiler, CPPCompiler): - def __init__(self, exelist, version, gcc_type, is_cross, exe_wrap, defines): - CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap) + def __init__(self, exelist, version, gcc_type, is_cross, exe_wrap, defines, **kwargs): + CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap, **kwargs) GnuCompiler.__init__(self, gcc_type, defines) default_warn_args = ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor'] self.warn_args = {'1': default_warn_args, @@ -133,8 +133,8 @@ class GnuCPPCompiler(GnuCompiler, CPPCompiler): class IntelCPPCompiler(IntelCompiler, CPPCompiler): - def __init__(self, exelist, version, icc_type, is_cross, exe_wrap): - CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap) + def __init__(self, exelist, version, icc_type, is_cross, exe_wrap, **kwargs): + CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap, **kwargs) IntelCompiler.__init__(self, icc_type) self.lang_header = 'c++-header' default_warn_args = ['-Wall', '-w3', '-diag-disable:remark', diff --git a/mesonbuild/compilers/cs.py b/mesonbuild/compilers/cs.py index b8a4d13..dd7a433 100644 --- a/mesonbuild/compilers/cs.py +++ b/mesonbuild/compilers/cs.py @@ -19,9 +19,9 @@ from ..mesonlib import EnvironmentException from .compilers import Compiler, mono_buildtype_args class MonoCompiler(Compiler): - def __init__(self, exelist, version): + def __init__(self, exelist, version, **kwargs): self.language = 'cs' - super().__init__(exelist, version) + super().__init__(exelist, version, **kwargs) self.id = 'mono' self.monorunner = 'mono' diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py index 9739f28..9681a9f 100644 --- a/mesonbuild/compilers/d.py +++ b/mesonbuild/compilers/d.py @@ -42,9 +42,9 @@ d_feature_args = {'gcc': {'unittest': '-funittest', } class DCompiler(Compiler): - def __init__(self, exelist, version, is_cross): + def __init__(self, exelist, version, is_cross, **kwargs): self.language = 'd' - super().__init__(exelist, version) + super().__init__(exelist, version, **kwargs) self.id = 'unknown' self.is_cross = is_cross @@ -224,8 +224,8 @@ class DCompiler(Compiler): class GnuDCompiler(DCompiler): - def __init__(self, exelist, version, is_cross): - DCompiler.__init__(self, exelist, version, is_cross) + def __init__(self, exelist, version, is_cross, **kwargs): + DCompiler.__init__(self, exelist, version, is_cross, **kwargs) self.id = 'gcc' default_warn_args = ['-Wall', '-Wdeprecated'] self.warn_args = {'1': default_warn_args, @@ -267,8 +267,8 @@ class GnuDCompiler(DCompiler): class LLVMDCompiler(DCompiler): - def __init__(self, exelist, version, is_cross): - DCompiler.__init__(self, exelist, version, is_cross) + def __init__(self, exelist, version, is_cross, **kwargs): + DCompiler.__init__(self, exelist, version, is_cross, **kwargs) self.id = 'llvm' self.base_options = ['b_coverage', 'b_colorout'] @@ -321,8 +321,8 @@ class LLVMDCompiler(DCompiler): class DmdDCompiler(DCompiler): - def __init__(self, exelist, version, is_cross): - DCompiler.__init__(self, exelist, version, is_cross) + def __init__(self, exelist, version, is_cross, **kwargs): + DCompiler.__init__(self, exelist, version, is_cross, **kwargs) self.id = 'dmd' self.base_options = ['b_coverage', 'b_colorout'] diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py index 2957a7c..1b42bfa 100644 --- a/mesonbuild/compilers/fortran.py +++ b/mesonbuild/compilers/fortran.py @@ -31,9 +31,9 @@ from .compilers import ( ) class FortranCompiler(Compiler): - def __init__(self, exelist, version, is_cross, exe_wrapper=None): + def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwargs): self.language = 'fortran' - super().__init__(exelist, version) + super().__init__(exelist, version, **kwargs) self.is_cross = is_cross self.exe_wrapper = exe_wrapper # Not really correct but I don't have Fortran compilers to test with. Sorry. @@ -99,7 +99,7 @@ end program prog def get_dependency_gen_args(self, outtarget, outfile): # Disabled until this is fixed: # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=62162 - # return ['-cpp', '-MMD', '-MQ', outtarget] + # return ['-cpp', '-MD', '-MQ', outtarget] return [] def get_output_args(self, target): @@ -149,8 +149,8 @@ end program prog class GnuFortranCompiler(FortranCompiler): - def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None, defines=None): - super().__init__(exelist, version, is_cross, exe_wrapper=None) + def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None, defines=None, **kwargs): + super().__init__(exelist, version, is_cross, exe_wrapper=None, **kwargs) self.gcc_type = gcc_type self.defines = defines or {} self.id = 'gcc' @@ -181,8 +181,8 @@ class GnuFortranCompiler(FortranCompiler): class G95FortranCompiler(FortranCompiler): - def __init__(self, exelist, version, is_cross, exe_wrapper=None): - super().__init__(exelist, version, is_cross, exe_wrapper=None) + def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwags): + super().__init__(exelist, version, is_cross, exe_wrapper=None, **kwags) self.id = 'g95' def get_module_outdir_args(self, path): @@ -205,8 +205,8 @@ class G95FortranCompiler(FortranCompiler): class SunFortranCompiler(FortranCompiler): - def __init__(self, exelist, version, is_cross, exe_wrapper=None): - super().__init__(exelist, version, is_cross, exe_wrapper=None) + def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwags): + super().__init__(exelist, version, is_cross, exe_wrapper=None, **kwags) self.id = 'sun' def get_dependency_gen_args(self, outtarget, outfile): @@ -228,9 +228,9 @@ class SunFortranCompiler(FortranCompiler): class IntelFortranCompiler(IntelCompiler, FortranCompiler): std_warn_args = ['-warn', 'all'] - def __init__(self, exelist, version, is_cross, exe_wrapper=None): + def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwags): self.file_suffixes = ('f90', 'f', 'for', 'ftn', 'fpp') - FortranCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) + FortranCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwags) # FIXME: Add support for OS X and Windows in detect_fortran_compiler so # we are sent the type of compiler IntelCompiler.__init__(self, ICC_STANDARD) @@ -246,8 +246,8 @@ class IntelFortranCompiler(IntelCompiler, FortranCompiler): class PathScaleFortranCompiler(FortranCompiler): std_warn_args = ['-fullwarn'] - def __init__(self, exelist, version, is_cross, exe_wrapper=None): - super().__init__(exelist, version, is_cross, exe_wrapper=None) + def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwags): + super().__init__(exelist, version, is_cross, exe_wrapper=None, **kwags) self.id = 'pathscale' def get_module_outdir_args(self, path): @@ -259,8 +259,8 @@ class PathScaleFortranCompiler(FortranCompiler): class PGIFortranCompiler(FortranCompiler): std_warn_args = ['-Minform=inform'] - def __init__(self, exelist, version, is_cross, exe_wrapper=None): - super().__init__(exelist, version, is_cross, exe_wrapper=None) + def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwags): + super().__init__(exelist, version, is_cross, exe_wrapper=None, **kwags) self.id = 'pgi' def get_module_incdir_args(self): @@ -279,8 +279,8 @@ class PGIFortranCompiler(FortranCompiler): class Open64FortranCompiler(FortranCompiler): std_warn_args = ['-fullwarn'] - def __init__(self, exelist, version, is_cross, exe_wrapper=None): - super().__init__(exelist, version, is_cross, exe_wrapper=None) + def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwags): + super().__init__(exelist, version, is_cross, exe_wrapper=None, **kwags) self.id = 'open64' def get_module_outdir_args(self, path): @@ -293,8 +293,8 @@ class Open64FortranCompiler(FortranCompiler): class NAGFortranCompiler(FortranCompiler): std_warn_args = [] - def __init__(self, exelist, version, is_cross, exe_wrapper=None): - super().__init__(exelist, version, is_cross, exe_wrapper=None) + def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwags): + super().__init__(exelist, version, is_cross, exe_wrapper=None, **kwags) self.id = 'nagfor' def get_module_outdir_args(self, path): diff --git a/mesonbuild/compilers/vala.py b/mesonbuild/compilers/vala.py index b91da6d..9ab5c8a 100644 --- a/mesonbuild/compilers/vala.py +++ b/mesonbuild/compilers/vala.py @@ -95,8 +95,8 @@ class ValaCompiler(Compiler): mlog.debug('Searched {!r} and {!r} wasn\'t found'.format(extra_dirs, libname)) return None - def thread_flags(self): + def thread_flags(self, env): return [] - def thread_link_flags(self): + def thread_link_flags(self, env): return [] diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index cf7df5e..0fdac8b 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -13,11 +13,12 @@ # See the License for the specific language governing permissions and # limitations under the License. +from . import mlog import pickle, os, uuid import sys from pathlib import PurePath from collections import OrderedDict -from .mesonlib import MesonException, commonpath +from .mesonlib import MesonException from .mesonlib import default_libdir, default_libexecdir, default_prefix import ast @@ -148,6 +149,9 @@ class UserArrayOption(UserOption): newvalue = ast.literal_eval(value) else: newvalue = [v.strip() for v in value.split(',')] + if len(set(newvalue)) != len(newvalue): + mlog.log(mlog.red('DEPRECATION:'), '''Duplicated values in an array type is deprecated. +This will become a hard error in the future.''') if not isinstance(newvalue, list): raise MesonException('"{0}" should be a string array, but it is not'.format(str(newvalue))) for i in newvalue: @@ -270,7 +274,7 @@ class CoreData: # commonpath will always return a path in the native format, so we # must use pathlib.PurePath to do the same conversion before # comparing. - if commonpath([value, prefix]) != str(PurePath(prefix)): + if os.path.commonpath([value, prefix]) != str(PurePath(prefix)): m = 'The value of the {!r} option is {!r} which must be a ' \ 'subdir of the prefix {!r}.\nNote that if you pass a ' \ 'relative path, it is assumed to be a subdir of prefix.' diff --git a/mesonbuild/dependencies/__init__.py b/mesonbuild/dependencies/__init__.py index 4dc2b27..69235da 100644 --- a/mesonbuild/dependencies/__init__.py +++ b/mesonbuild/dependencies/__init__.py @@ -13,7 +13,7 @@ # limitations under the License. from .base import ( # noqa: F401 - Dependency, DependencyException, DependencyMethods, ExternalProgram, + Dependency, DependencyException, DependencyMethods, ExternalProgram, NonExistingExternalProgram, ExternalDependency, ExternalLibrary, ExtraFrameworkDependency, InternalDependency, PkgConfigDependency, find_external_dependency, get_dep_identifier, packages, _packages_accept_language) from .dev import GMockDependency, GTestDependency, LLVMDependency, ValgrindDependency diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 0ef3372..e29d4de 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -284,17 +284,18 @@ class ConfigToolDependency(ExternalDependency): """Helper method to print messages about the tool.""" if self.config is None: if version is not None: - mlog.log('found {} {!r} but need:'.format(self.tool_name, version), - req_version) + mlog.log('Found', mlog.bold(self.tool_name), repr(version), + mlog.red('NO'), '(needed', req_version, ')') else: - mlog.log("No {} found; can't detect dependency".format(self.tool_name)) - mlog.log('Dependency {} found:'.format(self.name), mlog.red('NO')) + mlog.log('Found', mlog.bold(self.tool_name), repr(req_version), + mlog.red('NO')) + mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.red('NO')) if self.required: raise DependencyException('Dependency {} not found'.format(self.name)) return False mlog.log('Found {}:'.format(self.tool_name), mlog.bold(shutil.which(self.config)), '({})'.format(version)) - mlog.log('Dependency {} found:'.format(self.name), mlog.green('YES')) + mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.green('YES')) return True def get_config_value(self, args, stage): @@ -399,11 +400,22 @@ class PkgConfigDependency(ExternalDependency): m = 'Invalid version of dependency, need {!r} {!r} found {!r}.' raise DependencyException(m.format(name, not_found, self.version)) return - found_msg += [mlog.green('YES'), self.version] - # Fetch cargs to be used while using this dependency - self._set_cargs() - # Fetch the libraries and library paths needed for using this - self._set_libs() + + try: + # Fetch cargs to be used while using this dependency + self._set_cargs() + # Fetch the libraries and library paths needed for using this + self._set_libs() + found_msg += [mlog.green('YES'), self.version] + except DependencyException as e: + if self.required: + raise + else: + self.compile_args = [] + self.link_args = [] + self.is_found = False + found_msg += [mlog.red('NO'), '; reason: {}'.format(str(e))] + # Print the found message only at the very end because fetching cflags # and libs can also fail if other needed pkg-config files aren't found. if not self.silent: @@ -753,6 +765,17 @@ class ExternalProgram: def get_name(self): return self.name +class NonExistingExternalProgram(ExternalProgram): + + def __init__(self): + super().__init__(name = 'nonexistingprogram', silent = True) + + def __repr__(self): + r = '<{} {!r} -> {!r}>' + return r.format(self.__class__.__name__, self.name, self.command) + + def found(self): + return False class ExternalLibrary(ExternalDependency): def __init__(self, name, link_args, environment, language, silent=False): diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py index d15d5da..25316df 100644 --- a/mesonbuild/dependencies/dev.py +++ b/mesonbuild/dependencies/dev.py @@ -17,11 +17,10 @@ import os import re -import shutil from .. import mlog from .. import mesonlib -from ..mesonlib import version_compare, Popen_safe, stringlistify, extract_as_list +from ..mesonlib import version_compare, stringlistify, extract_as_list from .base import ( DependencyException, ExternalDependency, PkgConfigDependency, strip_system_libdirs, ConfigToolDependency, @@ -140,7 +139,7 @@ class LLVMDependency(ConfigToolDependency): 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__('config-tool', environment, 'cpp', kwargs) + super().__init__('LLVM', environment, 'cpp', kwargs) self.provided_modules = [] self.required_modules = set() if not self.is_found: @@ -150,7 +149,12 @@ class LLVMDependency(ConfigToolDependency): # Currently meson doesn't really attempt 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. + # + # If LLVM is built from svn then "svn" will be appended to the version + # string, if it's built from a git mirror then "git-<very short sha>" + # will be appended instead. self.version = self.version.rstrip('svn') + self.version = self.version.split('git')[0] self.provided_modules = self.get_config_value(['--components'], 'modules') modules = stringlistify(extract_as_list(kwargs, 'modules')) @@ -166,9 +170,37 @@ class LLVMDependency(ConfigToolDependency): else: self._set_old_link_args() self.link_args = strip_system_libdirs(environment, self.link_args) + self.link_args = self.__fix_bogus_link_args(self.link_args) + + @staticmethod + def __fix_bogus_link_args(args): + """This function attempts to fix bogus link arguments that llvm-config + generates. + + Currently it works around the following: + - FreeBSD: when statically linking -l/usr/lib/libexecinfo.so will + be generated, strip the -l in cases like this. + """ + new_args = [] + for arg in args: + if arg.startswith('-l') and arg.endswith('.so'): + new_args.append(arg.lstrip('-l')) + else: + new_args.append(arg) + return new_args def _set_new_link_args(self): """How to set linker args for LLVM versions >= 3.9""" + if ((mesonlib.is_dragonflybsd() or mesonlib.is_freebsd()) and not + self.static and version_compare(self.version, '>= 4.0')): + # llvm-config on DragonFly BSD and FreeBSD for versions 4.0, 5.0, + # and 6.0 have an error when generating arguments for shared mode + # linking, even though libLLVM.so is installed, because for some + # reason the tool expects to find a .so for each static library. + # This works around that. + self.link_args = self.get_config_value(['--ldflags'], 'link_args') + self.link_args.append('-lLLVM') + return link_args = ['--link-static', '--system-libs'] if self.static else ['--link-shared'] self.link_args = self.get_config_value( ['--libs', '--ldflags'] + link_args + list(self.required_modules), @@ -213,7 +245,7 @@ class LLVMDependency(ConfigToolDependency): """ for mod in sorted(set(modules)): if mod not in self.provided_modules: - mlog.log('LLVM module', mod, 'found:', mlog.red('NO'), + mlog.log('LLVM module', mlog.bold(mod), 'found:', mlog.red('NO'), '(optional)' if not required else '') if required: self.is_found = False @@ -222,7 +254,7 @@ class LLVMDependency(ConfigToolDependency): 'Could not find required LLVM Component: {}'.format(mod)) else: self.required_modules.add(mod) - mlog.log('LLVM module', mod, 'found:', mlog.green('YES')) + mlog.log('LLVM module', mlog.bold(mod), 'found:', mlog.green('YES')) def need_threads(self): return True diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index ce9313e..9614f1f 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -25,7 +25,6 @@ from pathlib import Path from .. import mlog from .. import mesonlib -from ..mesonlib import Popen_safe, extract_as_list from ..environment import detect_cpu_family from .base import ( @@ -52,7 +51,7 @@ from .base import ( # - boost_<module>.lib|.dll (shared) # where compiler is vc141 for example. # -# NOTE: -gb means runtime and build time debugging is on +# NOTE: -gd means runtime and build time debugging is on # -mt means threading=multi # # The `modules` argument accept library names. This is because every module that @@ -62,6 +61,47 @@ from .base import ( # * 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 +# **On Unix**, official packaged versions of boost libraries follow the following schemes: +# +# Linux / Debian: libboost_<module>.so.1.66.0 -> libboost_<module>.so +# Linux / Red Hat: libboost_<module>.so.1.66.0 -> libboost_<module>.so +# Linux / OpenSuse: libboost_<module>.so.1.66.0 -> libboost_<module>.so +# Mac / homebrew: libboost_<module>.dylib + libboost_<module>-mt.dylib (location = /usr/local/lib) +# Mac / macports: libboost_<module>.dylib + libboost_<module>-mt.dylib (location = /opt/local/lib) +# +# Its not clear that any other abi tags (e.g. -gd) are used in official packages. +# +# On Linux systems, boost libs have multithreading support enabled, but without the -mt tag. +# +# Boost documentation recommends using complex abi tags like "-lboost_regex-gcc34-mt-d-1_36". +# (See http://www.boost.org/doc/libs/1_66_0/more/getting_started/unix-variants.html#library-naming) +# However, its not clear that any Unix distribution follows this scheme. +# Furthermore, the boost documentation for unix above uses examples from windows like +# "libboost_regex-vc71-mt-d-x86-1_34.lib", so apparently the abi tags may be more aimed at windows. +# +# Probably we should use the linker search path to decide which libraries to use. This will +# make it possible to find the macports boost libraries without setting BOOST_ROOT, and will +# also mean that it would be possible to use user-installed boost libraries when official +# packages are installed. +# +# We thus follow the following strategy: +# 1. Look for libraries using compiler.find_library( ) +# 1.1 On Linux, just look for boost_<module> +# 1.2 On other systems (e.g. Mac) look for boost_<module>-mt if multithreading. +# 1.3 Otherwise look for boost_<module> +# 2. Fall back to previous approach +# 2.1. Search particular directories. +# 2.2. Find boost libraries with unknown suffixes using file-name globbing. + +# TODO: Unix: Don't assume we know where the boost dir is, rely on -Idir and -Ldir being set. +# TODO: Determine a suffix (e.g. "-mt" or "") and use it. +# TODO: Get_win_link_args( ) and get_link_args( ) +# TODO: Genericize: 'args += ['-L' + dir] => args += self.compiler.get_linker_search_args(dir) +# TODO: Allow user to specify suffix in BOOST_SUFFIX, or add specific options like BOOST_DEBUG for 'd' for debug. +# TODO: fix cross: +# is_windows() -> for_windows(self.want_cross, self.env) +# is_osx() and self.want_cross -> for_darwin(self.want_cross, self.env) + class BoostDependency(ExternalDependency): def __init__(self, environment, kwargs): super().__init__('boost', environment, 'cpp', kwargs) @@ -71,11 +111,6 @@ class BoostDependency(ExternalDependency): 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 = [] @@ -108,7 +143,25 @@ class BoostDependency(ExternalDependency): else: self.incdir = self.detect_nix_incdir() - if self.incdir is None: + if self.incdir is None and mesonlib.is_windows(): + self.log_fail() + return + + invalid_modules = [c for c in self.requested_modules if 'boost_' + c not in BOOST_LIBS] + + # previous versions of meson allowed include dirs as modules + remove = [] + for m in invalid_modules: + if m in BOOST_DIRS: + mlog.warning('Requested boost library', mlog.bold(m), 'that doesn\'t exist. ' + 'This will be an error in the future') + remove.append(m) + + self.requested_modules = [x for x in self.requested_modules if x not in remove] + invalid_modules = [x for x in invalid_modules if x not in remove] + + if invalid_modules: + mlog.log(mlog.red('ERROR:'), 'Invalid Boost modules: ' + ', '.join(invalid_modules)) self.log_fail() return @@ -125,6 +178,7 @@ class BoostDependency(ExternalDependency): else: self.log_fail() + def log_fail(self): module_str = ', '.join(self.requested_modules) mlog.log("Dependency Boost (%s) found:" % module_str, mlog.red('NO')) @@ -159,10 +213,8 @@ class BoostDependency(ExternalDependency): 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') + if self.boost_root: + return os.path.join(self.boost_root, 'include') return None # FIXME: Should pick a version that matches the requested version @@ -204,7 +256,7 @@ class BoostDependency(ExternalDependency): return args def get_requested(self, kwargs): - candidates = extract_as_list(kwargs, 'modules') + candidates = mesonlib.extract_as_list(kwargs, 'modules') for c in candidates: if not isinstance(c, str): raise DependencyException('Boost module argument is not a string.') @@ -218,25 +270,30 @@ class BoostDependency(ExternalDependency): def detect_version(self): try: - ifile = open(os.path.join(self.incdir, 'boost', 'version.hpp')) - except FileNotFoundError: + version = self.compiler.get_define('BOOST_LIB_VERSION', '#include <boost/version.hpp>', self.env, self.get_compile_args(), []) + except mesonlib.EnvironmentException: return except TypeError: return - with ifile: - for line in ifile: - if line.startswith("#define") and 'BOOST_LIB_VERSION' in line: - ver = line.split()[-1] - ver = ver[1:-1] - self.version = ver.replace('_', '.') - self.is_found = True - return + # Remove quotes + version = version[1:-1] + # Fix version string + self.version = version.replace('_', '.') + self.is_found = True def detect_lib_modules(self): if mesonlib.is_windows(): return self.detect_lib_modules_win() return self.detect_lib_modules_nix() + def modname_from_filename(self, filename): + modname = os.path.basename(filename) + modname = modname.split('.', 1)[0] + modname = modname.split('-', 1)[0] + if modname.startswith('libboost'): + modname = modname[3:] + return modname + def detect_lib_modules_win(self): arch = detect_cpu_family(self.env.coredata.compilers) comp_ts_version = self.env.detect_cpp_compiler(self.want_cross).get_toolset_version() @@ -278,12 +335,11 @@ class BoostDependency(ExternalDependency): 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 + self.lib_modules[self.modname_from_filename(libname)] = [libname] else: libname = "lib{}.lib".format(name) if os.path.isfile(os.path.join(self.libdir, libname)): - self.lib_modules[name[3:]] = libname + self.lib_modules[name[3:]] = [libname] # globber1 applies to a layout=system installation # globber2 applies to a layout=versioned installation @@ -296,24 +352,33 @@ class BoostDependency(ExternalDependency): 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) - 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 + fname = os.path.basename(entry) + self.lib_modules[self.modname_from_filename(fname)] = [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 + fname = os.path.basename(entry) + self.lib_modules[self.modname_from_filename(fname)] = [fname] def detect_lib_modules_nix(self): + all_found = True + for module in self.requested_modules: + args = None + libname = 'boost_' + module + if self.is_multithreading and mesonlib.for_darwin(self.want_cross, self.env): + # - Linux leaves off -mt but libraries are multithreading-aware. + # - Mac requires -mt for multithreading, so should not fall back to non-mt libraries. + libname = libname + '-mt' + args = self.compiler.find_library(libname, self.env, self.extra_lib_dirs()) + if args is None: + mlog.debug('Couldn\'t find library "{}" for boost module "{}"'.format(module, libname)) + all_found = False + else: + mlog.debug('Link args for boost module "{}" are {}'.format(module, args)) + self.lib_modules['boost_' + module] = args + if all_found: + return + if self.static: libsuffix = 'a' elif mesonlib.is_osx() and not self.want_cross: @@ -332,21 +397,25 @@ class BoostDependency(ExternalDependency): 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 + self.lib_modules[name] = [libname] for entry in glob.glob(os.path.join(libdir, globber)): - lib = os.path.basename(entry) - 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. # On debian all packages are built threading=multi # but not suffixed with -mt. # FIXME: implement detect_lib_modules_{debian, redhat, ...} + # FIXME: this wouldn't work with -mt-gd either. -BDR if self.is_multithreading and mesonlib.is_debianlike(): - self.lib_modules[name] = lib + pass elif self.is_multithreading and entry.endswith('-mt.{}'.format(libsuffix)): - self.lib_modules[name] = lib + pass elif not entry.endswith('-mt.{}'.format(libsuffix)): - self.lib_modules[name] = lib + pass + else: + continue + modname = self.modname_from_filename(entry) + if modname not in self.lib_modules: + self.lib_modules[modname] = [entry] def get_win_link_args(self): args = [] @@ -354,26 +423,25 @@ class BoostDependency(ExternalDependency): if self.libdir: args.append('-L' + self.libdir) for lib in self.requested_modules: - args.append(self.lib_modules['boost_' + lib]) + args += self.lib_modules['boost_' + lib] return args + def extra_lib_dirs(self): + dirs = [] + if self.boost_root: + dirs = [os.path.join(self.boost_root, 'lib')] + elif self.libdir: + dirs = [self.libdir] + return dirs + def get_link_args(self): if mesonlib.is_windows(): return self.get_win_link_args() args = [] - if self.boost_root: - args.append('-L' + os.path.join(self.boost_root, 'lib')) - elif self.libdir: - args.append('-L' + self.libdir) + for dir in self.extra_lib_dirs(): + args += ['-L' + dir] for lib in self.requested_modules: - # The compiler's library detector is the most reliable so use that first. - boost_lib = 'boost_' + lib - default_detect = self.compiler.find_library(boost_lib, self.env, []) - if default_detect is not None: - args += default_detect - elif boost_lib in self.lib_modules: - linkcmd = '-l' + boost_lib - args.append(linkcmd) + args += self.lib_modules['boost_' + lib] return args def get_sources(self): @@ -416,6 +484,7 @@ class MPIDependency(ExternalDependency): self.link_args = pkgdep.get_link_args() self.version = pkgdep.get_version() self.is_found = True + self.pcdep = pkgdep break except Exception: pass @@ -617,6 +686,7 @@ class Python3Dependency(ExternalDependency): self.link_args = self.pkgdep.get_link_args() self.version = self.pkgdep.get_version() self.is_found = True + self.pcdep = self.pkgdep return else: self.pkgdep = None @@ -750,6 +820,7 @@ class PcapDependency(ExternalDependency): self.compile_args = pcdep.get_compile_args() self.link_args = pcdep.get_link_args() self.version = pcdep.get_version() + self.pcdep = pcdep return except Exception as e: mlog.debug('Pcap not found via pkgconfig. Trying next, error was:', str(e)) @@ -792,6 +863,7 @@ class CupsDependency(ExternalDependency): self.compile_args = pcdep.get_compile_args() self.link_args = pcdep.get_link_args() self.version = pcdep.get_version() + self.pcdep = pcdep return except Exception as e: mlog.debug('cups not found via pkgconfig. Trying next, error was:', str(e)) @@ -804,7 +876,7 @@ class CupsDependency(ExternalDependency): self.type_name = 'config-tool' self.version = ctdep.version self.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args') - self.link_args = ctdep.get_config_value(['--libs'], 'link_args') + self.link_args = ctdep.get_config_value(['--ldflags', '--libs'], 'link_args') self.is_found = True return except Exception as e: @@ -841,6 +913,7 @@ class LibWmfDependency(ExternalDependency): self.compile_args = pcdep.get_compile_args() self.link_args = pcdep.get_link_args() self.version = pcdep.get_version() + self.pcdep = pcdep return except Exception as e: mlog.debug('LibWmf not found via pkgconfig. Trying next, error was:', str(e)) @@ -945,3 +1018,116 @@ BOOST_LIBS = [ 'boost_type_erasure', 'boost_wave' ] + +BOOST_DIRS = [ + 'lambda', + 'optional', + 'convert', + 'system', + 'uuid', + 'archive', + 'align', + 'timer', + 'chrono', + 'gil', + 'logic', + 'signals', + 'predef', + 'tr1', + 'multi_index', + 'property_map', + 'multi_array', + 'context', + 'random', + 'endian', + 'circular_buffer', + 'proto', + 'assign', + 'format', + 'math', + 'phoenix', + 'graph', + 'locale', + 'mpl', + 'pool', + 'unordered', + 'core', + 'exception', + 'ptr_container', + 'flyweight', + 'range', + 'typeof', + 'thread', + 'move', + 'spirit', + 'dll', + 'compute', + 'serialization', + 'ratio', + 'msm', + 'config', + 'metaparse', + 'coroutine2', + 'qvm', + 'program_options', + 'concept', + 'detail', + 'hana', + 'concept_check', + 'compatibility', + 'variant', + 'type_erasure', + 'mpi', + 'test', + 'fusion', + 'log', + 'sort', + 'local_function', + 'units', + 'functional', + 'preprocessor', + 'integer', + 'container', + 'polygon', + 'interprocess', + 'numeric', + 'iterator', + 'wave', + 'lexical_cast', + 'multiprecision', + 'utility', + 'tti', + 'asio', + 'dynamic_bitset', + 'algorithm', + 'xpressive', + 'bimap', + 'signals2', + 'type_traits', + 'regex', + 'statechart', + 'parameter', + 'icl', + 'python', + 'lockfree', + 'intrusive', + 'io', + 'pending', + 'geometry', + 'tuple', + 'iostreams', + 'heap', + 'atomic', + 'filesystem', + 'smart_ptr', + 'function', + 'fiber', + 'type_index', + 'accumulators', + 'function_types', + 'coroutine', + 'vmd', + 'date_time', + 'property_tree', + 'bind' +] diff --git a/mesonbuild/dependencies/ui.py b/mesonbuild/dependencies/ui.py index 1db518c..c066c31 100644 --- a/mesonbuild/dependencies/ui.py +++ b/mesonbuild/dependencies/ui.py @@ -47,6 +47,7 @@ class GLDependency(ExternalDependency): self.compile_args = pcdep.get_compile_args() self.link_args = pcdep.get_link_args() self.version = pcdep.get_version() + self.pcdep = pcdep return except Exception: pass @@ -228,6 +229,7 @@ class QtBaseDependency(ExternalDependency): self.link_args += m.get_link_args() self.is_found = True self.version = m.version + self.pcdep = list(modules.values()) # Try to detect moc, uic, rcc if 'Core' in modules: core = modules['Core'] @@ -235,6 +237,7 @@ class QtBaseDependency(ExternalDependency): corekwargs = {'required': 'false', 'silent': 'true'} core = PkgConfigDependency(self.qtpkgname + 'Core', self.env, corekwargs, language=self.language) + self.pcdep.append(core) # Used by self.compilers_detect() self.bindir = self.get_pkgconfig_host_bins(core) if not self.bindir: @@ -387,6 +390,7 @@ class SDL2Dependency(ExternalDependency): self.compile_args = pcdep.get_compile_args() self.link_args = pcdep.get_link_args() self.version = pcdep.get_version() + self.pcdep = pcdep return except Exception as e: mlog.debug('SDL 2 not found via pkgconfig. Trying next, error was:', str(e)) @@ -461,6 +465,7 @@ class VulkanDependency(ExternalDependency): self.compile_args = pcdep.get_compile_args() self.link_args = pcdep.get_link_args() self.version = pcdep.get_version() + self.pcdep = pcdep return except Exception: pass diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 0cb1450..e5aa43e 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -496,6 +496,7 @@ class Environment: popen_exceptions[' '.join(compiler + [arg])] = e continue version = search_version(out) + full_version = out.split('\n', 1)[0] if 'Free Software Foundation' in out: defines = self.get_gnu_compiler_defines(compiler) if not defines: @@ -504,7 +505,7 @@ class Environment: gtype = self.get_gnu_compiler_type(defines) version = self.get_gnu_version_from_defines(defines) cls = GnuCCompiler if lang == 'c' else GnuCPPCompiler - return cls(ccache + compiler, version, gtype, is_cross, exe_wrap, defines) + return cls(ccache + compiler, version, gtype, is_cross, exe_wrap, defines, full_version=full_version) if 'clang' in out: if 'Apple' in out or mesonlib.for_darwin(want_cross, self): cltype = CLANG_OSX @@ -513,7 +514,7 @@ class Environment: else: cltype = CLANG_STANDARD cls = ClangCCompiler if lang == 'c' else ClangCPPCompiler - return cls(ccache + compiler, version, cltype, is_cross, exe_wrap) + return cls(ccache + compiler, version, cltype, is_cross, exe_wrap, full_version=full_version) if 'Microsoft' in out or 'Microsoft' in err: # Latest versions of Visual Studio print version # number to stderr but earlier ones print version @@ -532,7 +533,7 @@ class Environment: # TODO: add microsoft add check OSX inteltype = ICC_STANDARD cls = IntelCCompiler if lang == 'c' else IntelCPPCompiler - return cls(ccache + compiler, version, inteltype, is_cross, exe_wrap) + return cls(ccache + compiler, version, inteltype, is_cross, exe_wrap, full_version=full_version) self._handle_exceptions(popen_exceptions, compilers) def detect_c_compiler(self, want_cross): @@ -555,6 +556,7 @@ class Environment: continue version = search_version(out) + full_version = out.split('\n', 1)[0] if 'GNU Fortran' in out: defines = self.get_gnu_compiler_defines(compiler) @@ -563,29 +565,29 @@ class Environment: continue gtype = self.get_gnu_compiler_type(defines) version = self.get_gnu_version_from_defines(defines) - return GnuFortranCompiler(compiler, version, gtype, is_cross, exe_wrap, defines) + return GnuFortranCompiler(compiler, version, gtype, is_cross, exe_wrap, defines, full_version=full_version) if 'G95' in out: - return G95FortranCompiler(compiler, version, is_cross, exe_wrap) + return G95FortranCompiler(compiler, version, is_cross, exe_wrap, full_version=full_version) if 'Sun Fortran' in err: version = search_version(err) - return SunFortranCompiler(compiler, version, is_cross, exe_wrap) + return SunFortranCompiler(compiler, version, is_cross, exe_wrap, full_version=full_version) if 'ifort (IFORT)' in out: - return IntelFortranCompiler(compiler, version, is_cross, exe_wrap) + return IntelFortranCompiler(compiler, version, is_cross, exe_wrap, full_version=full_version) if 'PathScale EKOPath(tm)' in err: - return PathScaleFortranCompiler(compiler, version, is_cross, exe_wrap) + return PathScaleFortranCompiler(compiler, version, is_cross, exe_wrap, full_version=full_version) if 'PGI Compilers' in out: - return PGIFortranCompiler(compiler, version, is_cross, exe_wrap) + return PGIFortranCompiler(compiler, version, is_cross, exe_wrap, full_version=full_version) if 'Open64 Compiler Suite' in err: - return Open64FortranCompiler(compiler, version, is_cross, exe_wrap) + return Open64FortranCompiler(compiler, version, is_cross, exe_wrap, full_version=full_version) if 'NAG Fortran' in err: - return NAGFortranCompiler(compiler, version, is_cross, exe_wrap) + return NAGFortranCompiler(compiler, version, is_cross, exe_wrap, full_version=full_version) self._handle_exceptions(popen_exceptions, compilers) def get_scratch_dir(self): @@ -606,6 +608,7 @@ class Environment: p, out, err = Popen_safe(compiler + arg) except OSError as e: popen_exceptions[' '.join(compiler + arg)] = e + continue version = search_version(out) if 'Free Software Foundation' in out: defines = self.get_gnu_compiler_defines(compiler) @@ -632,6 +635,7 @@ class Environment: p, out, err = Popen_safe(compiler + arg) except OSError as e: popen_exceptions[' '.join(compiler + arg)] = e + continue version = search_version(out) if 'Free Software Foundation' in out: defines = self.get_gnu_compiler_defines(compiler) @@ -665,8 +669,9 @@ class Environment: except OSError: raise EnvironmentException('Could not execute C# compiler "%s"' % ' '.join(exelist)) version = search_version(out) + full_version = out.split('\n', 1)[0] if 'Mono' in out: - return MonoCompiler(exelist, version) + return MonoCompiler(exelist, version, full_version=full_version) raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"') def detect_vala_compiler(self): @@ -721,12 +726,13 @@ class Environment: except OSError: raise EnvironmentException('Could not execute D compiler "%s"' % ' '.join(exelist)) version = search_version(out) + full_version = out.split('\n', 1)[0] if 'LLVM D compiler' in out: - return compilers.LLVMDCompiler(exelist, version, is_cross) + return compilers.LLVMDCompiler(exelist, version, is_cross, full_version=full_version) elif 'gdc' in out: - return compilers.GnuDCompiler(exelist, version, is_cross) - elif 'Digital Mars' in out: - return compilers.DmdDCompiler(exelist, version, is_cross) + return compilers.GnuDCompiler(exelist, version, is_cross, full_version=full_version) + elif 'The D Language Foundation' in out or 'Digital Mars' in out: + return compilers.DmdDCompiler(exelist, version, is_cross, full_version=full_version) raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"') def detect_swift_compiler(self): diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index a5aa5fa..c759892 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -1358,7 +1358,7 @@ build_target_common_kwargs = ( rust_kwargs | cs_kwargs) -exe_kwargs = (build_target_common_kwargs) | {'implib'} +exe_kwargs = (build_target_common_kwargs) | {'implib', 'export_dynamic'} shlib_kwargs = (build_target_common_kwargs) | {'version', 'soversion'} shmod_kwargs = shlib_kwargs stlib_kwargs = shlib_kwargs @@ -1585,7 +1585,7 @@ class Interpreter(InterpreterBase): modname = args[0] if modname.startswith('unstable-'): plainname = modname.split('-', 1)[1] - mlog.warning('Module %s has no backwards or forwards compatibility and might not exist in future releases.' % modname) + mlog.warning('Module %s has no backwards or forwards compatibility and might not exist in future releases' % modname, location=node) modname = 'unstable_' + plainname if modname not in self.environment.coredata.modules: try: @@ -1678,7 +1678,7 @@ external dependencies (including libraries) must go to "dependencies".''') search_dir = os.path.join(srcdir, self.subdir) prog = ExternalProgram(cmd, silent=True, search_dir=search_dir) if not prog.found(): - raise InterpreterException('Program or command {!r} not found' + 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) @@ -1824,9 +1824,18 @@ to directly access options of other subprojects.''') if coredata.is_builtin_option(key): if self.subproject != '': continue # Only the master project is allowed to set global options. + # If this was set on the command line, do not override. if not self.environment.had_argument_for(key): self.coredata.set_builtin_option(key, value) - # If this was set on the command line, do not override. + # If we are setting the prefix, then other options which + # have prefix-dependent defaults need their value updating, + # if they haven't been explicitly set (i.e. have their + # default value) + if key == 'prefix': + for option in coredata.builtin_dir_noprefix_options: + if not (self.environment.had_argument_for(option) or + any([k.startswith(option + '=') for k in default_options])): + self.coredata.set_builtin_option(option, coredata.get_builtin_option_default(option, value)) else: # Option values set with subproject() default_options override those # set in project() default_options. @@ -1885,10 +1894,14 @@ to directly access options of other subprojects.''') raise InvalidCode('Second call to project().') if not self.is_subproject() and 'subproject_dir' in kwargs: spdirname = kwargs['subproject_dir'] - if '/' in spdirname or '\\' in spdirname: - raise InterpreterException('Subproject_dir must not contain a path segment.') + if not isinstance(spdirname, str): + raise InterpreterException('Subproject_dir must be a string') + if os.path.isabs(spdirname): + raise InterpreterException('Subproject_dir must not be an absolute path.') if spdirname.startswith('.'): raise InterpreterException('Subproject_dir must not begin with a period.') + if '..' in spdirname: + raise InterpreterException('Subproject_dir must not contain a ".." segment.') self.subproject_dir = spdirname if 'meson_version' in kwargs: @@ -1937,7 +1950,7 @@ to directly access options of other subprojects.''') @noKwargs def func_warning(self, node, args, kwargs): argstr = self.get_message_string_arg(node) - mlog.warning(argstr) + mlog.warning(argstr, location=node) @noKwargs def func_error(self, node, args, kwargs): @@ -2032,7 +2045,11 @@ to directly access options of other subprojects.''') continue else: raise - mlog.log('Native %s compiler: ' % comp.get_display_language(), mlog.bold(' '.join(comp.get_exelist())), ' (%s %s)' % (comp.id, comp.version), sep='') + if comp.full_version is not None: + version_string = ' (%s %s "%s")' % (comp.id, comp.version, comp.full_version) + else: + version_string = ' (%s %s)' % (comp.id, comp.version) + mlog.log('Native %s compiler: ' % comp.get_display_language(), mlog.bold(' '.join(comp.get_exelist())), version_string, sep='') if not comp.get_language() in self.coredata.external_args: (preproc_args, compile_args, link_args) = environment.get_args_from_envvars(comp) self.coredata.external_preprocess_args[comp.get_language()] = preproc_args @@ -2117,7 +2134,7 @@ to directly access options of other subprojects.''') if required and (progobj is None or not progobj.found()): raise InvalidArguments('Program "%s" not found or not executable' % args[0]) if progobj is None: - return ExternalProgramHolder(dependencies.ExternalProgram('nonexistingprogram')) + return ExternalProgramHolder(dependencies.NonExistingExternalProgram()) return progobj def func_find_library(self, node, args, kwargs): @@ -2138,6 +2155,8 @@ to directly access options of other subprojects.''') # Check if we've already searched for and found this dep if identifier in self.coredata.deps: cached_dep = self.coredata.deps[identifier] + mlog.log('Dependency', mlog.bold(name), + 'found:', mlog.green('YES'), '(cached)') else: # Check if exactly the same dep with different version requirements # was found already. @@ -2154,13 +2173,59 @@ to directly access options of other subprojects.''') break return identifier, cached_dep + @staticmethod + def check_subproject_version(wanted, found): + if wanted == 'undefined': + return True + if found == 'undefined' or not mesonlib.version_compare(found, wanted): + return False + return True + + def get_subproject_dep(self, name, dirname, varname, required): + try: + dep = self.subprojects[dirname].get_variable_method([varname], {}) + except KeyError: + if required: + raise DependencyException('Could not find dependency {} in subproject {}' + ''.format(varname, dirname)) + # If the dependency is not required, don't raise an exception + subproj_path = os.path.join(self.subproject_dir, dirname) + mlog.log('Dependency', mlog.bold(name), 'from subproject', + mlog.bold(subproj_path), 'found:', mlog.red('NO')) + return None + if not isinstance(dep, DependencyHolder): + raise InvalidCode('Fetched variable {!r} in the subproject {!r} is ' + 'not a dependency object.'.format(varname, dirname)) + return dep + + def _find_cached_fallback_dep(self, name, dirname, varname, wanted, required): + if dirname not in self.subprojects: + return False + dep = self.get_subproject_dep(name, dirname, varname, required) + if not dep: + return False + found = dep.version_method([], {}) + if self.check_subproject_version(wanted, found): + subproj_path = os.path.join(self.subproject_dir, dirname) + mlog.log('Dependency', mlog.bold(name), 'from subproject', + mlog.bold(subproj_path), 'found:', mlog.green('YES'), '(cached)') + return dep + if required: + raise DependencyException('Version {} of subproject dependency {} already ' + 'cached, requested incompatible version {} for ' + 'dep {}'.format(found, dirname, wanted, name)) + return None + @permittedKwargs(permitted_kwargs['dependency']) def func_dependency(self, node, args, kwargs): self.validate_arguments(args, 1, [str]) + required = kwargs.get('required', True) + if not isinstance(required, bool): + raise DependencyException('Keyword "required" must be a boolean.') name = args[0] if name == '': - if kwargs.get('required', True): + if required: raise InvalidArguments('Dependency is both required and not-found') return DependencyHolder(Dependency('not-found', {})) @@ -2170,7 +2235,7 @@ to directly access options of other subprojects.''') identifier, cached_dep = self._find_cached_dep(name, kwargs) if cached_dep: - if kwargs.get('required', True) and not cached_dep.found(): + if required and not cached_dep.found(): m = 'Dependency {!r} was already checked and was not found' raise DependencyException(m.format(name)) dep = cached_dep @@ -2179,13 +2244,10 @@ to directly access options of other subprojects.''') # a higher level project, try to use it first. if 'fallback' in kwargs: dirname, varname = self.get_subproject_infos(kwargs) - if dirname in self.subprojects: - subproject = self.subprojects[dirname] - try: - # Never add fallback deps to self.coredata.deps - return subproject.get_variable_method([varname], {}) - except KeyError: - pass + wanted = kwargs.get('version', 'undefined') + dep = self._find_cached_fallback_dep(name, dirname, varname, wanted, required) + if dep: + return dep # We need to actually search for this dep exception = None @@ -2207,6 +2269,7 @@ to directly access options of other subprojects.''') # we won't actually read all the build files. return fallback_dep if not dep: + self.print_nested_info(name) assert(exception is not None) raise exception @@ -2220,6 +2283,28 @@ to directly access options of other subprojects.''') def func_disabler(self, node, args, kwargs): return Disabler() + def print_nested_info(self, dependency_name): + message_templ = '''\nDependency %s not found but it is available in a sub-subproject. +To use it in the current project, promote it by going in the project source +root and issuing %s. + +''' + sprojs = mesonlib.detect_subprojects('subprojects', self.source_root) + if dependency_name not in sprojs: + return + found = sprojs[dependency_name] + if len(found) > 1: + suffix = 'one of the following commands' + else: + suffix = 'the following command' + message = message_templ % (dependency_name, suffix) + cmds = [] + command_templ = 'meson wrap promote ' + for l in found: + cmds.append(command_templ + l[len(self.source_root)+1:]) + final_message = message + '\n'.join(cmds) + print(final_message) + def get_subproject_infos(self, kwargs): fbinfo = kwargs['fallback'] check_stringlist(fbinfo) @@ -2252,32 +2337,21 @@ to directly access options of other subprojects.''') mlog.bold(os.path.join(self.subproject_dir, dirname)), 'for the dependency', mlog.bold(name)) return None - try: - dep = self.subprojects[dirname].get_variable_method([varname], {}) - except KeyError: - if kwargs.get('required', True): - m = 'Fallback variable {!r} in the subproject {!r} does not exist' - raise DependencyException(m.format(varname, dirname)) - # If the dependency is not required, don't raise an exception - mlog.log('Also couldn\'t find the dependency', mlog.bold(name), - 'in the fallback subproject', - mlog.bold(os.path.join(self.subproject_dir, dirname))) + dep = self.get_subproject_dep(name, dirname, varname, kwargs.get('required', True)) + if not dep: return None - if not isinstance(dep, DependencyHolder): - raise InvalidCode('Fallback variable {!r} in the subproject {!r} is ' - 'not a dependency object.'.format(varname, dirname)) + subproj_path = os.path.join(self.subproject_dir, dirname) # Check if the version of the declared dependency matches what we want if 'version' in kwargs: wanted = kwargs['version'] found = dep.version_method([], {}) - if found == 'undefined' or not mesonlib.version_compare(found, wanted): - mlog.log('Subproject', mlog.bold(dirname), 'dependency', + if not self.check_subproject_version(wanted, found): + mlog.log('Subproject', mlog.bold(subproj_path), 'dependency', mlog.bold(varname), 'version is', mlog.bold(found), 'but', mlog.bold(wanted), 'is required.') return None - mlog.log('Found a', mlog.green('fallback'), 'subproject', - mlog.bold(os.path.join(self.subproject_dir, dirname)), 'for', - mlog.bold(name)) + mlog.log('Dependency', mlog.bold(name), 'from subproject', + mlog.bold(subproj_path), 'found:', mlog.green('YES')) return dep @permittedKwargs(permitted_kwargs['executable']) @@ -2514,6 +2588,7 @@ to directly access options of other subprojects.''') @permittedKwargs(permitted_kwargs['subdir']) def func_subdir(self, node, args, kwargs): self.validate_arguments(args, 1, [str]) + mesonlib.check_direntry_issues(args) if '..' in args[0]: raise InvalidArguments('Subdir contains ..') if self.subdir == '' and args[0] == self.subproject_dir: @@ -2691,7 +2766,7 @@ to directly access options of other subprojects.''') mlog.warning( "The variable(s) %s in the input file %s are not " "present in the given configuration data" % ( - var_list, inputfile)) + var_list, inputfile), location=node) else: mesonlib.dump_conf_header(ofile_abs, conf.held_object) conf.mark_used() @@ -2923,6 +2998,7 @@ different subdirectory. def source_strings_to_files(self, sources): results = [] + mesonlib.check_direntry_issues(sources) for s in sources: if isinstance(s, (mesonlib.File, GeneratedListHolder, CustomTargetHolder, CustomTargetIndexHolder)): diff --git a/mesonbuild/interpreterbase.py b/mesonbuild/interpreterbase.py index 91f4bd3..9dc6b0f 100644 --- a/mesonbuild/interpreterbase.py +++ b/mesonbuild/interpreterbase.py @@ -18,7 +18,7 @@ from . import mparser, mesonlib, mlog from . import environment, dependencies -import os, copy, re +import os, copy, re, types from functools import wraps # Decorators for method calls. @@ -63,17 +63,19 @@ class permittedKwargs: def __call__(self, f): @wraps(f) def wrapped(s, node_or_state, args, kwargs): + loc = types.SimpleNamespace() if hasattr(s, 'subdir'): - subdir = s.subdir - lineno = s.current_lineno + loc.subdir = s.subdir + loc.lineno = s.current_lineno elif hasattr(node_or_state, 'subdir'): - subdir = node_or_state.subdir - lineno = node_or_state.current_lineno + loc.subdir = node_or_state.subdir + loc.lineno = node_or_state.current_lineno + else: + loc = None for k in kwargs: if k not in self.permitted: - fname = os.path.join(subdir, environment.build_filename) - mlog.warning('''Passed invalid keyword argument "%s" in %s line %d. -This will become a hard error in the future.''' % (k, fname, lineno)) + mlog.warning('''Passed invalid keyword argument "{}"'''.format(k), location=loc) + mlog.warning('This will become a hard error in the future.') return f(s, node_or_state, args, kwargs) return wrapped diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index f10a138..4871bf7 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -19,34 +19,46 @@ import stat import time import platform, subprocess, operator, os, shutil, re import collections +from mesonbuild import mlog from glob import glob def detect_meson_py_location(): c = sys.argv[0] - c_fname = os.path.split(c)[1] - if c_fname == 'meson' or c_fname == 'meson.py': - # $ /foo/meson.py <args> - if os.path.isabs(c): - return c - # $ meson <args> (gets run from /usr/bin/meson) + c_dir, c_fname = os.path.split(c) + + # get the absolute path to the <mesontool> folder + m_dir = None + if os.path.isabs(c): + # $ /foo/<mesontool>.py <args> + m_dir = c_dir + elif c_dir == '': + # $ <mesontool> <args> (gets run from /usr/bin/<mesontool>) in_path_exe = shutil.which(c_fname) if in_path_exe: - # Special case: when run like "./meson.py <opts>" and user has - # period in PATH, we need to expand it out, because, for example, + m_dir, c_fname = os.path.split(in_path_exe) + # Special case: when run like "./meson.py <opts>", + # we need to expand it out, because, for example, # "ninja test" will be run from a different directory. - if '.' in os.environ['PATH'].split(':'): - p, f = os.path.split(in_path_exe) - if p == '' or p == '.': - return os.path.join(os.getcwd(), f) - return in_path_exe - # $ python3 ./meson.py <args> - if os.path.exists(c): - return os.path.join(os.getcwd(), c) - + if m_dir == '.': + m_dir = os.getcwd() + else: + m_dir = os.path.abspath(c_dir) + + # find meson in m_dir + if m_dir is not None: + for fname in ['meson', 'meson.py']: + m_path = os.path.join(m_dir, fname) + if os.path.exists(m_path): + return m_path + + # No meson found, which means that either: + # a) meson is not installed + # b) meson is installed to a non-standard location + # c) the script that invoked mesonlib is not the one of meson tools (e.g. run_unittests.py) # The only thing remaining is to try to find the bundled executable and # pray distro packagers have not moved it. - fname = os.path.join(os.path.dirname(__file__), '..', 'meson.py') + fname = os.path.normpath(os.path.join(os.path.dirname(__file__), '..', 'meson.py')) if not os.path.exists(fname): raise RuntimeError('Could not determine how to run Meson. Please file a bug with details.') return fname @@ -59,6 +71,34 @@ else: python_command = [sys.executable] meson_command = python_command + [detect_meson_py_location()] +def is_ascii_string(astring): + try: + if isinstance(astring, str): + astring.encode('ascii') + if isinstance(astring, bytes): + astring.decode('ascii') + except UnicodeDecodeError: + return False + return True + +def check_direntry_issues(direntry_array): + import locale + # Warn if the locale is not UTF-8. This can cause various unfixable issues + # such as os.stat not being able to decode filenames with unicode in them. + # There is no way to reset both the preferred encoding and the filesystem + # encoding, so we can just warn about it. + e = locale.getpreferredencoding() + if e.upper() != 'UTF-8' and not is_windows(): + if not isinstance(direntry_array, list): + direntry_array = [direntry_array] + for de in direntry_array: + if is_ascii_string(de): + continue + mlog.warning('''You are using {!r} which is not a Unicode-compatible ' +locale but you are trying to access a file system entry called {!r} which is +not pure ASCII. This may cause problems. +'''.format(e, de), file=sys.stderr) + # Put this in objects that should not get dumped to pickle files # by accident. import threading @@ -256,6 +296,12 @@ def is_cygwin(): def is_debianlike(): return os.path.isfile('/etc/debian_version') +def is_dragonflybsd(): + return platform.system().lower() == 'dragonfly' + +def is_freebsd(): + return platform.system().lower() == 'freebsd' + def for_windows(is_cross, env): """ Host machine is windows? @@ -280,6 +326,18 @@ def for_cygwin(is_cross, env): return env.cross_info.config['host_machine']['system'] == 'cygwin' return False +def for_linux(is_cross, env): + """ + Host machine is linux? + + Note: 'host' is the machine on which compiled binaries will run + """ + if not is_cross: + return is_linux() + elif env.cross_info.has_host(): + return env.cross_info.config['host_machine']['system'] == 'linux' + return False + def for_darwin(is_cross, env): """ Host machine is Darwin (iOS/OS X)? @@ -661,31 +719,6 @@ def Popen_safe_legacy(args, write=None, stderr=subprocess.PIPE, **kwargs): 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. - We currently use it everywhere so this receives enough testing. - ''' - # XXX: Replace me with os.path.commonpath when we start requiring Python 3.5 - import pathlib - if not paths: - raise ValueError('arg is an empty sequence') - common = pathlib.PurePath(paths[0]) - for path in paths[1:]: - new = [] - path = pathlib.PurePath(path) - for c, p in zip(common.parts, path.parts): - if c != p: - break - new.append(c) - # Don't convert '' into '.' - if not new: - common = '' - break - new = os.path.join(*new) - common = pathlib.PurePath(new) - return str(common) - def iter_regexin_iter(regexiter, initer): ''' Takes each regular expression in @regexiter and tries to search for it in @@ -852,6 +885,31 @@ def windows_proof_rmtree(f): # Try one last time and throw if it fails. shutil.rmtree(f) + +def detect_subprojects(spdir_name, current_dir='', result=None): + if result is None: + result = {} + spdir = os.path.join(current_dir, spdir_name) + if not os.path.exists(spdir): + return result + for trial in glob(os.path.join(spdir, '*')): + basename = os.path.split(trial)[1] + if trial == 'packagecache': + continue + append_this = True + if os.path.isdir(trial): + detect_subprojects(spdir_name, trial, result) + elif trial.endswith('.wrap') and os.path.isfile(trial): + basename = os.path.splitext(basename)[0] + else: + append_this = False + if append_this: + if basename in result: + result[basename].append(trial) + else: + result[basename] = [trial] + 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 f261935..e48122f 100644 --- a/mesonbuild/mesonmain.py +++ b/mesonbuild/mesonmain.py @@ -17,7 +17,7 @@ import time, datetime import os.path from . import environment, interpreter, mesonlib from . import build -from . import mconf, mintro, mtest, rewriter +from . import mconf, mintro, mtest, rewriter, minit import platform from . import mlog, coredata from .mesonlib import MesonException @@ -28,7 +28,7 @@ default_warning = '1' def add_builtin_argument(p, name, **kwargs): k = kwargs.get('dest', name.replace('-', '_')) c = coredata.get_builtin_option_choices(k) - b = True if kwargs.get('action', None) in ['store_true', 'store_false'] else False + b = kwargs.get('action', None) in ['store_true', 'store_false'] h = coredata.get_builtin_option_description(k) if not b: h = h.rstrip('.') + ' (default: %s).' % coredata.get_builtin_option_default(k) @@ -172,6 +172,7 @@ class MesonApp: elif self.options.backend == 'vs': from .backend import vs2010backend g = vs2010backend.autodetect_vs_version(b) + env.coredata.set_builtin_option('backend', g.name) mlog.log('Auto detected Visual Studio backend:', mlog.bold(g.name)) elif self.options.backend == 'vs2010': from .backend import vs2010backend @@ -278,8 +279,8 @@ def run_script_command(args): return cmdfunc(cmdargs) def run(original_args, mainfile=None): - if sys.version_info < (3, 4): - print('Meson works correctly only with python 3.4+.') + if sys.version_info < (3, 5): + print('Meson works correctly only with python 3.5+.') print('You have python %s.' % sys.version) print('Please update your environment') return 1 @@ -307,6 +308,8 @@ def run(original_args, mainfile=None): sys.exit(1) elif cmd_name == 'wrap': return wraptool.run(remaining_args) + elif cmd_name == 'init': + return minit.run(remaining_args) elif cmd_name == 'runpython': import runpy script_file = remaining_args[0] diff --git a/mesonbuild/minit.py b/mesonbuild/minit.py new file mode 100644 index 0000000..98817cb --- /dev/null +++ b/mesonbuild/minit.py @@ -0,0 +1,373 @@ +# Copyright 2017 The Meson development team +from pyclbr import Function + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# 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. + +"""Code that creates simple startup projects.""" + +import os, sys, argparse, re +from glob import glob + +lib_h_template = '''#pragma once +#if defined _WIN32 || defined __CYGWIN__ + #ifdef BUILDING_{utoken} + #define {utoken}_PUBLIC __declspec(dllexport) + #else + #define {utoken}_PUBLIC __declspec(dllimport) + #endif +#else + #ifdef BUILDING_{utoken} + #define {utoken}_PUBLIC __attribute__ ((visibility ("default"))) + #else + #define {utoken}_PUBLIC + #endif +#endif + +int {utoken}_PUBLIC {function_name}(); + +''' + +lib_c_template = '''#include <{header_file}> + +/* This function will not be exported and is not + * directly callable by users of this library. + */ +int internal_function() {{ + return 0; +}} + +int {function_name}() {{ + return internal_function(); +}} +''' + +lib_c_test_template = '''#include <{header_file}> +#include <stdio.h> + +int main(int argc, char **argv) {{ + if(argc != 1) {{ + printf("%s takes no arguments.\\n", argv[0]); + return 1; + }} + return {function_name}(); +}} +''' + +lib_c_meson_template = '''project('{project_name}', 'c', + version : '{version}', + default_options : ['warning_level=3']) + +# These arguments are only used to build the shared library +# not the executables that use the library. +lib_args = ['-DBUILDING_{utoken}'] + +# Hiding symbols that are not explicitly marked as exported +# requires a compiler flag on all compilers except VS. +cc = meson.get_compiler('c') +if cc.get_id() != 'msvc' + lib_args += ['-fvisibility=hidden'] +endif + +shlib = shared_library('{lib_name}', '{source_file}', + install : true, + c_args : lib_args, +) + +test_exe = executable('{test_exe_name}', '{test_source_file}', + link_with : shlib) +test('{test_name}', test_exe) + +# Make this library usable as a Meson subproject. +{ltoken}_dep = declare_dependency( + include_directories: include_directories('.'), + link_with : shlib) + +# Make this library usable from the system's +# package manager. +install_headers('{header_file}', subdir : '{header_dir}') + +pkg_mod = import('pkgconfig') +pkg_mod.generate( + name : '{project_name}', + filebase : '{ltoken}', + description : 'Meson sample project.', + subdirs : '{header_dir}', + libraries : shlib, + version : '{version}', +) +''' + +hello_c_template = '''#include <stdio.h> + +#define PROJECT_NAME "{project_name}" + +int main(int argc, char **argv) {{ + if(argc != 1) {{ + printf("%s takes no arguments.\\n", argv[0]); + return 1; + }} + printf("This is project %s.\\n", PROJECT_NAME); + return 0; +}} +''' + +hello_c_meson_template = '''project('{project_name}', 'c', + version : '{version}', + default_options : ['warning_level=3', + 'cpp_std=c++14']) + +exe = executable('{exe_name}', '{source_name}', + install : true) + +test('basic', exe) +''' + +hello_cpp_template = '''#include <iostream> + +#define PROJECT_NAME "{project_name}" + +int main(int argc, char **argv) {{ + if(argc != 1) {{ + std::cout << argv[0] << "takes no arguments.\\n"; + return 1; + }} + std::cout << "This is project " << PROJECT_NAME << ".\\n"; + return 0; +}} +''' + +hello_cpp_meson_template = '''project('{project_name}', 'cpp', + version : '{version}', + default_options : ['warning_level=3']) + +exe = executable('{exe_name}', '{source_name}', + install : true) + +test('basic', exe) +''' + +lib_hpp_template = '''#pragma once +#if defined _WIN32 || defined __CYGWIN__ + #ifdef BUILDING_{utoken} + #define {utoken}_PUBLIC __declspec(dllexport) + #else + #define {utoken}_PUBLIC __declspec(dllimport) + #endif +#else + #ifdef BUILDING_{utoken} + #define {utoken}_PUBLIC __attribute__ ((visibility ("default"))) + #else + #define {utoken}_PUBLIC + #endif +#endif + +namespace {namespace} {{ + +class {utoken}_PUBLIC {class_name} {{ + +public: + {class_name}(); + int get_number() const; + +private: + + int number; + +}}; + +}} + +''' + +lib_cpp_template = '''#include <{header_file}> + +namespace {namespace} {{ + +{class_name}::{class_name}() {{ + number = 6; +}} + +int {class_name}::get_number() const {{ + return number; +}} + +}} +''' + +lib_cpp_test_template = '''#include <{header_file}> +#include <iostream> + +int main(int argc, char **argv) {{ + if(argc != 1) {{ + std::cout << argv[0] << " takes no arguments.\\n"; + return 1; + }} + {namespace}::{class_name} c; + return c.get_number() != 6; +}} +''' + +lib_cpp_meson_template = '''project('{project_name}', 'cpp', + version : '{version}', + default_options : ['warning_level=3', 'cpp_std=c++14']) + +# These arguments are only used to build the shared library +# not the executables that use the library. +lib_args = ['-DBUILDING_{utoken}'] + +# Hiding symbols that are not explicitly marked as exported +# requires a compiler flag on all compilers except VS. +cpp = meson.get_compiler('cpp') +if cpp.get_id() != 'msvc' + lib_args += ['-fvisibility=hidden'] +endif + +shlib = shared_library('{lib_name}', '{source_file}', + install : true, + cpp_args : lib_args, +) + +test_exe = executable('{test_exe_name}', '{test_source_file}', + link_with : shlib) +test('{test_name}', test_exe) + +# Make this library usable as a Meson subproject. +{ltoken}_dep = declare_dependency( + include_directories: include_directories('.'), + link_with : shlib) + +# Make this library usable from the system's +# package manager. +install_headers('{header_file}', subdir : '{header_dir}') + +pkg_mod = import('pkgconfig') +pkg_mod.generate( + name : '{project_name}', + filebase : '{ltoken}', + description : 'Meson sample project.', + subdirs : '{header_dir}', + libraries : shlib, + version : '{version}', +) +''' + +info_message = '''Sample project created. To build it run the +following commands: + +meson builddir +ninja -C builddir +''' + +def create_exe_c_sample(project_name, project_version): + lowercase_token = re.sub(r'[^a-z0-9]', '_', project_name.lower()) + uppercase_token = lowercase_token.upper() + source_name = lowercase_token + '.c' + open(source_name, 'w').write(hello_c_template.format(project_name=project_name)) + open('meson.build', 'w').write(hello_c_meson_template.format(project_name=project_name, + exe_name=lowercase_token, + source_name=source_name, + version=project_version)) + +def create_lib_c_sample(project_name, version): + lowercase_token = re.sub(r'[^a-z0-9]', '_', project_name.lower()) + uppercase_token = lowercase_token.upper() + function_name = lowercase_token[0:3] + '_func' + lib_h_name = lowercase_token + '.h' + lib_c_name = lowercase_token + '.c' + test_c_name = lowercase_token + '_test.c' + kwargs = {'utoken': uppercase_token, + 'ltoken': lowercase_token, + 'header_dir': lowercase_token, + 'function_name': function_name, + 'header_file': lib_h_name, + 'source_file': lib_c_name, + 'test_source_file': test_c_name, + 'test_exe_name': lowercase_token, + 'project_name': project_name, + 'lib_name': lowercase_token, + 'test_name': lowercase_token, + 'version': version, + } + open(lib_h_name, 'w').write(lib_h_template.format(**kwargs)) + open(lib_c_name, 'w').write(lib_c_template.format(**kwargs)) + open(test_c_name, 'w').write(lib_c_test_template.format(**kwargs)) + open('meson.build', 'w').write(lib_c_meson_template.format(**kwargs)) + +def create_exe_cpp_sample(project_name, project_version): + lowercase_token = re.sub(r'[^a-z0-9]', '_', project_name.lower()) + uppercase_token = lowercase_token.upper() + source_name = lowercase_token + '.cpp' + open(source_name, 'w').write(hello_cpp_template.format(project_name=project_name)) + open('meson.build', 'w').write(hello_cpp_meson_template.format(project_name=project_name, + exe_name=lowercase_token, + source_name=source_name, + version=project_version)) + +def create_lib_cpp_sample(project_name, version): + lowercase_token = re.sub(r'[^a-z0-9]', '_', project_name.lower()) + uppercase_token = lowercase_token.upper() + class_name = uppercase_token[0] + lowercase_token[1:] + namespace = lowercase_token + lib_h_name = lowercase_token + '.hpp' + lib_c_name = lowercase_token + '.cpp' + test_c_name = lowercase_token + '_test.cpp' + kwargs = {'utoken': uppercase_token, + 'ltoken': lowercase_token, + 'header_dir': lowercase_token, + 'class_name': class_name, + 'namespace': namespace, + 'header_file': lib_h_name, + 'source_file': lib_c_name, + 'test_source_file': test_c_name, + 'test_exe_name': lowercase_token, + 'project_name': project_name, + 'lib_name': lowercase_token, + 'test_name': lowercase_token, + 'version': version, + } + open(lib_h_name, 'w').write(lib_hpp_template.format(**kwargs)) + open(lib_c_name, 'w').write(lib_cpp_template.format(**kwargs)) + open(test_c_name, 'w').write(lib_cpp_test_template.format(**kwargs)) + open('meson.build', 'w').write(lib_cpp_meson_template.format(**kwargs)) + +def create_sample(options): + if options.language == 'c': + if options.type == 'executable': + create_exe_c_sample(options.name, options.version) + elif options.type == 'library': + create_lib_c_sample(options.name, options.version) + else: + raise RuntimeError('Unreachable code') + elif options.language == 'cpp': + if options.type == 'executable': + create_exe_cpp_sample(options.name, options.version) + elif options.type == 'library': + create_lib_cpp_sample(options.name, options.version) + else: + raise RuntimeError('Unreachable code') + else: + raise RuntimeError('Unreachable code') + print(info_message) + +def run(args): + parser = argparse.ArgumentParser(prog='meson') + parser.add_argument('--name', default = 'mesonsample') + parser.add_argument('--type', default='executable', + choices=['executable', 'library']) + parser.add_argument('--language', default='c', choices=['c', 'cpp']) + parser.add_argument('--version', default='1.0') + options = parser.parse_args(args) + if len(glob('*')) != 0: + sys.exit('This command must be run in an empty directory.') + create_sample(options) + return 0 diff --git a/mesonbuild/mlog.py b/mesonbuild/mlog.py index a0d07ec..aa2ac20 100644 --- a/mesonbuild/mlog.py +++ b/mesonbuild/mlog.py @@ -103,6 +103,13 @@ def log(*args, **kwargs): force_print(*arr, **kwargs) def warning(*args, **kwargs): + from . import environment + + if kwargs.get('location'): + location = kwargs['location'] + del kwargs['location'] + args += ('in file {}, line {}.'.format(os.path.join(location.subdir, environment.build_filename), location.lineno),) + log(yellow('WARNING:'), *args, **kwargs) # Format a list for logging purposes as a string. It separates diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index 56765a5..ad99c14 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -626,7 +626,7 @@ class GnomeModule(ExtensionModule): rv = [scan_target, typelib_target] return ModuleReturnValue(rv, rv) - @permittedKwargs({'build_by_default'}) + @permittedKwargs({'build_by_default', 'depend_files'}) def compile_schemas(self, state, args, kwargs): if args: raise MesonException('Compile_schemas does not take positional arguments.') @@ -776,12 +776,39 @@ This will become a hard error in the future.''') args += self._unpack_args('--fixxrefargs=', 'fixxref_args', kwargs) args += self._unpack_args('--mkdbargs=', 'mkdb_args', kwargs) args += self._unpack_args('--html-assets=', 'html_assets', kwargs, state) - args += self._unpack_args('--content-files=', 'content_files', kwargs, state) + + depends = [] + content_files = [] + for s in mesonlib.extract_as_list(kwargs, 'content_files'): + if hasattr(s, 'held_object'): + s = s.held_object + if isinstance(s, (build.CustomTarget, build.CustomTargetIndex)): + depends.append(s) + content_files.append(os.path.join(state.environment.get_build_dir(), + state.backend.get_target_dir(s), + s.get_outputs()[0])) + elif isinstance(s, mesonlib.File): + content_files.append(s.rel_to_builddir(state.build_to_src)) + elif isinstance(s, build.GeneratedList): + depends.append(s) + for gen_src in s.get_outputs(): + content_files.append(os.path.join(state.environment.get_source_dir(), + state.subdir, + gen_src)) + elif isinstance(s, str): + content_files.append(os.path.join(state.environment.get_source_dir(), + state.subdir, + s)) + else: + raise MesonException( + 'Invalid object type: {!r}'.format(s.__class__.__name__)) + args += ['--content-files=' + '@@'.join(content_files)] + args += self._unpack_args('--expand-content-files=', 'expand_content_files', kwargs, state) 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, state.subproject)] + res = [build.RunTarget(targetname, command[0], command[1:] + args, depends, state.subdir, state.subproject)] if kwargs.get('install', True): res.append(build.RunScript(command, args)) return ModuleReturnValue(None, res) diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index f963323..54c2126 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -16,12 +16,87 @@ import os from pathlib import PurePath from .. import build +from .. import dependencies from .. import mesonlib from .. import mlog from . import ModuleReturnValue from . import ExtensionModule from ..interpreterbase import permittedKwargs +class DependenciesHelper: + def __init__(self, name): + self.name = name + self.pub_libs = [] + self.pub_reqs = [] + self.priv_libs = [] + self.priv_reqs = [] + self.cflags = [] + + def add_pub_libs(self, libs): + libs, reqs, cflags = self._process_libs(libs, True) + self.pub_libs += libs + self.pub_reqs += reqs + self.cflags += cflags + + def add_priv_libs(self, libs): + libs, reqs, _ = self._process_libs(libs, False) + self.priv_libs += libs + self.priv_reqs += reqs + + def add_pub_reqs(self, reqs): + self.pub_reqs += mesonlib.stringlistify(reqs) + + def add_priv_reqs(self, reqs): + self.priv_reqs += mesonlib.stringlistify(reqs) + + def add_cflags(self, cflags): + self.cflags += mesonlib.stringlistify(cflags) + + def _process_libs(self, libs, public): + libs = mesonlib.listify(libs) + processed_libs = [] + processed_reqs = [] + processed_cflags = [] + for obj in libs: + if hasattr(obj, 'held_object'): + obj = obj.held_object + if hasattr(obj, 'pcdep'): + pcdeps = mesonlib.listify(obj.pcdep) + processed_reqs += [i.name for i in pcdeps] + elif hasattr(obj, 'generated_pc'): + processed_reqs.append(obj.generated_pc) + elif isinstance(obj, dependencies.PkgConfigDependency): + processed_reqs.append(obj.name) + elif isinstance(obj, dependencies.ThreadDependency): + processed_libs += obj.get_compiler().thread_link_flags(obj.env) + processed_cflags += obj.get_compiler().thread_flags(obj.env) + elif isinstance(obj, dependencies.Dependency): + processed_libs += obj.get_link_args() + processed_cflags += obj.get_compile_args() + elif isinstance(obj, (build.SharedLibrary, build.StaticLibrary)): + processed_libs.append(obj) + if public: + if not hasattr(obj, 'generated_pc'): + obj.generated_pc = self.name + self.add_priv_libs(obj.get_dependencies()) + self.add_priv_libs(obj.get_external_deps()) + elif isinstance(obj, str): + processed_libs.append(obj) + else: + raise mesonlib.MesonException('library argument not a string, library or dependency object.') + + return processed_libs, processed_reqs, processed_cflags + + def remove_dups(self): + self.pub_libs = list(set(self.pub_libs)) + self.pub_reqs = list(set(self.pub_reqs)) + self.priv_libs = list(set(self.priv_libs)) + self.priv_reqs = list(set(self.priv_reqs)) + self.cflags = list(set(self.cflags)) + + # Remove from pivate libs/reqs if they are in public already + self.priv_libs = [i for i in self.priv_libs if i not in self.pub_libs] + self.priv_reqs = [i for i in self.priv_reqs if i not in self.pub_reqs] class PkgConfigModule(ExtensionModule): @@ -64,9 +139,9 @@ class PkgConfigModule(ExtensionModule): subdir = subdir.replace(prefix, '') return subdir - def generate_pkgconfig_file(self, state, libraries, subdirs, name, description, - url, version, pcfile, pub_reqs, priv_reqs, - conflicts, priv_libs, extra_cflags, variables): + def generate_pkgconfig_file(self, state, deps, subdirs, name, description, + url, version, pcfile, conflicts, variables): + deps.remove_dups() coredata = state.environment.get_coredata() outdir = state.environment.scratch_dir fname = os.path.join(outdir, pcfile) @@ -78,6 +153,8 @@ class PkgConfigModule(ExtensionModule): ofile.write('prefix={}\n'.format(self._escape(prefix))) ofile.write('libdir={}\n'.format(self._escape('${prefix}' / libdir))) ofile.write('includedir={}\n'.format(self._escape('${prefix}' / incdir))) + if variables: + ofile.write('\n') for k, v in variables: ofile.write('{}={}\n'.format(k, self._escape(v))) ofile.write('\n') @@ -87,11 +164,11 @@ class PkgConfigModule(ExtensionModule): if len(url) > 0: ofile.write('URL: %s\n' % url) ofile.write('Version: %s\n' % version) - if len(pub_reqs) > 0: - ofile.write('Requires: {}\n'.format(' '.join(pub_reqs))) - if len(priv_reqs) > 0: + if len(deps.pub_reqs) > 0: + ofile.write('Requires: {}\n'.format(' '.join(deps.pub_reqs))) + if len(deps.priv_reqs) > 0: ofile.write( - 'Requires.private: {}\n'.format(' '.join(priv_reqs))) + 'Requires.private: {}\n'.format(' '.join(deps.priv_reqs))) if len(conflicts) > 0: ofile.write('Conflicts: {}\n'.format(' '.join(conflicts))) @@ -99,6 +176,7 @@ class PkgConfigModule(ExtensionModule): msg = 'Library target {0!r} has {1!r} set. Compilers ' \ 'may not find it from its \'-l{2}\' linker flag in the ' \ '{3!r} pkg-config file.' + Lflags = [] for l in libs: if isinstance(l, str): yield l @@ -107,9 +185,12 @@ class PkgConfigModule(ExtensionModule): if install_dir is False: continue if isinstance(install_dir, str): - yield '-L${prefix}/%s ' % self._escape(self._make_relative(prefix, install_dir)) + Lflag = '-L${prefix}/%s ' % self._escape(self._make_relative(prefix, install_dir)) else: # install_dir is True - yield '-L${libdir}' + Lflag = '-L${libdir}' + if Lflag not in Lflags: + Lflags.append(Lflag) + yield Lflag lname = self._get_lname(l, msg, pcfile) # If using a custom suffix, the compiler may not be able to # find the library @@ -117,10 +198,10 @@ class PkgConfigModule(ExtensionModule): mlog.warning(msg.format(l.name, 'name_suffix', lname, pcfile)) yield '-l%s' % lname - if len(libraries) > 0: - ofile.write('Libs: {}\n'.format(' '.join(generate_libs_flags(libraries)))) - if len(priv_libs) > 0: - ofile.write('Libs.private: {}\n'.format(' '.join(generate_libs_flags(priv_libs)))) + if len(deps.pub_libs) > 0: + ofile.write('Libs: {}\n'.format(' '.join(generate_libs_flags(deps.pub_libs)))) + if len(deps.priv_libs) > 0: + ofile.write('Libs.private: {}\n'.format(' '.join(generate_libs_flags(deps.priv_libs)))) ofile.write('Cflags:') for h in subdirs: ofile.write(' ') @@ -128,30 +209,18 @@ class PkgConfigModule(ExtensionModule): ofile.write('-I${includedir}') else: ofile.write(self._escape(PurePath('-I${includedir}') / h)) - for f in extra_cflags: + for f in deps.cflags: ofile.write(' ') ofile.write(self._escape(f)) ofile.write('\n') - def process_libs(self, libs): - libs = mesonlib.listify(libs) - processed_libs = [] - for l in libs: - if hasattr(l, 'held_object'): - l = l.held_object - if not isinstance(l, (build.SharedLibrary, build.StaticLibrary, str)): - raise mesonlib.MesonException('Library argument not a library object nor a string.') - processed_libs.append(l) - return processed_libs - @permittedKwargs({'libraries', 'version', 'name', 'description', 'filebase', 'subdirs', 'requires', 'requires_private', 'libraries_private', '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.') - libs = self.process_libs(kwargs.get('libraries', [])) - priv_libs = self.process_libs(kwargs.get('libraries_private', [])) + subdirs = mesonlib.stringlistify(kwargs.get('subdirs', ['.'])) version = kwargs.get('version', None) if not isinstance(version, str): @@ -168,16 +237,20 @@ class PkgConfigModule(ExtensionModule): url = kwargs.get('url', '') if not isinstance(url, str): raise mesonlib.MesonException('URL is not a string.') - pub_reqs = mesonlib.stringlistify(kwargs.get('requires', [])) - priv_reqs = mesonlib.stringlistify(kwargs.get('requires_private', [])) conflicts = mesonlib.stringlistify(kwargs.get('conflicts', [])) - extra_cflags = mesonlib.stringlistify(kwargs.get('extra_cflags', [])) + + deps = DependenciesHelper(filebase) + deps.add_pub_libs(kwargs.get('libraries', [])) + deps.add_priv_libs(kwargs.get('libraries_private', [])) + deps.add_pub_reqs(kwargs.get('requires', [])) + deps.add_priv_reqs(kwargs.get('requires_private', [])) + deps.add_cflags(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})) + deps.add_cflags(compiler.get_feature_args({'versions': dversions})) def parse_variable_list(stringlist): reserved = ['prefix', 'libdir', 'includedir'] @@ -211,9 +284,8 @@ class PkgConfigModule(ExtensionModule): pkgroot = os.path.join(state.environment.coredata.get_builtin_option('libdir'), 'pkgconfig') if not isinstance(pkgroot, str): raise mesonlib.MesonException('Install_dir must be a string.') - self.generate_pkgconfig_file(state, libs, subdirs, name, description, url, - version, pcfile, pub_reqs, priv_reqs, - conflicts, priv_libs, extra_cflags, variables) + self.generate_pkgconfig_file(state, deps, subdirs, name, description, url, + version, pcfile, conflicts, variables) res = build.Data(mesonlib.File(True, state.environment.get_scratch_dir(), pcfile), pkgroot) return ModuleReturnValue(res, [res]) diff --git a/mesonbuild/mparser.py b/mesonbuild/mparser.py index 0465d24..eb03393 100644 --- a/mesonbuild/mparser.py +++ b/mesonbuild/mparser.py @@ -368,7 +368,8 @@ class ArgumentNode: def set_kwarg(self, name, value): if name in self.kwargs: - mlog.warning('Keyword argument "%s" defined multiple times. This will be a an error in future Meson releases.' % name) + mlog.warning('Keyword argument "{}" defined multiple times'.format(name), location=self) + mlog.warning('This will be an error in future Meson releases.') self.kwargs[name] = value def num_args(self): diff --git a/mesonbuild/optinterpreter.py b/mesonbuild/optinterpreter.py index f8ccbe6..df945ab 100644 --- a/mesonbuild/optinterpreter.py +++ b/mesonbuild/optinterpreter.py @@ -15,6 +15,7 @@ import os, re import functools +from . import mlog from . import mparser from . import coredata from . import mesonlib @@ -146,6 +147,14 @@ class OptionInterpreter: e.colno = cur.colno e.file = os.path.join('meson_options.txt') raise e + bad = [o for o in sorted(self.cmd_line_options) if not + (o in list(self.options) + forbidden_option_names or + any(o.startswith(p) for p in forbidden_prefixes))] + if bad: + sub = 'In subproject {}: '.format(self.subproject) if self.subproject else '' + mlog.warning( + '{}Unknown command line options: "{}"\n' + 'This will become a hard error in a future Meson release.'.format(sub, ', '.join(bad))) def reduce_single(self, arg): if isinstance(arg, str): diff --git a/mesonbuild/scripts/coverage.py b/mesonbuild/scripts/coverage.py index d596622..25451d4 100644 --- a/mesonbuild/scripts/coverage.py +++ b/mesonbuild/scripts/coverage.py @@ -59,6 +59,7 @@ def coverage(source_root, build_root, log_dir): remove_dir_from_trace(lcov_exe, covinfo, '/usr/include/*') remove_dir_from_trace(lcov_exe, covinfo, '/usr/local/include/*') remove_dir_from_trace(lcov_exe, covinfo, '/usr/src/*') + remove_dir_from_trace(lcov_exe, covinfo, '/usr/lib/llvm-*/include/*') subprocess.check_call([genhtml_exe, '--prefix', build_root, '--output-directory', htmloutdir, diff --git a/mesonbuild/scripts/scanbuild.py b/mesonbuild/scripts/scanbuild.py index 728214f..f381552 100644 --- a/mesonbuild/scripts/scanbuild.py +++ b/mesonbuild/scripts/scanbuild.py @@ -17,6 +17,7 @@ import subprocess import shutil import tempfile from ..environment import detect_ninja +from ..mesonlib import Popen_safe def scanbuild(exename, srcdir, blddir, privdir, logdir, args): with tempfile.TemporaryDirectory(dir=privdir) as scandir: @@ -34,7 +35,30 @@ def run(args): privdir = os.path.join(blddir, 'meson-private') logdir = os.path.join(blddir, 'meson-logs/scanbuild') shutil.rmtree(logdir, ignore_errors=True) - exename = os.environ.get('SCANBUILD', 'scan-build') + tools = [ + 'scan-build', # base + 'scan-build-5.0', 'scan-build50', # latest stable release + 'scan-build-4.0', 'scan-build40', # old stable releases + 'scan-build-3.9', 'scan-build39', + 'scan-build-3.8', 'scan-build38', + 'scan-build-3.7', 'scan-build37', + 'scan-build-3.6', 'scan-build36', + 'scan-build-3.5', 'scan-build35', + 'scan-build-6.0', 'scan-build-devel', # development snapshot + ] + toolname = 'scan-build' + for tool in tools: + try: + p, out = Popen_safe([tool, '--help'])[:2] + except (FileNotFoundError, PermissionError): + continue + if p.returncode != 0: + continue + else: + toolname = tool + break + + exename = os.environ.get('SCANBUILD', toolname) if not shutil.which(exename): print('Scan-build not installed.') return 1 diff --git a/mesonbuild/wrap/wraptool.py b/mesonbuild/wrap/wraptool.py index 79b00e0..0bdc417 100644 --- a/mesonbuild/wrap/wraptool.py +++ b/mesonbuild/wrap/wraptool.py @@ -21,6 +21,8 @@ from glob import glob from .wrap import API_ROOT, open_wrapdburl +from .. import mesonlib + help_templ = '''This program allows you to manage your Wrap dependencies using the online wrap database http://wrapdb.mesonbuild.com. @@ -38,6 +40,7 @@ Commands: update - update the project to its newest available release info - show available versions of a project status - show installed and available versions of your projects + promote - bring a subsubproject up to the master project ''' @@ -142,6 +145,36 @@ def info(name): for v in versions: print(' ', v['branch'], v['revision']) +def do_promotion(from_path, spdir_name): + if os.path.isfile(from_path): + assert(from_path.endswith('.wrap')) + shutil.copy(from_path, spdir_name) + elif os.path.isdir(from_path): + sproj_name = os.path.split(from_path)[1] + outputdir = os.path.join(spdir_name, sproj_name) + if os.path.exists(outputdir): + sys.exit('Output dir %s already exists. Will not overwrite.' % outputdir) + shutil.copytree(from_path, outputdir, ignore=shutil.ignore_patterns('subprojects')) + +def promote(argument): + path_segment, subproject_name = os.path.split(argument) + spdir_name = 'subprojects' + sprojs = mesonlib.detect_subprojects(spdir_name) + if subproject_name not in sprojs: + sys.exit('Subproject %s not found in directory tree.' % subproject_name) + matches = sprojs[subproject_name] + if len(matches) == 1: + do_promotion(matches[0], spdir_name) + return + if path_segment == '': + print('There are many versions of %s in tree. Please specify which one to promote:\n' % subproject_name) + for s in matches: + print(s) + sys.exit(1) + system_native_path_argument = argument.replace('/', os.sep) + if system_native_path_argument in matches: + do_promotion(argument, spdir_name) + def status(): print('Subproject status') for w in glob('subprojects/*.wrap'): @@ -189,6 +222,11 @@ def run(args): print('info requires exactly one argument.') return 1 info(args[0]) + elif command == 'promote': + if len(args) != 1: + print('promote requires exactly one argument.') + return 1 + promote(args[0]) elif command == 'status': status() else: diff --git a/run_project_tests.py b/run_project_tests.py index b94a976..d191e28 100755 --- a/run_project_tests.py +++ b/run_project_tests.py @@ -185,6 +185,7 @@ def get_relative_files_list_from_dir(fromdir): def platform_fix_name(fname, compiler): if '?lib' in fname: if mesonlib.is_cygwin(): + fname = re.sub(r'lib/\?lib(.*)\.so$', r'bin/cyg\1.dll', fname) fname = re.sub(r'\?lib(.*)\.dll$', r'cyg\1.dll', fname) else: fname = re.sub(r'\?lib', 'lib', fname) @@ -312,10 +313,19 @@ def parse_test_args(testdir): pass return args +# Build directory name must be the same so CCache works over +# consecutive invocations. +def create_deterministic_builddir(src_dir): + import hashlib + rel_dirname = 'b ' + hashlib.sha256(src_dir.encode(errors='ignore')).hexdigest()[0:10] + os.mkdir(rel_dirname) + abs_pathname = os.path.join(os.getcwd(), rel_dirname) + return abs_pathname + def run_test(skipped, testdir, extra_args, compiler, backend, flags, commands, should_fail): if skipped: return None - with AutoDeletedDir(tempfile.mkdtemp(prefix='b ', dir='.')) as build_dir: + with AutoDeletedDir(create_deterministic_builddir(testdir)) as build_dir: with AutoDeletedDir(tempfile.mkdtemp(prefix='i ', dir=os.getcwd())) as install_dir: try: return _run_test(testdir, build_dir, install_dir, extra_args, compiler, backend, flags, commands, should_fail) @@ -438,20 +448,28 @@ def have_objc_compiler(): env = environment.Environment(None, build_dir, None, get_fake_options('/'), []) try: objc_comp = env.detect_objc_compiler(False) - except: + except mesonlib.MesonException: return False if not objc_comp: return False try: objc_comp.sanity_check(env.get_scratch_dir(), env) - objcpp_comp = env.detect_objc_compiler(False) - except: + except mesonlib.MesonException: + return False + return True + +def have_objcpp_compiler(): + with AutoDeletedDir(tempfile.mkdtemp(prefix='b ', dir='.')) as build_dir: + env = environment.Environment(None, build_dir, None, get_fake_options('/'), []) + try: + objcpp_comp = env.detect_objcpp_compiler(False) + except mesonlib.MesonException: return False if not objcpp_comp: return False try: objcpp_comp.sanity_check(env.get_scratch_dir(), env) - except: + except mesonlib.MesonException: return False return True @@ -478,6 +496,7 @@ def detect_tests_to_run(): ('rust', 'rust', backend is not Backend.ninja or not shutil.which('rustc')), ('d', 'd', backend is not Backend.ninja or not have_d_compiler()), ('objective c', 'objc', backend not in (Backend.ninja, Backend.xcode) or mesonlib.is_windows() or not have_objc_compiler()), + ('objective c++', 'objcpp', backend not in (Backend.ninja, Backend.xcode) or mesonlib.is_windows() or not have_objcpp_compiler()), ('fortran', 'fortran', backend is not Backend.ninja or not shutil.which('gfortran')), ('swift', 'swift', backend not in (Backend.ninja, Backend.xcode) or not shutil.which('swiftc')), ('python3', 'python3', backend is not Backend.ninja), @@ -486,8 +505,13 @@ def detect_tests_to_run(): if mesonlib.is_windows(): # TODO: Set BOOST_ROOT in .appveyor.yml gathered_tests += [('framework', ['test cases/frameworks/1 boost'], 'BOOST_ROOT' not in os.environ)] - elif mesonlib.is_osx() or mesonlib.is_cygwin(): - gathered_tests += [('framework', gather_tests('test cases/frameworks'), True)] + elif mesonlib.is_osx(): + if os.path.exists('/usr/local/include/boost'): + # Just do the BOOST test + gathered_tests += [('framework', ['test cases/frameworks/1 boost'], False)] + elif mesonlib.is_cygwin(): + # Just do the BOOST test + gathered_tests += [('framework', ['test cases/frameworks/1 boost'], False)] else: gathered_tests += [('framework', gather_tests('test cases/frameworks'), False)] return gathered_tests diff --git a/run_unittests.py b/run_unittests.py index f717e6d..f61544f 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -34,10 +34,12 @@ 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.mesonlib import python_command, meson_command, version_compare -from mesonbuild.environment import Environment -from mesonbuild.dependencies import DependencyException +from mesonbuild.mesonlib import ( + is_linux, is_windows, is_osx, is_cygwin, is_dragonflybsd, + windows_proof_rmtree, python_command, meson_command, version_compare, +) +from mesonbuild.environment import Environment, detect_ninja +from mesonbuild.mesonlib import MesonException, EnvironmentException from mesonbuild.dependencies import PkgConfigDependency, ExternalProgram from run_tests import exe_suffix, get_fake_options @@ -191,26 +193,6 @@ class InternalTests(unittest.TestCase): l.append_direct('-lbar') self.assertEqual(l, ['-Lfoodir', '-lfoo', '-Lbardir', '-lbar', '-lbar']) - def test_commonpath(self): - from os.path import sep - commonpath = mesonbuild.mesonlib.commonpath - self.assertRaises(ValueError, commonpath, []) - self.assertEqual(commonpath(['/usr', '/usr']), sep + 'usr') - self.assertEqual(commonpath(['/usr', '/usr/']), sep + 'usr') - self.assertEqual(commonpath(['/usr', '/usr/bin']), sep + 'usr') - self.assertEqual(commonpath(['/usr/', '/usr/bin']), sep + 'usr') - self.assertEqual(commonpath(['/usr/./', '/usr/bin']), sep + 'usr') - self.assertEqual(commonpath(['/usr/bin', '/usr/bin']), sep + 'usr' + sep + 'bin') - self.assertEqual(commonpath(['/usr//bin', '/usr/bin']), sep + 'usr' + sep + 'bin') - self.assertEqual(commonpath(['/usr/./bin', '/usr/bin']), sep + 'usr' + sep + 'bin') - self.assertEqual(commonpath(['/usr/local', '/usr/lib']), sep + 'usr') - self.assertEqual(commonpath(['/usr', '/bin']), sep) - self.assertEqual(commonpath(['/usr', 'bin']), '') - self.assertEqual(commonpath(['blam', 'bin']), '') - prefix = '/some/path/to/prefix' - libdir = '/some/path/to/prefix/libdir' - self.assertEqual(commonpath([prefix, libdir]), str(PurePath(prefix))) - def test_string_templates_substitution(self): dictfunc = mesonbuild.mesonlib.get_filenames_templates_dict substfunc = mesonbuild.mesonlib.substitute_values @@ -468,6 +450,7 @@ class BasePlatformTests(unittest.TestCase): self.mconf_command = meson_command + ['configure'] self.mintro_command = meson_command + ['introspect'] self.mtest_command = meson_command + ['test', '-C', self.builddir] + self.wrap_command = meson_command + ['wrap'] # Backend-specific build commands self.build_command, self.clean_command, self.test_command, self.install_command, \ self.uninstall_command = get_backend_commands(self.backend) @@ -789,6 +772,45 @@ class AllPlatformTests(BasePlatformTests): self.assertEqual(value, expected[prefix][name]) self.wipe() + def test_default_options_prefix_dependent_defaults(self): + ''' + Tests that setting a prefix in default_options in project() sets prefix + dependent defaults for other options, and that those defaults can + be overridden in default_options or by the command line. + ''' + testdir = os.path.join(self.common_test_dir, '173 default options prefix dependent defaults') + expected = { + '': + {'prefix': '/usr', + 'sysconfdir': '/etc', + 'localstatedir': '/var', + 'sharedstatedir': '/sharedstate'}, + '--prefix=/usr': + {'prefix': '/usr', + 'sysconfdir': '/etc', + 'localstatedir': '/var', + 'sharedstatedir': '/sharedstate'}, + '--sharedstatedir=/var/state': + {'prefix': '/usr', + 'sysconfdir': '/etc', + 'localstatedir': '/var', + 'sharedstatedir': '/var/state'}, + '--sharedstatedir=/var/state --prefix=/usr --sysconfdir=sysconf': + {'prefix': '/usr', + 'sysconfdir': 'sysconf', + 'localstatedir': '/var', + 'sharedstatedir': '/var/state'}, + } + for args in expected: + self.init(testdir, args.split(), default_args=False) + opts = self.introspect('--buildoptions') + for opt in opts: + name = opt['name'] + value = opt['value'] + if name in expected[args]: + self.assertEqual(value, expected[args][name]) + self.wipe() + def test_static_library_overwrite(self): ''' Tests that static libraries are never appended to, always overwritten. @@ -1366,12 +1388,24 @@ int main(int argc, char **argv) { for each in ('prog', 'subdir/liblib1.so', ): rpath = get_rpath(os.path.join(self.builddir, each)) self.assertTrue(rpath) - for path in rpath.split(':'): + if is_dragonflybsd(): + # DragonflyBSD will prepend /usr/lib/gccVERSION to the rpath, + # so ignore that. + self.assertTrue(rpath.startswith('/usr/lib/gcc')) + rpaths = rpath.split(':')[1:] + else: + rpaths = rpath.split(':') + for path in rpaths: self.assertTrue(path.startswith('$ORIGIN'), msg=(each, path)) # These two don't link to anything else, so they do not need an rpath entry. for each in ('subdir/subdir2/liblib2.so', 'subdir/subdir3/liblib3.so'): rpath = get_rpath(os.path.join(self.builddir, each)) - self.assertTrue(rpath is None) + if is_dragonflybsd(): + # The rpath should be equal to /usr/lib/gccVERSION + self.assertTrue(rpath.startswith('/usr/lib/gcc')) + self.assertEqual(len(rpath.split(':')), 1) + else: + self.assertTrue(rpath is None) def test_dash_d_dedup(self): testdir = os.path.join(self.unit_test_dir, '10 d dedup') @@ -1643,6 +1677,58 @@ int main(int argc, char **argv) { self.setconf("-Dfree_array_opt=['a,b', 'c,d']", will_build=False) self.opt_has('free_array_opt', ['a,b', 'c,d']) + def test_subproject_promotion(self): + testdir = os.path.join(self.unit_test_dir, '13 promote') + workdir = os.path.join(self.builddir, 'work') + shutil.copytree(testdir, workdir) + spdir = os.path.join(workdir, 'subprojects') + s3dir = os.path.join(spdir, 's3') + scommondir = os.path.join(spdir, 'scommon') + self.assertFalse(os.path.isdir(s3dir)) + subprocess.check_call(self.wrap_command + ['promote', 's3'], cwd=workdir) + self.assertTrue(os.path.isdir(s3dir)) + self.assertFalse(os.path.isdir(scommondir)) + self.assertNotEqual(subprocess.call(self.wrap_command + ['promote', 'scommon'], + cwd=workdir, + stdout=subprocess.DEVNULL), 0) + self.assertFalse(os.path.isdir(scommondir)) + subprocess.check_call(self.wrap_command + ['promote', 'subprojects/s2/subprojects/scommon'], cwd=workdir) + self.assertTrue(os.path.isdir(scommondir)) + promoted_wrap = os.path.join(spdir, 'athing.wrap') + self.assertFalse(os.path.isfile(promoted_wrap)) + subprocess.check_call(self.wrap_command + ['promote', 'athing'], cwd=workdir) + self.assertTrue(os.path.isfile(promoted_wrap)) + self.init(workdir) + self.build() + + def test_warning_location(self): + tdir = os.path.join(self.unit_test_dir, '20 warning location') + out = self.init(tdir) + for expected in [ + r'WARNING: Keyword argument "link_with" defined multiple times in file meson.build, line 4', + r'WARNING: Keyword argument "link_with" defined multiple times in file sub' + os.path.sep + r'meson.build, line 3', + r'WARNING: a warning of some sort in file meson.build, line 6', + r'WARNING: subdir warning in file sub' + os.path.sep + r'meson.build, line 4', + r'WARNING: Module unstable-simd has no backwards or forwards compatibility and might not exist in future releases in file meson.build, line 7', + r"WARNING: The variable(s) 'MISSING' in the input file conf.in are not present in the given configuration data in file meson.build, line 10", + r'WARNING: Passed invalid keyword argument "invalid" in file meson.build, line 1' + ]: + self.assertRegex(out, re.escape(expected)) + + def test_templates(self): + ninja = detect_ninja() + if ninja is None: + raise unittest.SkipTest('This test currently requires ninja. Fix this once "meson build" works.') + for lang in ('c', 'cpp'): + for type in ('executable', 'library'): + with tempfile.TemporaryDirectory() as tmpdir: + self._run(meson_command + ['init', '--language', lang, '--type', type], + workdir=tmpdir) + self._run(self.meson_command + ['--backend=ninja', 'builddir'], + workdir=tmpdir) + self._run(ninja, + workdir=os.path.join(tmpdir, 'builddir')) + class FailureTests(BasePlatformTests): ''' @@ -1680,7 +1766,7 @@ class FailureTests(BasePlatformTests): f.write(contents) # Force tracebacks so we can detect them properly os.environ['MESON_FORCE_BACKTRACE'] = '1' - with self.assertRaisesRegex(DependencyException, match, msg=contents): + with self.assertRaisesRegex(MesonException, match, msg=contents): # Must run in-process or we'll get a generic CalledProcessError self.init(self.srcdir, extra_args=extra_args, inprocess=True) @@ -1741,7 +1827,7 @@ class FailureTests(BasePlatformTests): raise unittest.SkipTest('wx-config or wx-config-3.0 found') self.assertMesonRaises("dependency('wxwidgets')", self.dnf) self.assertMesonOutputs("dependency('wxwidgets', required : false)", - "No wx-config found;") + "Dependency .*WxWidgets.* found: .*NO.*") def test_wx_dependency(self): if not shutil.which('wx-config-3.0') and not shutil.which('wx-config'): @@ -1782,6 +1868,63 @@ class FailureTests(BasePlatformTests): ''' self.assertMesonRaises(code, "Method.*configtool.*is invalid.*internal") + def test_bad_option(self): + tdir = os.path.join(self.unit_test_dir, '19 bad command line options') + os.environ['MESON_FORCE_BACKTRACE'] = '1' + self.init(tdir, extra_args=['-Dopt=bar', '-Dc_args=-Wall'], inprocess=True) + self.wipe() + out = self.init(tdir, extra_args=['-Dfoo=bar', '-Dbad=true'], inprocess=True) + self.assertRegex( + out, r'Unknown command line options: "bad, foo"') + + def test_bad_option_subproject(self): + tdir = os.path.join(self.unit_test_dir, '19 bad command line options') + os.environ['MESON_FORCE_BACKTRACE'] = '1' + self.init(tdir, extra_args=['-Done:one=bar'], inprocess=True) + self.wipe() + out = self.init(tdir, extra_args=['-Done:two=bar'], inprocess=True) + self.assertRegex( + out, + r'In subproject one: Unknown command line options: "one:two"') + + def test_objc_cpp_detection(self): + ''' + Test that when we can't detect objc or objcpp, we fail gracefully. + ''' + env = Environment('', self.builddir, self.meson_command, + get_fake_options(self.prefix), []) + try: + objc = env.detect_objc_compiler(False) + objcpp = env.detect_objcpp_compiler(False) + except EnvironmentException: + code = "add_languages('objc')\nadd_languages('objcpp')" + self.assertMesonRaises(code, "Unknown compiler") + return + raise unittest.SkipTest("objc and objcpp found, can't test detection failure") + + def test_subproject_variables(self): + ''' + Test that: + 1. The correct message is outputted when a not-required dep is not + found and the fallback subproject is also not found. + 2. A not-found not-required dep with a fallback subproject outputs the + correct message when the fallback subproject is found but the + variable inside it is not. + 3. A fallback dependency is found from the subproject parsed in (2) + 4. A not-required fallback dependency is not found because the + subproject failed to parse. + ''' + tdir = os.path.join(self.unit_test_dir, '20 subproj dep variables') + out = self.init(tdir, inprocess=True) + self.assertRegex(out, r"Also couldn't find a fallback subproject " + "in.*subprojects.*nosubproj.*for the dependency.*somedep") + self.assertRegex(out, r'Dependency.*somenotfounddep.*from subproject.*' + 'subprojects.*somesubproj.*found:.*NO') + self.assertRegex(out, r'Dependency.*zlibproxy.*from subproject.*' + 'subprojects.*somesubproj.*found:.*YES.*(cached)') + self.assertRegex(out, r'Also couldn\'t find a fallback subproject in ' + '.*subprojects.*failingsubproj.*for the dependency.*somedep') + class WindowsTests(BasePlatformTests): ''' @@ -1912,6 +2055,36 @@ class LinuxlikeTests(BasePlatformTests): self.assertEqual(foo_dep.get_pkgconfig_variable('foo', {}), 'bar') self.assertPathEqual(foo_dep.get_pkgconfig_variable('datadir', {}), '/usr/data') + def test_pkgconfig_gen_deps(self): + ''' + Test that generated pkg-config files correctly handle dependencies + ''' + + testdir = os.path.join(self.common_test_dir, '51 pkgconfig-gen') + self.init(testdir) + + os.environ['PKG_CONFIG_LIBDIR'] = self.privatedir + cmd = ['pkg-config', 'dependency-test'] + + out = self._run(cmd + ['--print-requires']).strip().split() + self.assertEqual(sorted(out), sorted(['libexposed'])) + + out = self._run(cmd + ['--print-requires-private']).strip().split() + self.assertEqual(sorted(out), sorted(['libfoo'])) + + out = self._run(cmd + ['--cflags-only-other']).strip().split() + self.assertEqual(sorted(out), sorted(['-pthread', '-DCUSTOM'])) + + out = self._run(cmd + ['--libs-only-l', '--libs-only-other']).strip().split() + self.assertEqual(sorted(out), sorted(['-pthread', '-lcustom', + '-llibmain', '-llibexposed'])) + + out = self._run(cmd + ['--libs-only-l', '--libs-only-other', '--static']).strip().split() + self.assertEqual(sorted(out), sorted(['-pthread', '-lcustom', + '-llibmain', '-llibexposed', + '-llibinternal', '-lcustom2', + '-lfoo'])) + def test_vala_c_warnings(self): ''' Test that no warnings are emitted for C code generated by Vala. This @@ -2269,11 +2442,18 @@ class LinuxlikeTests(BasePlatformTests): testdir = os.path.join(self.unit_test_dir, '11 build_rpath') self.init(testdir) self.build() + # C program RPATH build_rpath = get_rpath(os.path.join(self.builddir, 'prog')) self.assertEqual(build_rpath, '$ORIGIN/sub:/foo/bar') self.install() install_rpath = get_rpath(os.path.join(self.installdir, 'usr/bin/prog')) self.assertEqual(install_rpath, '/baz') + # C++ program RPATH + build_rpath = get_rpath(os.path.join(self.builddir, 'progcxx')) + self.assertEqual(build_rpath, '$ORIGIN/sub:/foo/bar') + self.install() + install_rpath = get_rpath(os.path.join(self.installdir, 'usr/bin/progcxx')) + self.assertEqual(install_rpath, 'baz') def test_pch_with_address_sanitizer(self): testdir = os.path.join(self.common_test_dir, '13 pch') diff --git a/test cases/common/125 shared module/meson.build b/test cases/common/125 shared module/meson.build index 29277e9..08a284d 100644 --- a/test cases/common/125 shared module/meson.build +++ b/test cases/common/125 shared module/meson.build @@ -8,6 +8,6 @@ l = shared_library('runtime', 'runtime.c') # at runtime. This requires extra help on Windows, so # should be avoided unless really necessary. m = shared_module('mymodule', 'module.c') -e = executable('prog', 'prog.c', link_with : l, dependencies : dl) +e = executable('prog', 'prog.c', + link_with : l, export_dynamic : true, dependencies : dl) test('import test', e, args : m) - diff --git a/test cases/common/135 generated assembly/square-arm.S.in b/test cases/common/135 generated assembly/square-arm.S.in index 168c980..d2fb7ac 100644 --- a/test cases/common/135 generated assembly/square-arm.S.in +++ b/test cases/common/135 generated assembly/square-arm.S.in @@ -2,8 +2,8 @@ .text .globl SYMBOL_NAME(square_unsigned) -/* Only supported on Linux with GAS */ -# ifdef __linux__ +/* Only supported with GAS */ +# if defined(__linux__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) .type square_unsigned,%function #endif diff --git a/test cases/common/135 generated assembly/square-x86.S.in b/test cases/common/135 generated assembly/square-x86.S.in index 19dd9f5..ee77b81 100644 --- a/test cases/common/135 generated assembly/square-x86.S.in +++ b/test cases/common/135 generated assembly/square-x86.S.in @@ -21,8 +21,8 @@ END .text .globl SYMBOL_NAME(square_unsigned) -/* Only supported on Linux with GAS */ -# ifdef __linux__ +/* Only supported with GAS */ +# if defined(__linux__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) .type square_unsigned,@function # endif diff --git a/test cases/common/135 generated assembly/square-x86_64.S.in b/test cases/common/135 generated assembly/square-x86_64.S.in index 0834f16..856af13 100644 --- a/test cases/common/135 generated assembly/square-x86_64.S.in +++ b/test cases/common/135 generated assembly/square-x86_64.S.in @@ -18,8 +18,8 @@ END .text .globl SYMBOL_NAME(square_unsigned) -/* Only supported on Linux with GAS */ -# ifdef __linux__ +/* Only supported with GAS */ +# if defined(__linux__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) .type square_unsigned,@function # endif diff --git a/test cases/common/140 get define/meson.build b/test cases/common/140 get define/meson.build index e23b7de..fd87177 100644 --- a/test cases/common/140 get define/meson.build +++ b/test cases/common/140 get define/meson.build @@ -19,6 +19,19 @@ foreach lang : ['c', 'cpp'] elif host_system == 'haiku' d = cc.get_define('__HAIKU__') assert(d == '1', '__HAIKU__ value is @0@ instead of 1'.format(d)) + elif host_system == 'freebsd' + # the __FreeBSD__ define will be equal to the major version of the release + # (ex, in FreeBSD 11.x, __FreeBSD__ == 11). To make the test robust when + # being run on various versions of FreeBSD, just test that the define is + # set. + d = cc.get_define('__FreeBSD__') + assert(d != '', '__FreeBSD__ value is unset') + elif host_system == 'dragonfly' + d = cc.get_define('__DragonFly__') + assert(d == '1', '__DragonFly__ value is @0@ instead of 1'.format(d)) + elif host_system == 'netbsd' + d = cc.get_define('__NetBSD__') + assert(d == '1', '__NetBSD__ value is @0@ instead of 1'.format(d)) else error('Please report a bug and help us improve support for this platform') endif @@ -28,8 +41,16 @@ foreach lang : ['c', 'cpp'] # found in the compiler's default search path, GCC inserts an extra comment # between the delimiter and the define which causes a parsing error. # https://github.com/mesonbuild/meson/issues/1726 - ver = cc.get_define('ZLIB_VER_MAJOR', prefix : '#include <zlib.h>') - assert(ver == '1', 'ZLIB_VER_MAJOR value is "@0@" instead of "1"'.format(ver)) + if host_machine.system() == 'netbsd' + # NetBSD's zlib doesn't is version 1.2.3 and doesn't have a + # ZLIB_VER_MAJOR, but it does have a ZLIB_VERSION (which is a string), so + # check the first non-quote character of that. + ver = cc.get_define('ZLIB_VERSION', prefix : '#include <zlib.h>')[1] + assert(ver == '1', 'ZLIB_VERSION (major) value is "@0@" instead of "1"'.format(ver)) + else + ver = cc.get_define('ZLIB_VER_MAJOR', prefix : '#include <zlib.h>') + assert(ver == '1', 'ZLIB_VER_MAJOR value is "@0@" instead of "1"'.format(ver)) + endif endif # Check that an undefined value is empty. diff --git a/test cases/common/156 shared module resolving symbol in executable/meson.build b/test cases/common/156 shared module resolving symbol in executable/meson.build index 34a75f1..282a4d2 100644 --- a/test cases/common/156 shared module resolving symbol in executable/meson.build +++ b/test cases/common/156 shared module resolving symbol in executable/meson.build @@ -9,13 +9,7 @@ project('shared module resolving symbol in executable', 'c') # See testcase 125 for an example of the more complex portability gymnastics # required if we do not know (at link-time) what provides the symbol. -link_flags = [] -if host_machine.system() != 'windows' - # Needed to export dynamic symbols from the executable - link_flags += ['-rdynamic'] -endif - dl = meson.get_compiler('c').find_library('dl', required: false) -e = executable('prog', 'prog.c', dependencies: dl, implib: true, link_args: link_flags) +e = executable('prog', 'prog.c', dependencies: dl, export_dynamic: true) m = shared_module('module', 'module.c', link_with: e) test('test', e, args: m.full_path()) diff --git a/test cases/common/171 not-found dependency/meson.build b/test cases/common/171 not-found dependency/meson.build index 7d92f5a..85505ee 100644 --- a/test cases/common/171 not-found dependency/meson.build +++ b/test cases/common/171 not-found dependency/meson.build @@ -1,4 +1,4 @@ -project('dep-test') +project('dep-test', 'c') dep = dependency('', required:false) if dep.found() @@ -6,3 +6,6 @@ if dep.found() endif assert(dep.type_name() == 'not-found', 'dependency should be of type "not-found" not ' + dep.type_name()) + +library('testlib', 'testlib.c', dependencies: [dep]) +subdir('sub', if_found: dep) diff --git a/test cases/common/171 not-found dependency/sub/meson.build b/test cases/common/171 not-found dependency/sub/meson.build new file mode 100644 index 0000000..2a33cae --- /dev/null +++ b/test cases/common/171 not-found dependency/sub/meson.build @@ -0,0 +1 @@ +error('should be disabled by subdir(if_found:)') diff --git a/test cases/common/171 not-found dependency/testlib.c b/test cases/common/171 not-found dependency/testlib.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test cases/common/171 not-found dependency/testlib.c diff --git a/test cases/common/173 default options prefix dependent defaults/meson.build b/test cases/common/173 default options prefix dependent defaults/meson.build new file mode 100644 index 0000000..9ca4ec5 --- /dev/null +++ b/test cases/common/173 default options prefix dependent defaults/meson.build @@ -0,0 +1 @@ +project('default options prefix dependent defaults ', 'c', default_options : ['sharedstatedir=/sharedstate', 'prefix=/usr']) diff --git a/test cases/common/51 pkgconfig-gen/meson.build b/test cases/common/51 pkgconfig-gen/meson.build index 68ee812..a8dd092 100644 --- a/test cases/common/51 pkgconfig-gen/meson.build +++ b/test cases/common/51 pkgconfig-gen/meson.build @@ -1,5 +1,17 @@ project('pkgconfig-gen', 'c') +# First check we have pkg-config >= 0.29 + +pkgconfig = find_program('pkg-config', required: false) +if not pkgconfig.found() + error('MESON_SKIP_TEST: pkg-config not found') +endif + +v = run_command(pkgconfig, '--version').stdout().strip() +if v.version_compare('<0.29') + error('MESON_SKIP_TEST: pkg-config version \'' + v + '\' too old') +endif + pkgg = import('pkgconfig') lib = shared_library('simple', 'simple.c') @@ -18,19 +30,9 @@ pkgg.generate( libraries_private : [lib, '-lz'], ) -pkgconfig = find_program('pkg-config', required: false) -if pkgconfig.found() - v = run_command(pkgconfig, '--version').stdout().strip() - if v.version_compare('>=0.29') - test('pkgconfig-validation', pkgconfig, - args: ['--validate', 'simple'], - env: ['PKG_CONFIG_PATH=' + meson.current_build_dir() + '/meson-private' ]) - else - message('pkg-config version \'' + v + '\' too old, skipping validate test') - endif -else - message('pkg-config not found, skipping validate test') -endif +test('pkgconfig-validation', pkgconfig, + args: ['--validate', 'simple'], + env: [ 'PKG_CONFIG_PATH=' + meson.current_build_dir() + '/meson-private' ]) # Test that name_prefix='' and name='libfoo' results in '-lfoo' lib2 = shared_library('libfoo', 'simple.c', @@ -44,3 +46,36 @@ pkgg.generate( description : 'A foo library.', variables : ['foo=bar', 'datadir=${prefix}/data'] ) + +# libmain internally use libinternal and expose libexpose in its API +exposed_lib = shared_library('libexposed', 'simple.c') +internal_lib = shared_library('libinternal', 'simple.c') +main_lib = shared_library('libmain', link_with : [exposed_lib, internal_lib]) + +pkgg.generate(libraries : exposed_lib, + version : libver, + name : 'libexposed', + description : 'An exposed library in dependency test.' +) + +# Declare a few different Dependency objects +pc_dep = dependency('libfoo', required : false) +threads_dep = dependency('threads', required : false) +custom_dep = declare_dependency(link_args : ['-lcustom'], compile_args : ['-DCUSTOM']) +custom2_dep = declare_dependency(link_args : ['-lcustom2'], compile_args : ['-DCUSTOM2']) + +# Generate a PC file: +# - Having libmain in libraries should pull implicitely libexposed and libinternal in Libs.private +# - Having libexposed in libraries should remove it from Libs.private +# - We generated a pc file for libexposed so it should be in Requires instead of Libs +# - Having threads_dep in libraries should add '-pthread' in both Libs and Cflags +# - Having custom_dep in libraries and libraries_private should only add it in Libs +# - Having custom2_dep in libraries_private should not add its Cflags +# - Having pc_dep in libraries_private should add it in Requires.private +pkgg.generate(libraries : [main_lib, exposed_lib, threads_dep , custom_dep], + libraries_private : [custom_dep, custom2_dep, pc_dep], + version : libver, + name : 'dependency-test', + filebase : 'dependency-test', + description : 'A dependency test.' +) diff --git a/test cases/failing/68 subproj different versions/main.c b/test cases/failing/68 subproj different versions/main.c new file mode 100644 index 0000000..8793c62 --- /dev/null +++ b/test cases/failing/68 subproj different versions/main.c @@ -0,0 +1,9 @@ +#include <stdio.h> +#include "a.h" +#include "b.h" + +int main(int argc, char **argv) { + int life = a_fun() + b_fun(); + printf("%d\n", life); + return 0; +} diff --git a/test cases/failing/68 subproj different versions/meson.build b/test cases/failing/68 subproj different versions/meson.build new file mode 100644 index 0000000..7690277 --- /dev/null +++ b/test cases/failing/68 subproj different versions/meson.build @@ -0,0 +1,9 @@ +project('super', 'c') + +# A will use version 1 of C +a_dep = dependency('a', fallback: ['a', 'a_dep']) + +# B will fail becuase it requests version 2 of C +b_dep = dependency('b', fallback: ['b', 'b_dep']) + +main = executable('main', files('main.c'), dependencies: [a_dep, b_dep]) diff --git a/test cases/failing/68 subproj different versions/subprojects/a/a.c b/test cases/failing/68 subproj different versions/subprojects/a/a.c new file mode 100644 index 0000000..cd41a65 --- /dev/null +++ b/test cases/failing/68 subproj different versions/subprojects/a/a.c @@ -0,0 +1,5 @@ +#include "c.h" + +int a_fun() { + return c_fun(); +} diff --git a/test cases/failing/68 subproj different versions/subprojects/a/a.h b/test cases/failing/68 subproj different versions/subprojects/a/a.h new file mode 100644 index 0000000..8f1d49e --- /dev/null +++ b/test cases/failing/68 subproj different versions/subprojects/a/a.h @@ -0,0 +1 @@ +int a_fun(); diff --git a/test cases/failing/68 subproj different versions/subprojects/a/meson.build b/test cases/failing/68 subproj different versions/subprojects/a/meson.build new file mode 100644 index 0000000..e84182a --- /dev/null +++ b/test cases/failing/68 subproj different versions/subprojects/a/meson.build @@ -0,0 +1,11 @@ +project('a', 'c') + +c_dep = dependency('c', version:'1', fallback: ['c', 'c_dep']) + +alib = library('a', 'a.c', + dependencies: c_dep) + +a_dep = declare_dependency( + link_with: alib, + include_directories: include_directories('.'), +) diff --git a/test cases/failing/68 subproj different versions/subprojects/b/b.c b/test cases/failing/68 subproj different versions/subprojects/b/b.c new file mode 100644 index 0000000..f85f8c3 --- /dev/null +++ b/test cases/failing/68 subproj different versions/subprojects/b/b.c @@ -0,0 +1,5 @@ +#include "c.h" + +int b_fun(){ +return c_fun(); +} diff --git a/test cases/failing/68 subproj different versions/subprojects/b/b.h b/test cases/failing/68 subproj different versions/subprojects/b/b.h new file mode 100644 index 0000000..eced786 --- /dev/null +++ b/test cases/failing/68 subproj different versions/subprojects/b/b.h @@ -0,0 +1 @@ +int b_fun(); diff --git a/test cases/failing/68 subproj different versions/subprojects/b/meson.build b/test cases/failing/68 subproj different versions/subprojects/b/meson.build new file mode 100644 index 0000000..0398340 --- /dev/null +++ b/test cases/failing/68 subproj different versions/subprojects/b/meson.build @@ -0,0 +1,11 @@ +project('b', 'c') + +c_dep = dependency('c', version:'2', fallback: ['c', 'c_dep']) + +blib = library('b', 'b.c', + dependencies: c_dep) + +b_dep = declare_dependency( + link_with: blib, + include_directories: include_directories('.'), +) diff --git a/test cases/failing/68 subproj different versions/subprojects/c/c.h b/test cases/failing/68 subproj different versions/subprojects/c/c.h new file mode 100644 index 0000000..2b15f60 --- /dev/null +++ b/test cases/failing/68 subproj different versions/subprojects/c/c.h @@ -0,0 +1,3 @@ +static int c_fun(){ + return 3; +} diff --git a/test cases/failing/68 subproj different versions/subprojects/c/meson.build b/test cases/failing/68 subproj different versions/subprojects/c/meson.build new file mode 100644 index 0000000..7184933 --- /dev/null +++ b/test cases/failing/68 subproj different versions/subprojects/c/meson.build @@ -0,0 +1,5 @@ +project('c', 'c', version:'1') + +c_dep = declare_dependency( + include_directories: include_directories('.') +) diff --git a/test cases/failing/69 wrong boost module/meson.build b/test cases/failing/69 wrong boost module/meson.build new file mode 100644 index 0000000..7fb3a40 --- /dev/null +++ b/test cases/failing/69 wrong boost module/meson.build @@ -0,0 +1,5 @@ +project('boosttest', 'cpp', + default_options : ['cpp_std=c++11']) + +# abc doesn't exist +linkdep = dependency('boost', modules : ['thread', 'system', 'test', 'abc']) diff --git a/test cases/frameworks/1 boost/extralib.cpp b/test cases/frameworks/1 boost/extralib.cpp index 6a3e9e4..e5ab1b0 100644 --- a/test cases/frameworks/1 boost/extralib.cpp +++ b/test cases/frameworks/1 boost/extralib.cpp @@ -1,3 +1,5 @@ +#define _XOPEN_SOURCE 500 + #include <iostream> #include <boost/log/trivial.hpp> #include <boost/log/expressions.hpp> diff --git a/test cases/frameworks/1 boost/meson.build b/test cases/frameworks/1 boost/meson.build index b73f93a..771ecbc 100644 --- a/test cases/frameworks/1 boost/meson.build +++ b/test cases/frameworks/1 boost/meson.build @@ -9,7 +9,7 @@ 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. -linkdep = dependency('boost', modules : ['thread', 'system']) +linkdep = dependency('boost', modules : ['thread', 'system', 'test']) staticdep = dependency('boost', modules : ['thread', 'system'], static : true) testdep = dependency('boost', modules : ['unit_test_framework']) nomoddep = dependency('boost') diff --git a/test cases/frameworks/10 gtk-doc/doc/foobar-docs.sgml b/test cases/frameworks/10 gtk-doc/doc/foobar-docs.sgml index 028b808..3894317 100644 --- a/test cases/frameworks/10 gtk-doc/doc/foobar-docs.sgml +++ b/test cases/frameworks/10 gtk-doc/doc/foobar-docs.sgml @@ -34,6 +34,7 @@ </para> </partintro> <xi:include href="xml/foo.xml"/> + <xi:include href="../include/bar.xml"/> <xi:include href="xml/foo-version.xml"/> </reference> diff --git a/test cases/frameworks/10 gtk-doc/doc/meson.build b/test cases/frameworks/10 gtk-doc/doc/meson.build index 5f08e89..7aeb98d 100644 --- a/test cases/frameworks/10 gtk-doc/doc/meson.build +++ b/test cases/frameworks/10 gtk-doc/doc/meson.build @@ -4,4 +4,8 @@ configure_file(input : 'version.xml.in', output : 'version.xml', configuration : cdata) -gnome.gtkdoc('foobar', src_dir : inc, main_sgml : 'foobar-docs.sgml', install : true) +gnome.gtkdoc('foobar', + src_dir : inc, + main_sgml : 'foobar-docs.sgml', + content_files : docbook, + install : true) diff --git a/test cases/frameworks/10 gtk-doc/include/generate-enums-docbook.py b/test cases/frameworks/10 gtk-doc/include/generate-enums-docbook.py new file mode 100644 index 0000000..41c6121 --- /dev/null +++ b/test cases/frameworks/10 gtk-doc/include/generate-enums-docbook.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 + +import sys + +DOC_HEADER = '''<?xml version='1.0'?> +<?xml-stylesheet type="text/xsl" href="http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl"?> +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> + +<refentry id="{0}"> + <refmeta> + <refentrytitle role="top_of_page" id="{0}.top_of_page">{0}</refentrytitle> + <refmiscinfo>{0}</refmiscinfo> + </refmeta> + <refnamediv> + <refname>{0}</refname> + <refpurpose></refpurpose> + </refnamediv> + + <refsect2 id="{1}" role="enum"> + <title>enum {1}</title> + <indexterm zone="{1}"> + <primary>{1}</primary> + </indexterm> + <para><link linkend="{1}">{1}</link></para> + <refsect3 role="enum_members"> + <title>Values</title> + <informaltable role="enum_members_table" pgwide="1" frame="none"> + <tgroup cols="4"> + <colspec colname="enum_members_name" colwidth="300px" /> + <colspec colname="enum_members_value" colwidth="100px"/> + <colspec colname="enum_members_description" /> + <tbody> +''' + +DOC_ENUM = ''' <row role="constant"> + <entry role="enum_member_name"><para>{0}</para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>{1}</literal></para><para></para></entry> + <entry role="enum_member_description"></entry> + </row>''' + +DOC_FOOTER = ''' + </tbody> + </tgroup> + </informaltable> + </refsect3> + </refsect2> +</refentry> +''' + +if __name__ == '__main__': + if len(sys.argv) >= 4: + with open(sys.argv[1], 'w') as doc_out: + enum_name = sys.argv[2] + enum_type = sys.argv[3] + + doc_out.write(DOC_HEADER.format(enum_name, enum_type)) + for i, enum in enumerate(sys.argv[4:]): + doc_out.write(DOC_ENUM.format(enum, i)) + doc_out.write(DOC_FOOTER) + else: + print('Use: ' + sys.argv[0] + ' out name type [enums]') + + sys.exit(0) diff --git a/test cases/frameworks/10 gtk-doc/include/meson.build b/test cases/frameworks/10 gtk-doc/include/meson.build index 4c85b80..f6dd99f 100644 --- a/test cases/frameworks/10 gtk-doc/include/meson.build +++ b/test cases/frameworks/10 gtk-doc/include/meson.build @@ -8,3 +8,9 @@ configure_file(input : 'foo-version.h.in', configuration : cdata, install : true, install_dir : get_option('includedir')) + +generate_enums_docbook = find_program('generate-enums-docbook.py') + +docbook = custom_target('enum-docbook', + output : 'bar.xml', + command : [generate_enums_docbook, '@OUTPUT@', 'BAR', 'BAR_TYPE', 'BAR_FOO']) diff --git a/test cases/frameworks/11 gir subproject/gir/meson.build b/test cases/frameworks/11 gir subproject/gir/meson.build index 48e0a47..fe40dc6 100644 --- a/test cases/frameworks/11 gir subproject/gir/meson.build +++ b/test cases/frameworks/11 gir subproject/gir/meson.build @@ -31,6 +31,9 @@ message('TEST: ' + girsubproject.outdir()) envdata = environment() envdata.append('GI_TYPELIB_PATH', girsubproject.outdir(), 'subprojects/mesongir', separator : ':') envdata.append('LD_LIBRARY_PATH', girsubproject.outdir(), 'subprojects/mesongir') +if ['windows', 'cygwin'].contains(host_machine.system()) + envdata.append('PATH', girsubproject.outdir(), 'subprojects/mesongir') +endif test('gobject introspection/subproject/c', girexe) test('gobject introspection/subproject/py', find_program('prog.py'), diff --git a/test cases/frameworks/11 gir subproject/installed_files.txt b/test cases/frameworks/11 gir subproject/installed_files.txt index 434481e..87d49a1 100644 --- a/test cases/frameworks/11 gir subproject/installed_files.txt +++ b/test cases/frameworks/11 gir subproject/installed_files.txt @@ -2,5 +2,5 @@ usr/lib/girepository-1.0/Meson-1.0.typelib usr/lib/girepository-1.0/MesonSub-1.0.typelib usr/share/gir-1.0/Meson-1.0.gir usr/share/gir-1.0/MesonSub-1.0.gir -usr/lib/libgirsubproject.so -usr/lib/libgirlib.so +usr/lib/?libgirsubproject.so +usr/lib/?libgirlib.so diff --git a/test cases/frameworks/12 multiple gir/installed_files.txt b/test cases/frameworks/12 multiple gir/installed_files.txt index 9fb51bf..a5d16bc 100644 --- a/test cases/frameworks/12 multiple gir/installed_files.txt +++ b/test cases/frameworks/12 multiple gir/installed_files.txt @@ -1,6 +1,6 @@ usr/lib/girepository-1.0/Meson-1.0.typelib usr/lib/girepository-1.0/MesonSub-1.0.typelib -usr/lib/libgirlib.so -usr/lib/libgirsubproject.so +usr/lib/?libgirlib.so +usr/lib/?libgirsubproject.so usr/share/gir-1.0/Meson-1.0.gir usr/share/gir-1.0/MesonSub-1.0.gir diff --git a/test cases/frameworks/15 llvm/meson.build b/test cases/frameworks/15 llvm/meson.build index 5211006..549adce 100644 --- a/test cases/frameworks/15 llvm/meson.build +++ b/test cases/frameworks/15 llvm/meson.build @@ -20,17 +20,19 @@ foreach static : [true, false] 'llvm', modules : ['bitwriter', 'asmprinter', 'executionengine', 'target', 'mcjit', 'nativecodegen'], - required : true, + required : false, 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), - ] - ) + if llvm_dep.found() + 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), + ] + ) + endif endforeach diff --git a/test cases/frameworks/17 mpi/meson.build b/test cases/frameworks/17 mpi/meson.build index 17acd71..01ad61d 100644 --- a/test cases/frameworks/17 mpi/meson.build +++ b/test cases/frameworks/17 mpi/meson.build @@ -6,7 +6,10 @@ if build_machine.system() == 'windows' and cc.get_id() != 'msvc' error('MESON_SKIP_TEST: MPI not available on Windows without MSVC.') endif -mpic = dependency('mpi', language : 'c') +mpic = dependency('mpi', language : 'c', required : false) +if not mpic.found() + error('MESON_SKIP_TEST: MPI not found, skipping.') +endif exec = executable('exec', 'main.c', dependencies : [mpic]) diff --git a/test cases/frameworks/18 vulkan/meson.build b/test cases/frameworks/18 vulkan/meson.build index 54f1d47..e98854e 100644 --- a/test cases/frameworks/18 vulkan/meson.build +++ b/test cases/frameworks/18 vulkan/meson.build @@ -1,6 +1,9 @@ project('vulkan test', 'c') -vulkan_dep = dependency('vulkan') +vulkan_dep = dependency('vulkan', required : false) +if not vulkan_dep.found() + error('MESON_SKIP_TEST: vulkan not found.') +endif e = executable('vulkanprog', 'vulkanprog.c', dependencies : vulkan_dep) diff --git a/test cases/frameworks/2 gtest/meson.build b/test cases/frameworks/2 gtest/meson.build index 419f451..e5418e9 100644 --- a/test cases/frameworks/2 gtest/meson.build +++ b/test cases/frameworks/2 gtest/meson.build @@ -1,6 +1,9 @@ project('gtest', 'cpp') -gtest = dependency('gtest', main : true) +gtest = dependency('gtest', main : true, required : false) +if not gtest.found() + error('MESON_SKIP_TEST: gtest not installed.') +endif gtest_nomain = dependency('gtest', main : false) e = executable('testprog', 'test.cc', dependencies : gtest) diff --git a/test cases/frameworks/21 libwmf/meson.build b/test cases/frameworks/21 libwmf/meson.build index b39d8f4..1fdce2e 100644 --- a/test cases/frameworks/21 libwmf/meson.build +++ b/test cases/frameworks/21 libwmf/meson.build @@ -1,5 +1,10 @@ project('libwmf test', 'c') +wm = find_program('libwmf-config', required : false) +if not wm.found() + error('MESON_SKIP_TEST: libwmf-config not installed') +endif + libwmf_dep = dependency('libwmf', version : '>= 0.2.8') libwmf_ver = libwmf_dep.version() assert(libwmf_ver.split('.').length() > 1, 'libwmf version is "@0@"'.format(libwmf_ver)) diff --git a/test cases/frameworks/3 gmock/meson.build b/test cases/frameworks/3 gmock/meson.build index 341f9d7..516547f 100644 --- a/test cases/frameworks/3 gmock/meson.build +++ b/test cases/frameworks/3 gmock/meson.build @@ -3,8 +3,14 @@ project('gmock test', 'cpp') # Using gmock without gtest is a pain so just # don't support that then. -gtest = dependency('gtest', main : true) -gmock = dependency('gmock') +gtest = dependency('gtest', main : true, required : false) +if not gtest.found() + error('MESON_SKIP_TEST: gtest not installed.') +endif +gmock = dependency('gmock', required : false) +if not gmock.found() + error('MESON_SKIP_TEST: gmock not installed.') +endif e = executable('gmocktest', 'gmocktest.cc', dependencies : [gtest, gmock]) test('gmock test', e) diff --git a/test cases/frameworks/7 gnome/gir/meson.build b/test cases/frameworks/7 gnome/gir/meson.build index a91cb97..1771548 100644 --- a/test cases/frameworks/7 gnome/gir/meson.build +++ b/test cases/frameworks/7 gnome/gir/meson.build @@ -41,5 +41,8 @@ gir_paths = ':'.join([girlib.outdir(), dep1lib.outdir(), dep2lib.outdir()]) envdata = environment() envdata.append('GI_TYPELIB_PATH', gir_paths, separator : ':') envdata.append('LD_LIBRARY_PATH', gir_paths) +if ['windows', 'cygwin'].contains(host_machine.system()) + envdata.append('PATH', gir_paths) +endif test('gobject introspection/py', find_program('prog.py'), env : envdata) diff --git a/test cases/frameworks/7 gnome/installed_files.txt b/test cases/frameworks/7 gnome/installed_files.txt index d0d51d5..c7c704f 100644 --- a/test cases/frameworks/7 gnome/installed_files.txt +++ b/test cases/frameworks/7 gnome/installed_files.txt @@ -2,9 +2,9 @@ usr/include/enums.h usr/include/enums2.h usr/include/enums3.h usr/include/marshaller.h -usr/lib/libgir_lib.so -usr/lib/libdep1lib.so -usr/lib/libdep2lib.so +usr/lib/?libgir_lib.so +usr/lib/?libdep1lib.so +usr/lib/?libdep2lib.so usr/lib/girepository-1.0/Meson-1.0.typelib usr/lib/girepository-1.0/MesonDep1-1.0.typelib usr/lib/girepository-1.0/MesonDep2-1.0.typelib diff --git a/test cases/linuxlike/12 subprojects in subprojects/main.c b/test cases/linuxlike/12 subprojects in subprojects/main.c new file mode 100644 index 0000000..8793c62 --- /dev/null +++ b/test cases/linuxlike/12 subprojects in subprojects/main.c @@ -0,0 +1,9 @@ +#include <stdio.h> +#include "a.h" +#include "b.h" + +int main(int argc, char **argv) { + int life = a_fun() + b_fun(); + printf("%d\n", life); + return 0; +} diff --git a/test cases/linuxlike/12 subprojects in subprojects/meson.build b/test cases/linuxlike/12 subprojects in subprojects/meson.build new file mode 100644 index 0000000..4014149 --- /dev/null +++ b/test cases/linuxlike/12 subprojects in subprojects/meson.build @@ -0,0 +1,9 @@ +project('super', 'c') + +# A will use version 1 of C +a_dep = dependency('a', fallback: ['a', 'a_dep']) + +# B has an optional dependency on C version 2 and will therefore work +b_dep = dependency('b', fallback: ['b', 'b_dep']) + +main = executable('main', files('main.c'), dependencies: [a_dep, b_dep]) diff --git a/test cases/linuxlike/12 subprojects in subprojects/subprojects/a/a.c b/test cases/linuxlike/12 subprojects in subprojects/subprojects/a/a.c new file mode 100644 index 0000000..cd41a65 --- /dev/null +++ b/test cases/linuxlike/12 subprojects in subprojects/subprojects/a/a.c @@ -0,0 +1,5 @@ +#include "c.h" + +int a_fun() { + return c_fun(); +} diff --git a/test cases/linuxlike/12 subprojects in subprojects/subprojects/a/a.h b/test cases/linuxlike/12 subprojects in subprojects/subprojects/a/a.h new file mode 100644 index 0000000..8f1d49e --- /dev/null +++ b/test cases/linuxlike/12 subprojects in subprojects/subprojects/a/a.h @@ -0,0 +1 @@ +int a_fun(); diff --git a/test cases/linuxlike/12 subprojects in subprojects/subprojects/a/meson.build b/test cases/linuxlike/12 subprojects in subprojects/subprojects/a/meson.build new file mode 100644 index 0000000..5f579a3 --- /dev/null +++ b/test cases/linuxlike/12 subprojects in subprojects/subprojects/a/meson.build @@ -0,0 +1,11 @@ +project('a', 'c', version:'1.0') + +c_dep = dependency('c', version:'1', fallback: ['c', 'c_dep']) + +alib = library('a', 'a.c', + dependencies: c_dep) + +a_dep = declare_dependency( + link_with: alib, + include_directories: include_directories('.'), +) diff --git a/test cases/linuxlike/12 subprojects in subprojects/subprojects/b/b.c b/test cases/linuxlike/12 subprojects in subprojects/subprojects/b/b.c new file mode 100644 index 0000000..4824285 --- /dev/null +++ b/test cases/linuxlike/12 subprojects in subprojects/subprojects/b/b.c @@ -0,0 +1,11 @@ +#if defined(WITH_C) +#include "c.h" +#endif + +int b_fun(){ +#if defined(WITH_C) +return c_fun(); +#else +return 0; +#endif +} diff --git a/test cases/linuxlike/12 subprojects in subprojects/subprojects/b/b.h b/test cases/linuxlike/12 subprojects in subprojects/subprojects/b/b.h new file mode 100644 index 0000000..eced786 --- /dev/null +++ b/test cases/linuxlike/12 subprojects in subprojects/subprojects/b/b.h @@ -0,0 +1 @@ +int b_fun(); diff --git a/test cases/linuxlike/12 subprojects in subprojects/subprojects/b/meson.build b/test cases/linuxlike/12 subprojects in subprojects/subprojects/b/meson.build new file mode 100644 index 0000000..80903f3 --- /dev/null +++ b/test cases/linuxlike/12 subprojects in subprojects/subprojects/b/meson.build @@ -0,0 +1,17 @@ +project('b', 'c') + +c_dep = dependency('c', version:'2', fallback: ['c', 'c_dep'], required: false) + +assert(c_dep.found() == false, 'C project has the wrong version and should not be found') + +if c_dep.found() + add_global_arguments('-DWITH_C', language: 'c') +endif + +blib = library('b', 'b.c', + dependencies: c_dep) + +b_dep = declare_dependency( + link_with: blib, + include_directories: include_directories('.'), +) diff --git a/test cases/linuxlike/12 subprojects in subprojects/subprojects/c/c.h b/test cases/linuxlike/12 subprojects in subprojects/subprojects/c/c.h new file mode 100644 index 0000000..2b15f60 --- /dev/null +++ b/test cases/linuxlike/12 subprojects in subprojects/subprojects/c/c.h @@ -0,0 +1,3 @@ +static int c_fun(){ + return 3; +} diff --git a/test cases/linuxlike/12 subprojects in subprojects/subprojects/c/meson.build b/test cases/linuxlike/12 subprojects in subprojects/subprojects/c/meson.build new file mode 100644 index 0000000..7184933 --- /dev/null +++ b/test cases/linuxlike/12 subprojects in subprojects/subprojects/c/meson.build @@ -0,0 +1,5 @@ +project('c', 'c', version:'1') + +c_dep = declare_dependency( + include_directories: include_directories('.') +) diff --git a/test cases/linuxlike/5 dependency versions/meson.build b/test cases/linuxlike/5 dependency versions/meson.build index d4140b7..5d9eb32 100644 --- a/test cases/linuxlike/5 dependency versions/meson.build +++ b/test cases/linuxlike/5 dependency versions/meson.build @@ -41,6 +41,11 @@ assert(somelibver.type_name() == 'internal', 'somelibver should be of type "inte somelib = dependency('somelib', version : '== 0.1', fallback : ['somelib', 'some_dep']) +# Find an internal dependency again even if required = false +somelib_reqfalse = dependency('somelib', + required: false, + fallback : ['somelib', 'some_dep']) +assert(somelib_reqfalse.found(), 'somelib should have been found') # Find an internal dependency again with the same name and incompatible version somelibver = dependency('somelib', version : '>= 0.3', diff --git a/test cases/objc/2 nsstring/meson.build b/test cases/objc/2 nsstring/meson.build index a877d74..7f2483f 100644 --- a/test cases/objc/2 nsstring/meson.build +++ b/test cases/objc/2 nsstring/meson.build @@ -5,7 +5,10 @@ if host_machine.system() == 'darwin' elif host_machine.system() == 'cygwin' error('MESON_SKIP_TEST GNUstep is not packaged for Cygwin.') else - dep = dependency('gnustep') + dep = dependency('gnustep', required : false) + if not dep.found() + error('MESON_SKIP_TEST: GNUstep is not installed') + endif if host_machine.system() == 'linux' and meson.get_compiler('objc').get_id() == 'clang' error('MESON_SKIP_TEST: GNUstep is broken on Linux with Clang') endif diff --git a/test cases/objc/4 objc args/meson.build b/test cases/objc/3 objc args/meson.build index 8887d96..8887d96 100644 --- a/test cases/objc/4 objc args/meson.build +++ b/test cases/objc/3 objc args/meson.build diff --git a/test cases/objc/4 objc args/prog.m b/test cases/objc/3 objc args/prog.m index bfd686a..bfd686a 100644 --- a/test cases/objc/4 objc args/prog.m +++ b/test cases/objc/3 objc args/prog.m diff --git a/test cases/objc/6 c++ project objc subproject/master.cpp b/test cases/objc/6 c++ project objc subproject/master.cpp new file mode 100644 index 0000000..2f351d1 --- /dev/null +++ b/test cases/objc/6 c++ project objc subproject/master.cpp @@ -0,0 +1,11 @@ + +#include <iostream> + +extern "C" +int foo(); + +int main() { + std::cout << "Starting\n"; + std::cout << foo() << "\n"; + return 0; +} diff --git a/test cases/objc/6 c++ project objc subproject/meson.build b/test cases/objc/6 c++ project objc subproject/meson.build new file mode 100644 index 0000000..8a77ded --- /dev/null +++ b/test cases/objc/6 c++ project objc subproject/meson.build @@ -0,0 +1,6 @@ +project('master', ['cpp']) + +foo = subproject('foo') +dep = foo.get_variable('foo_dep') + +executable('master', 'master.cpp', dependencies: dep) diff --git a/test cases/objc/6 c++ project objc subproject/subprojects/foo/foo.m b/test cases/objc/6 c++ project objc subproject/subprojects/foo/foo.m new file mode 100644 index 0000000..e193b86 --- /dev/null +++ b/test cases/objc/6 c++ project objc subproject/subprojects/foo/foo.m @@ -0,0 +1,4 @@ + +int foo() { + return 42; +} diff --git a/test cases/objc/6 c++ project objc subproject/subprojects/foo/meson.build b/test cases/objc/6 c++ project objc subproject/subprojects/foo/meson.build new file mode 100644 index 0000000..2dbf8ab --- /dev/null +++ b/test cases/objc/6 c++ project objc subproject/subprojects/foo/meson.build @@ -0,0 +1,5 @@ +project('foo', ['objc']) + +l = static_library('foo', 'foo.m') + +foo_dep = declare_dependency(link_with : l) diff --git a/test cases/objc/3 objc++/meson.build b/test cases/objcpp/1 simple/meson.build index 7d91884..7d91884 100644 --- a/test cases/objc/3 objc++/meson.build +++ b/test cases/objcpp/1 simple/meson.build diff --git a/test cases/objc/3 objc++/prog.mm b/test cases/objcpp/1 simple/prog.mm index 927e810..927e810 100644 --- a/test cases/objc/3 objc++/prog.mm +++ b/test cases/objcpp/1 simple/prog.mm diff --git a/test cases/objc/5 objc++ args/meson.build b/test cases/objcpp/2 objc++ args/meson.build index e0e34b0..e0e34b0 100644 --- a/test cases/objc/5 objc++ args/meson.build +++ b/test cases/objcpp/2 objc++ args/meson.build diff --git a/test cases/objc/5 objc++ args/prog.mm b/test cases/objcpp/2 objc++ args/prog.mm index 3decaf2..3decaf2 100644 --- a/test cases/objc/5 objc++ args/prog.mm +++ b/test cases/objcpp/2 objc++ args/prog.mm diff --git a/test cases/unit/11 build_rpath/meson.build b/test cases/unit/11 build_rpath/meson.build index b84c259..c0bc3bd 100644 --- a/test cases/unit/11 build_rpath/meson.build +++ b/test cases/unit/11 build_rpath/meson.build @@ -1,4 +1,4 @@ -project('build rpath', 'c') +project('build rpath', 'c', 'cpp') subdir('sub') executable('prog', 'prog.c', @@ -7,3 +7,10 @@ executable('prog', 'prog.c', install_rpath : '/baz', install : true, ) + +executable('progcxx', 'prog.cc', + link_with : l, + build_rpath : '/foo/bar', + install_rpath : 'baz', + install : true, + ) diff --git a/test cases/unit/11 build_rpath/prog.cc b/test cases/unit/11 build_rpath/prog.cc new file mode 100644 index 0000000..c7c2123 --- /dev/null +++ b/test cases/unit/11 build_rpath/prog.cc @@ -0,0 +1,8 @@ +#include <string> +#include <iostream> + +int main(int argc, char **argv) { + std::string* s = new std::string("Hello"); + delete s; + return 0; +} diff --git a/test cases/unit/13 promote/meson.build b/test cases/unit/13 promote/meson.build new file mode 100644 index 0000000..066cf36 --- /dev/null +++ b/test cases/unit/13 promote/meson.build @@ -0,0 +1,5 @@ +project('promotion test', 'c') + +subproject('s1') +subproject('s2') + diff --git a/test cases/unit/13 promote/subprojects/s1/meson.build b/test cases/unit/13 promote/subprojects/s1/meson.build new file mode 100644 index 0000000..88c467b --- /dev/null +++ b/test cases/unit/13 promote/subprojects/s1/meson.build @@ -0,0 +1,7 @@ +project('s1', 'c') + +sc = subproject('scommon') +s3 = subproject('s3') + +executable('s1', 's1.c', + link_with : [sc.get_variable('clib'), s3.get_variable('l')]) diff --git a/test cases/unit/13 promote/subprojects/s1/s1.c b/test cases/unit/13 promote/subprojects/s1/s1.c new file mode 100644 index 0000000..7d1d775 --- /dev/null +++ b/test cases/unit/13 promote/subprojects/s1/s1.c @@ -0,0 +1,6 @@ +int func(); +int func2(); + +int main(int argc, char **argv) { + return func() + func2(); +} diff --git a/test cases/unit/13 promote/subprojects/s1/subprojects/s3/meson.build b/test cases/unit/13 promote/subprojects/s1/subprojects/s3/meson.build new file mode 100644 index 0000000..894fe26 --- /dev/null +++ b/test cases/unit/13 promote/subprojects/s1/subprojects/s3/meson.build @@ -0,0 +1,4 @@ +project('s3', 'c') + +l = static_library('s3', 's3.c') + diff --git a/test cases/unit/13 promote/subprojects/s1/subprojects/s3/s3.c b/test cases/unit/13 promote/subprojects/s1/subprojects/s3/s3.c new file mode 100644 index 0000000..0166603 --- /dev/null +++ b/test cases/unit/13 promote/subprojects/s1/subprojects/s3/s3.c @@ -0,0 +1,3 @@ +int func2() { + return -42; +} diff --git a/test cases/unit/13 promote/subprojects/s1/subprojects/scommon/meson.build b/test cases/unit/13 promote/subprojects/s1/subprojects/scommon/meson.build new file mode 100644 index 0000000..231f275 --- /dev/null +++ b/test cases/unit/13 promote/subprojects/s1/subprojects/scommon/meson.build @@ -0,0 +1,4 @@ +project('scommon', 'c') + +clib = static_library('scommon', 'scommon_broken.c') + diff --git a/test cases/unit/13 promote/subprojects/s1/subprojects/scommon/scommon_broken.c b/test cases/unit/13 promote/subprojects/s1/subprojects/scommon/scommon_broken.c new file mode 100644 index 0000000..3665a9c --- /dev/null +++ b/test cases/unit/13 promote/subprojects/s1/subprojects/scommon/scommon_broken.c @@ -0,0 +1 @@ +#error This file must not be used. The other scommon one should be instead. diff --git a/test cases/unit/13 promote/subprojects/s2/meson.build b/test cases/unit/13 promote/subprojects/s2/meson.build new file mode 100644 index 0000000..32bcf8f --- /dev/null +++ b/test cases/unit/13 promote/subprojects/s2/meson.build @@ -0,0 +1,6 @@ +project('s2', 'c') + +sc = subproject('scommon') + +executable('s2', 's2.c', link_with : sc.get_variable('clib')) + diff --git a/test cases/unit/13 promote/subprojects/s2/s2.c b/test cases/unit/13 promote/subprojects/s2/s2.c new file mode 100644 index 0000000..2a6d1e6 --- /dev/null +++ b/test cases/unit/13 promote/subprojects/s2/s2.c @@ -0,0 +1,6 @@ +int func(); + + +int main(int argc, char **argv) { + return func() != 42; +} diff --git a/test cases/unit/13 promote/subprojects/s2/subprojects/athing.wrap b/test cases/unit/13 promote/subprojects/s2/subprojects/athing.wrap new file mode 100644 index 0000000..09ba4e8 --- /dev/null +++ b/test cases/unit/13 promote/subprojects/s2/subprojects/athing.wrap @@ -0,0 +1,2 @@ +The contents of this wrap file are never evaluated so they +can be anything. diff --git a/test cases/unit/13 promote/subprojects/s2/subprojects/scommon/meson.build b/test cases/unit/13 promote/subprojects/s2/subprojects/scommon/meson.build new file mode 100644 index 0000000..e0d8c7d --- /dev/null +++ b/test cases/unit/13 promote/subprojects/s2/subprojects/scommon/meson.build @@ -0,0 +1,4 @@ +project('scommon', 'c') + +clib = static_library('scommon', 'scommon_ok.c') + diff --git a/test cases/unit/13 promote/subprojects/s2/subprojects/scommon/scommon_ok.c b/test cases/unit/13 promote/subprojects/s2/subprojects/scommon/scommon_ok.c new file mode 100644 index 0000000..652f4eb --- /dev/null +++ b/test cases/unit/13 promote/subprojects/s2/subprojects/scommon/scommon_ok.c @@ -0,0 +1,3 @@ +int func() { + return 42; +} diff --git a/test cases/unit/19 bad command line options/meson.build b/test cases/unit/19 bad command line options/meson.build new file mode 100644 index 0000000..b1670c0 --- /dev/null +++ b/test cases/unit/19 bad command line options/meson.build @@ -0,0 +1,17 @@ +# 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('Bad command line options') + +one = subproject('one') diff --git a/test cases/unit/19 bad command line options/meson_options.txt b/test cases/unit/19 bad command line options/meson_options.txt new file mode 100644 index 0000000..fc09712 --- /dev/null +++ b/test cases/unit/19 bad command line options/meson_options.txt @@ -0,0 +1,16 @@ +# 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. + +option('opt', type : 'string', description : 'An argument') +option('good', type : 'boolean', value : true, description : 'another argument') diff --git a/test cases/unit/19 bad command line options/subprojects/one/meson.build b/test cases/unit/19 bad command line options/subprojects/one/meson.build new file mode 100644 index 0000000..39ae07e --- /dev/null +++ b/test cases/unit/19 bad command line options/subprojects/one/meson.build @@ -0,0 +1,15 @@ +# 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('one subproject') diff --git a/test cases/unit/19 bad command line options/subprojects/one/meson_options.txt b/test cases/unit/19 bad command line options/subprojects/one/meson_options.txt new file mode 100644 index 0000000..7d90fae --- /dev/null +++ b/test cases/unit/19 bad command line options/subprojects/one/meson_options.txt @@ -0,0 +1,15 @@ +# 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. + +option('one', type : 'string', description : 'an option') diff --git a/test cases/unit/20 subproj dep variables/meson.build b/test cases/unit/20 subproj dep variables/meson.build new file mode 100644 index 0000000..f1622f9 --- /dev/null +++ b/test cases/unit/20 subproj dep variables/meson.build @@ -0,0 +1,13 @@ +project('subproj found dep not found', 'c') + +dependency('somedep', required : false, + fallback : ['nosubproj', 'dep_name']) + +dependency('somedep', required : false, + fallback : ['failingsubproj', 'dep_name']) + +dependency('somenotfounddep', required : false, + fallback : ['somesubproj', 'dep_name']) + +dependency('zlibproxy', required : true, + fallback : ['somesubproj', 'zlibproxy_dep']) diff --git a/test cases/unit/20 subproj dep variables/subprojects/failingsubproj/meson.build b/test cases/unit/20 subproj dep variables/subprojects/failingsubproj/meson.build new file mode 100644 index 0000000..3a84bd2 --- /dev/null +++ b/test cases/unit/20 subproj dep variables/subprojects/failingsubproj/meson.build @@ -0,0 +1,3 @@ +project('failingsubproj', 'c') + +dep_name = declare_dependency('arg') diff --git a/test cases/unit/20 subproj dep variables/subprojects/somesubproj/meson.build b/test cases/unit/20 subproj dep variables/subprojects/somesubproj/meson.build new file mode 100644 index 0000000..dd65c99 --- /dev/null +++ b/test cases/unit/20 subproj dep variables/subprojects/somesubproj/meson.build @@ -0,0 +1,3 @@ +project('dep', 'c') + +zlibproxy_dep = declare_dependency(dependencies : dependency('zlib', required : false)) diff --git a/test cases/unit/20 warning location/a.c b/test cases/unit/20 warning location/a.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test cases/unit/20 warning location/a.c diff --git a/test cases/unit/20 warning location/b.c b/test cases/unit/20 warning location/b.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test cases/unit/20 warning location/b.c diff --git a/test cases/unit/20 warning location/conf.in b/test cases/unit/20 warning location/conf.in new file mode 100644 index 0000000..a2903ed --- /dev/null +++ b/test cases/unit/20 warning location/conf.in @@ -0,0 +1 @@ +@MISSING@ diff --git a/test cases/unit/20 warning location/main.c b/test cases/unit/20 warning location/main.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test cases/unit/20 warning location/main.c diff --git a/test cases/unit/20 warning location/meson.build b/test cases/unit/20 warning location/meson.build new file mode 100644 index 0000000..15295a9 --- /dev/null +++ b/test cases/unit/20 warning location/meson.build @@ -0,0 +1,10 @@ +project('warning location', 'c', invalid: 'cheese') +a = library('liba', 'a.c') +b = library('libb', 'b.c') +executable('main', 'main.c', link_with: a, link_with: b) +subdir('sub') +warning('a warning of some sort') +import('unstable-simd') + +conf_data = configuration_data() +configure_file(input: 'conf.in' , output: 'conf', configuration: conf_data) diff --git a/test cases/unit/20 warning location/sub/c.c b/test cases/unit/20 warning location/sub/c.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test cases/unit/20 warning location/sub/c.c diff --git a/test cases/unit/20 warning location/sub/d.c b/test cases/unit/20 warning location/sub/d.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test cases/unit/20 warning location/sub/d.c diff --git a/test cases/unit/20 warning location/sub/meson.build b/test cases/unit/20 warning location/sub/meson.build new file mode 100644 index 0000000..27f6778 --- /dev/null +++ b/test cases/unit/20 warning location/sub/meson.build @@ -0,0 +1,4 @@ +c = library('libc', 'c.c') +d = library('libd', 'd.c') +executable('sub', 'sub.c', link_with: c, link_with: d) +warning('subdir warning') diff --git a/test cases/unit/20 warning location/sub/sub.c b/test cases/unit/20 warning location/sub/sub.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test cases/unit/20 warning location/sub/sub.c diff --git a/test cases/vala/11 generated vapi/installed_files.txt b/test cases/vala/11 generated vapi/installed_files.txt index 5993d01..aeaf2da 100644 --- a/test cases/vala/11 generated vapi/installed_files.txt +++ b/test cases/vala/11 generated vapi/installed_files.txt @@ -1,6 +1,6 @@ usr/bin/vapigen-test -usr/lib/libfoo.so -usr/lib/libbar.so +usr/lib/?libfoo.so +usr/lib/?libbar.so usr/share/vala/vapi/foo-1.0.vapi usr/share/vala/vapi/foo-1.0.deps usr/share/vala/vapi/bar-1.0.vapi diff --git a/test cases/vala/11 generated vapi/libbar/bar.c b/test cases/vala/11 generated vapi/libbar/bar.c index f0f5cb8..3037141 100644 --- a/test cases/vala/11 generated vapi/libbar/bar.c +++ b/test cases/vala/11 generated vapi/libbar/bar.c @@ -1,12 +1,29 @@ #include "bar.h" #include "foo.h" +struct _BarBar +{ + GObject parent_instance; +}; + +G_DEFINE_TYPE (BarBar, bar_bar, G_TYPE_OBJECT) + +static void +bar_bar_class_init (BarBarClass *klass) +{ +} + +static void +bar_bar_init (BarBar *self) +{ +} + /** - * bar_return_success: + * bar_bar_return_success: * * Returns 0 */ -int bar_return_success(void) +int bar_bar_return_success(void) { - return foo_return_success(); + return foo_foo_return_success(); } diff --git a/test cases/vala/11 generated vapi/libbar/bar.h b/test cases/vala/11 generated vapi/libbar/bar.h index 165b104..4ca7270 100644 --- a/test cases/vala/11 generated vapi/libbar/bar.h +++ b/test cases/vala/11 generated vapi/libbar/bar.h @@ -2,4 +2,8 @@ #pragma once -int bar_return_success(void); +#define BAR_TYPE_BAR (bar_bar_get_type()) + +G_DECLARE_FINAL_TYPE (BarBar, bar_bar, BAR, BAR, GObject) + +int bar_bar_return_success(void); diff --git a/test cases/vala/11 generated vapi/libfoo/foo.c b/test cases/vala/11 generated vapi/libfoo/foo.c index 0413ac5..dd2b891 100644 --- a/test cases/vala/11 generated vapi/libfoo/foo.c +++ b/test cases/vala/11 generated vapi/libfoo/foo.c @@ -1,11 +1,28 @@ #include "foo.h" +struct _FooFoo +{ + GObject parent_instance; +}; + +G_DEFINE_TYPE (FooFoo, foo_foo, G_TYPE_OBJECT) + +static void +foo_foo_class_init (FooFooClass *klass) +{ +} + +static void +foo_foo_init (FooFoo *self) +{ +} + /** - * foo_return_success: + * foo_foo_return_success: * * Returns 0 */ -int foo_return_success(void) +int foo_foo_return_success(void) { - return 0; + return 0; } diff --git a/test cases/vala/11 generated vapi/libfoo/foo.h b/test cases/vala/11 generated vapi/libfoo/foo.h index f09256d..e1887d8 100644 --- a/test cases/vala/11 generated vapi/libfoo/foo.h +++ b/test cases/vala/11 generated vapi/libfoo/foo.h @@ -2,4 +2,8 @@ #pragma once -int foo_return_success(void); +#define FOO_TYPE_FOO (foo_foo_get_type()) + +G_DECLARE_FINAL_TYPE (FooFoo, foo_foo, Foo, FOO, GObject) + +int foo_foo_return_success(void); diff --git a/test cases/vala/11 generated vapi/main.vala b/test cases/vala/11 generated vapi/main.vala index 303ab33..d61fba0 100644 --- a/test cases/vala/11 generated vapi/main.vala +++ b/test cases/vala/11 generated vapi/main.vala @@ -3,7 +3,7 @@ using Bar; class Main : GLib.Object { public static int main(string[] args) { - var ignore = Foo.return_success(); - return Bar.return_success(); + var ignore = Foo.Foo.return_success(); + return Bar.Bar.return_success(); } } diff --git a/test cases/vala/23 thread flags/meson.build b/test cases/vala/23 thread flags/meson.build new file mode 100644 index 0000000..3b385df --- /dev/null +++ b/test cases/vala/23 thread flags/meson.build @@ -0,0 +1,7 @@ +project('thread flags', 'c', 'vala') + +glib = dependency('glib-2.0') +gobject = dependency('gobject-2.0') +threads = dependency('threads') + +e = executable('valaprog', 'prog.vala', dependencies: [glib, gobject, threads]) diff --git a/test cases/vala/23 thread flags/prog.vala b/test cases/vala/23 thread flags/prog.vala new file mode 100644 index 0000000..0b2c54c --- /dev/null +++ b/test cases/vala/23 thread flags/prog.vala @@ -0,0 +1,2 @@ +void main () { +} diff --git a/test cases/vala/7 shared library/installed_files.txt b/test cases/vala/7 shared library/installed_files.txt index f70e439..012b107 100644 --- a/test cases/vala/7 shared library/installed_files.txt +++ b/test cases/vala/7 shared library/installed_files.txt @@ -1,5 +1,5 @@ -usr/lib/libinstalled_vala_lib.so -usr/lib/libinstalled_vala_all.so +usr/lib/?libinstalled_vala_lib.so +usr/lib/?libinstalled_vala_all.so usr/include/installed_vala_all.h usr/include/valah/installed_vala_all_nolib.h usr/include/installed_vala_onlyh.h diff --git a/test cases/vala/9 gir/installed_files.txt b/test cases/vala/9 gir/installed_files.txt index 7a0e055..64bddee 100644 --- a/test cases/vala/9 gir/installed_files.txt +++ b/test cases/vala/9 gir/installed_files.txt @@ -1,2 +1,2 @@ -usr/lib/libfoo.so +usr/lib/?libfoo.so usr/share/gir-1.0/Foo-1.0.gir diff --git a/test cases/windows/5 resources/prog.c b/test cases/windows/5 resources/prog.c index 2c6f153..2bef6a2 100644 --- a/test cases/windows/5 resources/prog.c +++ b/test cases/windows/5 resources/prog.c @@ -9,6 +9,6 @@ WinMain( LPSTR lpszCmdLine, int nCmdShow) { HICON hIcon; - hIcon = LoadIcon(NULL, IDI_APPLICATION); + hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(MY_ICON)); return hIcon ? 0 : 1; } diff --git a/wraptool.py b/wraptool.py index 5e03efd..a5ee9ef 100755 --- a/wraptool.py +++ b/wraptool.py @@ -17,4 +17,7 @@ from mesonbuild.wrap import wraptool import sys -sys.exit(wraptool.run(sys.argv[1:])) +if __name__ == '__main__': + print('Warning: This executable is deprecated. Use "meson wrap" instead.', + file=sys.stderr) + sys.exit(wraptool.run(sys.argv[1:])) |