diff options
35 files changed, 620 insertions, 161 deletions
diff --git a/data/shell-completions/zsh/_meson b/data/shell-completions/zsh/_meson new file mode 100644 index 0000000..877d700 --- /dev/null +++ b/data/shell-completions/zsh/_meson @@ -0,0 +1,213 @@ +#compdef meson mesonconf=meson-configure mesontest=meson-test mesonintrospect=meson-introspect + +# vim:ts=2 sw=2 + +# Copyright (c) 2017 Arseny Maslennikov +# All rights reserved. Individual authors, whether or not +# specifically named, retain copyright in all changes; in what follows, they +# are referred to as `the Meson development team'. This is for convenience +# only and this body has no legal status. This file is distributed under +# the following licence. +# +# Permission is hereby granted, without written agreement and without +# licence or royalty fees, to use, copy, modify, and distribute this +# software and to distribute modified versions of this software for any +# purpose, provided that the above copyright notice and the following +# two paragraphs appear in all copies of this software. +# +# In no event shall the Meson development team be liable to any party for +# direct, indirect, special, incidental, or consequential damages arising out +# of the use of this software and its documentation, even if the Meson +# development team have been advised of the possibility of such damage. +# +# The Meson development team specifically disclaim any warranties, including, +# but not limited to, the implied warranties of merchantability and fitness +# for a particular purpose. The software provided hereunder is on an "as is" +# basis, and the Meson development team have no obligation to provide +# maintenance, support, updates, enhancements, or modifications. + +local curcontext="$curcontext" state line +local -i ret + +local __meson_backends="(ninja xcode ${(j. .)${:-vs{,2010,2015,2017}}})" +local __meson_build_types="(plain debug debugoptimized minsize release)" +local __meson_wrap_modes="(WrapMode.{default,nofallback,nodownload})" + +local -a meson_commands=( +'setup:set up a build directory' +'configure:configure a project' +'test:run tests' +'introspect:query project properties' +'wrap:manage source dependencies' +) + +(( $+functions[__meson_is_build_dir] )) || __meson_is_build_dir() { + local mpd="${1:-$PWD}/meson-private" + [[ -f "$mpd/build.dat" && -f "$mpd/coredata.dat" ]] + return $? +} + +# TODO: implement build option completion +(( $+functions[__meson_build_options] )) || __meson_build_options() {} +# TODO: implement target name completion +(( $+functions[__meson_targets] )) || __meson_targets() {} +# `meson introspect` currently can provide that information in JSON. +# We can: +# 1) pipe its output to python3 -m json.tool | grep "$alovelyregex" | cut <...> +# 2) teach mintro.py to use a different output format +# (or perhaps just to select the fields printed) + +(( $+functions[__meson_test_names] )) || __meson_test_names() { + local rtests + if rtests="$(_call_program meson meson test ${opt_args[-C]:+-C "$opt_args[-C]"} --list)"; + then + local -a tests=(${(@f)rtests}) + _describe -t "tests" "Meson tests" tests + else + _message -r "current working directory is not a build directory" + _message -r 'use -C $build_dir or cd $build_dir' + fi +} + +(( $+functions[_meson_commands] )) || _meson_commands() { + _describe -t commands "Meson subcommands" meson_commands +} + +(( $+functions[_meson-setup] )) || _meson-setup() { + local firstd secondd + if [[ -f "meson.build" ]]; then + # if there's no second argument on the command line + # cwd will implicitly be substituted: + # - as the source directory if it has a file with the name "meson.build"; + # - as the build directory otherwise + # more info in mesonbuild/mesonmain.py + firstd="build" + secondd="source" + else + firstd="source" + secondd="build" + fi + + _arguments \ + '*-D-[set the value of a build option]:build option:__meson_build_options' \ + '--prefix=[installation prefix]: :_directories' \ + '--libdir=[library directory]: :_directories' \ + '--libexecdir=[library executable directory]: :_directories' \ + '--bindir=[executable directory]: :_directories' \ + '--sbindir=[system executable directory]: :_directories' \ + '--includedir=[header file directory]: :_directories' \ + '--datadir=[data file directory]: :_directories' \ + '--mandir=[manual page directory]: :_directories' \ + '--infodir=[info page directory]: :_directories' \ + '--localedir=[locale data directory]: :_directories' \ + '--sysconfdir=[system configuration directory]: :_directories' \ + '--localstatedir=[local state data directory]: :_directories' \ + '--sharedstatedir=[arch-independent data directory]: :_directories' \ + '--backend=[backend to use]:Meson backend:'"$__meson_backends" \ + '--buildtype=[build type to use]:Meson build type:'"$__meson_build_types" \ + '--strip[strip targets on install]' \ + '--unity=[unity builds on/off]:whether to do unity builds:(on off subprojects)' \ + '--werror[treat warnings as errors]' \ + '--layout=[build directory layout]:build directory layout:(flat mirror)' \ + '--default-library=[default library type]:default library type:(shared static)' \ + '--warnlevel=[compiler warning level]:compiler warning level:warning level:(1 2 3)' \ + '--stdsplit=[split stdout and stderr in test logs]' \ + '--errorlogs=[prints the logs from failing tests]' \ + '--cross-file=[cross-compilation environment description]:cross file:_files' \ + '--wrap-mode=[special wrap mode]:wrap mode:'"$__meson_wrap_modes" \ + ":$firstd directory:_directories" \ + "::$secondd directory:_directories" \ + # +} + +(( $+functions[_meson-configure] )) || _meson-configure() { + local curcontext="$curcontext" + # TODO: implement 'mesonconf @file' + local -a specs=( + '--clearcache[clear cached state]' + '*-D-[set the value of a build option]:build option:__meson_build_options' + '::build directory:_directories' + ) + + _arguments \ + '(: -)'{'--help','-h'}'[show a help message and quit]' \ + "${(@)specs}" +} + +(( $+functions[_meson-test] )) || _meson-test() { + local curcontext="$curcontext" + + # TODO: complete test suites + local -a specs=( + '(--quiet -q)'{'--quiet','-q'}'[produce less output to the terminal]' + '(--verbose -v)'{'--verbose','-v'}'[do not redirect stdout and stderr]' + '(--timeout-multiplier -t)'{'--timeout-multiplier','-t'}'[a multiplier for test timeouts]:Python floating-point number: ' + '-C[directory to cd into]: :_directories' + '--repeat[number of times to run the tests]:number of times to repeat: ' + '--no-rebuild[do not rebuild before running tests]' + '--gdb[run tests under gdb]' + '--list[list available tests]' + '(--wrapper --wrap)'{'--wrapper=','--wrap='}'[wrapper to run tests with]:wrapper program:_path_commands' + '(--no-suite)--suite[only run tests from this suite]:test suite: ' + '(--suite)--no-suite[do not run tests from this suite]:test suite: ' + '--no-stdsplit[do not split stderr and stdout in logs]' + '--print-errorlogs[print logs for failing tests]' + '--benchmark[run benchmarks instead of tests]' + '--logbase[base name for log file]:filename: ' + '--num-processes[how many threads to use]:number of processes: ' + '--setup[which test setup to use]:test setup: ' + '--test-args[arguments to pass to the tests]: : ' + '*:Meson tests:__meson_test_names' + ) + + _arguments \ + '(: -)'{'--help','-h'}'[show a help message and quit]' \ + "${(@)specs}" +} + +(( $+functions[_meson-introspect] )) || _meson-introspect() { + local curcontext="$curcontext" + local -a specs=( + '--targets[list top level targets]' + '--installed[list all installed files and directories]' + '--target-files[list source files for a given target]:target:__meson_targets' + '--buildsystem-files[list files that belong to the build system]' + '--buildoptions[list all build options]' + '--tests[list all unit tests]' + '--benchmarks[list all benchmarks]' + '--dependencies[list external dependencies]' + '--projectinfo[show project information]' + '::build directory:_directories' + ) +_arguments \ + '(: -)'{'--help','-h'}'[show a help message and quit]' \ + "${(@)specs}" +} + +(( $+functions[_meson-wrap] )) || _meson-wrap() { + # TODO +} + +if [[ $service != meson ]]; then + _call_function ret _$service + return ret +fi + +_arguments -C -R \ + '(: -)'{'--help','-h'}'[show a help message and quit]' \ + '(: -)'{'--version','-v'}'[show version information and quit]' \ + '(-): :_meson_commands' \ + '*:: :->post-command' \ +# +ret=$? + +[[ $ret = 300 ]] && case "$state" in + post-command) + service="meson-$words[1]" + curcontext=${curcontext%:*:*}:$service: + _call_function ret _$service + ;; +esac + +return ret + diff --git a/data/meson.el b/data/syntax-highlighting/emacs/meson.el index 36f7eb9..36f7eb9 100644 --- a/data/meson.el +++ b/data/syntax-highlighting/emacs/meson.el diff --git a/syntax-highlighting/vim/README b/data/syntax-highlighting/vim/README index 1afa243..1afa243 100644 --- a/syntax-highlighting/vim/README +++ b/data/syntax-highlighting/vim/README diff --git a/syntax-highlighting/vim/ftdetect/meson.vim b/data/syntax-highlighting/vim/ftdetect/meson.vim index 84db70c..84db70c 100644 --- a/syntax-highlighting/vim/ftdetect/meson.vim +++ b/data/syntax-highlighting/vim/ftdetect/meson.vim diff --git a/syntax-highlighting/vim/indent/meson.vim b/data/syntax-highlighting/vim/indent/meson.vim index b00c942..8553ec0 100644 --- a/syntax-highlighting/vim/indent/meson.vim +++ b/data/syntax-highlighting/vim/indent/meson.vim @@ -78,7 +78,7 @@ function GetMesonIndent(lnum) " When inside parenthesis: If at the first line below the parenthesis add - " two 'shiftwidth', otherwise same as previous line. + " a 'shiftwidth', otherwise same as previous line. " i = (a " + b " + c) @@ -97,7 +97,7 @@ function GetMesonIndent(lnum) if pp > 0 return indent(plnum) + (exists("g:pyindent_nested_paren") ? eval(g:pyindent_nested_paren) : shiftwidth()) endif - return indent(plnum) + (exists("g:pyindent_open_paren") ? eval(g:pyindent_open_paren) : (shiftwidth() * 2)) + return indent(plnum) + (exists("g:pyindent_open_paren") ? eval(g:pyindent_open_paren) : shiftwidth()) endif if plnumstart == p return indent(plnum) diff --git a/syntax-highlighting/vim/syntax/meson.vim b/data/syntax-highlighting/vim/syntax/meson.vim index 49921c1..49921c1 100644 --- a/syntax-highlighting/vim/syntax/meson.vim +++ b/data/syntax-highlighting/vim/syntax/meson.vim diff --git a/docs/markdown/Dependencies.md b/docs/markdown/Dependencies.md index 3aa82b4..8e780d6 100644 --- a/docs/markdown/Dependencies.md +++ b/docs/markdown/Dependencies.md @@ -45,7 +45,52 @@ non-found dependencies. The dependency detector works with all libraries that provide a `pkg-config` file. Unfortunately several packages don't provide -pkg-config files. Meson has autodetection support for some of these. +pkg-config files. Meson has autodetection support for some of these, +and they are described later on this page. + +# Declaring your own + +You can declare your own dependency objects that can be used +interchangeably with dependency objects obtained from the system. The +syntax is straightforward: + +```meson +my_inc = include_directories(...) +my_lib = static_library(...) +my_dep = declare_dependency(link_with : my_lib, + include_directories : my_inc) +``` + +This declares a dependency that adds the given include directories and +static library to any target you use it in. + +# Building dependencies as subprojects + +Many platforms do not provide a system package manager. On these +systems dependencies must be compiled from source. Meson's subprojects +make it simple to use system dependencies when they are available and +to build dependencies manually when they are not. + +To make this work, the dependency must have Meson build definitions +and it must declare its own dependency like this: + + foo_dep = declare_dependency(...) + +Then any project that wants to use it can write out the following +declaration in their main `meson.build` file. + + foo_dep = dependency('foo', fallback : ['foo', 'foo_dep']) + +What this declaration means is that first Meson tries to look up the +dependency from the system (such as by using pkg-config). If it is not +available, then it builds subproject named `foo` and from that +extracts a variable `foo_dep`. That means that the return value of +this function is either an external or an internal dependency +object. Since they can be used interchangeably, the rest of the build +definitions do not need to care which one it is. Meson will take care +of all the work behind the scenes to make this work. + +# Dependencies with custom lookup functionality ## Boost @@ -162,19 +207,3 @@ automatically: ```meson libwmf_dep = dependency('libwmf', version : '>=0.2.8') ``` - -## Declaring your own - -You can declare your own dependency objects that can be used -interchangeably with dependency objects obtained from the system. The -syntax is straightforward: - -```meson -my_inc = include_directories(...) -my_lib = static_library(...) -my_dep = declare_dependency(link_with : my_lib, - include_directories : my_inc) -``` - -This declares a dependency that adds the given include directories and -static library to any target you use it in. diff --git a/docs/markdown/Subprojects.md b/docs/markdown/Subprojects.md index 85453e3..923b6a3 100644 --- a/docs/markdown/Subprojects.md +++ b/docs/markdown/Subprojects.md @@ -42,7 +42,7 @@ else l = sp.get_variable('l') endif exe = executable('prog', 'prog.c', include_directories : i, link_with : l, - deps : dep, install : true) + dependencies : dep, install : true) ``` With this setup the system dependency is used when it is available, otherwise we fall back on the bundled version. diff --git a/docs/markdown/Syntax.md b/docs/markdown/Syntax.md index eaf24cf..88b9bbb 100644 --- a/docs/markdown/Syntax.md +++ b/docs/markdown/Syntax.md @@ -4,23 +4,39 @@ short-description: Syntax and structure of Meson files # Syntax -The syntax of Meson's specification language has been kept as simple as possible. It is *strongly typed* so no object is ever converted to another under the covers. Variables have no visible type which makes Meson *dynamically typed* (also known as *duck typed*). - -The main building blocks of the language are *variables*, *numbers*, *booleans*, *strings*, *arrays*, *function calls*, *method calls*, *if statements* and *includes*. - -Usually one Meson statement takes just one line. There is no way to have multiple statements on one line as in e.g. *C*. Function and method calls' argument lists can be split over multiple lines. Meson will autodetect this case and do the right thing. In other cases you can get multi-line statements by ending the line with a `\`. Apart from line ending whitespace has no syntactic meaning. +The syntax of Meson's specification language has been kept as simple +as possible. It is *strongly typed* so no object is ever converted to +another under the covers. Variables have no visible type which makes +Meson *dynamically typed* (also known as *duck typed*). + +The main building blocks of the language are *variables*, *numbers*, +*booleans*, *strings*, *arrays*, *function calls*, *method calls*, *if +statements* and *includes*. + +Usually one Meson statement takes just one line. There is no way to +have multiple statements on one line as in e.g. *C*. Function and +method calls' argument lists can be split over multiple lines. Meson +will autodetect this case and do the right thing. In other cases you +can get multi-line statements by ending the line with a `\`. Apart +from line ending whitespace has no syntactic meaning. Variables -- -Variables in Meson work just like in other high level programming languages. A variable can contain a value of any type, such as an integer or a string. Variables don't need to be predeclared, you can just assign to them and they appear. Here's how you would assign values to two different variables. +Variables in Meson work just like in other high level programming +languages. A variable can contain a value of any type, such as an +integer or a string. Variables don't need to be predeclared, you can +just assign to them and they appear. Here's how you would assign +values to two different variables. ```meson var1 = 'hello' var2 = 102 ``` -One important difference in how variables work in Meson is that all variables are immutable. This is different from, for example, how Python works. +One important difference in how variables work in Meson is that all +objects are immutable. This is different from, for example, how Python +works. ```meson var1 = [1, 2, 3] @@ -33,7 +49,8 @@ var2 += [4] Numbers -- -Meson supports only integer numbers. They are declared simply by writing them out. Basic arithmetic operations are supported. +Meson supports only integer numbers. They are declared simply by +writing them out. Basic arithmetic operations are supported. ```meson x = 1 + 2 @@ -60,13 +77,15 @@ truth = true Strings -- -Strings in Meson are declared with single quotes. To enter a literal single quote do it like this: +Strings in Meson are declared with single quotes. To enter a literal +single quote do it like this: ```meson single quote = 'contains a \' character' ``` -Similarly `\n` gets converted to a newline and `\\\\` to a single backslash. +Similarly `\n` gets converted to a newline and `\\\\` to a single +backslash. #### String concatenation @@ -80,7 +99,8 @@ combined = str1 + '_' + str2 # combined is now abc_xyz #### Strings running over multiple lines -Strings running over multiple lines can be declared with three single quotes, like this: +Strings running over multiple lines can be declared with three single +quotes, like this: ```meson multiline_string = '''#include <foo.h> @@ -89,7 +109,8 @@ int main (int argc, char ** argv) { }''' ``` -This can also be combined with the string formatting functionality described below. +This can also be combined with the string formatting functionality +described below. #### String formatting @@ -101,11 +122,13 @@ res = template.format('text', 1, true) # res now has value 'string: text, number: 1, bool: true' ``` -As can be seen, the formatting works by replacing placeholders of type `@number@` with the corresponding argument. +As can be seen, the formatting works by replacing placeholders of type +`@number@` with the corresponding argument. #### String methods -Strings also support a number of other methods that return transformed copies. +Strings also support a number of other methods that return transformed +copies. **.strip()** @@ -226,7 +249,9 @@ my_array += ['something'] my_array += 'else' ``` -Note appending to an array will always create a new array object and assign it to `my_array` instead of modifying the original since all objects in Meson are immutable. +Note appending to an array will always create a new array object and +assign it to `my_array` instead of modifying the original since all +objects in Meson are immutable. #### Array methods @@ -239,7 +264,8 @@ The following methods are defined for all arrays: Function calls -- -Meson provides a set of usable functions. The most common use case is creating build objects. +Meson provides a set of usable functions. The most common use case is +creating build objects. ```meson executable('progname', 'prog.c') @@ -248,7 +274,8 @@ executable('progname', 'prog.c') Method calls -- -Objects can have methods, which are called with the dot operator. The exact methods it provides depends on the object. +Objects can have methods, which are called with the dot operator. The +exact methods it provides depends on the object. ```meson myobj = some_function() @@ -279,7 +306,9 @@ endif ## Foreach statements -To do an operation on all elements of an array, use the `foreach` command. As an example, here's how you would define two executables with corresponding tests. +To do an operation on all elements of an array, use the `foreach` +command. As an example, here's how you would define two executables +with corresponding tests. ```meson progs = [['prog1', ['prog1.c', 'foo.c']], @@ -291,7 +320,9 @@ foreach p : progs endforeach ``` -Note that Meson variables are immutable. Trying to assign a new value to `progs` inside a foreach loop will not affect foreach's control flow. +Note that Meson variables are immutable. Trying to assign a new value +to `progs` inside a foreach loop will not affect foreach's control +flow. Logical operations -- @@ -334,12 +365,20 @@ The ternary operator works just like in other languages. x = condition ? true_value : false_value ``` -The only exception is that nested ternary operators are forbidden to improve legibility. If your branching needs are more complex than this you need to write an `if/else` construct. +The only exception is that nested ternary operators are forbidden to +improve legibility. If your branching needs are more complex than this +you need to write an `if/else` construct. Includes -- -Most source trees have multiple subdirectories to process. These can be handled by Meson's `subdir` command. It changes to the given subdirectory and executes the contents of `meson.build` in that subdirectory. All state (variables etc) are passed to and from the subdirectory. The effect is roughly the same as if the contents of the subdirectory's Meson file would have been written where the include command is. +Most source trees have multiple subdirectories to process. These can +be handled by Meson's `subdir` command. It changes to the given +subdirectory and executes the contents of `meson.build` in that +subdirectory. All state (variables etc) are passed to and from the +subdirectory. The effect is roughly the same as if the contents of the +subdirectory's Meson file would have been written where the include +command is. ```meson test_data_dir = 'data' @@ -349,4 +388,12 @@ subdir('tests') User-defined functions and methods -- -Meson does not currently support user-defined functions or methods. The addition of user-defined functions would make Meson Turing-complete which would make it harder to reason about and more difficult to integrate with tools like IDEs. More details about this are [in the FAQ](FAQ.md#why-is-meson-not-just-a-python-module-so-i-could-code-my-build-setup-in-python). If because of this limitation you find yourself copying and pasting code a lot you may be able to use a [`foreach` loop instead](#foreach-statements). +Meson does not currently support user-defined functions or +methods. The addition of user-defined functions would make Meson +Turing-complete which would make it harder to reason about and more +difficult to integrate with tools like IDEs. More details about this +are [in the +FAQ](FAQ.md#why-is-meson-not-just-a-python-module-so-i-could-code-my-build-setup-in-python). If +because of this limitation you find yourself copying and pasting code +a lot you may be able to use a [`foreach` loop +instead](#foreach-statements). diff --git a/docs/markdown/Using-wraptool.md b/docs/markdown/Using-wraptool.md index e000695..8e5f898 100644 --- a/docs/markdown/Using-wraptool.md +++ b/docs/markdown/Using-wraptool.md @@ -53,7 +53,7 @@ To check if your projects are up to date you can issue the `status` command. In this case `zlib` has a newer release available. Updating it is straightforward: - $ wraptool.py update zlib + $ wraptool update zlib Updated zlib to branch 1.2.8 revision 4 Wraptool can do other things besides these. Documentation for these can be found in the command line help, which can be accessed by `wraptool --help`. diff --git a/docs/markdown/Wrap-dependency-system-manual.md b/docs/markdown/Wrap-dependency-system-manual.md index a850896..d97fc9a 100644 --- a/docs/markdown/Wrap-dependency-system-manual.md +++ b/docs/markdown/Wrap-dependency-system-manual.md @@ -52,7 +52,7 @@ are downloaded and automatically applied to the subproject. These files contain a Meson build definition for the given subproject. A wrap file with an additional patch URL would look like this. -``` +```ini [wrap-file] directory = libfoobar-1.0 @@ -83,7 +83,7 @@ packaged files. Sometimes you want to check code out directly from Git. Meson supports this natively. All you need to do is to write a slightly different wrap file. -``` +```ini [wrap-git] directory=samplesubproject url=https://github.com/jpakkane/samplesubproject.git diff --git a/docs/markdown/i18n-module.md b/docs/markdown/i18n-module.md index 1144e29..8fb650a 100644 --- a/docs/markdown/i18n-module.md +++ b/docs/markdown/i18n-module.md @@ -17,21 +17,17 @@ argument which is the name of the gettext module. * `args`: list of extra arguments to pass to `xgettext` when generating the pot file - * `data_dirs`: (*Added 0.36.0*) list of directories to be set for `GETTEXTDATADIRS` env var (Requires gettext 0.19.8+), used for local its files - * `languages`: list of languages that are to be generated. As of 0.37.0 this is optional and the [LINGUAS](https://www.gnu.org/software/gettext/manual/html_node/po_002fLINGUAS.html) file is read. - * `preset`: (*Added 0.37.0*) name of a preset list of arguments, current option is `'glib'`, see [source](https://github.com/mesonbuild/meson/blob/master/mesonbuild/modules/i18n.py) for for their value - * `install`: (*Added 0.43.0*) if false, do not install the built translations. This function also defines targets for maintainers to use: diff --git a/docs/markdown/snippets/llvm-static-linking.md b/docs/markdown/snippets/llvm-static-linking.md new file mode 100644 index 0000000..bb72a56 --- /dev/null +++ b/docs/markdown/snippets/llvm-static-linking.md @@ -0,0 +1,8 @@ +# LLVM dependency supports both dynamic and static linking + +The LLVM dependency has been improved to consistently use dynamic linking. +Previously recent version (>= 3.9) would link dynamically while older versions +would link statically. + +Now LLVM also accepts the `static` keyword to enable statically linking to LLVM +modules instead of dynamically linking. diff --git a/docs/markdown/snippets/prefix-dependent-defaults.md b/docs/markdown/snippets/prefix-dependent-defaults.md new file mode 100644 index 0000000..7cc1792 --- /dev/null +++ b/docs/markdown/snippets/prefix-dependent-defaults.md @@ -0,0 +1,10 @@ +# Prefix-dependent defaults for sysconfdir, localstatedir and sharedstatedir + +These options now default in a way consistent with +[FHS](http://refspecs.linuxfoundation.org/fhs.shtml) and common usage. + +If prefix is `/usr`, default sysconfdir to `/etc`, localstatedir to `/var` and +sharedstatedir to `/var/lib`. + +If prefix is `/usr/local` (the default), default localstatedir to `/var/local` +and sharedstatedir to `/var/local/lib`. diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 3f088b0..5a3c8d1 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -273,7 +273,7 @@ def sanitizer_compile_args(value): if value == 'none': return [] args = ['-fsanitize=' + value] - if value == 'address': + if 'address' in value: # For -fsanitize=address,undefined args.append('-fno-omit-frame-pointer') return args @@ -923,11 +923,15 @@ def get_largefile_args(compiler): def gnulike_default_include_dirs(compiler, lang): if lang == 'cpp': lang = 'c++' + env = os.environ.copy() + env["LC_ALL"] = 'C' + cmd = compiler + ['-x{}'.format(lang), '-E', '-v', '-'] p = subprocess.Popen( - compiler + ['-x{}'.format(lang), '-E', '-v', '-'], + cmd, stdin=subprocess.DEVNULL, stderr=subprocess.PIPE, - stdout=subprocess.PIPE + stdout=subprocess.PIPE, + env=env ) stderr = p.stderr.read().decode('utf-8') parse_state = 0 @@ -946,6 +950,8 @@ def gnulike_default_include_dirs(compiler, lang): break else: paths.append(line[1:]) + if len(paths) == 0: + mlog.warning('No include directory found parsing "{cmd}" output'.format(cmd=" ".join(cmd))) return paths class GnuCompiler: diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index cf5f077..e8b23fd 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -1,3 +1,4 @@ + # Copyright 2012-2017 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,9 +30,6 @@ class UserOption: self.choices = choices self.description = description - def parse_string(self, valuestring): - return valuestring - # Check that the input is a valid value and return the # "cleaned" or "native" version. For example the Boolean # option could take the string "true" and return True. @@ -72,13 +70,6 @@ class UserBooleanOption(UserOption): def set_value(self, newvalue): self.value = self.tobool(newvalue) - def parse_string(self, valuestring): - if valuestring == 'false': - return False - if valuestring == 'true': - return True - raise MesonException('Value "%s" for boolean option "%s" is not a boolean.' % (valuestring, self.name)) - def __bool__(self): return self.value @@ -109,9 +100,6 @@ class UserIntegerOption(UserOption): except: raise MesonException('Value string "%s" is not convertable to an integer.' % valuestring) - def parse_string(self, valuestring): - return self.toint(valuestring) - def validate_value(self, value): return self.toint(value) @@ -245,7 +233,7 @@ class CoreData: value = self.sanitize_dir_option_value(options.prefix, key, value) setattr(options, key, value) else: - value = get_builtin_option_default(key) + value = get_builtin_option_default(key, prefix=options.prefix) args = [key] + builtin_options[key][1:-1] + [value] self.builtins[key] = builtin_options[key][0](*args) @@ -321,11 +309,19 @@ def get_builtin_option_description(optname): else: raise RuntimeError('Tried to get the description for an unknown builtin option \'%s\'.' % optname) -def get_builtin_option_default(optname): +def get_builtin_option_default(optname, prefix='', noneIfSuppress=False): if is_builtin_option(optname): o = builtin_options[optname] if o[0] == UserComboOption: return o[3] + if optname in builtin_dir_noprefix_options: + if noneIfSuppress: + # Return None if argparse defaulting should be suppressed for + # this option (so we can determine the default later based on + # prefix) + return None + elif prefix in builtin_dir_noprefix_options[optname]: + return builtin_dir_noprefix_options[optname][prefix] return o[2] else: raise RuntimeError('Tried to get the default value for an unknown builtin option \'%s\'.' % optname) @@ -344,15 +340,6 @@ builtin_options = { 'mandir': [UserStringOption, 'Manual page directory.', 'share/man'], 'infodir': [UserStringOption, 'Info page directory.', 'share/info'], 'localedir': [UserStringOption, 'Locale data directory.', 'share/locale'], - # sysconfdir, localstatedir and sharedstatedir are a bit special. These defaults to ${prefix}/etc, - # ${prefix}/var and ${prefix}/com but nobody uses that. Instead they always set it - # manually to /etc, /var and /var/lib. This default values is thus pointless and not really used - # but we set it to this for consistency with other systems. - # - # Projects installing to sysconfdir, localstatedir or sharedstatedir probably want - # to set the following in project(): - # - # default_options : ['sysconfdir=/etc', 'localstatedir=/var', 'sharedstatedir=/var/lib'] 'sysconfdir': [UserStringOption, 'Sysconf data directory.', 'etc'], 'localstatedir': [UserStringOption, 'Localstate data directory.', 'var'], 'sharedstatedir': [UserStringOption, 'Architecture-independent data directory.', 'com'], @@ -365,8 +352,13 @@ builtin_options = { 'errorlogs': [UserBooleanOption, "Whether to print the logs from failing tests.", True], } -# Installation directories that can reside in a path outside of the prefix -builtin_dir_noprefix_options = {'sysconfdir', 'localstatedir', 'sharedstatedir'} +# Special prefix-dependent defaults for installation directories that reside in +# a path outside of the prefix in FHS and common usage. +builtin_dir_noprefix_options = { + 'sysconfdir': {'/usr': '/etc'}, + 'localstatedir': {'/usr': '/var', '/usr/local': '/var/local'}, + 'sharedstatedir': {'/usr': '/var/lib', '/usr/local': '/var/local/lib'}, +} forbidden_target_names = {'clean': None, 'clean-ctlist': None, diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py index 308ae55..257bf7a 100644 --- a/mesonbuild/dependencies/dev.py +++ b/mesonbuild/dependencies/dev.py @@ -16,6 +16,7 @@ # development purposes, such as testing, debugging, etc.. import os +import re import shlex import shutil @@ -116,19 +117,20 @@ class LLVMDependency(ExternalDependency): # Ordered list of llvm-config binaries to try. Start with base, then try # newest back to oldest (3.5 is abitrary), and finally the devel version. - # Please note that llvm-config-5.0 is a development snapshot and it should + # Please note that llvm-config-6.0 is a development snapshot and it should # not be moved to the beginning of the list. The only difference between - # llvm-config-5.0 and llvm-config-devel is that the former is used by + # llvm-config-6.0 and llvm-config-devel is that the former is used by # Debian and the latter is used by FreeBSD. llvm_config_bins = [ 'llvm-config', # base - 'llvm-config-4.0', 'llvm-config40', # latest stable release - 'llvm-config-3.9', 'llvm-config39', # old stable releases + 'llvm-config-5.0', 'llvm-config50', # latest stable release + 'llvm-config-4.0', 'llvm-config40', # old stable releases + 'llvm-config-3.9', 'llvm-config39', 'llvm-config-3.8', 'llvm-config38', 'llvm-config-3.7', 'llvm-config37', 'llvm-config-3.6', 'llvm-config36', 'llvm-config-3.5', 'llvm-config35', - 'llvm-config-5.0', 'llvm-config-devel', # development snapshot + 'llvm-config-6.0', 'llvm-config-devel', # development snapshot ] __cpp_blacklist = {'-DNDEBUG'} @@ -136,8 +138,10 @@ class LLVMDependency(ExternalDependency): # It's necessary for LLVM <= 3.8 to use the C++ linker. For 3.9 and 4.0 # the C linker works fine if only using the C API. super().__init__('llvm-config', environment, 'cpp', kwargs) - self.modules = [] + self.provided_modules = [] + self.required_modules = set() self.llvmconfig = None + self.static = kwargs.get('static', False) self.__best_found = None # FIXME: Support multiple version requirements ala PkgConfigDependency req_version = kwargs.get('version', None) @@ -169,31 +173,90 @@ class LLVMDependency(ExternalDependency): # for users who want the patch version. self.version = out.strip().rstrip('svn') - p, out = Popen_safe( - [self.llvmconfig, '--libs', '--ldflags'])[:2] + p, out, err = Popen_safe([self.llvmconfig, '--components']) if p.returncode != 0: - raise DependencyException('Could not generate libs for LLVM.') - self.link_args = strip_system_libdirs(environment, shlex.split(out)) - p, out = Popen_safe([self.llvmconfig, '--cppflags'])[:2] + raise DependencyException('Could not generate modules for LLVM:\n' + err) + self.provided_modules = shlex.split(out) + + modules = stringlistify(extract_as_list(kwargs, 'modules')) + self.check_components(modules) + opt_modules = stringlistify(extract_as_list(kwargs, 'optional_modules')) + self.check_components(opt_modules, required=False) + + p, out, err = Popen_safe([self.llvmconfig, '--cppflags']) if p.returncode != 0: - raise DependencyException('Could not generate includedir for LLVM.') + raise DependencyException('Could not generate includedir for LLVM:\n' + err) cargs = mesonlib.OrderedSet(shlex.split(out)) self.compile_args = list(cargs.difference(self.__cpp_blacklist)) - p, out = Popen_safe([self.llvmconfig, '--components'])[:2] + if version_compare(self.version, '>= 3.9'): + self._set_new_link_args() + else: + self._set_old_link_args() + self.link_args = strip_system_libdirs(environment, self.link_args) + + def _set_new_link_args(self): + """How to set linker args for LLVM versions >= 3.9""" + link_args = ['--link-static', '--system-libs'] if self.static else ['--link-shared'] + p, out, err = Popen_safe( + [self.llvmconfig, '--libs', '--ldflags'] + link_args + list(self.required_modules)) if p.returncode != 0: - raise DependencyException('Could not generate modules for LLVM.') - self.modules = shlex.split(out) + raise DependencyException('Could not generate libs for LLVM:\n' + err) + self.link_args = shlex.split(out) - modules = stringlistify(extract_as_list(kwargs, 'modules')) + def _set_old_link_args(self): + """Setting linker args for older versions of llvm. + + Old versions of LLVM bring an extra level of insanity with them. + llvm-config will provide the correct arguments for static linking, but + not for shared-linnking, we have to figure those out ourselves, because + of course we do. + """ + if self.static: + p, out, err = Popen_safe( + [self.llvmconfig, '--libs', '--ldflags', '--system-libs'] + list(self.required_modules)) + if p.returncode != 0: + raise DependencyException('Could not generate libs for LLVM:\n' + err) + self.link_args = shlex.split(out) + else: + # llvm-config will provide arguments for static linking, so we get + # to figure out for ourselves what to link with. We'll do that by + # checking in the directory provided by --libdir for a library + # called libLLVM-<ver>.(so|dylib|dll) + p, out, err = Popen_safe([self.llvmconfig, '--libdir']) + if p.returncode != 0: + raise DependencyException('Could not generate libs for LLVM:\n' + err) + libdir = out.strip() + + expected_name = 'libLLVM-{}'.format(self.version) + re_name = re.compile(r'{}.(so|dll|dylib)'.format(expected_name)) + + for file_ in os.listdir(libdir): + if re_name.match(file_): + self.link_args = ['-L{}'.format(libdir), + '-l{}'.format(os.path.splitext(file_.lstrip('lib'))[0])] + break + else: + raise DependencyException( + 'Could not find a dynamically linkable library for LLVM.') + + def check_components(self, modules, required=True): + """Check for llvm components (modules in meson terms). + + The required option is whether the module is required, not whether LLVM + is required. + """ for mod in sorted(set(modules)): - if mod not in self.modules: - mlog.log('LLVM module', mod, 'found:', mlog.red('NO')) - self.is_found = False - if self.required: - raise DependencyException( - 'Could not find required LLVM Component: {}'.format(mod)) + if mod not in self.provided_modules: + mlog.log('LLVM module', mod, 'found:', mlog.red('NO'), + '(optional)' if not required else '') + if required: + self.is_found = False + if self.required: + raise DependencyException( + 'Could not find required LLVM Component: {}'.format(mod)) else: + self.required_modules.add(mod) mlog.log('LLVM module', mod, 'found:', mlog.green('YES')) def check_llvmconfig(self, version_req): diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index e65675b..c807926 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -66,6 +66,11 @@ 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 = [] @@ -198,8 +203,6 @@ class BoostDependency(ExternalDependency): for c in candidates: if not isinstance(c, str): raise DependencyException('Boost module argument is not a string.') - if 'boost_' + c not in BOOST_LIBS: - raise DependencyException('Dependency {} not found. It is not a valid boost library.'.format(c)) return candidates def validate_requested(self): diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index a746cab..7f07c8d 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -349,10 +349,9 @@ class Environment: def is_cross_build(self): return self.cross_info is not None - def dump_coredata(self, mtime): + def dump_coredata(self): cdf = os.path.join(self.get_build_dir(), Environment.coredata_file) coredata.save(self.coredata, cdf) - os.utime(cdf, times=(mtime, mtime)) return cdf def get_script_dir(self): diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 28cb5ad..c7a0fb7 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -696,7 +696,8 @@ class CompilerHolder(InterpreterObject): if not isinstance(i, IncludeDirsHolder): raise InterpreterException('Include directories argument must be an include_directories object.') for idir in i.held_object.get_incdirs(): - idir = os.path.join(self.environment.get_source_dir(), idir) + idir = os.path.join(self.environment.get_source_dir(), + i.held_object.get_curdir(), idir) args += self.compiler.get_include_args(idir, False) if not nobuiltins: opts = self.environment.coredata.compiler_options @@ -1390,6 +1391,8 @@ class Interpreter(InterpreterBase): self.subproject_stack = [] self.default_project_options = default_project_options[:] # Passed from the outside, only used in subprojects. self.build_func_dict() + # build_def_files needs to be defined before parse_project is called + self.build_def_files = [os.path.join(self.subdir, environment.build_filename)] self.parse_project() self.builtin['build_machine'] = BuildMachine(self.coredata.compilers) if not self.build.environment.is_cross_build(): @@ -1405,7 +1408,6 @@ class Interpreter(InterpreterBase): self.builtin['target_machine'] = CrossMachineInfo(cross_info.config['target_machine']) else: self.builtin['target_machine'] = self.builtin['host_machine'] - self.build_def_files = [os.path.join(self.subdir, environment.build_filename)] def build_func_dict(self): self.funcs.update({'add_global_arguments': self.func_add_global_arguments, diff --git a/mesonbuild/mconf.py b/mesonbuild/mconf.py index ee4dbf8..09b0f12 100644 --- a/mesonbuild/mconf.py +++ b/mesonbuild/mconf.py @@ -17,7 +17,7 @@ import pickle import argparse from . import coredata, mesonlib -parser = argparse.ArgumentParser() +parser = argparse.ArgumentParser(prog='meson configure') parser.add_argument('-D', action='append', default=[], dest='sets', help='Set an option to the given value.') diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py index 45e6026..8d5fb85 100644 --- a/mesonbuild/mesonmain.py +++ b/mesonbuild/mesonmain.py @@ -24,7 +24,7 @@ from .mesonlib import MesonException from .wrap import WrapMode, wraptool -parser = argparse.ArgumentParser() +parser = argparse.ArgumentParser(prog='meson') default_warning = '1' @@ -37,7 +37,12 @@ def add_builtin_argument(name, **kwargs): h = h.rstrip('.') + ' (default: %s).' % coredata.get_builtin_option_default(k) if c and not b: kwargs['choices'] = c - parser.add_argument('--' + name, default=coredata.get_builtin_option_default(k), help=h, **kwargs) + default = coredata.get_builtin_option_default(k, noneIfSuppress=True) + if default is not None: + kwargs['default'] = default + else: + kwargs['default'] = argparse.SUPPRESS + parser.add_argument('--' + name, help=h, **kwargs) add_builtin_argument('prefix') add_builtin_argument('libdir') @@ -193,23 +198,19 @@ class MesonApp: mlog.log('Build machine cpu family:', mlog.bold(intr.builtin['build_machine'].cpu_family_method([], {}))) mlog.log('Build machine cpu:', mlog.bold(intr.builtin['build_machine'].cpu_method([], {}))) intr.run() - coredata_mtime = time.time() - g.generate(intr) - dumpfile = os.path.join(env.get_scratch_dir(), 'build.dat') - with open(dumpfile, 'wb') as f: - pickle.dump(b, f) - # Write this as late as possible since we use the existence of this - # file to check if we generated the build file successfully, so we - # don't want an error that pops up during generation, etc to cause us to - # incorrectly signal a successful meson run which will cause an error - # about an already-configured build directory when the user tries again. - # - # However, we set the mtime to an earlier value to ensure that doing an - # mtime comparison between the coredata dump and other build files - # shows the build files to be newer, not older. - cdf = env.dump_coredata(coredata_mtime) - # Post-conf scripts must be run after writing coredata or else introspection fails. try: + # We would like to write coredata as late as possible since we use the existence of + # this file to check if we generated the build file successfully. Since coredata + # includes settings, the build files must depend on it and appear newer. However, due + # to various kernel caches, we cannot guarantee that any time in Python is exactly in + # sync with the time that gets applied to any files. Thus, we dump this file as late as + # possible, but before build files, and if any error occurs, delete it. + cdf = env.dump_coredata() + g.generate(intr) + dumpfile = os.path.join(env.get_scratch_dir(), 'build.dat') + with open(dumpfile, 'wb') as f: + pickle.dump(b, f) + # Post-conf scripts must be run after writing coredata or else introspection fails. g.run_postconf_scripts() except: os.unlink(cdf) diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py index 7356175..568bdfc 100644 --- a/mesonbuild/mintro.py +++ b/mesonbuild/mintro.py @@ -25,7 +25,7 @@ import argparse import sys, os import pathlib -parser = argparse.ArgumentParser() +parser = argparse.ArgumentParser(prog='meson introspect') parser.add_argument('--targets', action='store_true', dest='list_targets', default=False, help='List top level targets.') parser.add_argument('--installed', action='store_true', dest='list_installed', default=False, @@ -104,6 +104,7 @@ def list_targets(coredata, builddata, installdata): t['install_filename'] = determine_installed_path(target, installdata) else: t['installed'] = False + t['build_by_default'] = target.build_by_default tlist.append(t) print(json.dumps(tlist)) diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index 4d20cc1..7e61242 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -723,7 +723,7 @@ This will become a hard error in the future.''') @permittedKwargs({'main_xml', 'main_sgml', 'src_dir', 'dependencies', 'install', 'install_dir', 'scan_args', 'scanobjs_args', 'gobject_typesfile', 'fixxref_args', 'html_args', 'html_assets', 'content_files', - 'mkdb_args', 'ignore_headers'}) + 'mkdb_args', 'ignore_headers', 'include_directories'}) def gtkdoc(self, state, args, kwargs): if len(args) != 1: raise MesonException('Gtkdoc must have one positional argument.') diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py index cba9fc3..267e130 100644 --- a/mesonbuild/mtest.py +++ b/mesonbuild/mtest.py @@ -58,7 +58,7 @@ def determine_worker_count(): num_workers = 1 return num_workers -parser = argparse.ArgumentParser() +parser = argparse.ArgumentParser(prog='meson test') parser.add_argument('--repeat', default=1, dest='repeat', type=int, help='Number of times to run the tests.') parser.add_argument('--no-rebuild', default=False, action='store_true', diff --git a/mesonbuild/optinterpreter.py b/mesonbuild/optinterpreter.py index 4b8e147..01dd036 100644 --- a/mesonbuild/optinterpreter.py +++ b/mesonbuild/optinterpreter.py @@ -180,5 +180,5 @@ class OptionInterpreter: if opt.description == '': opt.description = opt_name if opt_name in self.cmd_line_options: - opt.set_value(opt.parse_string(self.cmd_line_options[opt_name])) + opt.set_value(self.cmd_line_options[opt_name]) self.options[opt_name] = opt diff --git a/mesonbuild/rewriter.py b/mesonbuild/rewriter.py index b88c5ef..0191c30 100644 --- a/mesonbuild/rewriter.py +++ b/mesonbuild/rewriter.py @@ -29,7 +29,7 @@ from mesonbuild import mlog import sys, traceback import argparse -parser = argparse.ArgumentParser() +parser = argparse.ArgumentParser(prog='meson rewrite') parser.add_argument('--sourcedir', default='.', help='Path to source directory.') diff --git a/mesonbuild/scripts/gtkdochelper.py b/mesonbuild/scripts/gtkdochelper.py index 45ed96b..4406b28 100644 --- a/mesonbuild/scripts/gtkdochelper.py +++ b/mesonbuild/scripts/gtkdochelper.py @@ -112,7 +112,8 @@ def build_gtkdoc(source_root, build_root, doc_subdir, src_subdirs, scanobjs_cmd = ['gtkdoc-scangobj'] + scanobjs_args + ['--types=' + gobject_typesfile, '--module=' + module, '--cflags=' + cflags, - '--ldflags=' + ldflags] + '--ldflags=' + ldflags, + '--ld=' + ld] gtkdoc_run_check(scanobjs_cmd, abs_out) diff --git a/mesonbuild/scripts/meson_install.py b/mesonbuild/scripts/meson_install.py index 985b0e9..9485967 100644 --- a/mesonbuild/scripts/meson_install.py +++ b/mesonbuild/scripts/meson_install.py @@ -20,7 +20,7 @@ from . import destdir_join from ..mesonlib import is_windows, Popen_safe install_log_file = None -use_selinux = True +selinux_updates = [] class DirMaker: def __init__(self): @@ -84,27 +84,24 @@ def set_mode(path, mode): msg = '{!r}: Unable to set permissions {!r}: {}, ignoring...' print(msg.format(path, mode.perms_s, e.strerror)) -def restore_selinux_context(to_file): +def restore_selinux_contexts(): ''' - Restores the SELinux context for @to_file + Restores the SELinux context for files in @selinux_updates ''' - global use_selinux - - if not use_selinux: - return - try: subprocess.check_call(['selinuxenabled']) - try: - subprocess.check_call(['restorecon', '-F', to_file], stderr=subprocess.DEVNULL) - except subprocess.CalledProcessError as e: - use_selinux = False - msg = "{!r}: Failed to restore SELinux context, ignoring SELinux context for all remaining files..." - print(msg.format(to_file, e.returncode)) except (FileNotFoundError, PermissionError, subprocess.CalledProcessError) as e: # If we don't have selinux or selinuxenabled returned 1, failure # is ignored quietly. - use_selinux = False + return + + with subprocess.Popen(['restorecon', '-F', '-f-', '-0'], + stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as proc: + out, err = proc.communicate(input=b'\0'.join(os.fsencode(f) for f in selinux_updates) + b'\0') + if proc.returncode != 0: + print('Failed to restore SELinux context of installed files...', + 'Standard output:', out.decode(), + 'Standard error:', err.decode(), sep='\n') def append_to_log(line): install_log_file.write(line) @@ -126,7 +123,7 @@ def do_copyfile(from_file, to_file): os.unlink(to_file) shutil.copyfile(from_file, to_file) shutil.copystat(from_file, to_file) - restore_selinux_context(to_file) + selinux_updates.append(to_file) append_to_log(to_file) def do_copydir(data, src_prefix, src_dir, dst_dir, exclude): @@ -192,6 +189,7 @@ def do_install(datafilename): install_headers(d) install_man(d) install_data(d) + restore_selinux_contexts() run_install_script(d) def install_subdirs(d): diff --git a/run_unittests.py b/run_unittests.py index fa8f049..ce1bf06 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -1,3 +1,4 @@ + #!/usr/bin/env python3 # Copyright 2016-2017 The Meson development team @@ -490,7 +491,10 @@ class BasePlatformTests(unittest.TestCase): print(f.read()) def tearDown(self): - windows_proof_rmtree(self.builddir) + try: + windows_proof_rmtree(self.builddir) + except FileNotFoundError: + pass os.environ = self.orig_env super().tearDown() @@ -739,6 +743,49 @@ class AllPlatformTests(BasePlatformTests): self.init(testdir) self.assertRaises(subprocess.CalledProcessError, self.setconf, '-Dlibdir=/opt', False) + def test_prefix_dependent_defaults(self): + ''' + Tests that configured directory paths are set to prefix dependent + defaults. + ''' + testdir = os.path.join(self.common_test_dir, '1 trivial') + expected = { + '/opt': {'prefix': '/opt', + 'bindir': 'bin', 'datadir': 'share', 'includedir': 'include', + 'infodir': 'share/info', + 'libexecdir': 'libexec', 'localedir': 'share/locale', + 'localstatedir': 'var', 'mandir': 'share/man', + 'sbindir': 'sbin', 'sharedstatedir': 'com', + 'sysconfdir': 'etc'}, + '/usr': {'prefix': '/usr', + 'bindir': 'bin', 'datadir': 'share', 'includedir': 'include', + 'infodir': 'share/info', + 'libexecdir': 'libexec', 'localedir': 'share/locale', + 'localstatedir': '/var', 'mandir': 'share/man', + 'sbindir': 'sbin', 'sharedstatedir': '/var/lib', + 'sysconfdir': '/etc'}, + '/usr/local': {'prefix': '/usr/local', + 'bindir': 'bin', 'datadir': 'share', + 'includedir': 'include', 'infodir': 'share/info', + 'libexecdir': 'libexec', + 'localedir': 'share/locale', + 'localstatedir': '/var/local', 'mandir': 'share/man', + 'sbindir': 'sbin', 'sharedstatedir': '/var/local/lib', + 'sysconfdir': 'etc'}, + # N.B. We don't check 'libdir' as it's platform dependent, see + # default_libdir(): + } + for prefix in expected: + args = ['--prefix', prefix] + self.init(testdir, args, default_args=False) + opts = self.introspect('--buildoptions') + for opt in opts: + name = opt['name'] + value = opt['value'] + if name in expected[prefix]: + self.assertEqual(value, expected[prefix][name]) + self.wipe() + def test_static_library_overwrite(self): ''' Tests that static libraries are never appended to, always overwritten. diff --git a/test cases/common/163 includedir subproj/meson.build b/test cases/common/163 includedir subproj/meson.build new file mode 100644 index 0000000..b3de5af --- /dev/null +++ b/test cases/common/163 includedir subproj/meson.build @@ -0,0 +1,9 @@ +project('include dir in subproj test', 'c') + + +subproject('inctest') + + +exe = executable('prog', 'prog.c') + +test('dummy', exe) diff --git a/test cases/common/163 includedir subproj/prog.c b/test cases/common/163 includedir subproj/prog.c new file mode 100644 index 0000000..772681e --- /dev/null +++ b/test cases/common/163 includedir subproj/prog.c @@ -0,0 +1,4 @@ + +int main(int argc, char **argv) { + return 0; +} diff --git a/test cases/common/163 includedir subproj/subprojects/inctest/include/incfile.h b/test cases/common/163 includedir subproj/subprojects/inctest/include/incfile.h new file mode 100644 index 0000000..ec740da --- /dev/null +++ b/test cases/common/163 includedir subproj/subprojects/inctest/include/incfile.h @@ -0,0 +1,2 @@ + +/* file which is used in the subproject */ diff --git a/test cases/common/163 includedir subproj/subprojects/inctest/meson.build b/test cases/common/163 includedir subproj/subprojects/inctest/meson.build new file mode 100644 index 0000000..74aabcb --- /dev/null +++ b/test cases/common/163 includedir subproj/subprojects/inctest/meson.build @@ -0,0 +1,13 @@ + +project('subproj with includedir', 'c') + + + +compile_check = ''' +#include "incfile.h" +''' + +if not meson.get_compiler('c').compiles(compile_check, name : 'include in subproj', + include_directories: include_directories('include')) + error('failed') +endif diff --git a/test cases/frameworks/15 llvm/meson.build b/test cases/frameworks/15 llvm/meson.build index 468094a..5211006 100644 --- a/test cases/frameworks/15 llvm/meson.build +++ b/test cases/frameworks/15 llvm/meson.build @@ -1,21 +1,36 @@ project('llvmtest', ['c', 'cpp'], default_options : ['c_std=c99']) -llvm_dep = dependency( - 'llvm', - modules : ['bitwriter', 'asmprinter', 'executionengine', 'target', - 'mcjit', 'nativecodegen'], - required : true, -) - d = dependency('llvm', modules : 'not-found', required : false) assert(d.found() == false, 'not-found llvm module found') d = dependency('llvm', version : '<0.1', required : false) assert(d.found() == false, 'ancient llvm module found') -executable('sum', 'sum.c', dependencies : [ - llvm_dep, - dependency('zlib'), - meson.get_compiler('c').find_library('dl', required : false), - dependency('tinfo'), - ]) +d = dependency('llvm', optional_modules : 'not-found', required : false) +assert(d.found() == true, 'optional module stopped llvm from being found.') + +dep_tinfo = dependency('tinfo', required : false) +if not dep_tinfo.found() + cpp = meson.get_compiler('cpp') + dep_tinfo = cpp.find_library('tinfo') +endif + +foreach static : [true, false] + llvm_dep = dependency( + 'llvm', + modules : ['bitwriter', 'asmprinter', 'executionengine', 'target', + 'mcjit', 'nativecodegen'], + required : true, + static : static, + ) + name = static ? 'static' : 'dynamic' + executable( + 'sum-@0@'.format(name), + 'sum.c', + dependencies : [ + llvm_dep, dep_tinfo, + dependency('zlib'), + meson.get_compiler('c').find_library('dl', required : false), + ] + ) +endforeach |