diff options
107 files changed, 6333 insertions, 0 deletions
diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..61d2e05 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,16 @@ +# Building the documentation + +1. Get [hotdoc](https://hotdoc.github.io/installing.html) (0.8.9 required) +1. Run hotdoc: + + hotdoc run + +## Upload + +We are using the git-upload hotdoc plugin which basically +removes the html pages and replaces with the new content. + +You can simply run: + + hotdoc run --git-upload-activate + diff --git a/docs/hotdoc.json b/docs/hotdoc.json new file mode 100644 index 0000000..c9f6972 --- /dev/null +++ b/docs/hotdoc.json @@ -0,0 +1,16 @@ +{ + "extra_assets": [ + "images/" + ], + "html_extra_theme": "theme/extra/", + "include_paths": [ + "markdown/" + ], + "output": "built_docs/", + "project_name": "Meson documentation", + "project_version": "1.0", + "default-license": "CC-BY-SAv4.0", + "sitemap": "sitemap.txt", + "git_upload_repository": "git@github.com:thiblahute/jpakkane.github.io.git", + "edit_on_github_repository": "https://github.com/mesonbuild/meson/" +} diff --git a/docs/images/buildtime.png b/docs/images/buildtime.png Binary files differnew file mode 100644 index 0000000..2a44422 --- /dev/null +++ b/docs/images/buildtime.png diff --git a/docs/images/conftime.png b/docs/images/conftime.png Binary files differnew file mode 100644 index 0000000..63754db --- /dev/null +++ b/docs/images/conftime.png diff --git a/docs/images/emptytime.png b/docs/images/emptytime.png Binary files differnew file mode 100644 index 0000000..d80eab9 --- /dev/null +++ b/docs/images/emptytime.png diff --git a/docs/images/glib_build.png b/docs/images/glib_build.png Binary files differnew file mode 100644 index 0000000..ddb9947 --- /dev/null +++ b/docs/images/glib_build.png diff --git a/docs/images/glib_conf.png b/docs/images/glib_conf.png Binary files differnew file mode 100644 index 0000000..5de60d5 --- /dev/null +++ b/docs/images/glib_conf.png diff --git a/docs/images/glib_empty.png b/docs/images/glib_empty.png Binary files differnew file mode 100644 index 0000000..5976e7f --- /dev/null +++ b/docs/images/glib_empty.png diff --git a/docs/images/glib_link.png b/docs/images/glib_link.png Binary files differnew file mode 100644 index 0000000..23d9044 --- /dev/null +++ b/docs/images/glib_link.png diff --git a/docs/images/gtksample.png b/docs/images/gtksample.png Binary files differnew file mode 100644 index 0000000..1784b77 --- /dev/null +++ b/docs/images/gtksample.png diff --git a/docs/markdown/ARM-performance-test.md b/docs/markdown/ARM-performance-test.md new file mode 100644 index 0000000..7e42fb3 --- /dev/null +++ b/docs/markdown/ARM-performance-test.md @@ -0,0 +1,37 @@ +# Arm performance test + +Performance differences in build systems become more apparent on slower platforms. To examine this difference we compared the performance of Meson with GNU Autotools. We took the GLib software project and rewrote its build setup with Meson. GLib was chosen because it is a relatively large C code base which requires lots of low level configuration. + +The Meson version of the build system is not fully equivalent to the original Autotools one. It does not do all the same configuration steps and does not build all the same targets. The biggest missing piece being internationalisation support with Gettext. However it does configure the system enough to build all C source and run all unit tests. + +All measurements were done on a Nexus 4 smart phone running the latest Ubuntu touch image (updated on September 9th 2013). + +Measurements +------ + +The first thing we measured was the time it took to run the configure step. + +![GLib config time](images/glib_conf.png) + +Meson takes roughly 20 seconds whereas Autotools takes 220. This is a difference of one order of magnitude. Autotools' time contains both autogen and configure. Again it should be remembered that Meson does not do all the configure steps that Autotools does. It does do about 90% of them and it takes just 10% of the time to do it. + +Then we measured the build times. Two parallel compilation processes were used for both systems. + +![GLib build time](images/glib_build.png) + +On desktop machines Ninja based build systems are 10-20% faster than Make based ones. On this platform the difference grows to 50%. The difference is probably caused by Make's inefficient disk access patterns. Ninja is better at keeping both cores running all the time which yields impressive performance improvements. + +![GLib no-op time](images/glib_empty.png) + +Next we measured the "empty build" case. That is, how long does it take for the build system to detect that no changes need to be made. This is one of the most important metrics of build systems because it places a hard limit on how fast you can iterate on your code. Autotools takes 14 seconds to determine that no work needs to be done. Meson (or, rather, Ninja) takes just one quarter of a second. + +![GLib link time](images/glib_link.png) + +One step which takes quite a lot of time is linking. A common case is that you are working on a library and there are tens of small test executables that link to it. Even if the compilation step would be fast, relinking all of the test executables takes time. It is common for people to manually compile only one test application with a command such as `make sometest` rather than rebuild everything. + +Meson has an optimization for this case. Whenever a library is rebuilt, Meson inspects the ABI it exports. If it has not changed, Meson will skip all relinking steps as unnecessary. The difference this makes can be clearly seen in the chart above. In that test the source was fully built, then the file `glib/gbytes.c` was touched to force the rebuild of the base glib shared library. As can be seen, Autotools then relinks all test executables that link with glib. Since Meson can detect that the ABI is the same it can skip those steps. The end result being that Meson is almost one hundred times faster on this very common use case. + +Conclusions +----- + +One of the main drawbacks of C and C++ compared to languages such as Java are long compilation times. However at least some of the blame can be found in the build tools used rather than the languages themselves or their compilers. Choosing proper tools can bring C and C++ compilation very close to instantaneous rebuilds. This has a direct impact on programmer productivity. diff --git a/docs/markdown/Adding-arguments.md b/docs/markdown/Adding-arguments.md new file mode 100644 index 0000000..80f02d9 --- /dev/null +++ b/docs/markdown/Adding-arguments.md @@ -0,0 +1,35 @@ +# Adding arguments + +Often you need to specify extra compiler arguments. Meson provides two different ways to achieve this: global arguments and per-target arguments. + +Global arguments +-- + +Global compiler arguments are set with the following command. As an example you could do this. + +```meson +add_global_arguments('-DFOO=bar', language : 'c') +``` + +This makes Meson add the define to all C compilations. Usually you would use this setting for flags for global settings. Note that for setting the C/C++ language standard (the `-std=c99` argument in Gcc), you would probably want to use a default option of the `project()` function. For details see the [reference manual](Reference manual). + +Global arguments have certain limitations. They all have to be defined before any build targets are specified. This ensures that the global flags are the same for every single source file built in the entire project with one exception. Compilation tests that are run as part of your project configuration do not use these flags. The reason for that is that you may need to run a test compile with and without a given flag to determine your build setup. For this reason tests do not use these global arguments. + +You should set only the most essential flags with this setting, you should *not* set debug or optimization flags. Instead they should be specified by selecting an appropriate build type. + +Per target arguments +-- + +Per target arguments are just as simple to define. + +```meson +executable('prog', 'prog.cc', cpp_args : '-DCPPTHING') +``` + +Here we create a C++ executable with an extra argument that is used during compilation but not for linking. + +Specifying extra linker arguments is done in the same way: + +```meson +executable('prog', 'prog.cc', link_args : '-Wl,--linker-option') +``` diff --git a/docs/markdown/Adding-new-projects-to-wrapdb.md b/docs/markdown/Adding-new-projects-to-wrapdb.md new file mode 100644 index 0000000..ceaa51f --- /dev/null +++ b/docs/markdown/Adding-new-projects-to-wrapdb.md @@ -0,0 +1,74 @@ +# Adding new projects to wrap + +**If you don't have permissions to do something on this page, please open issue against https://github.com/mesonbuild/wrapweb/issues to let us know that you want to start new project.** + +## Overview + +The wrap provider service is a simple web service that makes it easy to download build definitions for projects. It works in much the same way as Debian: we take the unaltered upstream source package and add a new build system to it as a patch. These build systems are stored as Git repositories on Github. They only contain build definition files. You may also think of them as an overlay to upstream source. + +## Creator script + +The WrapDB repository has a [helper script](https://github.com/mesonbuild/wrapweb/blob/master/tools/repoinit.py) to generate new repositories. The documentation below roughly explains what it does using plain shell commands. + +## Choosing the repository name + +Wrapped subprojects are used much like external dependencies. Thus they should have the same name as the upstream projects. If the project provides a pkg-config file, then the repository name should be the same as the pkg-config name. Usually this is the name of the project, such as `libpng`. Sometimes it is slightly different, however. As an example the libogg project's chosen pkg-config name is `ogg` instead of `libogg`, which is the reason why the repository is named plain `ogg`. + +## Adding new project to the Wrap provider service + +Each project gets its own repo. It is initialised like this: + + git init + git add readme.txt + git commit -a -m 'Start of project foobar.' + git tag commit_zero -a -m 'A tag that helps get revision ids for releases.' + git remote add origin <repo url> + git push -u origin master + git push --tags + +Note that this is the *only* commit that will ever be made to master branch. All other commits are done to branches. + +Repo names must fully match this regexp: `[a-z0-9._]+`. + +## Adding a new branch to an existing project + +Create a new branch whose name matches the upstream release number. + + git checkout master + git checkout -b 1.0.0 + git push origin 1.0.0 + (or from Github web page, remember to branch from master) + +Branch names must fully match this regexp: `[a-z0-9._]+`. + +## Adding a new release to an existing branch + +Here is where the magic happens. Whenever a new commit is pushed into Github's project branch, a new wrap is generated with an incremented version number. All the old releases remain unaltered. New commits are always done via Github merge requests and must be reviewed by someone other than the submitter. + +Note that your Git repo must *not* contain the subdirectory of the source release. That gets added automatically by the service. You also must *not* commit any source code from the original tarball into the wrap repository. + +First you need to fork the repository to your own page. Then you can create the first Wrap commit that usually looks something like this. + + tar xzf libfoo_1.0.0.tar.gz + git clone -b 1.0.0 git@github.com:yourusername/libfoo.git tmpdir + mv tmpdir/.git libfoo-1.0.0 + rm -rf tmpdir + cd libfoo-1.0.0 + git reset --hard + emacs upstream.wrap meson.build + <verify that your project builds and runs> + git add upstream.wrap meson.build + git commit -a -m 'Created wrap files for libfoo-1.0.0.' + git push origin 1.0.0 + +Now you can file a merge request. Remember to file it against branch 1.0.0 rather than master. Github should do this automatically. + +## Changes to original source + +The point of a wrap is to provide the upstream project with as few changes as possible. Most projects should not contain anything more than a few Meson definition files. Sometimes it may be necessary to add a template header file or something similar. These should be held at a minimum. + +It should especially be noted that there must **not** be any patches to functionality. All such changes must be submitted to upstream. You may also host your own Git repo with the changes if you wish. The Wrap system has native support for Git subprojects. + +## Reviewing wraps + +See [Wrap review guidelines](Wrap-review-guidelines.md). diff --git a/docs/markdown/Additionnal.md b/docs/markdown/Additionnal.md new file mode 100644 index 0000000..2fff488 --- /dev/null +++ b/docs/markdown/Additionnal.md @@ -0,0 +1,8 @@ +--- +short-description: Misc documentation +... + +# Additional documentation + +This section references documents miscellaneous design, benchmarks, or +basically anything concerning Meson. diff --git a/docs/markdown/Build-options.md b/docs/markdown/Build-options.md new file mode 100644 index 0000000..64e2d38 --- /dev/null +++ b/docs/markdown/Build-options.md @@ -0,0 +1,31 @@ +# Build options + +Most non-trivial builds require user-settable options. As an example a program may have two different data backends that are selectable at build time. Meson provides for this by having a option definition file. Its name is `meson_options.txt` and it is placed at the root of your source tree. + +Here is a simple option file. + +```meson +option('someoption', type : 'string', value : 'optval', description : 'An option') +option('other_one', type : 'boolean', value : false) +option('combo_opt', type : 'combo', choices : ['one', 'two', 'three'], value : 'three') +``` + +This demonstrates the three basic option types and their usage. String option is just a free form string and a boolean option is, unsurprisingly, true or false. The combo option can have any value from the strings listed in argument `choices`. If `value` is not set, it defaults to empty string for strings, `true` for booleans or the first element in a combo. You can specify `description`, which is a free form piece of text describing the option. It defaults to option name. + +These options are accessed in Meson code with the `get_option` function. + +```meson +optval = get_option('opt_name') +``` + +This function also allows you to query the value of Meson's built-in project options. For example, to get the installation prefix you would issue the following command: + +```meson +prefix = get_option('prefix') +``` + +It should be noted that you can not set option values in your Meson scripts. They have to be set externally with the `mesonconf` command line tool. Running `mesonconf` without arguments in a build dir shows you all options you can set. To change their values use the `-D` option: + +```console +$ mesonconf -Doption=newvalue +``` diff --git a/docs/markdown/Build-system-converters.md b/docs/markdown/Build-system-converters.md new file mode 100644 index 0000000..f4ee501 --- /dev/null +++ b/docs/markdown/Build-system-converters.md @@ -0,0 +1,9 @@ +# Build system converters + +Moving from one build system into another includes a fair bit of work. To make things easier, Meson provides scripts to convert other build systems into Meson. At the time of writing, scripts for CMake and autotools exist. It can be found in the `tools` subdirectory in Meson's source tree. + +The scripts do not try to do a perfect conversion. This would be extremely difficult because the data models of other build systems are very different. The goal of the converter script is to convert as much of the low level drudgery as possible. Using the scripts is straightforward. We'll use the CMake one as an example but the Autotools one works exactly the same way. + + cmake2meson.py path/to/CMake/project/root + +This command generates a skeleton Meson project definition that tries to mirror CMake's setup as close as possible. Once this is done, you need to go through these files manually and finalise the conversion. To make this task as simple as possible, the converter script will transfer all comments from the CMake definition into Meson definition. diff --git a/docs/markdown/Build-targets.md b/docs/markdown/Build-targets.md new file mode 100644 index 0000000..b30e33d --- /dev/null +++ b/docs/markdown/Build-targets.md @@ -0,0 +1,61 @@ +--- +short-description: Definition of build targets +... + +# Build targets + +Meson provides three kinds of build targets: executables, static libraries and shared libraries. They are created with the commands `executable`, `static_library` and `shared_library`, respectively. All objects created in this way are **immutable**. That is, you can not change any aspect of them after they have been constructed. This ensures that all information pertaining to a given build target is specified in one well defined place. + +As an example, here is how you would build a shared library. + +```meson +project('shared lib', 'c') +shared_library('mylib', 'source.c') +``` + +In unix-like operating systems, shared libraries can be versioned. Meson supports this with keyword arguments. + +```meson +project('shared lib', 'c') +shared_library('mylib', 'source.c', version : '1.2.3', soversion : '0') +``` + +It is common to build a library and then an executable that links against it. This is supported as well. + +```meson +project('shared lib', 'c') +lib = shared_library('mylib', 'source.c') +executable('program', 'prog.c', link_with : lib) +``` + +Meson sets things up so that the resulting executable can be run directly from the build directory. There is no need to write shell scripts or set environment variables. + +One target can have multiple language source files. + +```meson +project('multilang', 'c', 'cpp') +executable('multiexe', 'file.c', 'file2.cc') +``` + +Object files +-- + +Sometimes you can't build files from sources but need to utilize an existing object file. A typical case is using an object file provided by a third party. Object files can be specified just like sources. + +```meson +exe = executable('myexe', 'source.cpp', objects : 'third_party_object.o') +``` + +A different case is when you want to use object files built in one target directly in another. A typical case is when you build a shared library and it has an internal class that is not exported in the ABI. This means you can't access it even if you link against the library. Typical workarounds for this include building both a shared and static version of the library or putting the source file in the test executable's source list. Both of these approaches cause the source to be built twice, which is slow. + +In Meson you can extract object files from targets and use them as-is on other targets. This is the syntax for it. + +```meson +lib = shared_library('somelib', 'internalclass.cc', 'file.cc', ...) +eo = lib.extract_objects('internalclass.cc') +executable('classtest', 'classtest.cpp', objects : eo) +``` + +Here we take the internal class object and use it directly in the test. The source file is only compiled once. + +Note that careless use of this feature may cause strange bugs. As an example trying to use objects of an executable or static library in a shared library will not work because shared library objects require special compiler flags. Getting this right is the user's responsibility. For this reason it is strongly recommended that you only use this feature for generating unit test executables in the manner described above. diff --git a/docs/markdown/Comparisons.md b/docs/markdown/Comparisons.md new file mode 100644 index 0000000..ede3cf9 --- /dev/null +++ b/docs/markdown/Comparisons.md @@ -0,0 +1,57 @@ +--- +title: Comparisions +... + +# Comparing Meson with other build systems # + +A common question is *Why should I choose Meson over a different build system X?* There is no one true answer to this as it depends on the use case. Almost all build systems have all the functionality needed to build medium-to-large projects so the decision is usually made on other points. Here we list some pros and cons of various build systems to help you do the decision yourself. + +## GNU Autotools ## + +### Pros ### + +Excellent support for legacy Unix platforms, large selection of existing modules. + +### Cons ### + +Needlessly slow, complicated, hard to use correctly, unreliable, painful to debug, ununderstandable for most people, poor support for non-Unix platforms (especially Windows). + +## CMake ## + +### Pros ### + +Great support for multiple backends (Visual Studio, XCode, etc). + +### Cons ### + +The scripting language is cumbersome to work with. Some simple things are more complicated than necessary. + +## SCons ## + +### Pros ### + +Full power of Python available for defining your build. + +### Cons ### + +Slow. Requires you to pass your configuration settings on every invocation. That is, if you do `scons OPT1 OPT2` and then just `scons`, it will reconfigure everything without settings `OPT1` and `OPT2`. Every other build system remembers build options from the previous invocation. + +## Bazel + +# Pros + +Proven to scale to very large projects. + +## Cons + +Implemented in Java. Poor Windows support. Heavily focused on Google's way of doing things (which may be a good or a bad thing). Contributing code requires [signing a CLA](https://bazel.build/contributing.html). + +## Meson ## + +### Pros ### + +The fastest build system [see measurements](Performance comparison), user friendly, designed to be as invisible to the developer as possible, native support for modern tools (precompiled headers, coverage, Valgrind etc). Not Turing complete so build definition files are easy to read and understand. + +### Cons ### + +Relatively new so it does not have a large user base yet, and may thus contain some unknown bugs. Visual Studio and XCode backends not as high quality as Ninja one. diff --git a/docs/markdown/Compiler-properties.md b/docs/markdown/Compiler-properties.md new file mode 100644 index 0000000..9d533cd --- /dev/null +++ b/docs/markdown/Compiler-properties.md @@ -0,0 +1,179 @@ +# Compiler properties + +Not all compilers and platforms are alike. Therefore Meson provides the tools to detect properties of the system during configure time. To get most of this information, you first need to extract the *compiler object* from the main *meson* variable. + +```meson +compiler = meson.get_compiler('c') +``` + +Here we extract the C compiler. We could also have given the argument `cpp` to get the C++ compiler, `objc` to get the objective C compiler and so on. The call is valid for all languages specified in the *project* declaration. Trying to obtain some other compiler will lead to an unrecoverable error. + +## System information + +This is a bit complex and more throughly explained on the page on [cross compilation](Cross compilation). But if you just want to know the operating system your code will run on, issue this command: + +```meson +host_machine.system() +``` + +Compiler id +== + +The compiler object has a method called `get_id`, which returns a lower case string describing the "family" of the compiler. It has one of the following values. + +| Value | Compiler family | +| ----- | ---------------- | +| gcc | The GNU Compiler Collection | +| clang | The Clang compiler | +| msvc | Microsoft Visual Studio | +| intel | Intel compiler | +| pathscale | The Pathscale Fortran compiler | +| pgi | The Portland Fortran compiler | +| sun | Sun Fortran compiler | +| g95 | The G95 Fortran compiler | +| open64 | The Open64 Fortran Compiler | +| nagfor | The NAG Fortran compiler | + +Does code compile? +== + +Sometimes the only way to test the system is to try to compile some sample code and see if it works. This is a two-phase operation. First we define some code using the multiline string operator: + +```meson +code = '''#include<stdio.h> +void func() { printf("Compile me.\n"); } +''' +``` + +Then we can run the test. + +```meson +result = compiler.compiles(code, name : 'basic check') +``` + +The variable *result* will now contain either `true` or `false` depending on whether the compilation succeeded or not. The keyword argument `name` is optional. If it is specified, Meson will write the result of the check to its log. + +Does code compile and link? +== + +Sometimes it is necessary to check whether a certain code fragment not only +compiles, but also links successfully, e.g. to check if a symbol is actually +present in a library. This can be done using the '''.links()''' method on a +compiler object like this: + +```meson +code = '''#include<stdio.h> +void func() { printf("Compile me.\n"); } +''' +``` + +Then we can run the test. + +```meson +result = compiler.links(code, args : '-lfoo', name : 'link check') +``` + +The variable *result* will now contain either `true` or `false` +depending on whether the compilation and linking succeeded or not. The keyword +argument `name` is optional. If it is specified, Meson will write the +result of the check to its log. + + +Compile and run test application +== + +Here is how you would compile and run a small test application. + +```meson +code = '''#include<stdio.h> +int main(int argc, char **argv) { + printf("%s\n", "stdout"); + fprintf(stderr, "%s\n", "stderr"); + return 0; +} +''' +result = compiler.run(code, name : 'basic check') +``` + +The `result` variable encapsulates the state of the test, which can be extracted with the following methods. The `name` keyword argument works the same as with `compiles`. + +Method | Return value +-------|---------------- +compiled | `True` if compilation succeeded. If `false` then all other methods return undefined values. +returncode | The return code of the application as an integer +stdout | Program's standard out as text. +stderr | Program's standard error as text. + +Here is an example usage: + +```meson +if result.stdout().strip() == 'some_value' + # do something +endif +``` + + +Does a header exist? +== + +Header files provided by different platforms vary quite a lot. Meson has functionality to detect whether a given header file is available on the system. The test is done by trying to compile a simple test program that includes the specified header. The following snippet describes how this feature can be used. + +```meson +if compiler.has_header('sys/fstat.h') + # header exists, do something +endif +``` + +Expression size +== + +Often you need to determine the size of a particular element (such as `int`, `wchar_t` or `char*`). Using the `compiler` variable mentioned above, the check can be done like this. + +```meson +wcharsize = compiler.sizeof('wchar_t', prefix : '#include<wchar.h>') +``` + +This will put the size of `wchar_t` as reported by sizeof into variable `wcharsize`. The keyword argument `prefix` is optional. If specified its contents is put at the top of the source file. This argument is typically used for setting `#include` directives in configuration files. + +In older versions (<= 0.30) meson would error out if the size could not be determined. Since version 0.31 it returns -1 if the size could not be determined. + +Does a function exist? +== + +Just having a header does say anything about its contents. Sometimes you need to explicitly check if some function exists. This is how we would check whether the function `somefunc` exists in header `someheader.h` + +```meson +if compiler.has_function('somefunc', prefix : '#include<someheader.h>') + # function exists, do whatever is required. +endif +``` + +Does a structure contain a member? +== + +Some platforms have different standard structures. Here's how one would check if a struct called `mystruct` from header `myheader.h</hh> contains a member called `some_member`. + +```meson +if compiler.has_member('struct mystruct', 'some_member', prefix : '#include<myheader.h>') + # member exists, do whatever is required +endif +``` + +Type alignment +== + +Most platforms can't access some data types at any address. For example it is common that a `char` can be at any address but a 32 bit integer only at locations which are divisible by four. Determining the alignment of data types is simple. + +```meson +int_alignment = compiler.alignment('int') # Will most likely contain the value 4. +``` + +## Has argument + +This method tests if the compiler supports a given command line argument. This is implemented by compiling a small file with the given argument. + +```meson +has_special_flags = compiler.has_argument('-Wspecialthing') +``` + +*Note*: some compilers silently swallow command line arguments they do not understand. Thus this test can not be made 100% reliable. diff --git a/docs/markdown/Conference-presentations.md b/docs/markdown/Conference-presentations.md new file mode 100644 index 0000000..b6e725b --- /dev/null +++ b/docs/markdown/Conference-presentations.md @@ -0,0 +1,17 @@ +# Conference presentations on Meson + +- Fosdem 2014, [Introducing the Meson build system](http://video.fosdem.org/2014/H2215_Ferrer/Sunday/Introducing_the_Meson_build_system.webm) (jpakkane) + +- LCA 2015, [Making build systems not suck](https://www.youtube.com/watch?v=KPi0AuVpxLI) (jpakkane) + +- Guadec 2015, [Improving the way Gnome apps are built](https://www.youtube.com/watch?v=wTf0NjjNwTU) (jpakkane) + +- GStreamer conference 2015, [Done in 6.0 seconds](https://gstconf.ubicast.tv/videos/done-in-60-seconds-a-new-build-system-for-gstreamer) (jpakkane) + +- LCA 2016, [Builds, dependencies and deployment in the modern multiplatform world](https://www.youtube.com/watch?v=CTJtKtQ8R5k&feature=youtu.be) (jpakkane) + +- Guadec 2016, [Making your GNOME app compile 2.4x faster](https://media.ccc.de/v/44-making_your_gnome_app_compile_24x_faster) (nirbheek) + +- Libre Application Summit 2016, [New world, new tools](https://youtu.be/0-gx1qU2pPo) (jpakkane) + +- Gstreamer conference 2016, [GStreamer Development on Windows and faster builds everywhere with Meson](https://gstconf.ubicast.tv/videos/gstreamer-development-on-windows-ans-faster-builds-everywhere-with-meson/) (tpm) diff --git a/docs/markdown/Configuration.md b/docs/markdown/Configuration.md new file mode 100644 index 0000000..037bcbd --- /dev/null +++ b/docs/markdown/Configuration.md @@ -0,0 +1,91 @@ +# Configuration + +If there are multiple configuration options, passing them through compiler flags becomes very burdensome. It also makes the configuration settings hard to inspect. To make things easier, Meson supports the generation of configure files. This feature is similar to one found in other build systems such as CMake. + +Suppose we have the following Meson snippet: + +```meson +conf_data = configuration_data() +conf_data.set('version', '1.2.3') +configure_file(input : 'config.h.in', + output : 'config.h', + configuration : conf_data) +``` + +and that the contents of `config.h.in` are + +```c +#define VERSION_STR "@version@" +``` + +Meson will then create a file called `config.h` in the corresponding build directory whose contents are the following. + +```c +#define VERSION_STR "1.2.3" +``` + +More specifically, Meson will find all strings of the type `@varname@` and replace them with respective values set in `conf_data`. You can use a single `configuration_data` object as many times as you like, but it becomes immutable after the first use. That is, after it has been used once the `set` function becomes unusable and trying to call it causes an error. + +For more complex configuration file generation Meson provides a second form. To use it, put a line like this in your configuration file. + + #mesondefine TOKEN + +The replacement that happens depends on what the value and type of TOKEN is: + +```c +#define TOKEN // If TOKEN is set to boolean true. +#undef TOKEN // If TOKEN is set to boolean false. +#define TOKEN 4 // If TOKEN is set to an integer or string value. +/* undef TOKEN */ // If TOKEN has not been set to any value. +``` + +Note that if you want to define a C string, you need to do the quoting yourself like this: + +```meson +conf.set('TOKEN', '"value"') +``` + +Since this is such a common operation, Meson provides a convenience method: + +```meson +plain_var = 'value' +conf.set_quoted('TOKEN', plain_var) # becomes #define TOKEN "value" +``` + +Often you have a boolean value in Meson but need to define the C/C++ token as 0 or 1. Meson provides a convenience function for this use case. + +```meson +conf.set10(token, boolean_value) +# The line above is equivalent to this: +if boolean_value + conf.set(token, 1) +else + conf.set(token, 0) +endif +``` + +## Configuring without an input file + +If the input file is not defined then Meson will generate a header file all the entries in the configuration data object. The replacements are the same as when generating `#mesondefine` entries: + +```meson +cdata.set('FOO', '"string"') => #define FOO "string" +cdata.set('FOO', 'a_token') => #define FOO a_token +cdata.set('FOO', true) => #define FOO +cdata.set('FOO', false) => #undef FOO +cdata.set('FOO', 1) => #define FOO 1 +cdata.set('FOO', 0) => #define FOO 0 +``` + +In this mode, you can also specify a comment which will be placed before the value so that your generated files are self-documenting. + +```meson +cdata.set('BAR', true, description : 'Set BAR if it is available') +``` + +Will produce: + +```c +/* Set BAR if it is available */ +#define BAR +``` diff --git a/docs/markdown/Configuring-a-build-directory.md b/docs/markdown/Configuring-a-build-directory.md new file mode 100644 index 0000000..e887e9e --- /dev/null +++ b/docs/markdown/Configuring-a-build-directory.md @@ -0,0 +1,46 @@ +# Configuring a build directory + +Often you want to change the settings of your build after it has been generated. For example you might want to change from a debug build into a release build, set custom compiler flags, change the build options provided in your `meson_options.txt` file and so on. + +The main tool for this is the `mesonconf` script. You may also use the `mesongui` graphical application if you want. However this document describes the use of the command line client. + +You invoke `mesonconf` by giving it the location of your build dir. If omitted, the current working directory is used instead. Here's a sample output for a simple project. + + Core properties + + Source dir /home/jpakkane/clangdemo/2_address + Build dir /home/jpakkane/clangdemo/2_address/buildmeson + + Core options + + type Build type debug + strip Strip on install False + coverage Coverage report False + pch Precompiled headers True + unity Unity build False + + Compiler flags + + cflags [] + + Linker flags + + clinkflags [] + + Directories + + installprefix Install prefix /usr/local + libdir Library directory lib + bindir Binary directory bin + includedir Header directory include + datadir Data directory share + mandir Man page directory share/man + localedir Locale file directory share/locale + + This project does not have any options + +These are all the options available for the current project arranged into related groups. The first column in every field is the name of the option. To set an option you use the `-D` option. For example, changing the installation prefix from `/usr/local` to `/tmp/testroot` you would issue the following command. + + mesonconf -Dprefix=/tmp/testroot + +Then you would run your build command (usually `ninja`), which would cause Meson to detect that the build setup has changed and do all the work required to bring your build tree up to date. diff --git a/docs/markdown/Contact-information.md b/docs/markdown/Contact-information.md new file mode 100644 index 0000000..4075573 --- /dev/null +++ b/docs/markdown/Contact-information.md @@ -0,0 +1,7 @@ +# Contact information + +For general discussion and questions, it is strongly recommended that you use the [mailing list](https://groups.google.com/forum/#!forum/mesonbuild). + +If you find bugs, please file them in the [issue tracker](https://github.com/jpakkane/meson/issues). + +The maintainer of Meson is Jussi Pakkanen. You should usually not contact him privately but rather use the channels listed above. However if such a need arises, he can be reached at gmail where his username is `jpakkane` (that is not a typo, the last letter is indeed *e*). diff --git a/docs/markdown/Continuous-Integration.md b/docs/markdown/Continuous-Integration.md new file mode 100644 index 0000000..1dff200 --- /dev/null +++ b/docs/markdown/Continuous-Integration.md @@ -0,0 +1,102 @@ +# Continous Integration + +Here you will find snippets to use Meson with various CI such as Travis and Appveyor. + +Please [file an issue](https://github.com/mesonbuild/meson/issues/new) if these instructions don't work for you. + +## Travis for OS X and Linux (with Docker) + +Travis for Linux provides ancient versions of Ubuntu which will likely cause problems building your projects regardless of which build system you're using. We recommend using Docker to get a more-recent version of Ubuntu and installing Ninja, Python3, and Meson inside it. + +This `yml` file is derived from the [configuration used by Meson for running its own tests](https://github.com/mesonbuild/meson/blob/master/.travis.yml). + +```yaml +sudo: false + +os: + - linux + - osx + +language: + - cpp + +services: + - docker + +before_install: + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install ninja python3; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then pip3 install meson; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker pull YOUR/REPO:yakkety; fi + +script: + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then echo FROM YOUR/REPO:yakkety > Dockerfile; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then echo ADD . /root >> Dockerfile; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker build -t withgit .; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker run withgit /bin/sh -c "cd /root && TRAVIS=true CC=$CC CXX=$CXX meson build && ninja -C build test"; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then SDKROOT=$(xcodebuild -version -sdk macosx Path) meson build && ninja -C build test; fi +``` + +## AppVeyor for Windows + +For CI on Windows, [AppVeyor](https://www.appveyor.com/) is probably your best bet. Here's a sample `yml` file for use with that. + +```yaml +os: Visual Studio 2015 + +matrix: + - arch: x86 + compiler: msvc2010 + - arch: x86 + compiler: msvc2015 + - arch: x64 + compiler: msvc2015 + +platform: + - x64 + +install: + # Use the x86 python only when building for x86 for the cpython tests. + # For all other archs (including, say, arm), use the x64 python. + - ps: (new-object net.webclient).DownloadFile('https://dl.dropboxusercontent.com/u/37517477/ninja.exe', 'C:\projects\meson\ninja.exe') + - cmd: if %arch%==x86 (set MESON_PYTHON_PATH=C:\python34) else (set MESON_PYTHON_PATH=C:\python34-x64) + - cmd: echo Using Python at %MESON_PYTHON_PATH% + - cmd: %MESON_PYTHON_PATH%\pip install meson + - cmd: if %compiler%==msvc2010 ( call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" %arch% ) + - cmd: if %compiler%==msvc2015 ( call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %arch% ) + +build_script: + - cmd: echo Building on %arch% with %compiler% + - cmd: PATH=%cd%;%MESON_PYTHON_PATH%;%PATH%; && python meson.py --backend=ninja build + - cmd: PATH=%cd%;%MESON_PYTHON_PATH%;%PATH%; && ninja -C build + +test_script: + - cmd: PATH=%cd%;%MESON_PYTHON_PATH%;%PATH%; && ninja -C build test +``` + +## Travis without Docker + +This setup is not recommended but included here for completeness + +```yaml +sudo: false +language: cpp +group: beta + +matrix: + include: + - os: linux + dist: trusty + - os: osx + +install: + - export PATH="`pwd`/build:${PATH}" + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update && brew install python3 ninja; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then wget https://github.com/ninja-build/ninja/releases/download/v1.7.2/ninja-linux.zip && unzip -q ninja-linux.zip -d build; fi + - pip3 install meson + +script: + - meson build + - ninja -C build + - ninja -C build test +``` diff --git a/docs/markdown/Creating-Linux-binaries.md b/docs/markdown/Creating-Linux-binaries.md new file mode 100644 index 0000000..2d5da1c --- /dev/null +++ b/docs/markdown/Creating-Linux-binaries.md @@ -0,0 +1,85 @@ +# Creating Linux binaries + +Creating Linux binaries that can be downloaded and run on any distro (like .dmg packages for OSX or .exe installers for Windows) has traditionally been difficult. This is even more tricky if you want to use modern compilers and features, which is especially desired in game development. There is still no simple turn key solution for this problem but with a bit of setup it can be relatively straightforward. + +## Installing system and GCC + +First you need to do a fresh operating system install. You can use spare hardware, VirtualBox, cloud or whatever you want. Note that the distro you install must be *at least as old* as the oldest release you wish to support. Debian stable is usually a good choice, though immediately after its release you might want to use Debian oldstable or the previous Ubuntu LTS. The oldest supported version of CentOS is also a good choice. + +Once you have installed the system, you need to install build dependencies for GCC. In Debian based distros this can be done with the following commands: + +```console +$ apt get build dep g++ +$ apt get install pkg config libgmp dev libmpfr dev libmpc dev +``` + +Then create a `src` subdirectory in your home directory. Copypaste the following into `install_gcc.sh` and execute it. + +```bash +#!/bin/sh + +wget ftp://ftp.fu berlin.de/unix/languages/gcc/releases/gcc 4.9.2/gcc 4.9.2.tar.bz2 +tar xf gcc 4.9.2.tar.bz2 + +mkdir objdir +cd objdir +../gcc 4.9.2/configure disable bootstrap prefix=${HOME}/devroot \ + disable multilib enable languages=c,c++ +make j 4 +make install strip +ln s gcc ${HOME}/devroot/bin/cc +``` + +Then finally add the following lines to your `.bashrc`. + +```console +$ export LD_LIBRARY_PATH=${HOME}/devroot/lib +$ export PATH=${HOME}/devroot/bin:$PATH +$ export PKG_CONFIG_PATH=${HOME}/devroot/lib/pkgconfig +``` + +Log out and back in and now your build environment is ready to use. + +## Adding other tools + +Old distros might have too old versions of some tools. For Meson this could include Python 3 and Ninja. If this is the case you need to download, build and install new versions into `~/devroot` in the usual way. + +## Adding dependencies + +You want to embed and statically link every dependency you can (especially C++ dependencies). Meson's [Wrap package manager might be of use here](Wrap dependency system manual). This is equivalent to what you would do on Windows, OSX, Android etc. Sometimes static linking is not possible. In these cases you need to copy the .so files inside your package. Let's use SDL2 as an example. First we download and install it as usual giving it our custom install prefix (that is, `./configure prefix=${HOME}/devroot`). This makes Meson's dependency detector pick it up automatically. + +## Building and installing + +Building happens in much the same way as normally. There are just two things to note. First, you must tell GCC to link the C++ standard library statically. If you don't then your app is guaranteed to break as different distros have binary incompatible C++ libraries. The second thing is that you need to point your install prefix to some empty staging area. Here's the meson command to do that: + +```console +$ LDFLAGS= static libstdc++ meson prefix=/tmp/myapp <other args> +``` + +The aim is to put the executable in `/tmp/myapp/bin` and shared libraries to `/tmp/myapp/lib`. The next thing you need is the embedder. It takes your dependencies (in this case only `libSDL2 2.0.so.0`) and copies them in the lib directory. Depending on your use case you can either copy the files by hand or write a script that parses the output of `ldd binary_file`. Be sure not to copy system libraries (`libc`, `libpthread`, `libm` etc). For an example, see the [sample project](https://github.com/jpakkane/meson/tree/master/manual%20tests/4%20standalone%20binaries). + +Make the script run during install with this: + +```meson +meson.set_install_script('linux_bundler.sh') +``` + +## Final steps + +If you try to run the program now it will most likely fail to start or crashes. The reason for this is that the system does not know that the executable needs libraries from the `lib` directory. The solution for this is a simple wrapper script. Create a script called `myapp.sh` with the following content: + +```bash +#!/bin/bash + +cd "${0%/*}" +export LD_LIBRARY_PATH="`pwd`/lib" +bin/myapp +``` + +Install it with this Meson snippet: + +```meson +install_data('myapp.sh', install_dir : '.') +``` + +And now you are done. Zip up your `/tmp/myapp` directory and you have a working binary ready for deployment. To run the program, just unzip the file and run `myapp.sh`. diff --git a/docs/markdown/Creating-OSX-packages.md b/docs/markdown/Creating-OSX-packages.md new file mode 100644 index 0000000..a2b462a --- /dev/null +++ b/docs/markdown/Creating-OSX-packages.md @@ -0,0 +1,96 @@ +# Creating OSX packages + +Meson does not have native support for building OSX packages but it does provide all the tools you need to create one yourself. The reason for this is that it is a very hard task to write a system that provides for all the different ways to do that but it is very easy to write simple scripts for each application. + +Sample code for this can be found in [the Meson manual test suite](https://github.com/jpakkane/meson/tree/master/manual%20tests/4%20standalone%20binaries). + +## Creating an app bundle + +OSX app bundles are actually extremely simple. They are just a directory of files in a certain format. All the details you need to know are on [this page](https://stackoverflow.com/questions/1596945/building-osx-app-bundle) and it is highly recommended that you read it first. + +Let's assume that we are creating our app bundle into `/tmp/myapp.app`. Suppose we have one executable, so we need to install that into `Contents/MacOS`. If we define the executable like this: + +```meson +executable('myapp', 'foo1.c', ..., install : true) +``` + +then we just need to initialize our build tree with this command: + +```console +$ meson --prefix=/tmp/myapp.app \ + --bindir=Contents/MacOS \ + builddir \ + <other flags you might need> +``` + +Now when we do `ninja install` the bundle is properly staged. If you have any resource files or data, you need to install them into `Contents/Resources` either by custom install commands or specifying more install paths to the Meson command. + +Next we need to install an `Info.plist` file and an icon. For those we need the following two Meson definitions. + +```meson +install_data('myapp.icns', install_dir : 'Contents/Resources') +install_data('Info.plist', install_dir : 'Contents') +``` + +The format of `Info.plist` can be found in the link or the sample project linked above. Be careful, the sample code on the linked page is malformed, it is missing a less than character (<) before `!DOCTYPE`. The simplest way to get an icon in the `icns` format is to save your image as a tiff an then use the `tiff2icns` helper application that comes with XCode. + +Some applications assume that the working directory of the app process is the same where the binary executable is. If this is the case for you, then you need to create a wrapper script that looks like this: + +```bash +#!/bin/bash + +cd "${0%/*}" +./myapp +``` + +install it with this: + +```meson +install_data('myapp.sh', install_dir : 'Contents/MacOS') +``` + +and make sure that you specify `myapp.sh` as the executable to run in your `Info.plist`. + +If you are not using any external libraries, this is all you need to do. You now have a full app bundle in `/tmp/myapp.app` that you can use. Most applications use third party frameworks and libraries, though, so you need to add them to the bundle so it will work on other peoples' machines. + +As an example we are going to use the [SDL2](https://libsdl.org/) framework. In order to bundle it in our app, we first specify an installer script to run. + +```meson +meson.set_install_script('install_script.sh') +``` + +The install script does two things. First it copies the whole framework into our bundle. + +```console +$ mkdir -p ${MESON_INSTALL_PREFIX}/Contents/Frameworks +$ cp -R /Library/Frameworks/SDL2.framework \ + ${MESON_INSTALL_PREFIX}/Contents/Frameworks +``` + +Then it needs to alter the library search path of our executable(s). This tells OSX that the libraries your app needs are inside your bundle. In the case of SDL2, the invocation goes like this: + +```console +$ install_name_tool -change @rpath/SDL2.framework/Versions/A/SDL2 \ + @executable_path/../FrameWorks/SDL2.framework/Versions/A/SDL2 \ + ${MESON_INSTALL_PREFIX}/Contents/MacOS/myapp +``` + +This is the part of OSX app bundling that you must always do manually. OSX dependencies come in many shapes and forms and unfortunately there is no reliable automatic way to determine how each dependency should be handled. Frameworks go to the `Frameworks` directory while plain `.dylib` files usually go to `Contents/Resources/lib` (but you can put them wherever you like). To get this done you have to check what your program links against with `otool -L /path/to/binary` and manually add the copy and fix steps to your install script. Do not copy system libraries inside your bundle, though. + +After this you have a fully working, self-contained OSX app bundle ready for distribution. + +## Creating a .dmg installer + +A .dmg installer is similarly quite simple, at its core it is basically a fancy compressed archive. A good description can be found on [this page](https://el-tramo.be/guides/fancy-dmg/). Please read it and create a template image file according to its instructions. + +The actual process of creating the installer is very simple: you mount the template image, copy your app bundle in it, unmount it and convert the image into a compressed archive. The actual commands to do this are not particularly interesting, feel free to steal them from either the linked page above or from the sample script in Meson's test suite. + +## Putting it all together + +There are many ways to put the .dmg installer together and different people will do it in different ways. The linked sample code does it by having two different scripts. This separates the different pieces generating the installer into logical pieces. + +`install_script.sh` only deals with embedding dependencies and fixing the library paths. + +`build_osx_installer.sh` sets up the build with the proper paths, compiles, installs and generates the .dmg package. + +The main reasoning here is that in order to build a complete OSX installer package from source, all you need to do is to cd into the source tree and run `./build_osx_installer.sh`. To build packages on other platforms you would write scripts such as `build_windows_installer.bat` and so on. diff --git a/docs/markdown/Cross-compilation.md b/docs/markdown/Cross-compilation.md new file mode 100644 index 0000000..b5df8b3 --- /dev/null +++ b/docs/markdown/Cross-compilation.md @@ -0,0 +1,144 @@ +# Cross compilation + +Meson has full support for cross compilation. Since cross compiling is more complicated than native building, +let's first go over some nomenclature. The three most important definitions are traditionally called *build*, *host* and *target*. This is confusing because those terms are used for quite many different things. To simplify the issue, we are going to call these the *build machine*, *host machine* and *target machine*. Their definitions are the following + +* *build machine* is the computer that is doing the actual compiling +* *host machine* is the machine on which the compiled binary will run +* *target machine* is the machine on which the compiled binary's output will run (this is only meaningful for programs such as compilers that, when run, produce object code for a different CPU than what the program is being run on) + +The `tl/dr` summary is the following: if you are doing regular cross compilation, you only care about *build_machine* and *host_machine*. Just ignore *target_machine* altogether and you will be correct 99% of the time. If your needs are more complex or you are interested in the actual details, do read on. + +This might be easier to understand through examples. Let's start with the regular, not cross-compiling case. In these cases all of these three machines are the same. Simple so far. + +Let's next look at the most common cross-compilation setup. Let's suppose you are on a 64 bit OSX machine and you are cross compiling a binary that will run on a 32 bit ARM Linux board. In this case your *build machine* is 64 bit OSX and both your *host* and *target machines* are 32 bit ARM Linux. This should be quite understandable as well. + +It gets a bit trickier when we think about how the cross compiler was generated. It was built and it runs on a specific platform but the output it generates is for a different platfom. In this case *build* and *host machines* are the same, but *target machine* is different. + +The most complicated case is when you cross-compile a cross compiler. As an example you can, on a Linux machine, generate a cross compiler that runs on Windows but produces binaries on MIPS Linux. In this case *build machine* is x86 Linux, *host machine* is x86 Windows and *target machine* is MIPS Linux. This setup is known as the [Canadian Cross](https://en.wikipedia.org/wiki/Cross_compiler#Canadian_Cross). As a side note, be careful when reading cross compilation articles on Wikipedia or the net in general. It is very common for them to get build, host and target mixed up, even in consecutive sentences, which can leave you puzzled until you figure it out. + +If you did not understand all of the details, don't worry. For most people it takes a while to wrap their head around these concepts. Don't panic, it might take a while to click, but you will get the hang of it eventually. + +## Defining the environment + +Meson requires you to write a cross build definition file. It defines various properties of the cross build environment. The cross file consists of different sections. The first one is the list of executables that we are going to use. A sample snippet might look like this: + +```ini +[binaries] +c = '/usr/bin/i586-mingw32msvc-gcc' +cpp = '/usr/bin/i586-mingw32msvc-g++' +ar = '/usr/i586-mingw32msvc/bin/ar' +strip = '/usr/i586-mingw32msvc/bin/strip' +exe_wrapper = 'wine' # A command used to run generated executables. +``` + +The entries are pretty self explanatory but the last line is special. It defines a *wrapper command* that can be used to run executables for this host. In this case we can use Wine, which runs Windows applications on Linux. Other choices include running the application with qemu or a hardware simulator. If you have this kind of a wrapper, these lines are all you need to write. Meson will automatically use the given wrapper when it needs to run host binaries. This happens e.g. when running the project's test suite. + +The next section lists properties of the cross compiler and thus of the target system. It looks like this: + +```ini +[properties] +sizeof_int = 4 +sizeof_wchar_t = 4 +sizeof_void* = 4 + +alignment_char = 1 +alignment_void* = 4 +alignment_double = 4 + +has_function_printf = true + +c_args = ['-DCROSS=1', '-DSOMETHING=3'] +c_link_args = ['-some_link_arg'] +``` + +In most cases you don't need the size and alignment settings, Meson will detect all these by compiling and running some sample programs. If your build requires some piece of data that is not listed here, Meson will stop and write an error message describing how to fix the issue. If you need extra compiler arguments to be used during cross compilation you can set them with `[langname]_args = [args]`. Just remember to specify the args as an array and not as a single string (i.e. not as `'-DCROSS=1 -DSOMETHING=3'`). + +The last bit is the definition of host and target machines. Every cross build definition must have one or both of them. If it had neither, the build would not be a cross build but a native build. You do not need to define the build machine, as all necessary information about it is extracted automatically. The definitions for host and target machines look the same. Here is a sample for host machine. + +```ini +[host_machine] +system = 'windows' +cpu_family = 'x86' +cpu = 'i686' +endian = 'little' +``` + +These values define the machines sufficiently for cross compilation purposes. The corresponding target definition would look the same but have `target_machine` in the header. These values are available in your Meson scripts. There are three predefined variables called, surprisingly, `build_machine`, `host_machine` and `target_machine`. Determining the operating system of your host machine is simply a matter of calling `host_machine.system()`. + +There are two different values for the CPU. The first one is `cpu_family`. It is a general type of the CPU. Common values might include `x86`, `arm` or `x86_64`. The second value is `cpu` which is a more specific subtype for the CPU. Typical values for a `x86` CPU family might include `i386` or `i586` and for `arm` family `armv5` or `armv7hl`. Note that CPU type strings are very system dependent. You might get a different value if you check its value on the same machine but with different operating systems. + +If you do not define your host machine, it is assumed to be the build machine. Similarly if you do not specify target machine, it is assumed to be the host machine. + +## Starting a cross build + + +Once you have the cross file, starting a build is simple + +```console +$ meson srcdir builddir --cross-file cross_file.txt +``` + +Once configuration is done, compilation is started by invoking Ninja in the usual way. + +## Introspection and system checks + +The main *meson* object provides two functions to determine cross compilation status. + +```meson +meson.is_cross_build() # returns true when cross compiling +meson.has_exe_wrapper() # returns true if an exe wrapper has been defined +``` + +Note that the latter gives undefined return value when doing a native build. + +You can run system checks on both the system compiler or the cross compiler. You just have to specify which one to use. + +```meson +build_compiler = meson.get_compiler('c', native : true) +host_compiler = meson.get_compiler('c', native : false) + +build_int_size = build_compiler.sizeof('int') +host_int_size = host_compiler.sizeof('int') +``` + +## Mixing host and build targets + +Sometimes you need to build a tool which is used to generate source files. These are then compiled for the actual target. For this you would want to build some targets with the system's native compiler. This requires only one extra keyword argument. + +```meson +native_exe = executable('mygen', 'mygen.c', native : true) +``` + +You can then take `native_exe` and use it as part of a generator rule or anything else you might want. + +## Using a custom standard library + +Sometimes in cross compilation you need to build your own standard library instead of using the one provided by the compiler. Meson has built-in support for switching standard libraries transparently. The invocation to use in your cross file is the following: + +```ini +[properties] +c_stdlib = ['mylibc', 'mylibc_dep'] # Subproject name, dependency name +``` + +This specifies that C standard library is provided in the Meson subproject `mylibc` in internal dependency variable `mylibc_dep`. It is used on every cross built C target in the entire source tree (including subprojects) and the standard library is disabled. The build definitions of these targets do not need any modification. + +## Changing cross file settings + +Cross file settings are only read when the build directory is set up the first time. Any changes to them after the fact will be ignored. This is the same as regular compiles where you can't change the compiler once a build tree has been set up. If you need to edit your cross file, then you need to wipe your build tree and recreate it from scratch. + +## Custom data + +You can store arbitrary data in `properties` and access them from your Meson files. As an example if you cross file has this: + +```ini +[properties] +somekey = 'somevalue' +``` + +then you can access that using the `meson` object like this: + +```meson +myvar = meson.get_cross_property('somekey') +# myvar now has the value 'somevalue' +``` diff --git a/docs/markdown/Custom-build-targets.md b/docs/markdown/Custom-build-targets.md new file mode 100644 index 0000000..0c34b1f --- /dev/null +++ b/docs/markdown/Custom-build-targets.md @@ -0,0 +1,27 @@ +# Custom build targets + +While Meson tries to support as many languages and tools as possible, there is no possible way for it to cover all corner cases. For these cases it permits you to define custom build targets. Here is how one would use it. + +```meson +comp = find_program('custom_compiler') + +infile = 'source_code.txt' +outfile = 'output.bin' + +mytarget = custom_target('targetname', + output : 'output.bin', + input : 'source_code.txt', + command : [comp, '@INPUT@', '@OUTPUT@'], + install : true, + install_dir : 'subdir') +``` + +This would generate the binary `output.bin` and install it to `${prefix}/subdir/output.bin`. Variable substitution works just like it does for source generation. + +## Details on compiler invocations ## + +Meson only permits you to specify one command to run. This is by design as writing shell pipelines into build definition files leads to code that is very hard to maintain. If your compilation requires multiple steps you need to write a wrapper script that does all the necessary work. When doing this you need to be mindful of the following issues: + +* do not assume that the command is invoked in any specific directory +* a target called `target` file `outfile` defined in subdir `subdir` must be written to `build_dir/subdir/foo.dat` +* if you need a subdirectory for temporary files, use `build_dir/subdir/target.dir` diff --git a/docs/markdown/Dependencies.md b/docs/markdown/Dependencies.md new file mode 100644 index 0000000..9862986 --- /dev/null +++ b/docs/markdown/Dependencies.md @@ -0,0 +1,83 @@ +# Dependencies + +Very few applications are fully self-contained, but rather they use external libraries and frameworks to do their work. Meson makes it very easy to find and use external dependencies. Here is how one would use the Zlib compression library. + +```meson +zdep = dependency('zlib', version : '>=1.2.8') +exe = executable('zlibprog', 'prog.c', dependencies : zdep) +``` + +First Meson is told to find the external library `zlib` and error out if it is not found. The `version` keyword is optional and specifies a version requirement for the dependency. Then an executable is built using the specified dependency. Note how the user does not need to manually handle compiler or linker flags or deal with any other minutiae. + +If you have multiple dependencies, pass them as an array: + +```meson +executable('manydeps', 'file.c', dependencies : [dep1, dep2, dep3, dep4]) +``` + +If the dependency is optional, you can tell Meson not to error out if the dependency is not found and then do further configuration. + +```meson +opt_dep = dependency('somedep', required : false) +if opt_dep.found() + # Do something. +else + # Do something else. +endif +``` + +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. + +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. + +## Boost ## + +Boost is not a single dependency but rather a group of different libraries. To use Boost with Meson, simply list which Boost modules you would like to use. + +```meson +boost_dep = dependency('boost', modules : ['thread', 'utility']) +exe = executable('myprog', 'file.cc', dependencies : boost_dep) +``` + +You can call `dependency` multiple times with different modules and use those to link against your targets. + +## GTest and GMock ## + +GTest and GMock come as sources that must be compiled as part of your project. With Meson you don't have to care about the details, just pass `gtest` or `gmock` to `dependency` and it will do everything for you. If you want to use GMock, it is recommended to use GTest as well, as getting it to work standalone is tricky. + +## Qt5 ## + +Meson has native Qt5 support. Its usage is best demonstrated with an example. + +```meson +qt5_mod = import('qt5') +qt5widgets = dependency('qt5', modules : 'Widgets') + +processed = qt5_mod.preprocess( + moc_headers : 'mainWindow.h', # Only headers that need moc should be put here + moc_sources : 'helperFile.cpp', # must have #include"moc_helperFile.cpp" + ui_files : 'mainWindow.ui', + qresources : 'resources.qrc', +) + +q5exe = executable('qt5test', + sources : ['main.cpp', + 'mainWindow.cpp', + processed], + dependencies: qt5widgets) +``` + +Here we have an UI file created with Qt Designer and one source and header file each that require preprocessing with the `moc` tool. We also define a resource file to be compiled with `rcc`. We just have to tell Meson which files are which and it will take care of invoking all the necessary tools in the correct order, which is done with the `preprocess` method of the `qt5` module. Its output is simply put in the list of sources for the target. The `modules` keyword of `dependency` works just like it does with Boost. It tells which subparts of Qt the program uses. + +## 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/Design-rationale.md b/docs/markdown/Design-rationale.md new file mode 100644 index 0000000..2f6068e --- /dev/null +++ b/docs/markdown/Design-rationale.md @@ -0,0 +1,133 @@ +--- +title: Design rationale +... + +This is the original design rationale for Meson. The syntax it describes does not match the released version +== + +A software developer's most important tool is the editor. If you talk to coders about the editors they use, you are usually met with massive enthusiasm and praise. You will hear how Emacs is the greatest thing ever or how vi is so elegant or how Eclipse's integration features make you so much more productive. You can sense the enthusiasm and affection that the people feel towards these programs. + +The second most important tool, even more important than the compiler, is the build system. + +Those are pretty much universally despised. + +The most positive statement on build systems you can usually get (and it might require some coaxing) is something along the lines of *well, it's a terrible system, but all other options are even worse*. It is easy to see why this is the case. For starters, commonly used free build systems have obtuse syntaxes. They use for the most part global variables that are set in random locations so you can never really be sure what a given line of code does. They do strange and unpredictable things at every turn. + +Let's illustrate this with a simple example. Suppose we want to run a program built with GNU Autotools under gdb. The instinctive thing to do is to just run `gdb programname`. The problem is that this may or may not work. In some cases the executable file is a binary whereas at other times it is a wrapper shell script that invokes the real binary which resides in a hidden subdirectory. Gdb invocation fails if the binary is a script but succeeds if it is not. The user has to remember the type of each one of his executables (which is an implementation detail of the build system) just to be able to debug them. Several other such pain points can be found in [this blog post](http://voices.canonical.com/jussi.pakkanen/2011/09/13/autotools/). + +Given these idiosyncrasies it is no wonder that most people don't want to have anything to do with build systems. They'll just copypaste code that works (somewhat) in one place to another and hope for the best. They actively go out of their way not to understand the system because the mere thought of it is repulsive. Doing this also provides a kind of inverse job security. If you don't know tool X, there's less chance of finding yourself responsible for its use in your organisation. Instead you get to work on more enjoyable things. + +This leads to a vicious circle. Since people avoid the tools and don't want to deal with them, very few work on improving them. The result is apathy and stagnation. + +Can we do better? +-- + +At its core, building C and C++ code is not a terribly difficult task. In fact, writing a text editor is a lot more complicated and takes more effort. Yet we have lots of very high quality editors but only few build systems with questionable quality and usability. + +So, in the grand tradition of own-itch-scratching, I decided to run a scientific experiment. The purpose of this experiment was to explore what would it take to build a "good" build system. What kind of syntax would suit this problem? What sort of problems would this application need to solve? What sort of solutions would be the most appropriate? + +To get things started, here is a list of requirements any modern cross-platform build system needs to provide. + +###1. Must be simple to use### + +One of the great virtues of Python is the fact that it is very readable. It is easy to see what a given block of code does. It is concise, clear and easy to understand. The proposed build system must be syntactically and semantically clean. Side effects, global state and interrelations must be kept at a minimum or, if possible, eliminated entirely. + +###2. Must do the right thing by default### + +Most builds are done by developers working on the code. Therefore the defaults must be tailored towards that use case. As an example the system shall build objects without optimization and with debug information. It shall make binaries that can be run directly from the build directory without linker tricks, shell scripts or magic environment variables. + +###3. Must enforce established best practices### + +There really is no reason to compile source code without the equivalent of `-Wall`. So enable it by default. A different kind of best practice is the total separation of source and build directories. All build artifacts must be stored in the build directory. Writing stray files in the source directory is not permitted under any circumstances. + +###4. Must have native support for platforms that are in common use### + +A lot of free software projects can be used on non-free platforms such as Windows or OSX. The system must provide native support for the tools of choice on those platforms. In practice this means native support for Visual Studio and XCode. Having said IDEs invoke external builder binaries does not count as native support. + +###5. Must not add complexity due to obsolete platforms### + +Work on this build system started during the Christmas holidays of 2012. This provides a natural hard cutoff line of 2012/12/24. Any platform, tool or library that was not in active use at that time is explicitly not supported. These include unixes such as IRIX, SunOS, OSF-1, Ubuntu versions older than 12/10, GCC versions older than 4.7 and so on. If these old versions happen to work, great. If they don't, not a single line of code will be added to the system to work around their bugs. + +###6. Must be fast### + +Running the configuration step on a moderate sized project must not take more than five seconds. Running the compile command on a fully up to date tree of 1000 source files must not take more than 0.1 seconds. + +###7. Must provide easy to use support for modern sw development features### + +An example is precompiled headers. Currently no free software build system provides native support for them. Other examples could include easy integration of Valgrind and unit tests, test coverage reporting and so on. + +###8. Must allow override of default values### + +Sometimes you just have to compile files with only given compiler flags and no others, or install files in weird places. The system must allow the user to do this if he really wants to. + +Overview of the solution +-- + +Going over these requirements it becomes quite apparent that the only viable approach is roughly the same as taken by CMake: having a domain specific language to declare the build system. Out of this declaration a configuration is generated for the backend build system. This can be a Makefile, Visual Studio or XCode project or anything else. + +The difference between the proposed DSL and existing ones is that the new one is declarative. It also tries to work on a higher level of abstraction than existing systems. As an example, using external libraries in current build systems means manually extracting and passing around compiler flags and linker flags. In the proposed system the user just declares that a given build target uses a given external dependency. The build system then takes care of passing all flags and settings to their proper locations. This means that the user can focus on his own code rather than marshalling command line arguments from one place to another. + +A DSL is more work than the approach taken by SCons, which is to provide the system as a Python library. However it allows us to make the syntax more expressive and prevent certain types of bugs by e.g. making certain objects truly immutable. The end result is again the same: less work for the user. + +The backend for Unix requires a bit more thought. The default choice would be Make. However it is extremely slow. It is not uncommon on large code bases for Make to take several minutes just to determine that nothing needs to be done. Instead of Make we use [Ninja](http://martine.github.com/ninja/), which is extremely fast. The backend code is abstracted away from the core, so other backends can be added with relatively little effort. + +Sample code +-- + +Enough design talk, let's get to the code. Before looking at the examples we would like to emphasize that this is not in any way the final code. It is proof of concept code that works in the system as it currently exists (February 2013), but may change at any time. + +Let's start simple. Here is the code to compile a single executable binary. + +```meson +project('compile one', 'c') +executable('program', 'prog.c') +``` + +This is about as simple as one can get. First you declare the project name and the languages it uses. Then you specify the binary to build and its sources. The build system will do all the rest. It will add proper suffixes (e.g. '.exe' on Windows), set the default compiler flags and so on. + +Usually programs have more than one source file. Listing them all in the function call can become unwieldy. That is why the system supports keyword arguments. They look like this. + +```meson +project('compile several', 'c') +sources = ['main.c', 'file1.c', 'file2.c', 'file3.c'] +executable('program', sources : sourcelist) +``` + +External depencencies are simple to use. + +```meson +project('external lib', 'c') +libdep = find_dep('extlibrary', required : true) +sources = ['main.c', 'file1.c', 'file2.c', 'file3.c'] +executable('program', sources : sourcelist, dep : libdep) +``` + +In other build systems you have to manually add the compile and link flags from external dependencies to targets. In this system you just declare that extlibrary is mandatory and that the generated program uses that. The build system does all the plumbing for you. + +Here's a slightly more complicated definition. It should still be understandable. + +```meson +project('build library', 'c') +foolib = shared_library('foobar', sources : 'foobar.c',\ +install : true) +exe = executable('testfoobar', 'tester.c', link : foolib) +add_test('test library', exe) +``` + +First we build a shared library named foobar. It is marked installable, so running `ninja install` installs it to the library directory (the system knows which one so the user does not have to care). Then we build a test executable which is linked against the library. It will no tbe installed, but instead it is added to the list of unit tests, which can be run with the command `ninja test`. + +Above we mentioned precompiled headers as a feature not supported by other build systems. Here's how you would use them. + +```meson +project('pch demo', 'cxx') +executable('myapp', 'myapp.cpp', pch : 'pch/myapp.hh') +``` + +The main reason other build systems can not provide pch support this easily is because they don't enforce certain best practices. Due to the way include paths work, it is impossible to provide pch support that always works with both in-source and out-of-source builds. Mandating separate build and source directories makes this and many other problems a lot easier. + +Get the code +-- + +The code for this experiment can be found at [the Meson repository](https://sourceforge.net/p/meson/code/). It should be noted that it is not a build system. It is only a proposal for one. It does not work reliably yet. You probably should not use it as the build system of your project. + +All that said I hope that this experiment will eventually turn into a full blown build system. For that I need your help. Comments and especially patches are more than welcome. diff --git a/docs/markdown/External-commands.md b/docs/markdown/External-commands.md new file mode 100644 index 0000000..af19794 --- /dev/null +++ b/docs/markdown/External-commands.md @@ -0,0 +1,16 @@ +# External commands + +As a part of the software configuration, you may want to get extra data by running external commands. The basic syntax is the following. + +```meson +r = run_command('command', 'arg1', 'arg2', 'arg3') +if r.returncode() != 0 + # it failed +endif +output = r.stdout().strip() +errortxt = r.stderr().strip() +``` + +The `run_command` function returns an object that can be queried for return value and text written to stdout and stderr. The `strip` method call is used to strip trailing and leading whitespace from strings. Usually output from command line programs ends in a newline, which is unwanted in string variables. The first argument can be either a string or an executable you have detected earlier with `find_program`. + +Note that you can not pass your command line as a single string. That is, calling `run_command('do_something foo bar')` will not work. You must either split up the string into separate arguments or pass the split command as an array. It should also be noted that Meson will not pass the command to the shell, so any command lines that try to use things such as environment variables, backticks or pipelines will not work. If you require shell semantics, write your command into a script file and call that with `run_command`. diff --git a/docs/markdown/FAQ.md b/docs/markdown/FAQ.md new file mode 100644 index 0000000..7c27ee3 --- /dev/null +++ b/docs/markdown/FAQ.md @@ -0,0 +1,157 @@ +--- +title: FAQ +... +# Meson Frequently Asked Questions + +See also [How do I do X in Meson](howtox.md). + +## Why is it called Meson? + +When the name was originally chosen, there were two main limitations: there must not exist either a Debian package or a Sourceforge project of the given name. This ruled out tens of potential project names. At some point the name Gluon was considered. Gluons are elementary particles that hold protons and neutrons together, much like a build system's job is to take pieces of source code and a compiler and bind them to a complete whole. + +Unfortunately this name was taken, too. Then the rest of physical elementary particles were examined and Meson was found to be available. + +## What is the correct way to use threads (such as pthreads)? + +```meson +thread_dep = dependency('threads') +``` + +This will set up everything on your behalf. People coming from Autotools or CMake want to do this by looking for `libpthread.so` manually. Don't do that, it has tricky corner cases especially when cross compiling. + +## How to use Meson on a host where it is not available in system packages? + +Starting from version 0.29.0, Meson is available from the [Python Package Index](https://pypi.python.org/pypi/meson/), so installing it simply a matter of running this command: + +```console +$ pip3 install <your options here> meson +``` + +If you don't have access to PyPi, that is not a problem either. Meson has been designed to be easily runnable from an extracted source tarball or even a git checkout. First you need to download Meson. Then use this command to set up you build instead of plain `meson`. + +```console +$ /path/to/meson.py <options> +``` + +After this you don't have to care about invoking Meson any more. It remembers where it was originally invoked from and calls itself appropriately. As a user the only thing you need to do is to `cd` into your build directory and invoke `ninja`. + +## Why can't I specify target files with a wildcard? + +Instead of specifying files explicitly, people seem to want to do this: + +```meson +executable('myprog', sources : '*.cpp') # This does NOT work! +``` + +Meson does not support this syntax and the reason for this is simple. This can not be made both reliable and fast. By reliable we mean that if the user adds a new source file to the subdirectory, Meson should detect that and make it part of the build automatically. + +One of the main requirements of Meson is that it must be fast. This means that a no-op build in a tree of 10 000 source files must take no more than a fraction of a second. This is only possible because Meson knows the exact list of files to check. If any target is specified as a wildcard glob, this is no longer possible. Meson would need to re-evaluate the glob every time and compare the list of files produced against the previous list. This means inspecting the entire source tree (because the glob pattern could be `src/\*/\*/\*/\*.cpp` or something like that). This is impossible to do efficiently. + +The main backend of Meson is Ninja, which does not support wildcard matches either, and for the same reasons. + +Because of this, all source files must be specified explicitly. + +## But I really want to use wildcards! + +If the tradeoff between reliability and convenience is acceptable to you, then Meson gives you all the tools necessary to do wildcard globbing. You are allowed to run arbitrary commands during configuration. First you need to write a script that locates the files to compile. Here's a simple shell script that writes all `.c` files in the current directory, one per line. + + +```bash +#!/bin/sh + +for i in *.c; do + echo $i +done +``` + +Then you need to run this script in your Meson file, convert the output into a string array and use the result in a target. + +```meson +c = run_command('grabber.sh') +sources = c.stdout().strip().split('\n') +e = executable('prog', sources) +``` + +The script can be any executable, so it can be written in shell, Python, Lua, Perl or whatever you wish. + +As mentioned above, the tradeoff is that just adding new files to the source directory does *not* add them to the build automatically. To add them you need to tell Meson to reinitialize itself. The simplest way is to touch the `meson.build` file in your source root. Then Meson will reconfigure itself next time the build command is run. Advanced users can even write a small background script that utilizes a filesystem event queue, such as [inotify](https://en.wikipedia.org/wiki/Inotify), to do this automatically. + +## Should I use `subdir` or `subproject`? + +The answer is almost always `subdir`. Subproject exists for a very specific use case: embedding external dependencies into your build process. As an example, suppose we are writing a game and wish to use SDL. Let us further suppose that SDL comes with a Meson build definition. Let us suppose even further that we don't want to use prebuilt binaries but want to compile SDL for ourselves. + +In this case you would use `subproject`. The way to do it would be to grab the source code of SDL and put it inside your own source tree. Then you would do `sdl = subproject('sdl')`, which would cause Meson to build SDL as part of your build and would then allow you to link against it or do whatever else you may prefer. + +For every other use you would use `subdir`. As an example, if you wanted to build a shared library in one dir and link tests against it in another dir, you would do something like this: + +```meson +project('simple', 'c') +subdir('src') # library is built here +subdir('tests') # test binaries would link against the library here +``` + +## Why is there not a Make backend? + +Because Make is slow. This is not an implementation issue, Make simply can not be made fast. For further info we recommend you read [this post](http://neugierig.org/software/chromium/notes/2011/02/ninja.html) by Evan Martin, the author of Ninja. Makefiles also have a syntax that is very unpleasant to write which makes them a big maintenance burden. + +The only reason why one would use Make instead of Ninja is working on a platform that does not have a Ninja port. Even in this case it is an order of magnitude less work to port Ninja than it is to write a Make backend for Meson. + +Just use Ninja, you'll be happier that way. I guarantee it. + +## Why is Meson not just a Python module so I could code my build setup in Python? ## + +A related question to this is *Why is Meson's configuration language not Turing-complete?* + +There are many good reasons for this, most of which are summarized on this web page: [Against The Use Of Programming Languages in Configuration Files](http://taint.org/2011/02/18/001527a.html). + +In addition to those reasons, not exposing Python or any other "real" programming language makes it possible to port Meson's implementation to a different language. This might become necessary if, for example, Python turns out to be a performance bottleneck. This is an actual problem that has caused complications for GNU Autotools and Scons. + +## How do I do the equivalent of Libtools export-symbol and export-regex? + +Either by using [gcc symbol visibility](https://gcc.gnu.org/wiki/Visibility) or by writing a [linker script](http://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_mono/ld.html). This has the added benefit that your symbol definitions are in a standalone file instead of being buried inside your build definitions. An example can be found [here](https://github.com/jpakkane/meson/tree/master/test%20cases/linuxlike/3%20linker%20script). + +## My project works fine on Linux and MinGW but fails with MSVC due to a missing .lib file + +With gcc, all symbols on shared libraries are exported automatically unless you specify otherwise. With MSVC no symbols are exported by default. If your shared library exports no symbols, MSVC will silently not produce an import library file leading to failures. The solution is to add symbol visibility definitions [as specified in GCC wiki](https://gcc.gnu.org/wiki/Visibility). + +## I added some compiler flags and now the build fails with weird errors. What is happening? + +You probably did the equivalent to this: + +```meson +executable('foobar', ... + c_args : '-some_arg -other_arg') +``` + +Meson is *explicit*. In this particular case it will **not** automatically split your strings at whitespaces, instead it will take it as is and work extra hard to pass it to the compiler unchanged, including quoting it properly over shell invocations. This is mandatory to make e.g. files with spaces in them work flawlessly. To pass multiple command line arguments, you need to explicitly put them in an array like this: + +```meson +executable('foobar', ... + c_args : ['-some_arg', '-other_arg']) +``` + +## Why are changes to default project options ignored? + +You probably had a project that looked something like this: + +```meson +project('foobar', 'cpp') +``` + +This defaults to `c++11` on Gcc compilers. Suppose you want to use `c++14` instead, so you change the definition to this: + +```meson +project('foobar', 'cpp', default_options : ['cpp_std=c++14']) +``` + +But when you recompile, it still uses `c++11`. The reason for this is that default options are only looked at when you are setting up a build directory for the very first time. After that the setting is considered to have a value and thus the default value is ignored. To change an existing build dir to `c++14`, either reconfigure your build dir with `mesonconf` or delete the build dir and recreate it from scratch. + +## Does wrap download sources behind my back? + +It does not. In order for Meson to download anything from the net while building, two conditions must be met. + +First of all there needs to be a `.wrap` file with a download URL in the `subprojects` directory. If one does not exist, Meson will not download anything. + +The second requirement is that there needs to be an explicit subproject invocation in your `meson.build` files. Either `subproject('foobar')` or `dependency('foobar', fallback : ['foobar', 'foo_dep'])`. If these declarations either are not in any build file or they are not called (due to e.g. `if/else`) then nothing is downloaded. + +If this is not sufficient for you, starting from release 0.40.0 Meson has a option called `wrap-mode`, which can be used to disable wrap downloads altogether. diff --git a/docs/markdown/Feature-autodetection.md b/docs/markdown/Feature-autodetection.md new file mode 100644 index 0000000..b6a4f41 --- /dev/null +++ b/docs/markdown/Feature-autodetection.md @@ -0,0 +1,15 @@ +# Feature autodetection + +Meson is designed for high productivity. It tries to do as many things automatically as it possibly can. + +CCache +-- + +[CCache](http://ccache.samba.org/) is a cache system designed to make compiling faster. When you run Meson for the first time for a given project, it checks if CCache is installed. If it is, Meson will use it automatically. + +If you do not wish to use CCache for some reason, just specify your compiler with environment variables `CC` and/or `CXX` when first running Meson (remember that once specified the compiler can not be changed). Meson will then use the specified compiler without CCache. + +Coverage +-- + +When doing a code coverage build, Meson will check the existance of binaries `gcovr`, `lcov` and `genhtml`. If the first one is found, it will create targets called *coverage-text* and *coverage-xml*. If the latter two are found, it generates the target *coverage-html*. You can then generate coverage reports just by calling e.g. `ninja coverage-xml`. diff --git a/docs/markdown/Generating-sources.md b/docs/markdown/Generating-sources.md new file mode 100644 index 0000000..19213af --- /dev/null +++ b/docs/markdown/Generating-sources.md @@ -0,0 +1,70 @@ +# Generating sources + + Sometimes source files need to be preprocessed before they are passed to the actual compiler. As an example you might want build an IDL compiler and then run some files through that to generate actual source files. In Meson this is done with [`generator()`](https://github.com/mesonbuild/meson/wiki/Reference-manual#generator) or [`custom_target()`](https://github.com/mesonbuild/meson/wiki/Reference-manual#custom_target). + +## Using custom_target() + +Let's say you have a build target that must be built using sources generated by a compiler. The compiler can either be a built target: + +```meson +mycomp = executable('mycompiler', 'compiler.c') +``` + +Or an external program provided by the system, or script inside the source tree: + +```meson +mycomp = find_program('mycompiler') +``` + +Custom targets can take zero or more input files and use them to generate one or more output files. Using a custom target, you can run this compiler at build time to generate the sources: + +```meson +gen_src = custom_target('gen-output, + input : ['somefile1.c', 'file2.c'] + output : ['out.c', 'out.h'] + command : [mycomp, '@INPUT@', + '--c-out', '@OUTPUT0@', + '--h-out', '@OUTPUT1@']) +``` + +The `@INPUT@` there will be transformed to `'out.c' 'out.h'`. Just like the output, you can also refer to each input file individually by index. + +Then you just put that in your program and you're done. + +```meson +executable('program', 'main.c', gen_src) +``` + +## Using generator() + +Generators are similar to custom targets, except that we define a *generator*, which defines how to transform an input file into one or more output files, and then use that on as many input files as we want. + +Note that generators should only be used for outputs that will only be used as inputs for a build target or a custom target. When you use the processed output of a generator in multiple targets, the generator will be run multiple times to create outputs for each target. Each output will be created in a target-private directory `@BUILD_DIR@`. + +If you want to generate files for general purposes such as for generating headers to be used by several sources, or data that will be installed, and so on, use a [`custom_target()`](https://github.com/mesonbuild/meson/wiki/Reference-manual#custom_target) instead. + + +```meson +gen = generator(mycomp, + output : '@BASENAME@.c', + arguments : ['@INPUT@', '@OUTPUT@']) +``` + +The first argument is the executable file to run. The next file specifies a name generation rule. It specifies how to build the output file name for a given input name. `@BASENAME@` is a placeholder for the input file name without preceding path or suffix (if any). So if the input file name were `some/path/filename.idl`, then the output name would be `filename.c`. You can also use `@PLAINNAME@`, which preserves the suffix which would result in a file called `filename.idl.c`. The last line specifies the command line arguments to pass to the executable. `@INPUT@` and `@OUTPUT@` are placeholders for the input and output files, respectively, and will be automatically filled in by Meson. If your rule produces multiple output files and you need to pass them to the command line, append the location to the output holder like this: `@OUTPUT0@`, `@OUTPUT1@` and so on. + +With this rule specified we can generate source files and add them to a target. + +```meson +gen_src = gen.process('input1.idl', 'input2.idl') +executable('program', 'main.c', gen_src) +``` + +Generators can also generate multiple output files with unknown names: + +```meson +gen2 = generator(someprog, + outputs : ['@BASENAME@.c', '@BASENAME@.h'], + arguments : ['--out_dir=@BUILD_DIR@', '@INPUT@'] +``` + +In this case you can not use the plain `@OUTPUT@` variable, as it would be ambiguous. This program only needs to know the output directory, it will generate the file names by itself. diff --git a/docs/markdown/Getting-meson.md b/docs/markdown/Getting-meson.md new file mode 100644 index 0000000..f28a7e2 --- /dev/null +++ b/docs/markdown/Getting-meson.md @@ -0,0 +1,28 @@ +# Getting meson + +## Downloading Meson + +Meson releases can be downloaded from the [Github release page]. + +Meson is also available in the [Python Package Index] and can be +installed with <tt>pip3 install meson</tt>. + +The newest development code can be obtained directly from [Git] + +## Dependencies + +Meson is implemented in Python 3. If your operating system provides a +package manager, use should install it with that. For platforms that +don't have a package manager, you need to download it from [Python's +home page]. + +Depending on your platform and backend you wish to use, you might need +the [Ninja executable]. Again, use your distro-provided version if +possible. Otherwise download it from Ninja project's web site. + + [Github release page]: https://github.com/jpakkane/meson/releases + [Python Package Index]: https://pypi.python.org/pypi/meson/ + [Git]: https://github.com/jpakkane/meson + [Python's home page]: https://www.python.org/downloads/ + [Ninja executable]: https://ninja-build.org/ + diff --git a/docs/markdown/Gnome-module.md b/docs/markdown/Gnome-module.md new file mode 100644 index 0000000..af1e059 --- /dev/null +++ b/docs/markdown/Gnome-module.md @@ -0,0 +1,147 @@ +# GNOME module + +This module provides helper tools for build operations needed when building Gnome/GLib programs. + +**Note**:Ā the compilation commands here might not work properly when you change the source files. This is a bug in the respective compilers which do not expose the required dependency information. This has been reported upstream in [this bug]. Until this is fixed you need to be careful when changing your source files. + + [this bug]: https://bugzilla.gnome.org/show_bug.cgi?id=745754 + +## Usage + +To use this module, just do: **`gnome = import('gnome')`**. The following functions will then be available as methods on the object with the name `gnome`. You can, of course, replace the name `gnome` with anything else. + +### gnome.compile_resources() + +This function compiles resources specified in an XML file into code that can be embedded inside the main binary. Similar a build target it takes two positional arguments. The first one is the name of the resource and the second is the xml file containing the resource definitions. If the name is `foobar`, Meson will generate a header file called `foobar.h`, which you can then include in your sources. There are two keyword arguments. + +* `source_dir`: a list of subdirectories where the resource compiler should look up the files, relative to the location of the xml file +* `c_name`: passed to the resource compiler as an argument after `--c-name` +* `extra_args`: extra command line arguments to pass to the resource compiler + +Returns an array of two elements which are: `[c_source, header_file]` + +### gnome.generate_gir() + +Generates GObject introspection data. Takes one positional argument, the build target you want to build gir data for. There are several keyword arguments. Many of these map directly to the `g-ir-scanner` tool so see its documentation for more information. + +* `sources`: the list of sources to be scanned for gir data +* `nsversion`: namespace version +* `namespace`: the namespace for this gir object which determines output files +* `symbol_prefix`: the symbol prefix for the gir object, e.g. `gtk` +* `identifier_prefix`: the identifier prefix for the gir object, e.g. `Gtk` +* `export_packages`: extra packages the gir file exports +* `includes`: list of gir names to be included, can also be a GirTarget +* `dependencies`: deps to use during introspection scanning +* `link_with`: list of libraries to link with +* `include_directories`: extra include paths to look for gir files +* `install`: if true, install the generated files +* `install_dir_gir`: (*Added 0.35.0*) which directory to install the gir file into +* `install_dir_typelib`: (*Added 0.35.0*) which directory to install the typelib file into +* `extra_args`: command line arguments to pass to gir compiler + +Returns an array of two elements which are: `[gir_target, typelib_target]` + +### gnome.genmarshal() + +Generates a marshal file using the `glib-genmarshal` tool. The first argument is the basename of +the output files. + +* `sources`: the list of sources to use as inputs +* `prefix`: the prefix to use for symbols +* `install_header`: if true, install the generated header +* `install_dir`: directory to install header to +* `stdinc`: if true, include the standard marshallers from glib +* `nostdinc`: if true, don't include the standard marshallers from glib +* `internal`: if true, mark generated sources as internal +* `skip_source`: if true, skip source location comments +* `valist_marshallers`: if true, generate va_list marshallers + + +*Added 0.35.0* + +Returns an array of two elements which are: `[c_source, header_file]` + +### gnome.mkenums() + +Generates enum files for GObject using the `glib-mkenums` tool. The first argument is the base name of the output files. + +Note that if you `#include` the generated header in any of the sources for a build target, you must add the generated header to the build target's list of sources to codify the dependency. This is true for all generated sources, not just `mkenums`. + +* `sources`: the list of sources to make enums with +* `c_template`: template to use for generating the source +* `h_template`: template to use for generating the header +* `install_header`: if true, install the generated header +* `install_dir`: directory to install the header +* `comments`: comment passed to the command +* `identifier_prefix`: prefix to use for the identifiers +* `symbol_prefix`: prefix to use for the symbols +* `eprod`: enum text +* `fhead`: file header +* `fprod`: file text +* `ftail`: file tail +* `vhead`: value text +* `vtail`: value tail + +*Added 0.35.0* + +Returns an array of two elements which are: `[c_source, header_file]` + +### gnome.compile_schemas() + +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. + +### gnome.gdbus_codegen() + +Compiles the given XML schema into gdbus source code. Takes two positional arguments, the first one specifies the name of the source files and the second specifies the XML file name. There are three keyword arguments. `interface_prefix` and `namespace` map to corresponding features of the compiler while `object_manager` (since 0.40.0), when set to true, generates object manager code. + +Returns an opaque object containing the source files. Add it to a top level target's source list. + +### gnome.compile_vapi() + +Creates a vapi file from gir. The first argument is the name of the library. + +* `sources`: the gir source to generate the vapi from +* `packages`: vapi packages that are depended upon +* `metadata_dirs`: extra directories to include for metadata files +* `gir_dirs`: extra directories to include for gir files +* `vapi_dirs`: extra directories to include for vapi files + +Returns a custom dependency that can be included when building other vapi or vala binaries. + +*Added 0.36.0* + +### gnome.yelp() + +Installs help documentation using Yelp. The first argument is the project id. + +This also creates two targets for translations `help-$project-update-po` and `help-$project-pot`. + +* `sources`: list of pages +* `media`: list of media such as images +* `symlink_media`: if media should be symlinked (requires newish yelp) defaults to `false` +* `languages`: list of languages for translations + +*Added 0.36.0* + +### gnome.gtkdoc() + +Compiles and installs gtkdoc documentation. Takes one positional arguments; The name of the module. + +* `main_xml`: specifies the main xml file +* `main_sgml`: equal to `main_xml` +* `src_dir`: include_directories to include +* `dependencies`: a list of dependencies +* `install`: if true, installs the generated docs +* `install_dir`: the directory to install the generated docs +* `scan_args`: a list of arguments to pass to `gtkdoc-scan` +* `scanobjs_args`: a list of arguments to pass to `gtkdoc-scangobj` +* `gobject_typesfile`: a list of type files +* `fixxref_args`: a list of arguments to pass to `gtkdoc-fixxref` +* `html_args` a list of arguments to pass to `gtkdoc-mkhtml` +* `html_assets`: a list of assets for the html pages +* `content_files`: a list of content files + +### gnome.gtkdoc_html_dir() + +Takes as argument a module name and returns the path where that module's HTML files will be installed. Usually used with `install_data` to install extra files, such as images, to the output directory. diff --git a/docs/markdown/IDE-integration.md b/docs/markdown/IDE-integration.md new file mode 100644 index 0000000..7e046c6 --- /dev/null +++ b/docs/markdown/IDE-integration.md @@ -0,0 +1,41 @@ +# IDE integration + +Meson has exporters for Visual Studio and XCode, but writing a custom backend for every IDE out there is not a scalable approach. To solve this problem, Meson provides an API that makes it easy for any IDE or build tool to integrate Meson builds and provide an experience comparable to a solution native to the IDE. + +The basic tool for this is a script called `mesonintrospect.py`. Some distro packages might not expose this script in the regular path, and in this case you need to execute it from the install directory. + +The first thing to do when setting up a Meson project in an IDE is to select the source and build directories. For this example we assume that the source resides in an Eclipse-like directory called `workspace/project` and the build tree is nested inside it as `workspace/project/build`. First we initialise Meson by running the following command in the source directory. + + meson build + +For the remainder of the document we assume that all commands are executed inside the build directory unless otherwise specified. + +The first thing you probably want is to get a list of top level targets. For that we use the introspection tool. It comes with extensive command line help so we recommend using that in case problems appear. + + mesonintrospect.py --targets + +The JSON formats will not be specified in this document. The easiest way of learning them is to look at sample output from the tool. + +Once you have a list of targets, you probably need the list of source files that comprise the target. To get this list for a target, say `exampletarget`, issue the following command. + + mesonintrospect.py --target-files exampletarget + +In order to make code completion work, you need the compiler flags for each compilation step. Meson does not provide this itself, but the Ninja tool Meson uses to build does provide it. To find out the compile steps necessary to build target foo, issue the following command. + + ninja -t commands foo + +Note that if the target has dependencies (such as generated sources), then the commands for those show up in this list as well, so you need to do some filtering. Alternatively you can grab every command invocation in the [clang tools db](http://clang.llvm.org/docs/JSONCompilationDatabase.html) format that is written to a file called `compile_commands.json` in the build directory. + +The next thing to display is the list of options that can be set. These include build type and so on. Here's how to extract them. + + mesonintrospect.py --buildoptions + +To set the options, use the `mesonconf.py` binary. + +Compilation and unit tests are done as usual by running the `ninja` and `ninja test` commands. A JSON formatted result log can be found in `workspace/project/build/meson-logs/testlog.json`. + +When these tests fail, the user probably wants to run the failing test in a debugger. To make this as integrated as possible, extract the test test setups with this command. + + mesonintrospect.py --tests + +This provides you with all the information needed to run the test: what command to execute, command line arguments and environment variable settings. diff --git a/docs/markdown/In-the-press.md b/docs/markdown/In-the-press.md new file mode 100644 index 0000000..6f6df46 --- /dev/null +++ b/docs/markdown/In-the-press.md @@ -0,0 +1,8 @@ +# In the press + +This page lists cases where Meson has been presented in the press. + +* [Linux Magazin](http://www.linux-magazin.de/Ausgaben/2014/08/), in German, August 2014, and also later in [Linux Magazine](http://www.linux-magazine.com/Issues/2014/166/Meson-Build-System) in English +* [Admin Magazine](http://www.admin-magazine.com/HPC/Articles/The-Meson-Build-System) +* [Phoronix](http://www.phoronix.com/scan.php?page=news_item&px=MTc1MDc) regarding compilation of Mesa3D +* [CppCast](http://cppcast.com/2015/12/jussi-pakkanen/) interviewed Jussi about Meson for C++ development in 12/2015 diff --git a/docs/markdown/Include-directories.md b/docs/markdown/Include-directories.md new file mode 100644 index 0000000..949bf2c --- /dev/null +++ b/docs/markdown/Include-directories.md @@ -0,0 +1,17 @@ +# Include directories + +Most `C`/`C++` projects have headers in different directories than sources. Thus you need to specify include directories. Let's assume that we are at some subdirectory and wish to add its `include` subdirectory to some target's search path. To create a include directory object we do this: + +```meson +incdir = include_directories('include') +``` + +The `incdir` variable now holds a reference to the `include` subdir. Now we pass that as an argument to a build target: + +```meson +executable('someprog', 'someprog.c', include_directories : incdir) +``` + +Note that these two commands can be given in any subdirectories and it will still work. Meson will keep track of the locations and generate proper compiler flags to make it all work. + +Another thing to note is that `include_directories` adds both the source directory and corresponding build directory to include path, so you don't have to care. diff --git a/docs/markdown/IndepthTutorial.md b/docs/markdown/IndepthTutorial.md new file mode 100644 index 0000000..d67adf7 --- /dev/null +++ b/docs/markdown/IndepthTutorial.md @@ -0,0 +1,90 @@ +# An in-depth tutorial + +In this tutorial we set up a project with multiple targets, unit tests and dependencies between targets. Our main product is a shared library called *foo* that is written in `C++11`. We are going to ignore the contents of the source files, as they are not really important from a build definition point of view. The library makes use of the `GLib` library so we need to detect and link it properly. We also make the resulting library installable. + +The source tree contains three subdirectories `src`, `include` and `test` that contain, respectively, the source code, headers and unit tests of our project. + +To start things up, here is the top level `meson.build` file. + +```meson +project('c++ foolib', 'cpp', + version : '1.0.0', + license : 'MIT') +add_global_arguments('-DSOME_TOKEN=value', language : 'cpp') +glib_dep = dependency('glib-2.0') + +inc = include_directories('include') + +subdir('include') +subdir('src') +subdir('test') + +pkg_mod = import('pkgconfig') +pkg_mod.generate(libraries : foolib, + version : '1.0', + name : 'libfoobar', + filebase : 'foobar', + description : 'A Library to barnicate your foos.') +``` + +The definition always starts with a call to the `project` function. In it you must specify the project's name and programming languages to use, in this case only `C++`. We also specify two additional arguments, the project's version and the license it is under. Our project is version `1.0.0` and is specified to be under the MIT license. + +Then we find GLib, which is an *external dependency*. The `dependency` function tells Meson to find the library (by default using `pkg-config`). If the library is not found, Meson will raise an error and stop processing the build definition. + +Then we add a global compiler argument `-DSOME_TOKEN=value`. This flag is used for *all* C++ source file compilations. It is not possible to unset it for some targets. The reason for this is that it is hard to keep track of what compiler flags are in use if global settings change per target. + +Since `include` directory contains the header files, we need a way to tell compilations to add that directory to the compiler command line. This is done with the `include_directories` command that takes a directory and returns an object representing this directory. It is stored in variable `inc` which makes it accessible later on. + +After this are three `subdir` commands. These instruct Meson to go to the specified subdirectory, open the `meson.build` file that's in there and execute it. The last few lines are a stanza to generate a `pkg-config` file. We'll skip that for now and come back to it at the end of this document. + +The first subdirectory we go into is `include`. In it we have a a header file for the library that we want to install. This requires one line. + +```meson +install_headers('foolib.h') +``` + +This installs the given header file to the system's header directory. This is by default `/[install prefix]/include`, but it can be changed with a command line argument. + +The Meson definition of `src` subdir is simple. + +```meson +foo_sources = ['source1.cpp', 'source2.cpp'] +foolib = shared_library('foo', + foo_sources, + include_directories : inc, + dependencies : glib_dep, + install : true) +``` + +Here we just tell Meson to build the library with the given sources. We also tell it to use the include directories we stored to variable `inc` earlier. Since this library uses GLib, we tell Meson to add all necessary compiler and linker flags with the `dependencies` keyword argument. Its value is `glib_dep` which we set at the top level `meson.build` file. The `install` argument tells Meson to install the result. As with the headers, the shared library is installed to the system's default location (usually `/[install prefix]/lib`) but is again overridable. + +The resulting library is stored in variable `foolib` just like the include directory was stored in the previous file. + +Once Meson has processed the `src` subdir it returns to the main Meson file and executes the next line that moves it into the `test` subdir. Its contents look like this. + +```meson +testexe = executable('testexe', 'footest.cpp', + include_directories : inc, + link_with : foolib) +test('foolib test', testexe) +``` + +First we build a test executable that has the same include directory as the main library and which also links against the freshly built shared library. Note that you don't need to specify `glib_dep` here just to be able to use the built library `foolib`. If the executable used GLib functionality itself, then we would of course need to add it as a keyword argument here. + +Finally we define a test with the name `foolib test`. It consists of running the binary we just built. If the executable exits with a zero return value, the test is considered passed. Nonzero return values mark the test as failed. + +At this point we can return to the pkg-config generator line. All shared libraries should provide a pkg-config file, which explains how that library is used. Meson provides this simple generator that should be sufficient for most simple projects. All you need to do is list a few basic pieces of information and Meson takes care of generating an appropriate file. More advanced users might want to create their own pkg-config files using Meson's [configuration file generator system](Configuration.md). + +With these four files we are done. To configure, build and run the test suite, we just need to execute the following commands (starting at source tree root directory). + +```console +$ meson build && cd build +$ ninja +$ ninja test +``` + +To then install the project you only need one command. + +```console +$ ninja install +``` diff --git a/docs/markdown/Installing.md b/docs/markdown/Installing.md new file mode 100644 index 0000000..37590c1 --- /dev/null +++ b/docs/markdown/Installing.md @@ -0,0 +1,70 @@ +# Installing + +By default Meson will not install anything. Build targets can be installed by tagging them as installable in the definition. + +```meson +project('install', 'c') +shared_library('mylib', 'libfile.c', install : true) +``` + +There is usually no need to specify install paths or the like. Meson +will automatically install it to the standards-conforming location. In +this particular case the executable is installed to the `bin` +subdirectory of the install prefix. However if you wish to override the +install dir, you can do that with the `install_dir` argument. + +```meson +executable('prog', 'prog.c', install : true, install_dir : 'my/special/dir') +``` + +Other install commands are the following. + +```meson +install_headers('header.h', subdir : 'projname') # -> include/projname/header.h +install_man('foo.1') # -> share/man/man1/foo.1.gz +install_data('datafile.cat', install_dir : join_paths(get_option('datadir'), 'progname')) # -> share/progname/datafile.dat +``` + +Sometimes you want to copy an entire subtree directly. For this use case there is the `install_subdir` command, which can be used like this. + +```meson +install_subdir('mydir', install_dir : 'include') # mydir subtree -> include/mydir +``` + +Most of the time you want to install files relative to the install +prefix. Sometimes you need to go outside of the prefix (such as writing +files to `/etc` instead of `/usr/etc`. This can be accomplished by +giving an absolute install path. + +```meson +install_data(sources : 'foo.dat', install_dir : '/etc') # -> /etc/foo.dat +``` + +## Custom install behaviour ## + +Sometimes you need to do more than just install basic targets. Meson makes this easy by allowing you to specify a custom script to execute at install time. As an example, here is a script that generates an empty file in a custom directory. + +```bash +#!/bin/sh + +mkdir "${DESTDIR}/${MESON_INSTALL_PREFIX}/mydir" +touch "${DESTDIR}/${MESON_INSTALL_PREFIX}/mydir/file.dat" +``` + +As you can see, Meson sets up some environment variables to help you write your script (`DESTDIR` is not set by Meson, it is inherited from the outside environment). In addition to the install prefix, Meson also sets the variables `MESON_SOURCE_ROOT` and `MESON_BUILD_ROOT`. + +Telling Meson to run this script at install time is a one-liner. + +```meson +meson.set_install_script('myscript.sh') +``` + +The argument is the name of the script file relative to the current subdirectory. + +## DESTDIR support ## + +Sometimes you need to install to a different directory than the install prefix. This is most common when building rpm or deb packages. This is done with the `DESTDIR` environment variable and it is used just like with other build systems: + +```console +$ DESTDIR=/path/to/staging/area ninja install +``` diff --git a/docs/markdown/Java.md b/docs/markdown/Java.md new file mode 100644 index 0000000..8501bdf --- /dev/null +++ b/docs/markdown/Java.md @@ -0,0 +1,22 @@ +--- +title: Java +... + +# Compiling Java applications + +Meson has experimental support for compiling Java programs. The basic syntax consists of only one function and would be used like this: + +```meson +project('javaprog', 'java') + +myjar = jar('mything', 'com/example/Prog.java', + main_class : 'com.example.Prog') + +test('javatest', myjar) +``` + +However note that Meson places limitations on how you lay out your code. + +* all Java files for a jar must be under the subdirectory the jar definition is in +* all Java files must be in paths specified by their package, e.g. a class called `com.example.Something` must be in a Java file situated at `com/example/Something.java`. +* Meson only deals with jar files, you cannot poke individual class files (unless you do so manually) diff --git a/docs/markdown/Localisation.md b/docs/markdown/Localisation.md new file mode 100644 index 0000000..9fde970 --- /dev/null +++ b/docs/markdown/Localisation.md @@ -0,0 +1,36 @@ +# Localisation + +Localising your application with GNU Gettext takes a little effort but is quite straightforward. This documentation assumes that you have a `po` subdirectory at your project root directory that contains all the localisation info. + +The first thing you need is a file called `POTFILES`. It lists all the source files that Gettext should scan in order to find strings to translate. The syntax of the file is one line per source file and the line must contain the relative path from source root. A sample POTFILES might look like this. + + src/file1.c + src/file2.c + src/subdir/file3.c + include/mything/somefile.h + +We also need to define an array of strings containing all the locales we want to generate. This is done in the Meson file in the `po` subdirectory. Assuming we want to generate Finnish and German localisations, the definition would look like this. + +```meson +langs = ['fi', 'de'] +``` + +Then we need to generate the main pot file. Usually this is generated manually or exists already. If not, see later on how to generate it using Meson. The potfile can have any name but is usually the name of the Gettext package. Let's say the project is called *intltest*. In this case the corresponding pot file would be called `inltest.pot`. + +For each language listed in the array above we need a corresponding `.po` file. This has to be generated manually, see the Gettext manual for details. Once we have all this, we can define the localisation to Meson with these lines. + +```meson +i18n = import('i18n') +langs = ['fi', 'de'] +i18n.gettext('intltest', languages : langs) +``` + +The first command imports the `i18n` module that provides Gettext features. The second line does the actual invocation. The first argument to the is the Gettext package name. This causes two things to happen. The first is that Meson will generate binary mo files and put them to their proper locations when doing an install. The second is that it creates a build rule to regenerate the main pot file. If you are using the Ninja backend, this is how you would invoke the rebuild. + +```console +$ ninja intltest-pot +``` + +If the pot file does not yet exist, it will be created. It is recommended to inspect it manually afterwards and fill in e.g. proper copyright and contact information. + +Meson does not currently have built in commands for generating po files from the pot file. This is because translations are usually done by people who are not developers and thus have their own workflows. diff --git a/docs/markdown/Manual.md b/docs/markdown/Manual.md new file mode 100644 index 0000000..0c126c0 --- /dev/null +++ b/docs/markdown/Manual.md @@ -0,0 +1,7 @@ +--- +short-description: User manual for Meson +... + +# Manual + +This is the user manual for Meson. It currently tracks the state of Git head. If you are using an older version, some of the information here might not work for you. diff --git a/docs/markdown/Meson-design-rationale:-A-proposal-for-a-better-cross-platform-build-system.md b/docs/markdown/Meson-design-rationale:-A-proposal-for-a-better-cross-platform-build-system.md new file mode 100644 index 0000000..9636238 --- /dev/null +++ b/docs/markdown/Meson-design-rationale:-A-proposal-for-a-better-cross-platform-build-system.md @@ -0,0 +1,122 @@ +# Meson design rationale: A proposal for a better cross platform build system + +_This document is the original design description for Meson. The syntax listed here does not necessarily correspond to the current status of Meson._ + +-------- + +A software developer's most important tool is the editor. If you talk to coders about the editors they use, you are usually met with massive enthusiasm and praise. You will hear how Emacs is the greatest thing ever or how vi is so elegant or how Eclipse's integration features make you so much more productive. You can sense the enthusiasm and affection that the people feel towards these programs. + +The second most important tool, even more important than the compiler, is the build system. + +Those are pretty much universally despised. + +The most positive statement on build systems you can usually get (and it might require some coaxing) is something along the lines of *well, it's a terrible system, but all other options are even worse*. It is easy to see why this is the case. For starters, commonly used free build systems have obtuse syntaxes. They use for the most part global variables that are set in random locations so you can never really be sure what a given line of code does. They do strange and unpredictable things at every turn. + +Let's illustrate this with a simple example. Suppose we want to run a program built with GNU Autotools under gdb. The instinctive thing to do is to just run `gdb programname`. The problem is that this may or may not work. In some cases the executable file is a binary whereas at other times it is a wrapper shell script that invokes the real binary which resides in a hidden subdirectory. Gdb invocation fails if the binary is a script but succeeds if it is not. The user has to remember the type of each one of his executables (which is an implementation detail of the build system) just to be able to debug them. Several other such pain points can be found in [this blog post](http://voices.canonical.com/jussi.pakkanen/2011/09/13/autotools/). + +Given these idiosyncrasies it is no wonder that most people don't want to have anything to do with build systems. They'll just copypaste code that works (somewhat) in one place to another and hope for the best. They actively go out of their way not to understand the system because the mere thought of it is repulsive. Doing this also provides a kind of inverse job security. If you don't know tool X, there's less chance of finding yourself responsible for its use in your organisation. Instead you get to work on more enjoyable things. + +This leads to a vicious circle. Since people avoid the tools and don't want to deal with them, very few work on improving them. The result is apathy and stagnation. + +Can we do better? +-- + +At its core, building C and C++ code is not a terribly difficult task. In fact, writing a text editor is a lot more complicated and takes more effort. Yet we have lots of very high quality editors but only few build systems with questionable quality and usability. + +So, in the grand tradition of own-itch-scratching, I decided to run a scientific experiment. The purpose of this experiment was to explore what would it take to build a "good" build system. What kind of syntax would suit this problem? What sort of problems would this application need to solve? What sort of solutions would be the most appropriate? + +To get things started, here is a list of requirements any modern cross-platform build system needs to provide. + +###1. Must be simple to use### + +One of the great virtues of Python is the fact that it is very readable. It is easy to see what a given block of code does. It is concise, clear and easy to understand. The proposed build system must be syntactically and semantically clean. Side effects, global state and interrelations must be kept at a minimum or, if possible, eliminated entirely. + +###2. Must do the right thing by default### + +Most builds are done by developers working on the code. Therefore the defaults must be tailored towards that use case. As an example the system shall build objects without optimization and with debug information. It shall make binaries that can be run directly from the build directory without linker tricks, shell scripts or magic environment variables. + +###3. Must enforce established best practices### + +There really is no reason to compile source code without the equivalent of `-Wall`. So enable it by default. A different kind of best practice is the total separation of source and build directories. All build artifacts must be stored in the build directory. Writing stray files in the source directory is not permitted under any circumstances. + +###4. Must have native support for platforms that are in common use### + +A lot of free software projects can be used on non-free platforms such as Windows or OSX. The system must provide native support for the tools of choice on those platforms. In practice this means native support for Visual Studio and XCode. Having said IDEs invoke external builder binaries does not count as native support. + +###5. Must not add complexity due to obsolete platforms### + +Work on this build system started during the Christmas holidays of 2012. This provides a natural hard cutoff line of 2012/12/24. Any platform, tool or library that was not in active use at that time is explicitly not supported. These include unixes such as IRIX, SunOS, OSF-1, Ubuntu versions older than 12/10, GCC versions older than 4.7 and so on. If these old versions happen to work, great. If they don't, not a single line of code will be added to the system to work around their bugs. + +###6. Must be fast### + +Running the configuration step on a moderate sized project must not take more than five seconds. Running the compile command on a fully up to date tree of 1000 source files must not take more than 0.1 seconds. + +###7. Must provide easy to use support for modern sw development features### + +An example is precompiled headers. Currently no free software build system provides native support for them. Other examples could include easy integration of Valgrind and unit tests, test coverage reporting and so on. + +###8. Must allow override of default values### + +Sometimes you just have to compile files with only given compiler flags and no others, or install files in weird places. The system must allow the user to do this if he really wants to. + +Overview of the solution +-- + +Going over these requirements it becomes quite apparent that the only viable approach is roughly the same as taken by CMake: having a domain specific language to declare the build system. Out of this declaration a configuration is generated for the backend build system. This can be a Makefile, Visual Studio or XCode project or anything else. + +The difference between the proposed DSL and existing ones is that the new one is declarative. It also tries to work on a higher level of abstraction than existing systems. As an example, using external libraries in current build systems means manually extracting and passing around compiler flags and linker flags. In the proposed system the user just declares that a given build target uses a given external dependency. The build system then takes care of passing all flags and settings to their proper locations. This means that the user can focus on his own code rather than marshalling command line arguments from one place to another. + +A DSL is more work than the approach taken by SCons, which is to provide the system as a Python library. However it allows us to make the syntax more expressive and prevent certain types of bugs by e.g. making certain objects truly immutable. The end result is again the same: less work for the user. + +The backend for Unix requires a bit more thought. The default choice would be Make. However it is extremely slow. It is not uncommon on large code bases for Make to take several minutes just to determine that nothing needs to be done. Instead of Make we use [Ninja](http://martine.github.com/ninja/), which is extremely fast. The backend code is abstracted away from the core, so other backends can be added with relatively little effort. + +Sample code +-- + +Enough design talk, let's get to the code. Before looking at the examples we would like to emphasize that this is not in any way the final code. It is proof of concept code that works in the system as it currently exists (February 2013), but may change at any time. + +Let's start simple. Here is the code to compile a single executable binary. + + project('compile one', 'c') + executable('program', 'prog.c')< + +This is about as simple as one can get. First you declare the project name and the languages it uses. Then you specify the binary to build and its sources. The build system will do all the rest. It will add proper suffixes (e.g. '.exe' on Windows), set the default compiler flags and so on. + +Usually programs have more than one source file. Listing them all in the function call can become unwieldy. That is why the system supports keyword arguments. They look like this. + + project('compile several', 'c') + sources = ['main.c', 'file1.c', 'file2.c', 'file3.c'] + executable('program', sources : sourcelist) + +External depencencies are simple to use. + +`project('external lib', 'c') +libdep = find_dep('extlibrary', required : true) +sources = ['main.c', 'file1.c', 'file2.c', 'file3.c'] +executable('program', sources : sourcelist, dep : libdep)` + +In other build systems you have to manually add the compile and link flags from external dependencies to targets. In this system you just declare that extlibrary is mandatory and that the generated program uses that. The build system does all the plumbing for you. + +Here's a slightly more complicated definition. It should still be understandable. + +`project('build library', 'c') +foolib = shared_library('foobar', sources : 'foobar.c',\ + install : true) +exe = executable('testfoobar', 'tester.c', link : foolib) +add_test('test library', exe)` + +First we build a shared library named foobar. It is marked installable, so running `ninja install` installs it to the library directory (the system knows which one so the user does not have to care). Then we build a test executable which is linked against the library. It will no tbe installed, but instead it is added to the list of unit tests, which can be run with the command `ninja test`. + +Above we mentioned precompiled headers as a feature not supported by other build systems. Here's how you would use them. + + project('pch demo', 'cxx') + executable('myapp', 'myapp.cpp', pch : 'pch/myapp.hh') + +The main reason other build systems can not provide pch support this easily is because they don't enforce certain best practices. Due to the way include paths work, it is impossible to provide pch support that always works with both in-source and out-of-source builds. Mandating separate build and source directories makes this and many other problems a lot easier. + +Get the code +-- + +The code for this experiment can be found at [the Meson repository](https://sourceforge.net/p/meson/code/). It should be noted that it is not a build system. It is only a proposal for one. It does not work reliably yet. You probably should not use it as the build system of your project. + +All that said I hope that this experiment will eventually turn into a full blown build system. For that I need your help. Comments and especially patches are more than welcome. diff --git a/docs/markdown/Meson-sample.md b/docs/markdown/Meson-sample.md new file mode 100644 index 0000000..6f26f36 --- /dev/null +++ b/docs/markdown/Meson-sample.md @@ -0,0 +1,58 @@ +--- +short-description: Simple project step by step explanation +... + +# Meson sample + +A Meson file that builds an executable looks like this. + +```meson +project('simple', 'c') +executable('myexe', 'source.c') +``` + +All Meson build definitions begin with the `project` command. It specifies the name of the project and what programming languages it uses. Here the project is called *simple* and it uses only the C programming language. All strings are single-quoted. + +On the next line we define a *build target*, in this case an executable called *myexe*. It consists of one source file. This is all the code that a user needs to write to compile an executable with Meson. + +Variables are fully supported. The above code snippet could also have been declared like this. + +```meson +project('simple', 'c') +src = 'source.c' +executable('myexe', src) +``` + +Most executables consist of more than one source file. The easiest way to deal with this is to put them in an array. + +```meson +project('simple', 'c') +src = ['source1.c', 'source2.c', 'source3.c'] +executable('myexe', src) +``` + +Meson also supports the notion of *keyword arguments*. Indeed most arguments to functions can only be passed using them. The above snippet could be rewritten like this. + +```meson +project('simple', 'c') +src = ['source1.c', 'source2.c', 'source3.c'] +executable('myexe', sources : src) +``` + +These two formats are equivalent and choosing one over the other is mostly a question of personal preference. + +The `executable` command actually returns an *executable object*, which represents the given build target. It can be passed on to other functions, like this. + +```meson +project('simple', 'c') +src = ['source1.c', 'source2.c', 'source3.c'] +exe = executable('myexe', src) +test('simple test', exe) +``` + +Here we create a unit test called *simple test*, and which uses the built executable. When the tests are run with the `ninja test` command, the built executable is run. If it returns zero, the test passes. A non-zero return value indicates an error, which Meson will then report to the user. + +A note to Visual Studio users +----- + +There's a slight terminology difference between Meson and Visual Studio. A Meson *project* is the equivalent to a Visual Studio *solution*. That is, the topmost thing that encompasses all things to be built. A Visual Studio *project* on the other hand is the equivalent of a Meson top level build target, such as an executable or a shared library. diff --git a/docs/markdown/Module-reference.md b/docs/markdown/Module-reference.md new file mode 100644 index 0000000..866c141 --- /dev/null +++ b/docs/markdown/Module-reference.md @@ -0,0 +1,10 @@ +Meson has a selection of modules to make common requirements easy to use. Modules can be thought of like the standard library of a programming language. Currently Meson provides the following modules. + +* [Gnome](Gnome-module.md) +* [i18n](i18n-module.md) +* [Qt4](Qt4-module.md) +* [Qt5](Qt5-module.md) +* [Pkgconfig](Pkgconfig-module.md) +* [Python3](Python-3-module.md) +* [RPM](RPM-module.md) +* [Windows](Windows-module.md) diff --git a/docs/markdown/Modules.md b/docs/markdown/Modules.md new file mode 100644 index 0000000..e594383 --- /dev/null +++ b/docs/markdown/Modules.md @@ -0,0 +1,18 @@ +# Modules + +In addition to core language features, Meson also provides a module system aimed at providing helper methods for common build operations. Using modules is simple, first you import them: + +```meson +mymod = import('somemodule') +``` + +After this you can use the returned object to use the functionality provided: + +```meson +mymod.do_something('text argument') +``` + +Meson has a selection of modules to make common requirements easy to +use. Modules can be thought of like the standard library of a +programming language. Currently Meson provides the modules listed on +subpages. diff --git a/docs/markdown/Overview.md b/docs/markdown/Overview.md new file mode 100644 index 0000000..b469d9a --- /dev/null +++ b/docs/markdown/Overview.md @@ -0,0 +1,22 @@ +--- +short-description: Overview of the Meson build system +... + +# Overview + +Meson is a build system that is designed to be as user-friendly as possible without sacrificing performance. The main tool for this is a custom language that the user uses to describe the structure of his build. The main design goals of this language has been simplicity, clarity and conciseness. Much inspiration was drawn from the Python programming language, which is considered very readable, even to people who have not programmed in Python before. + +Another main idea has been to provide first class support for modern programming tools and best practices. These include features as varied as unit testing, code coverage reporting, precompiled headers and the like. All of these features should be immediately available to any project using Meson. The user should not need to hunt for third party macros or write shell scripts to get these features. They just just work out of the box. + +This power should not come at the expense of limited usability. Many software builds require unorthodox steps. A common example is that you first need to build a custom tool and then use that tool to generate more source code to build. This functionality needs to be supported and be as easy to use as other parts of the system. + +Terminology +-- + +Meson follows the overall structure of other popular build systems, such as CMake and GNU Autotools. This means that the build is divided into two discrete steps: *configure step* and *build step*. The first step inspects the system, checks for dependencies and does all other steps necessary to configure the build. It then generates the actual build system. The second step is simply executing this generated build system. The end result is a bunch of *build targets*, which are usually executables and shared and static libraries. + +The directory that contains the source code is called the *source directory*. Correspondingly the directory where the output is written is called the *build directory*. In other build systems it is common to have these two be the same directory. This is called an *in-source build*. The case where the build directory is separate is called an *out-of-source build*. + +What sets Meson apart from most build systems is that it enforces a separate build directory. All files created by the build system are put in the build directory. It is actually impossible to do an in-source build. For people used to building inside their source tree, this may seem like a needles complication. However there are several benefits to doing only out-of-source builds. These will be explained in the next chapter. + +When the source code is built, a set of *unit tests* is usually run. They ensure that the program is working as it should. If it does, the build result can be *installed* after which it is ready for use. diff --git a/docs/markdown/Performance-comparison.md b/docs/markdown/Performance-comparison.md new file mode 100644 index 0000000..3f15e82 --- /dev/null +++ b/docs/markdown/Performance-comparison.md @@ -0,0 +1,6 @@ +# Performance comparison + +This page lists experiments comparing build performance between Meson and other build systems. + +- [Simple comparison](Simple-comparison.md) +- [ARM performance test](ARM-performance-test.md) diff --git a/docs/markdown/Pkg-config-files.md b/docs/markdown/Pkg-config-files.md new file mode 100644 index 0000000..bac90bc --- /dev/null +++ b/docs/markdown/Pkg-config-files.md @@ -0,0 +1,19 @@ +# Pkg config files + +[Pkg-config](https://en.wikipedia.org/wiki/Pkg-config) is a way for shared libraries to declare the compiler flags needed to use them. There are two different ways of generating Pkg-config files in Meson. The first way is to build them manually with the `configure_files` command. The second way is to use Meson's built in Pkg-config file generator. The difference between the two is that the latter is very simple and meant for basic use cases. The former should be used when you need to provide a more customised solution. + +In this document we describe the simple generator approach. It is used in the following way. + +```meson +pkg = import('pkgconfig') +libs = ... # the library/libraries users need to link against +h = ['.', ...] # subdirectories of ${prefix}/${includedir} to add to header path +pkg.generate(libraries : libs, + subdirs : h, + version : '1.0', + name : 'libsimple', + filebase : 'simple', + description : 'A simple demo library.') +``` + +This causes a file called `simple.pc` to be created and placed into the install directory during the install phase. diff --git a/docs/markdown/Pkgconfig-module.md b/docs/markdown/Pkgconfig-module.md new file mode 100644 index 0000000..81ca020 --- /dev/null +++ b/docs/markdown/Pkgconfig-module.md @@ -0,0 +1,22 @@ +# Pkgconfig module + +This module is a simple generator for [pkg-config](http://pkg-config.freedesktop.org/) files. + +## Usage + +To use this module, just do: **`pkg = import('pkgconfig')`**. The following function will then be available as `pkg.generate()`. You can, of course, replace the name `pkg` with anything else. + +### pkg.generate() + +The generated file's properties are specified with the following keyword arguments. + +- `libraries` a list of built libraries (usually results of shared_library) that the user needs to link against +- `version` a string describing the version of this library +- `name` the name of this library +- `description` a string describing the library +- `filebase`, the base name to use for the pkg-config file, as an example the value of `libfoo` would produce a pkg-config file called `libfoo.pc` +- `subdirs` which subdirs of `include` should be added to the header search path, for example if you install headers into `${PREFIX}/include/foobar-1`, the correct value for this argument would be `foobar-1` +- `requires` list of strings to put in the `Requires` field +- `requires_private` list of strings to put in the `Requires.private` field +- `libraries_private` list of strings to put in the `Libraries.private` field +- `install_dir` the directory to install to, defaults to the value of option `libdir` followed by `/pkgconfig` diff --git a/docs/markdown/Playground.md b/docs/markdown/Playground.md new file mode 100644 index 0000000..5699f22 --- /dev/null +++ b/docs/markdown/Playground.md @@ -0,0 +1,31 @@ +# playground + +This page is *not* part of official documentation. It exists merely for testing new stuff for the wiki. + +## Ref manual reformat + +The current format is not very readable. We should have something more like what [glib](https://developer.gnome.org/glib/stable/glib-Hash-Tables.html) or [Python](https://docs.python.org/3/library/os.html) do. + +Here's a first proposal. + + project(<project name>, + <languages to use, comma separated>, + version : <project version>, + subproject_dir : <alternative directory to store subprojects>, + meson_version : <required version of Meson>, + license : <string or array of licenses>, + default_options : <default values for project options>, + +Longer descriptions of arguments go here. + +Take two: + +## project + + <project name> + <languages to use, comma separated> + version : <project version> + subproject_dir : <alternative directory to store subprojects> + meson_version : <required version of Meson> + license : <string or array of licenses> + default_options : <default values for project options> diff --git a/docs/markdown/Porting-from-autotools.md b/docs/markdown/Porting-from-autotools.md new file mode 100644 index 0000000..7bd9efd --- /dev/null +++ b/docs/markdown/Porting-from-autotools.md @@ -0,0 +1,627 @@ +# Porting from autotools + +This page uses [appstream-glib](https://github.com/hughsie/appstream-glib/) as an example project. Appstream-Glib contains some libraries, gobject-introspection, tests, man pages, i18n, bash-completion with optional flags to build/notbuild support for some things. + +Meson comes with a helper script `ac_converter` that you can use to convert the basic autoconf checks for your project. + +## Configure.ac + +First let's look at `configure.ac` and write the same in `meson.build`. + +```autoconf +AC_PREREQ(2.63) +``` +Meson doesn't provide the same function, so just ignore this. + +### Defining variables +`configure.ac`: +```autoconf +m4_define([as_major_version], [0]) +m4_define([as_minor_version], [3]) +m4_define([as_micro_version], [6]) +m4_define([as_version], + [as_major_version.as_minor_version.as_micro_version]) +``` +`meson.build`: +```meson + +as_version = meson.project_version() # set in project() below +ver_arr = as_version.split('.') + +as_major_version = ver_arr[0] +as_minor_version = ver_arr[1] +as_micro_version = ver_arr[2] +``` + +### Initializing project and setting compilers +`configure.ac`: +```autoconf +AC_INIT([appstream-glib],[as_version]) +AC_PROG_CC +``` +`meson.build`: +```meson +project('appstream-glib', 'c', version : '0.3.6') +``` +Note that this must be the first line of your `meson.build` file. + +### AC_SUBST +`configure.ac`: +```autoconf +AC_SUBST(AS_MAJOR_VERSION) +AC_SUBST(AS_MINOR_VERSION) +AC_SUBST(AS_MICRO_VERSION) +AC_SUBST(AS_VERSION) +``` + +You don't need to do the same in Meson, because it does not have two different types of files (Makefile, configure). + +### Auto headers + +`configure.ac`: + +```autoconf +AC_CONFIG_HEADERS([config.h]) +``` + +`meson.build`: + +```meson +conf = configuration_data() +# Surround the version in quotes to make it a C string +conf.set_quoted('VERSION', as_version) +configure_file(output : 'config.h', + configuration : conf) +``` + +Meson doesn't support autoheaders, you need to manually specify what do you want to see in header file, write `configuration_data()` object and use `configure_file()`. + +You can also substitute variables of type `@SOME_VAR@` with configure data. The details are on the [configuration page](Configuration.md). + +### Finding programs + +`configure.ac`: + +```autoconf +AC_PATH_PROG(GPERF, [gperf], [no]) +if test x$GPERF != xno ; then + AC_DEFINE(HAVE_GPERF,[1], [Use gperf]) +fi +AM_CONDITIONAL(HAVE_GPERF, [test x$GPERF != xno]) +``` + +`meson.build`: + +```meson +gperf = find_program('gperf', required : false) +if gperf.found() + conf.set('HAVE_GPERF', 1) +endif +``` + +### Finding pkgconfig modules + +`configure.ac`: + +```autoconf +PKG_CHECK_MODULES(SOUP, libsoup-2.4 >= 2.24) +``` + +`meson.build`: + +```meson +soup = dependency('libsoup-2.4', version : '>= 2.24') +``` + +### Arguments + +`configure.ac`: + +```autoconf +AC_ARG_ENABLE(dep11, AS_HELP_STRING([--enable-dep11],[enable DEP-11]), + enable_dep11=$enableval,enable_dep11=yes) +AM_CONDITIONAL(HAVE_DEP11, test x$enable_dep11 = xyes) +if test x$enable_dep11 = xyes; then + AC_CHECK_HEADER(yaml.h, [], [AC_MSG_ERROR([No yaml.h])]) + YAML_LIBS="-lyaml" + AC_SUBST(YAML_LIBS) + AC_DEFINE(AS_BUILD_DEP11,1,[Build DEP-11 code]) +fi +``` + +`meson.build`: + +```meson +if get_option('enable-dep11') + yaml = dependency('yaml-0.1') + conf.set('AS_BUILD_DEP11', 1) +else + yaml = dependency('yaml-0.1', required : false) +endif +``` + +`meson_options.txt`: + +```meson +option('enable-dep11', type : 'boolean', value : true, description : 'enable DEP-11') +``` + +## Makefile.am + +Next step is `Makefile.am`. In meson you don't need to have other file, you still use `meson.build`. + +### Sub directories + +`Makefile.am`: + +```make +SUBDIRS = \ + libappstream-glib +``` + +`meson.build`: + +```meson +subdir('libappstream-glib') +``` + +### *CLEANFILES, EXTRA_DIST, etc. + +`Makefile.am`: + +```make +DISTCLEANFILES = \ + appstream-glib-*.tar.xz + +MAINTAINERCLEANFILES = \ + *~ \ + ABOUT-NLS \ + aclocal.m4 \ + ChangeLog \ + compile \ + config.guess \ + config.h.* \ + config.rpath + +EXTRA_DIST = \ + COPYING \ + MAINTAINERS \ + AUTHORS \ + README.md \ + NEWS \ + autogen.sh \ + config.h +``` + +In Meson you don't need have `*CLEANFILES`, because in meson you are building in temporary directory (usually called `build`), you manually removing it. You also not need to use `EXTRA_DIST`, because you will make tarballs via `git archive` or something like this. + +### glib-compile-resources + +`Makefile.am`: +```make +as-resources.c: appstream-glib.gresource.xml \ + as-stock-icons.txt \ + as-license-ids.txt \ + as-blacklist-ids.txt \ + as-category-ids.txt \ + as-environment-ids.txt + $(AM_V_GEN) \ + glib-compile-resources \ + --sourcedir=$(srcdir) \ + --sourcedir=$(top_builddir)/data \ + --target=$@ \ + --generate-source \ + --c-name as \ + $(srcdir)/appstream-glib.gresource.xml +as-resources.h: appstream-glib.gresource.xml \ + as-stock-icons.txt \ + as-license-ids.txt \ + as-blacklist-ids.txt \ + as-category-ids.txt \ + as-environment-ids.txt + $(AM_V_GEN) \ + glib-compile-resources \ + --sourcedir=$(srcdir) \ + --sourcedir=$(top_builddir)/data \ + --target=$@ \ + --generate-header \ + --c-name as \ + $(srcdir)/appstream-glib.gresource.xml + +BUILT_SOURCES = \ + as-resources.c \ + as-resources.h +``` + +`meson.build`: + +```meson +asresources = gnome.compile_resources( + 'as-resources', 'appstream-glib.gresource.xml', + source_dir : '.', + c_name : 'as') +``` + +### Headers + +`Makefile.am`: + +```make +libappstream_glib_includedir = $(includedir)/libappstream-glib +libappstream_glib_include_HEADERS = \ + appstream-glib.h \ + as-app.h \ + as-bundle.h \ + as-enums.h \ + as-icon.h \ + as-image.h \ + as-inf.h \ + as-node.h \ + as-problem.h \ + as-provide.h \ + as-release.h \ + as-screenshot.h \ + as-store.h \ + as-tag.h \ + as-utils.h \ + as-version.h +``` + +`meson.build`: + +```meson +headers = [ + 'appstream-glib.h', + 'as-app.h', + 'as-bundle.h', + 'as-enums.h', + 'as-icon.h', + 'as-image.h', + 'as-inf.h', + 'as-node.h', + 'as-problem.h', + 'as-provide.h', + 'as-release.h', + 'as-screenshot.h', + 'as-store.h', + 'as-tag.h', + 'as-utils.h', + 'as-version.h'] +install_headers(headers, subdir : 'libappstream-glib') +``` + +### Libraries + +`Makefile.am`: +```make +lib_LTLIBRARIES = \ + libappstream-glib.la +libappstream_glib_la_SOURCES = \ + as-app.c \ + as-app-desktop.c \ + as-app-inf.c \ + as-app-private.h \ + as-app-validate.c \ + as-bundle.c \ + as-bundle-private.h \ + as-cleanup.h \ + as-enums.c \ + as-icon.c \ + as-icon-private.h \ + as-image.c \ + as-image-private.h \ + as-inf.c \ + as-inf.h \ + as-node.c \ + as-node-private.h \ + as-problem.c \ + as-problem.h \ + as-provide.c \ + as-provide-private.h \ + as-release.c \ + as-release-private.h \ + as-resources.c \ + as-resources.h \ + as-screenshot.c \ + as-screenshot-private.h \ + as-store.c \ + as-tag.c \ + as-utils.c \ + as-utils-private.h \ + as-version.h \ + as-yaml.c \ + as-yaml.h + +libappstream_glib_la_LIBADD = \ + $(GLIB_LIBS) \ + $(GDKPIXBUF_LIBS) \ + $(LIBARCHIVE_LIBS) \ + $(SOUP_LIBS) \ + $(YAML_LIBS) + +libappstream_glib_la_LDFLAGS = \ + -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \ + -export-dynamic \ + -no-undefined \ + -export-symbols-regex '^as_.*' +``` + +`meson.build`: + +```meson +sources = [ + 'as-app.c', + 'as-app-desktop.c', + 'as-app-inf.c', + 'as-app-private.h', + 'as-app-validate.c', + 'as-bundle.c', + 'as-bundle-private.h', + 'as-cleanup.h', + 'as-enums.c', + 'as-icon.c', + 'as-icon-private.h', + 'as-image.c', + 'as-image-private.h', + 'as-inf.c', + 'as-inf.h', + 'as-node.c', + 'as-node-private.h', + 'as-problem.c', + 'as-problem.h', + 'as-provide.c', + 'as-provide-private.h', + 'as-release.c', + 'as-release-private.h', + asresources, + 'as-screenshot.c', + 'as-screenshot-private.h', + 'as-store.c', + 'as-tag.c', + 'as-utils.c', + 'as-utils-private.h', + 'as-version.h', + 'as-yaml.c', + 'as-yaml.h'] + +deps = [glib, gdkpixbuf, libarchive, soup, yaml] + +mapfile = 'appstream-glib.map' +vflag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), mapfile) +asglib = shared_library( + 'appstream-glib', sources, + soversion : lt_current, + version : lt_version, + dependencies : deps, + include_directories : include_directories('@0@/..'.format(meson.current_build_dir())), + link_args : ['-Wl,--no-undefined', vflag], + link_depends : mapfile, + install : true) +``` + +`appstream-glib.map`: + +``` +{ +global: + as_*; +local: + *; +}; +``` + +### Custom targets + +`Makefile.am`: + +```make +if HAVE_GPERF +as-tag-private.h: as-tag.gperf + $(AM_V_GEN) gperf < $< > $@ + +libappstream_glib_la_SOURCES += as-tag-private.h +BUILT_SOURCES += as-tag-private.h +endif +``` + +`meson.build`: + +```meson +if gperf.found() + astagpriv = custom_target('gperf as-tag', + output : 'as-tag-private.h', + input : 'as-tag.gperf', + command : [gperf, '@INPUT@', '--output-file', '@OUTPUT@']) + sources = sources + [astagpriv] +endif +``` + +### Global CFLAGS + +`Makefile.am`: + +```make +AM_CPPFLAGS = \ + -DAS_COMPILATION \ + -DLOCALSTATEDIR=\""$(localstatedir)"\" \ + -DG_LOG_DOMAIN=\"As\" +``` + +`meson.build`: + +```meson +add_global_arguments('-DG_LOG_DOMAIN="As"', language : 'c') +add_global_arguments('-DAS_COMPILATION', language : 'c') +add_global_arguments('-DLOCALSTATEDIR="/var"', language : 'c') +``` + +### Tests + +`Makefile.am`: + +```make +check_PROGRAMS = \ + as-self-test +as_self_test_SOURCES = \ + as-self-test.c +as_self_test_LDADD = \ + $(GLIB_LIBS) \ + $(GDKPIXBUF_LIBS) \ + $(LIBARCHIVE_LIBS) \ + $(SOUP_LIBS) \ + $(YAML_LIBS) \ + $(lib_LTLIBRARIES) +as_self_test_CFLAGS = -DTESTDATADIR=\""$(top_srcdir)/data/tests"\" + +TESTS = as-self-test +``` + +`meson.build`: + +```meson +selftest = executable( + 'as-self-test', 'as-self-test.c', + include_directories : include_directories('@0@/..'.format(meson.current_build_dir())), + dependencies : deps, + c_args : '-DTESTDATADIR="@0@/../data/tests"'.format(meson.current_source_dir()), + link_with : asglib) +test('as-self-test', selftest) +``` + +### GObject Introspection + +`Makefile.am`: + +```make +introspection_sources = \ + as-app.c \ + as-app-validate.c \ + as-app.h \ + as-bundle.c \ + as-bundle.h \ + as-enums.c \ + as-enums.h \ + as-icon.c \ + as-icon.h \ + as-image.c \ + as-image.h \ + as-inf.c \ + as-inf.h \ + as-node.c \ + as-node.h \ + as-problem.c \ + as-problem.h \ + as-provide.c \ + as-provide.h \ + as-release.c \ + as-release.h \ + as-screenshot.c \ + as-screenshot.h \ + as-store.c \ + as-store.h \ + as-tag.c \ + as-tag.h \ + as-utils.c \ + as-utils.h \ + as-version.h + +AppStreamGlib-1.0.gir: libappstream-glib.la +AppStreamGlib_1_0_gir_INCLUDES = GObject-2.0 Gio-2.0 GdkPixbuf-2.0 +AppStreamGlib_1_0_gir_CFLAGS = $(AM_CPPFLAGS) +AppStreamGlib_1_0_gir_SCANNERFLAGS = --identifier-prefix=As \ + --symbol-prefix=as_ \ + --warn-all \ + --add-include-path=$(srcdir) +AppStreamGlib_1_0_gir_EXPORT_PACKAGES = appstream-glib +AppStreamGlib_1_0_gir_LIBS = libappstream-glib.la +AppStreamGlib_1_0_gir_FILES = $(introspection_sources) +INTROSPECTION_GIRS += AppStreamGlib-1.0.gir + +girdir = $(datadir)/gir-1.0 +gir_DATA = $(INTROSPECTION_GIRS) + +typelibdir = $(libdir)/girepository-1.0 +typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib) + +CLEANFILES += $(gir_DATA) $(typelib_DATA) +``` + +`meson.build`: + +```meson +introspection_sources = [ + 'as-app.c', + 'as-app-validate.c', + 'as-app.h', + 'as-bundle.c', + 'as-bundle.h', + 'as-enums.c', + 'as-enums.h', + 'as-icon.c', + 'as-icon.h', + 'as-image.c', + 'as-image.h', + 'as-inf.c', + 'as-inf.h', + 'as-node.c', + 'as-node.h', + 'as-problem.c', + 'as-problem.h', + 'as-provide.c', + 'as-provide.h', + 'as-release.c', + 'as-release.h', + 'as-screenshot.c', + 'as-screenshot.h', + 'as-store.c', + 'as-store.h', + 'as-tag.c', + 'as-tag.h', + 'as-utils.c', + 'as-utils.h'] + 'as-version.h'] + +gnome.generate_gir(asglib, + sources : introspection_sources, + nsversion : '1.0', + namespace : 'AppStreamGlib', + symbol_prefix : 'as_', + identifier_prefix : 'As', + export_packages : 'appstream-glib', + includes : ['GObject-2.0', 'Gio-2.0', 'GdkPixbuf-2.0'], + install : true +) +``` + +### GSettings + +`configure.ac`: +```sh +GLIB_GSETTINGS +``` + +`Makefile.am`: +```make +gsettings_SCHEMAS = foo.gschema.xml +@GSETTINGS_RULES@ +``` + +`meson.build`: +```meson +install_data('foo.gschema.xml', install_dir: join_paths(get_option('datadir'), 'glib-2.0', 'schemas')) +meson.add_install_script('meson_post_install.py') +``` + +`meson_post_install.py`: +```python +#!/usr/bin/env python3 + +import os +import subprocess + +schemadir = os.path.join(os.environ['MESON_INSTALL_PREFIX'], 'share', 'glib-2.0', 'schemas') + +if not os.environ.get('DESTDIR'): + print('Compiling gsettings schemas...') + subprocess.call(['glib-compile-schemas', schemadir]) +``` diff --git a/docs/markdown/Precompiled-headers.md b/docs/markdown/Precompiled-headers.md new file mode 100644 index 0000000..a7bcbf8 --- /dev/null +++ b/docs/markdown/Precompiled-headers.md @@ -0,0 +1,62 @@ +# Precompiled headers + +Parsing header files of system libraries is surprisingly expensive. A typical source file has less than one thousand lines of code. In contrast the headers of large libraries can be tens of thousands of lines. This is especially problematic with C++, where header-only libraries are common and they may contain extremely complex code. This makes them slow to compile. + +Precompiled headers are a tool to mitigate this issue. Basically what they do is parse the headers and then serialize the compiler's internal state to disk. The downside of precompiled headers is that they are tricky to set up. Meson has native support for precompiled headers, but using them takes a little work. + +A precompiled header file is relatively simple. It is a header file that contains `#include` directives for the system headers to precompile. Here is a C++ example. + +```cpp + #include<vector> + #include<string> + #include<map> +``` + +In Meson, precompiled header files are always per-target. That is, the given precompiled header is used when compiling every single file in the target. Due to limitations of the underlying compilers, this header file must not be in the same subdirectory as any of the source files. It is strongly recommended that you create a subdirectory called `pch` in the target directory and put the header files (and nothing else) there. + +Toggling the usage of precompiled headers +-- + +If you wish to compile your project without precompiled headers, you can configure it by running Meson with the `--disable-pch` flag. You can also toggle the use of pch in a configured build directory with the gui tool. You don't have to do any changes to the source code. Typically this is done to test whether your project compiles cleanly without pch (that is, checking that its #includes are in order) and working around compiler bugs. + +Using precompiled headers with GCC and derivatives +-- + +Once you have a file to precompile, you can enable the use of pch for a give target with a *pch* keyword argument. As an example, here's how you would use it with a C binary. + +```meson +executable('myexe', sources : sourcelist, c_pch : 'pch/myexe_pch.h') +``` + +You should note that your source files must _not_ include the file `myexe_pch.h` and you must _not_ add the pch subdirectory to your search path. Meson will make the compiler include the pch with compiler options. If you want to disable pch (because of, say, compiler bugs), it can be done entirely on the build system side with no changes to source code. + +You can use precompiled headers on any build target. If your target has multiple languages, you can specify multiple pch files like this. + +```meson +executable('multilang', sources : srclist, + c_pch : 'pch/c_pch.h', cpp_pch : 'pch/cpp_pch.h']) +``` + +Using precompiled headers with MSVC +-- + +MSVC is a bit trickier, because in addition to the header file, it also requires a correspongind source file. If your header is called `foo_pch.h`, the corresponding source file is usually called `foo_pch.cpp` and it resides in the same `pch` subdirectory as the header. Its contents are this: + +```cpp +#if !defined(_MSC_VER) +#error "This file is only for use with MSVC." +#endif + +#include "foo_pch.h" +``` + +To enable pch, simply list both files in the target definition: + +```meson +executable('myexe', sources : srclist, + cpp_pch : ['pch/foo_pch.h', 'pch/foo_pch.cpp']) +``` + +This form will work with both gcc and msvc, because Meson knows that gcc does not need a `.cpp` file and thus just ignores it. + +It should be noted that due to implementation details of the MSVC compiler, having precompiled headers for multiple languages in the same target is not guaranteed to work. diff --git a/docs/markdown/Python-3-module.md b/docs/markdown/Python-3-module.md new file mode 100644 index 0000000..2a33ba8 --- /dev/null +++ b/docs/markdown/Python-3-module.md @@ -0,0 +1,27 @@ +# Python 3 module + +This module provides support for dealing with Python 3. It has the following methods. + +## find_python + +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. + +*Added 0.38.0* + +## extension_module + +Creates a `shared_module` target that is named according to the naming conventions of the target platform. All positional and keyword arguments are the same as for [shared_module](Reference-manual.md#shared_module). + +*Added 0.38.0* + +## language_version + +Returns a string with the Python language version such as `3.5`. + +*Added 0.40.0* + +## sysconfig_path + +Returns the Python sysconfig path without prefix, such as `lib/python3.6/site-packages`. + +*Added 0.40.0* diff --git a/docs/markdown/Qt4-module.md b/docs/markdown/Qt4-module.md new file mode 100644 index 0000000..77e271d --- /dev/null +++ b/docs/markdown/Qt4-module.md @@ -0,0 +1,3 @@ +# Qt4 module + +This module provides support for Qt4's `moc`, `uic` and `rcc` tools. It is used identically to the [Qt 5 module](Qt5-module.md). diff --git a/docs/markdown/Qt5-module.md b/docs/markdown/Qt5-module.md new file mode 100644 index 0000000..2b733bb --- /dev/null +++ b/docs/markdown/Qt5-module.md @@ -0,0 +1,15 @@ +# Qt5 module + +The Qt5 module provides tools to automatically deal with the various tools and steps required for Qt. The module has one method. + +## preprocess + +This method takes four keyword arguments, `moc_headers`, `moc_sources`, `ui_files` and `qresources` which define the files that require preprocessing with `moc`, `uic` and `rcc`. It returns an opaque object that should be passed to a main build target. A simple example would look like this: + +```meson +qt5 = import('qt5') +qt5_dep = dependency('qt5', ...) +moc_files = qt5.preprocess(moc_headers : 'myclass.h') +executable('myprog', 'main.cpp', 'myclass.cpp', moc_files, + dependencies : qt5_dep) +``` diff --git a/docs/markdown/Quick-guide.md b/docs/markdown/Quick-guide.md new file mode 100644 index 0000000..3966084 --- /dev/null +++ b/docs/markdown/Quick-guide.md @@ -0,0 +1,71 @@ +--- +title: Quick guide +short-description: Guide to get started using meson +... + +# Using Meson + +Meson has been designed to be as easy to use as possible. This page outlines the basic use cases. For more advanced cases refer to Meson's command line help which is accessible with the command `meson --help`. + +Requirements +-- + +Meson has two main dependencies. + +* [Python 3](http://python.org) +* [Ninja](https://github.com/ninja-build/ninja/) + +Ninja is only needed if you use the Ninja backend. Meson can also generate native VS and XCode project files. + +On Ubuntu these can be easily installed with the following command: + +```console +$ sudo apt-get install python3 ninja-build +``` + +The best way to get Meson is to `pip install` it for your user + +```console +$ pip3 install --user meson +``` + +You can also use Meson as packaged by your distro, but beware that due to our frequent release cycle and development speed this version might be out of date. + +Another option is to clone the git repository and run it directly from there. + +Compiling a Meson project +-- + +The most common use case of Meson is compiling code on a code base you are working on. The steps to take are very simple. + +```console +$ cd /path/to/source/root +$ meson build && cd build +$ ninja +$ ninja test +``` + +The only thing to note is that you need to create a separate build directory. Meson will not allow you to build source code inside your source tree. All build artifacts are stored in the build directory. This allows you to have multiple build trees with different configurations at the same time. This way generated files are not added into revision control by accident. + +To recompile after code changes, just type `ninja`. The build command is always the same. You can do arbitrary changes to source code and build system files and Meson will detect those and will do the right thing. If you want to build optimized binaries, just use the argument `--buildtype=debugoptimized` when running Meson. It is recommended that you keep one build directory for unoptimized builds and one for optimized ones. To compile any given configuration, just go into the corresponding build directory and run `ninja`. + +Meson will automatically add compiler flags to enable debug information and compiler warnings (i.e. `-g` and `-Wall`). This means the user does not have to deal with them and can instead focus on coding. + +Using Meson as a distro packager +-- + +Distro packagers usually want total control on the build flags used. Meson supports this use case natively. The commands needed to build and install Meson projects are the following. + +```console +$ cd /path/to/source/root +$ CFLAGS=... CXXFLAGS=... LDFLAGS=.. meson --prefix /usr --buildtype=plain build +$ ninja -v -C build +$ ninja -C build test +$ DESTDIR=/path/to/staging/root ninja -C build install +```` + +The command line switch `--buildtype=plain` tells Meson not to add its own flags to the command line. This gives the packager total control on used flags. + +This is very similar to other build systems. The only difference is that the `DESTDIR` variable is passed as an environment variable rather than as an argument to `ninja install`. + +As distro builds happen always from scratch, we recommend you to enable [unity builds](Unity-builds.md) whenever possible on your packages because they are faster and produce better code. diff --git a/docs/markdown/RPM-module.md b/docs/markdown/RPM-module.md new file mode 100644 index 0000000..f32b9ad --- /dev/null +++ b/docs/markdown/RPM-module.md @@ -0,0 +1,10 @@ +# RPM module + +The RPM module can be used to create a sample rpm spec file for a Meson project. It autodetects installed files, dependencies and so on. Using it is very simple. At the very end of your Meson project (that is, the end of your toplevel `meson.build` file) add these two lines. + +```meson +rpm = import('rpm') +rpm.generate_spec_template() +``` + +Run Meson once on your code and the template will be written in your build directory. Then remove the two lines above and manually edit the template to add missing information. After this it is ready for use. diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md new file mode 100644 index 0000000..dd99bde --- /dev/null +++ b/docs/markdown/Reference-manual.md @@ -0,0 +1,889 @@ +# Reference manual + +## Functions + +The following functions are available in build files. Click on each to see the description and usage. The objects returned by them are [list afterwards](#returned-objects). + + +### add_global_arguments() + +``` meson + void add_global_arguments(arg1, arg2, ...) +``` + +Adds the positional arguments to the compiler command line for the language specified in `language` keyword argument. If a list of languages is given, the arguments are added to each of the corresponding compiler command lines. Note that there is no way to remove an argument set in this way. If you have an argument that is only used in a subset of targets, you have to specify it in per-target flags. + +The arguments are used in all compiler invocations with the exception of compile tests, because you might need to run a compile test with and without the argument in question. For this reason only the arguments explicitly specified are used during compile tests. + +**Note:** Usually you should use `add_project_arguments` instead, because that works even when you project is used as a subproject. + +**Note:** You must pass always arguments individually `arg1, arg2, ...` rather than as a string `'arg1 arg2', ...` + +### add_global_link_arguments() + +``` meson + void add_global_link_arguments(*arg1*, *arg2*, ...) +``` + +Like `add_global_arguments` but the arguments are passed to the linker. + +### add_languages() + +``` meson + add_languages(*langs*) +``` + +Add support for new programming languages. Equivalent to having them in the `project` declaration. This function is usually used to add languages that are only used on some platforms like this: + +```meson +project('foobar', 'c') +if compiling_for_osx + add_languages('objc') +endif +```` + +Takes one keyword argument, `required`. It defaults to `true`, which means that if any of the languages specified is not found, Meson will halt. Returns true if all languages specified were found and false otherwise. + +### add_project_arguments() + +``` meson + void add_project_arguments(arg1, arg2, ...) +``` + +This function behaves in the same way as `add_global_arguments` except that the arguments are only used for the current project, they won't be used in any other subproject. + +### add_project_link_arguments() + +``` meson + void add_project_link_arguments(*arg1*, *arg2*, ...) +``` + +Like `add_project_arguments` but the arguments are passed to the linker. + +### add_test_setup() + +``` meson + void add_test_setup(*name*, ...) +``` + +Add a custom test setup that can be used to run the tests with a custom setup, for example under Valgrind. The keyword arguments are the following: + +- `exe_wrapper` a list containing the wrapper command or script followed by the arguments to it +- `gdb` if `true`, the tests are also run under `gdb` +- `timeout_multiplier` a number to multiply the test timeout with +- `env` an [environment object](#environment-object) to use a custom environment + +To use the test setup, run `mesontest --setup=*name*` inside the build dir. + +Note that all these options are also available while running the `mesontest` script for running tests instead of `ninja test` or `msbuild RUN_TESTS.vcxproj`, etc depending on the backend. + +### benchmark() + +``` meson + void benchmark(name, executable, ...) +``` + +Creates a benchmark item that will be run when the benchmark target is run. The behaviour of this function is identical to `test` with the exception that there is no `is_parallel` keyword, because benchmarks are never run in parallel. + +### build_target() + +Creates a build target whose type can be set dynamically with the `target_type` keyword argument. This declaration: + +```meson +executable(<arguments and keyword arguments>) +``` + +is equivalent to this: + +```meson +build_target(<arguments and keyword arguments>, target_type : 'executable') +``` + +The object returned by `build_target` and all convenience wrappers for `build_target` such as [`executable`](#executable) and [`library`](#library) has methods that are documented in the [object methods section](#build-target-object) below. + +### configuration_data() + +``` meson + configuration_data_object = configuration_data() +``` + +Creates an empty configuration object. You should add your configuration with [its method calls](#configuration-data-object) and finally use it in a call to `configure_file`. + +### configure_file() + +``` meson + generated_file = configure_file(...) +``` + +This function can run in two modes depending on the keyword arguments passed to it. + +When a [`configuration_data()`](#configuration_data) object is passed to the `configuration:` keyword argument, it takes a template file as the `input:` (optional) and produces the `output:` (required) by substituting values from the configuration data as detailed in [the configuration file documentation](Configuration.md). + +When a list of strings is passed to the `command:` keyword argument, it takes any source or configured file as the `input:` and assumes that the `output:` is produced when the specified command is run. + +These are all the supported keyword arguments: + +- `input` the input file name. If it's not specified in configuration mode, all the variables in the `configuration:` object (see above) are written to the `output:` file. +- `output` the output file name. In configuration mode, the permissions of the input file (if it is specified) are copied to the output file. +- `configuration` as explained above, this is where you pass the configuration data object as returned by `configuration_data()` +- `command` as explained above, if specified, Meson does not create the file itself but rather runs the specified command, which allows you to do fully custom file generation +- `install_dir` the subdirectory to install the generated file to (e.g. `share/myproject`), if omitted the file is not installed. + +### custom_target() + +``` meson + ctarget custom_target(*name*, ...) +``` + +Create a custom top level build target. The only positional argument is the name of this target and the keyword arguments are the following. + +- `input` list of source files +- `output` list of output files +- `command` command to run to create outputs from inputs. The command may be strings or the return of `find_program()` or `executable()` (note: always specify commands in array form `['commandname', '-arg1', '-arg2']` rather than as a string `'commandname -arg1 -arg2'` as the latter will *not* work) +- `install` when true, this target is installed during the install step +- `install_dir` directory to install to +- `build_always` if `true` this target is always considered out of date and is rebuilt every time, useful for things such as build timestamps or revision control tags +- `capture`, there are some compilers that can't be told to write their output to a file but instead write it to standard output. When this argument is set to true, Meson captures `stdout` and writes it to the target file. Note that your command argument list may not contain `@OUTPUT@` when capture mode is active. +- `depends` specifies that this target depends on the specified target(s), even though it does not take any of them as a command line argument. This is meant for cases where you have a tool that e.g. does globbing internally. Usually you should just put the generated sources as inputs and Meson will set up all dependencies automatically. +- `depend_files` files ([`string`](#string-object), [`files()`](#files), or [`configure_file()`](#configure_file)) that this target depends on but are not listed in the `command` kwarg. Useful for adding regen dependencies. +- `depfile` is a dependency file that the command can write listing all the additional files this target depends on, for example a C compiler would list all the header files it included, and a change in any one of these files triggers a recompilation +- `build_by_default` *(added 0.38.0)* causes, when set to true, to have this target be built by default, that is, when invoking plain `ninja`; the default value is false + +The list of strings passed to the `command` kwarg accept the following special string substitutions: + +- `@INPUT@` the full path to the input passed to `input`. If more than one input is specified, all of them will be substituted as separate arguments only if the command uses `'@INPUT@'` as a standalone-argument. For instance, this would not work: `command : ['cp', './@INPUT@']`, but this would: `command : ['cp', '@INPUT@']`. +- `@OUTPUT@` the full path to the output passed to `output`. If more than one outputs are specified, the behaviour is the same as `@INPUT@`. +- `@INPUT0@` `@INPUT1@` `...` the full path to the input with the specified array index in `input` +- `@OUTPUT0@` `@OUTPUT1@` `...` the full path to the output with the specified array index in `output` +- `@OUTDIR@` the full path to the directory where the output(s) must be written +- `@DEPFILE@` the full path to the dependency file passed to `depfile` + +### declare_dependency() + +``` meson + dependency_object declare_dependency(...) +``` + +This function returns a [dependency object](#dependency-object) that behaves like the return value of [`dependency`](#dependency) but is internal to the current build. The main use case for this is in subprojects. This allows a subproject to easily specify how it should be used. This makes it interchangeable with the same dependency that is provided externally by the system. This function has the following keyword arguments. + + - `include_directories`, the directories to add to header search path + - `link_with`, libraries to link against + - `sources`, sources to add to targets (or generated header files that should be built before sources including them are built) + - `dependencies`, other dependencies needed to use this dependency + - `compile_args`, compile arguments to use + - `link_args`, link arguments to use + - `version`, the version of this depency, such as `1.2.3` + +### dependency() + +``` meson + dependency_object dependency(*dependency_name*, ...) +``` + +Finds an external dependency with the given name with `pkg-config` if possible and with fallback detection logic otherwise. Dependency supports the following keyword arguments. + +- `modules` specifies submodules to use for dependencies such as Qt5 or Boost. +- `required`, when set to false, Meson will proceed with the build even if the dependency is not found +- `version`, specifies the required version, a string containing a comparison operator followed by the version string, examples include `>1.0.0`, `<=2.3.5` or `3.1.4` for exact matching. (*Added 0.37.0*) You can also specify multiple restrictions by passing a list to this kwarg, such as: `['>=3.14.0', '<=4.1.0']`. +- `native` if set to `true`, causes Meson to find the dependency on the build machine system rather than the host system (i.e. where the cross compiled binary will run on), usually only needed if you build a tool to be used during compilation. +- `static` tells the dependency provider to try to get static libraries instead of dynamic ones (note that this is not supported by all dependency backends) +- `fallback` specifies a subproject fallback to use in case the dependency is not found in the system. The value is an array `['subproj_name', 'subproj_dep']` where the first value is the name of the subproject and the second is the variable name in that subproject that contains the value of [`declare_dependency`](#declare_dependency). +- `default_options` *(added 0.37.0)* an array of option values that override those set in the project's `default_options` invocation (like `default_options` in [`project()`](#project), they only have effect when Meson is run for the first time, and command line arguments override any default options in build files) +- `method` defines the way the dependency is detected, the default is `auto` but can be overridden to be e.g. `qmake` for Qt development, and different dependencies support different values for this (though `auto` will work on all of them) + +The returned object also has methods that are documented in the [object methods section](#dependency-object) below. + +### error() + +``` meson + void error(message) +``` + +Print the argument string and halts the build process. + +### environment() + +``` meson + environment_object environment() +``` + +Returns an empty [environment variable object](#environment-object). + +### executable() + +``` meson + exe executable(*exe_name*, *sources*, ...) +``` + +Creates a new executable. The first argument specifies its name and the remaining positional arguments define the input files to use. They can be of the following types: + +- Strings relative to the current source directory +- [`files()`](#files) objects defined in any preceding build file +- The return value of configure-time generators such as [`configure_file()`](#configure_file) +- The return value of build-time generators such as [`custom_target()`](#custom_target) or [`generator.process()`](#generator-object) + +These input files can be sources, objects, libraries, or any other file. Meson will automatically categorize them based on the extension and use them accordingly. For instance, sources (`.c`, `.cpp`, `.vala`, `.rs`, etc) will be compiled, objects (`.o`, `.obj`) and libraries (`.so`, `.dll`, etc) will be linked, and all other files (headers, unknown extensions, etc) will be ignored. + +With the Ninja backend, Meson will create a build-time [order-only dependency](https://ninja-build.org/manual.html#ref_dependencies) on all generated input files, including unknown files. For all input files (generated and non-generated), Meson uses the [dependency file](https://ninja-build.org/manual.html#ref_headers) generated by your compiler to determine when to rebuild sources. The behaviour is similar for other backends. + +Executable supports the following keyword arguments. Note that just like the positional arguments above, these keyword arguments can also 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 +- `link_whole` links all contents of the given static libraries whether they are used by not, equivalent to the `-Wl,--whole-archive` argument flag of GCC, available since 0.40.0 +- `<languagename>_pch` precompiled header file to use for the given language +- `<languagename>_args` compiler flags to use for the given language; eg: `cpp_args` for C++ +- `link_args` flags to use during linking. You can use unix-style flags here for all platforms. +- `link_depends` an extra file in the source tree that the link step depends on such as a symbol visibility map. The purpose is to automatically trigger a re-link (but not a re-compile) of the target when this file changes. +- `include_directories` one or more objects created with the `include_directories` function +- `dependencies` one or more objects created with [`dependency`](#dependency) or [`find_library`](#compiler-object) (for external deps) or [`declare_dependency`](#declare_dependency) (for deps built by the project) +- `gui_app` when set to true flags this target as a GUI application on platforms where this makes a difference (e.g. Windows) +- `extra_files` are not used for the build itself but are shown as source files in IDEs that group files by targets (such as Visual Studio) +- `install`, when set to true, this executable should be installed +- `install_rpath` a string to set the target's rpath to after install (but *not* before that) +- `install_dir` override install directory for this file. The value is relative to the `prefix` specified. F.ex, if you want to install plugins into a subdir, you'd use something like this: `install_dir : get_option('libdir') + '/projectname-1.0'`. +- `objects` list of prebuilt object files (usually for third party products you don't have source to) that should be linked in this target, **never** use this for object files that you build yourself. +- `name_suffix` the string that will be used as the extension for the target by overriding the default. By default on Windows this is `exe` and on other platforms it is omitted. +- `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, since 0.38.0 +- `override_options` takes an array of strings in the same format as `project`'s `default_options` overriding the values of these options for this target only, since 0.40.0 + +The list of `sources`, `objects`, and `dependencies` is always flattened, which means you can freely nest and add lists while creating the final list. As a corollary, the best way to handle a 'disabled dependency' is by assigning an empty list `[]` to it and passing it like any other dependency to the `dependencies:` kwarg. + +The returned object also has methods that are documented in the [object methods section](#build-target-object) below. + +### find_library() + +This function is deprecated and in the 0.31.0 release it was moved to [the compiler object](#compiler-object) as obtained from `meson.get_compiler(lang)`. + +### find_program() + +``` meson + program find_program(program_name1, program_name2, ...) +``` + +`program_name1` here is a string that can be an executable or script to be searched for in `PATH`, or a script in the current source directory. + +Meson will also autodetect scripts with a shebang line and run them with the executable/interpreter specified in it both on Windows (because the command invocator will reject the command otherwise) and UNIXes (if the script file does not have the executable bit set). Hence, you *must not* manually add the interpreter while using this script as part of a list of commands. + +`program_name2` and later positional arguments are used as fallback strings to search for. This is meant to be used for cases where the program may have many alternative names, such as `foo` and `foo.py`. The function will check for the arguments one by one and the first one that is found is returned. Meson versions earlier than 0.37.0 only accept one argument. + +If none of the programs are found, Meson will abort. You can tell it not to by setting the keyword argument `required` to false, and then use the `.found()` method on the returned object to check whether it was found or not. + +The returned object also has methods that are documented in the [object methods section](#external-program-object) below. + +### files() + +``` meson + file_array files(list_of_filenames) +``` + +This command takes the strings given to it in arguments and returns corresponding File objects that you can use as sources for build targets. The difference is that file objects remember the subdirectory they were defined in and can be used anywhere in the source tree. As an example suppose you have source file `foo.cpp` in subdirectory `bar1` and you would like to use it in a build target that is defined in `bar2`. To make this happen you first create the object in `bar1` like this: + +```meson + foofile = files('foo.cpp') +``` + +Then you can use it in `bar2` like this: + +```meson + executable('myprog', 'myprog.cpp', foofile, ...) +``` + +Meson will then do the right thing. + +### generator() + +``` meson + generator_object gen(*executable*, ...) +``` + +See also: [`custom_target`](#custom_target) + +This function creates a [generator object](#generator-object) that can be used to run custom compilation commands. The only positional argument is the executable to use. It can either be a self-built executable or one returned by find_program. Keyword arguments are the following: + +- `arguments` a list of template strings that will be the command line arguments passed to the executable +- `output` a template string (or list of template strings) defining how an output file name is (or multiple output names are) generated from a single source file name +- `depfile` is a template string pointing to a dependency file that a generator can write listing all the additional files this target depends on, for example a C compiler would list all the header files it included, and a change in any one of these files triggers a recompilation + +The returned object also has methods that are documented in the [object methods section](#generator-object) below. + +The template strings passed to all the above kwargs accept the following special substitutions: + +- `@PLAINNAME@`: the complete input file name, e.g: `foo.c` becomes `foo.c` (unchanged) +- `@BASENAME@`: the base of the input filename, e.g.: `foo.c.y` becomes `foo.c` (extension is removed) + +Each string passed to the `outputs` kwarg *must* be constructed using one or both of these two substitutions. + +In addition to the above substitutions, the `arguments` kwarg also accepts the following: + +- `@OUTPUT@`: the full path to the output file +- `@INPUT@`: the full path to the input file +- `@SOURCE_DIR@`: the full path to the root of the source tree +- `@BUILD_DIR@`: the full path to the root of the build dir where the output will be placed + +NOTE: Generators should only be used for outputs that will ***only*** be used as inputs for a [build target](#build_target) or a [custom target](#custom_target). When you use the processed output of a generator in multiple targets, the generator will be run multiple times to create outputs for each target. Each output will be created in a target-private directory `@BUILD_DIR@`. + +If you want to generate files for general purposes such as for generating headers to be used by several sources, or data that will be installed, and so on, use a [`custom_target`](#custom_target) instead. + +### get_option() + +``` meson + value get_option(option_name) +``` + +Obtains the value of the [project build option](Build options) specified in the positional argument. + +### get_variable() + +``` meson + value get_variable(variable_name, fallback) +``` + +This function can be used to dynamically obtain a variable. `res = get_variable(varname, fallback)` takes the value of `varname` (which must be a string) and stores the variable of that name into `res`. If the variable does not exist, the variable `fallback` is stored to `res`instead. If a fallback is not specified, then attempting to read a non-existing variable will cause a fatal error. + +### import() + +``` meson + module_object import(module_name) +``` + +Imports the given extension module. Returns an opaque object that can be used to call the methods of the module. Here's an example for a hypothetical `testmod` module. + +```meson + tmod = import('testmod') + tmod.do_something() +``` + +### include_directories() + +``` meson + include_object include_directories(directory_names, ...) +``` + +Returns an opaque object which contains the directories (relative to the current directory) given in the positional arguments. The result can then be passed to the `include_directories:` keyword argument when building executables or libraries. You can use the returned object in any subdirectory you want, Meson will make the paths work automatically. + +Note that this function call itself does not add the directories into the search path, since there is no global search path. For something like that, see [`add_project_arguments()`](#add_project_arguments). + +Each directory given is converted to two include paths: one that is relative to the source root and one relative to the build root. + +For example, with the following source tree layout in `/home/user/project.git`: + +`meson.build`: +```meson +project(...) + +subdir('include') +subdir('src') + +... +``` + +`include/meson.build`: +```meson +inc = include_directories('.') + +... +``` + +`src/meson.build`: +```meson +sources = [...] + +executable('some-tool', sources, + include_directories : inc, + ...) + +... +``` + +If the build tree is `/tmp/build-tree`, the following include paths will be added to the `executable()` call: `-I/tmp/build-tree/include -I/home/user/project.git/include`. + +This function has one keyword argument `is_system` which, if set, flags the specified directories as system directories. This means that they will be used with the `-isystem` compiler argument rather than `-I` on compilers that support this flag (in practice everything except Visual Studio). + +### install_data() + +``` meson + void install_data(list_of_files, ...) +``` + +Installs files from the source tree that are listed as positional arguments. The following keyword arguments are supported: + +- `install_dir` the absolute or relative path to the installation directory. If this is a relative path, it is assumed to be relative to the prefix. +- `install_mode` specify the file mode in symbolic format and optionally the owner/uid and group/gid for the installed files. For example: + + `install_mode: 'rw-r--r--'` for just the file mode + + `install_mode: ['rw-r--r--', 'nobody', 'nobody']` for the file mode and the user/group + + `install_mode: ['rw-r-----', 0, 0]` for the file mode and uid/gid + + To leave any of these three as the default, specify `false`. + +### install_headers() + +``` meson + void install_headers(list_of_headers, ...) +``` + +Installs the specified header files from the source tree into the system header directory (usually `/{prefix}/include`) during the install step. This directory can be overridden by specifying it with the `install_dir` keyword argument. If you just want to install into a subdirectory of the system header directory, then use the `subdir` argument. As an example if this has the value `myproj` then the headers would be installed to `/{prefix}/include/myproj`. + +For example, this will install `common.h` and `kola.h` into `/{prefix}/include`: + +```meson +install_headers('common.h', 'proj/kola.h') +``` + +This will install `common.h` and `kola.h` into `/{prefix}/include/myproj`: + +```meson +install_headers('common.h', 'proj/kola.h', subdir : 'myproj') +``` + +This will install `common.h` and `kola.h` into `/{prefix}/cust/myproj`: + +```meson +install_headers('common.h', 'proj/kola.h', install_dir : 'cust', subdir : 'myproj') +``` + +### install_man() + +``` meson + void install_man(list_of_manpages, ...) +``` + +Installs the specified man files from the source tree into system's man directory during the install step. This directory can be overridden by specifying it with the `install_dir` keyword argument. All man pages are compressed during installation and installed with a `.gz` suffix. + +### install_subdir() + +``` meson + void install_subdir(subdir_name) +``` + +Installs the entire given subdirectory and its contents from the source tree to the location specified by the keyword argument `install_dir`. Note that due to implementation issues this command deletes the entire target dir before copying the files, so you should never use `install_subdir` to install into two overlapping directories (such as `foo` and `foo/bar`) because if you do the behaviour is undefined. + +### is_variable() + +``` meson + bool is_variable(varname) +``` + +Returns true if a variable of the given name exists and false otherwise. + +### jar() + +```meson + jar_object jar(name, list_of_sources, ...) +``` + +Build a jar from the specified Java source files. Keyword arguments are the same as executable's, with the addition of `main_class` which specifies the main class to execute when running the jar with `java -jar file.jar`. + +### join_paths() + +``` meson + string join_paths(string1, string2, ...) +``` + +Joins the given strings into a file system path segment. For example `join_paths('foo', 'bar')` results in `foo/bar`. If any one of the individual segments is an absolute path, all segments before it are dropped. That means that `join_paths('foo', '/bar')` returns `/bar`. + +*Added 0.36.0* + +### library() + +``` meson + buildtarget library(library_name, list_of_sources, ...) +``` + +Builds a library that is either static or shared depending on the value of `default_library` user option. You should use this instead of [`shared_library`](#shared_library) or [`static_library`](#static_library) most of the time. This allows you to toggle your entire project (including subprojects) from shared to static with only one option. + +The keyword arguments for this are the same as for [`executable`](#executable) with the following addition: + +- `name_prefix` the string that will be used as the suffix for the target by overriding the default (only used for libraries). By default this is `lib` on all platforms and compilers except with MSVC where it is omitted. + +`static_library` and `shared_library` also accept this keyword argument. + +### message() + +``` meson + void message(text) +``` + +This function prints its argument to stdout. + +### project() + +``` meson + void project(project_name, list_of_languages, ...) +``` + +The first argument to this function must be a string defining the name of this project. It must be followed by one or more programming languages that the project uses. Supported values for languages are `c`, `cpp` (for `C++`), `objc`, `objcpp`, `fortran`, `java`, `cs` (for `C#`) and `vala`. + +The project name can be any string you want, it's not used for anything except descriptive purposes. However since it is written to e.g. the dependency manifest is usually makes sense to have it be the same as the project tarball or pkg-config name. So for example you would probably want to use the name _libfoobar_ instead of _The Foobar Library_. + +Project supports the following keyword arguments. + + - `version`, which is a free form string describing the version of this project. You can access the value in your Meson build files with `meson.project_version()`. + + - `subproject_dir` specifies the top level directory name that holds Meson subprojects. This is only meant as a compatibility option for existing code bases that house their embedded source code in a custom directory. All new projects should not set this but instead use the default value. It should be noted that this keyword argument is ignored inside subprojects. There can be only one subproject dir and it is set in the top level Meson file. + + - `meson_version` takes a string describing which Meson version the project requires. Usually something like `>0.28.0`. Similarly you can specify the license(s) the code is under with the `license` keyword argument. Usually this would be something like `license : 'GPL2+'`, but if the code has multiple licenses you can specify them as an array like this: `license : ['proprietary', 'GPL3']`. Note that the text is informal and is only written to the dependency manifest. Meson does not do any license validation, you are responsible for verifying that you abide by all licensing terms. + + - `default_options` takes an array of strings. The strings are in the form `key=value` and have the same format as options to `mesonconf`. For example to set the default project type you would set this: `default_options : ['buildtype=debugoptimized']`. Note that these settings are only used when running Meson for the first time. Global options such as `buildtype` can only be specified in the master project, settings in subprojects are ignored. Project specific options are used normally even in subprojects. + +### run_command() + +``` meson + runresult run_command(command, list_of_args) +``` + +Runs the command specified in positional arguments. Returns [an opaque object](#run-result-object) containing the result of the invocation. The script is run from an *unspecified* directory, and Meson will set three environment variables `MESON_SOURCE_ROOT`, `MESON_BUILD_ROOT` and `MESON_SUBDIR` that specify the source directory, build directory and subdirectory the target was defined in, respectively. + +### run_target + +``` meson + buildtarget run_target(target_name, ...) +``` + +This function creates a new top-level target that runs a specified command with the specified arguments. Like all top-level targets, this integrates with the selected backend. For instance, with Ninja you can run it as `ninja target_name`. + +The script is run from an *unspecified* directory, and Meson will set three environment variables `MESON_SOURCE_ROOT`, `MESON_BUILD_ROOT` and `MESON_SUBDIR` that specify the source directory, build directory and subdirectory the target was defined in, respectively. + + - `command` is a list containing the command to run and the arguments to pass to it. Each list item may be a string or a target. For instance, passing the return value of [`executable()`](#executable) as the first item will run that executable, or passing a string as the first item will find that command in `PATH` and run it. + - `depends` is a list of targets that this target depends on but which are not listed in the command array (because, for example, the script does file globbing internally) + +### set_variable() + +``` meson + void set_variable(variable_name, value) +``` + +Assigns a value to the given variable name. Calling `set_variable('foo', bar)` is equivalent to `foo = bar`. + +### shared_library() + +``` meson + buildtarget shared_library(library_name, list_of_sources, ...) +``` + +Builds a shared library with the given sources. Positional and keyword arguments are the same as for [`library`](#library) with the following extra keyword arguments. + +- `version` a string specifying the version of this shared library, such as `1.1.0`. On Linux and OS X, this is used to set the shared library version in the filename, such as `libfoo.so.1.1.0` and `libfoo.1.1.0.dylib`. If this is not specified, `soversion` is used instead (see below). +- `soversion` a string specifying the soversion of this shared library, such as `0`. On Linux and Windows this is used to set the soversion (or equivalent) in the filename. For example, if `soversion` is `4`, a Windows DLL will be called `foo-4.dll` and one of the aliases of the Linux shared library would be `libfoo.so.4`. If this is not specified, the first part of `version` is used instead. For example, if `version` is `3.6.0` and `soversion` is not defined, it is set to `3`. +- `vs_module_defs` a string pointing to a file that contains Visual Studio symbol export definitions. + +### shared_module() + +``` meson + buildtarget shared_module(module_name, list_of_sources, ...) +``` + +Builds a shared module with the given sources. Positional and keyword arguments are the same as for [`library`](#library). + +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. + +*Added 0.37.0* + +### static_library() + +``` meson + buildtarget static_library(library_name, list_of_sources, ...) +``` + +Builds a static library with the given sources. Positional and keyword arguments are otherwise the same as for [`library`](#library), but it has one argument the others don't have: + + - `pic`, (*Added 0.36.0*) builds the library as positional independent code (so it can be linked into a shared library). This option has no effect on Windows and OS X since it doesn't make sense on Windows and PIC cannot be disabled on OS X. + +### subdir() + +``` meson + void subdir(dir_name) +``` + +Enters the specified subdirectory and executes the `meson.build` file in it. Once that is done, it returns and execution continues on the line following this `subdir()` command. Variables defined in that `meson.build` file are then available for use in later parts of the current build file and in all subsequent build files executed with `subdir()`. + +Note that this means that each `meson.build` file in a source tree can and must only be executed once. + +### subproject() + +``` meson + subproject_object subproject(subproject_name, ...) +``` + +Takes the project specified in the positional argument and brings that in the current build specification by returning a [subproject object](#subproject-object). Subprojects must always be placed inside the `subprojects` directory at the top source directory. So for example a subproject called `foo` must be located in `${MESON_SOURCE_ROOT}/subprojects/foo`. Supports the following keyword arguments: + + - `version` keyword argument that works just like the one in `dependency`. It specifies what version the subproject should be, as an example `>=1.0.1` + - `default_options`, *(added 0.37.0)* an array of default option values that override those set in the project's `default_options` invocation (like `default_options` in `project`, they only have effect when Meson is run for the first time, and command line arguments override any default options in build files) + +### test() + +``` meson + void test(name, executable, ...) +``` + +Defines an unit test. Takes two positional arguments, the first is the name of this test and the second is the executable to run. Keyword arguments are the following. + +- `args` arguments to pass to the executable +- `env` environment variables to set, such as `['NAME1=value1', 'NAME2=value2']`, or an [`environment()` object](#environment-object) which allows more sophisticated environment juggling +- `is_parallel` when false, specifies that no other test must be running at the same time as this test +- `should_fail` when true the test is considered passed if the executable returns a non-zero return value (i.e. reports an error) +- `timeout` the amount of seconds the test is allowed to run, a test that exceeds its time limit is always considered failed, defaults to 30 seconds +- `workdir` absolute path that will be used as the working directory for the test + +Defined tests can be run in a backend-agnostic way by calling `mesontest` inside the build dir, or by using backend-specific commands, such as `ninja test` or `msbuild RUN_TESTS.vcxproj`. + +### vcs_tag() + +``` meson + ctarget vcs_tag(...) +``` + +This command detects revision control commit information at build time and places it in the specified output file. This file is guaranteed to be up to date on every build. Keywords are similar to `custom_target` and all of them are mandatory. + +- `input` file to modify (e.g. `version.c.in`) +- `output` file to write the results to (e.g. `version.c`) +- `fallback` version number to use when no revision control information is present, such as when building from a release tarball + +Meson will read the contents of `input`, replace the string `@VCS_TAG@` with the detected revision number and write the result to `output`. This method returns an opaque [`custom_target`](#custom_target) object that you should put in your main program. If you desire more specific behavior than what this command provides, you should use `custom_target`. + +## Built-in objects + +These are built-in objects that are always available. + +### `meson` object + +The `meson` object allows you to introspect various properties of the system. This object is always mapped in the `meson` variable. It has the following methods. + +- `get_compiler(language)` returns [an object describing a compiler](#compiler-object), takes one positional argument which is the language to use. It also accepts one keyword argument, `native` which when set to true makes Meson return the compiler for the build machine (the "native" compiler) and when false it returns the host compiler (the "cross" compiler). If `native` is omitted, Meson returns the "cross" compiler if we're currently cross-compiling and the "native" compiler if we're not. + +- `backend()` *(added 0.37.0)* returns a string representing the current backend: `ninja`, `vs2010`, `vs2015`, or `xcode`. + +- `is_cross_build()` returns `true` if the current build is a cross build and `false` otherwise + +- `is_unity()` returns `true` when doing a unity build and `false` otherwise + +- `is_subproject()` returns `true` if the current project is being built as a subproject of some other project and `false` otherwise + +- `has_exe_wrapper()` returns true when doing a cross build if there is a wrapper command that can be used to execute cross built binaries (for example when cross compiling from Linux to Windows, one can use `wine` as the wrapper) + +- `add_install_script(script_name, arg1, arg2, ...)` causes the script given as an argument to be run during the install step, this script will have the environment variables `MESON_SOURCE_ROOT`, `MESON_BUILD_ROOT`, `MESON_INSTALL_PREFIX`, and `MESON_INSTALL_DESTDIR_PREFIX` set. All additional arguments are passed as parameters. + + `MESON_INSTALL_PREFIX` has the value of the `prefix` option passed to Meson, and `MESON_INSTALL_DESTDIR_PREFIX` has both the value of `DESTDIR` and `prefix` joined together. This is useful because both are absolute paths, and many path-joining functions such as [`os.path.join` in Python](https://docs.python.org/3/library/os.path.html#os.path.join) special-case absolute paths. + +- `add_postconf_script(script_name, arg1, arg2, ...)` will run the executable given as an argument after all project files have been generated. This script will have the environment variables `MESON_SOURCE_ROOT` and `MESON_BUILD_ROOT` set. + +- `current_source_dir()` returns a string to the current source directory. Note: **you do not need to use this function** when passing files from the current source directory to a function since that is the default. Also, you can use the `files()` function to refer to files in the current or any other source directory instead of constructing paths manually with `meson.current_source_dir()`. + +- `current_build_dir()` returns a string to the current build directory + +- `source_root()` returns a string with the absolute path to the source root directory. Note: you should use the `files()` function to refer to files in the root source directory instead of constructing paths manually with `meson.source_root()`. + +- `build_root()` returns a string with the absolute path to the build root directory + +- `project_version()` returns the version string specified in `project` function call + +- `project_name()` returns the project name specified in the `project` function call + +- `version()` return a string with the version of Meson + +- `get_cross_property(propname, fallback_value)` returns the given property from a cross file, the optional second argument is returned if not cross compiling or the given property is not found + +- `install_dependency_manifest(output_name)` installs a manifest file containing a list of all subprojects, their versions and license files to the file name given as the argument + +### `build_machine` object + +Provides information about the build machine ā the machine that is doing the actual compilation. See [Cross-compilation](Cross-compilation.md). It has the following methods: + +- `cpu_family()` returns the CPU family name. Guaranteed to return `x86` for 32-bit userland on x86 CPUs, `x86_64` for 64-bit userland on x86 CPUs, `arm` for 32-bit userland on all ARM CPUs, etc. +- `cpu()` returns a more specific CPU name, such as `i686`, `amd64`, etc. +- `system()` returns the operating system name, such as `windows` (all versions of Windows), `linux` (all Linux distros), `darwin` (all versions of OS X), etc. +- `endian()` returns `big` on big-endian systems and `little` on little-endian systems. + +Currently, these values are populated using the [`platform.system()`](https://docs.python.org/3.4/library/platform.html#platform.system) and [`platform.machine()`](https://docs.python.org/3.4/library/platform.html#platform.machine). If you think the returned values for any of these are incorrect for your system or CPU, please file [a bug report](/mesonbuild/meson/issues/new). + +### `host_machine` object + +Provides information about the host machine ā the machine on which the compiled binary will run. See [Cross-compilation](Cross-compilation.md). + +It has the same methods as [`build_machine`](#build_machine-object). + +When not cross-compiling, all the methods return the same values as `build_machine` (because the build machine is the host machine) + +Note that while cross-compiling, it simply returns the values defined in the cross-info file. + +### `target_machine` object + +Provides information about the target machine ā the machine on which the compiled binary's output will run. Hence, this object should only be used while cross-compiling a compiler. See [Cross-compilation](Cross-compilation.md). + +It has the same methods as [`build_machine`](#build_machine-object). + +When all compilation is 'native', all the methods return the same values as `build_machine` (because the build machine is the host machine and the target machine). + +Note that while cross-compiling, it simply returns the values defined in the cross-info file. If `target_machine` values are not defined in the cross-info file, `host_machine` values are returned instead. + +### `build target` object + +A build target is either an [executable](#executable), [shared](#shared_library) or [static library](#static_library). + +- `extract_objects()` returns an opaque value representing the generated object files of arguments, usually used to take single object files and link them to unit tests or to compile some source files with custom flags. To use the object file(s) in another build target, use the `objects:` keyword argument. + +- `extract_all_objects()` is same as above but returns all object files generated by this target + +- `private_dir_include()` returns a opaque value that works like `include_directories` but points to the private directory of this target, usually only needed if an another target needs to access some generated internal headers of this target + +- `full_path()` returns a full path pointing to the result target file + +### `compiler` object + +This object is returned by [`meson.get_compiler(lang)`](#meson-object). It represents a compiler for a given language and allows you to query its properties. It has the following methods: + +- `get_id()` returns a string identifying the compiler (e.g. `'gcc'`) +- `version()` returns the compiler's version number as a string +- `find_library(lib_name, ...)` tries to find the library specified in the positional argument. The [result object](#external-library-object) can be used just like the return value of `dependency`. If the keyword argument `required` is false, Meson will proceed even if the library is not found. By default the library is searched for in the system library directory (e.g. /usr/lib). This can be overridden with the `dirs` keyword argument, which can be either a string or a list of strings. +- `sizeof(typename, ...)` returns the size of the given type (e.g. `'int'`) or -1 if the type is unknown, to add includes set them in the `prefix` keyword argument, you can specify external dependencies to use with `dependencies` keyword argument +- `alignment(typename)` returns the alignment of the type specified in the positional argument, you can specify external dependencies to use with `dependencies` keyword argument +- `compiles(code)` returns true if the code fragment given in the positional argument compiles, you can specify external dependencies to use with `dependencies` keyword argument, `code` can be either a string containing source code or a `file` object pointing to the source code +- `links(code)` returns true if the code fragment given in the positional argument compiles and links, you can specify external dependencies to use with `dependencies` keyword argument, `code` can be either a string containing source code or a `file` object pointing to the source code +- `run(code)` attempts to compile and execute the given code fragment, returns a run result object, you can specify external dependencies to use with `dependencies` keyword argument, `code` can be either a string containing source code or a `file` object pointing to the source code +- `has_header` returns true if the specified header can be included, you can specify external dependencies to use with `dependencies` keyword argument and extra code to put above the header test with the `prefix` keyword. In order to look for headers in a specific directory you can use `args : '-I/extra/include/dir`, but this should only be used in exceptional cases for includes that can't be detected via pkg-config and passed via `dependencies`. +- `has_type(typename)` returns true if the specified token is a type, you can specify external dependencies to use with `dependencies` keyword argument +- `has_function(funcname)` returns true if the given function is provided by the standard library or a library passed in with the `args` keyword, you can specify external dependencies to use with `dependencies` keyword argument +- `has_member(typename, membername)` takes two arguments, type name and member name and returns true if the type has the specified member, you can specify external dependencies to use with `dependencies` keyword argument +- `has_members(typename, membername1, membername2, ...)` takes at least two arguments, type name and one or more member names, returns true if the type has all the specified members, you can specify external dependencies to use with `dependencies` keyword argument +- `has_header_symbol(headername, symbolname)` allows one to detect whether a particular symbol (function, variable, #define, type definition, etc) is declared in the specified header, you can specify external dependencies to use with `dependencies` keyword argument +- `has_argument(argument_name)` returns true if the compiler accepts the specified command line argument, that is, can compile code without erroring out or printing a warning about an unknown flag, you can specify external dependencies to use with `dependencies` keyword argument +- `has_multi_arguments(arg1, arg2, arg3, ...)` is the same as `has_argument` but takes multiple arguments and uses them all in a single compiler invocation, available since 0.37.0 +- `first_supported_argument(list_of_strings)`, given a list of strings, returns the first argument that passes the `has_argument` test above or an empty array if none pass +- `symbols_have_underscore_prefix()` returns `true` if the C symbol mangling is one underscore (`_`) prefixed to the symbol, available since 0.37.0 +- `compute_int(expr, ...')` computes the value of the given expression (as an example `1 + 2`). When cross compiling this is evaluated with an iterative algorithm, you can specify keyword arguments `low` (defaults to -1024), `high` (defaults to 1024) and `guess` to specify max and min values for the search and the value to try first. +- `get_define(definename)` returns the given preprocessor symbol's value as a string or empty string if it is not defined + +The following keyword arguments can be used: + +- `name` the name to use for printing a message about the compiler check. Supported by the methods `compiles()`, `links()`, and `run()`. If this kwarg is not passed to those methods, no message will be printed about the check. + +- `prefix` can be used to add #includes and other things that are required for the symbol to be declared. System definitions should be passed via compiler args (eg: `_GNU_SOURCE` is often required for some symbols to be exposed on Linux, and it should be passed via `args` keyword argument, see below). Supported by the methods `sizeof`, `has_type`, `has_function`, `has_member`, `has_members`, `has_header_symbol`. + +- `include_directories` specifies extra directories for header searches. *(added 0.38.0)* + +- `args` can be used to pass a list of compiler arguments that are required to find the header or symbol. For example, you might need to pass the include path `-Isome/path/to/header` if a header is not in the default include path. In versions newer than 0.38.0 you should use the `include_directories` keyword described above. You may also want to pass a library name `-lfoo` for `has_function` to check for a function. Supported by all methods except `get_id`, `version`, and `find_library`. + +Note that if you have a single prefix with all your dependencies, you might find it easier to append to the environment variables `C_INCLUDE_PATH` with gcc/clang and `INCLUDE` with msvc to expand the default include path, and `LIBRARY_PATH` with gcc/clang and `LIB` with msvc to expand the default library search path. + +However, with GCC, these variables will be ignored when cross-compiling. In that case you need to use a specs file. See: <http://www.mingw.org/wiki/SpecsFileHOWTO> + +### `string` object + +All [strings](Syntax.md#strings) have the following methods. Strings are immutable, all operations return their results as a new string. + + - `strip()` removes whitespace at the beginning and end of the string + - `format()` formats text, see the [Syntax manual](Syntax.md#string-formatting) for usage info + - `to_upper()` creates an upper case version of the string + - `to_lower()` creates a lower case version of the string + - `underscorify()` creates a string where every non-alphabetical non-number character is replaced with `_` + - `split(split_character)` splits the string at the specified character (or whitespace if not set) and returns the parts in an array + - `startswith(string)` returns true if string starts with the string specified as the argument + - `endswith(string)` returns true if string ends with the string specified as the argument + - `contains(string)` returns true if string contains the string specified as the argument + - `to_int` returns the string converted to an integer (error if string is not a number) + - `join(list_of_strings)` is the opposite of split, for example `'.'.join(['a', 'b', 'c']` yields `'a.b.c'` + - `version_compare(comparison_string)` does semantic version comparison, if `x = '1.2.3'` then `x.version_compare('>1.0.0')` returns `true` + +### `Number` object + +[Numbers](Syntax.md#numbers) support these methods: + + - `is_even()` returns true if the number is even + - `is_odd()` returns true if the number is odd + +### `boolean` object + +A [boolean](Syntax.md#booleans) object has two simple methods: + + - `to_string()` returns the string `'true'` if the boolean is true or `'false'` otherwise. You can also pass it two strings as positional arguments to specify what to return for true/false. For instance, `bool.to_string('yes', 'no')` will return `yes` if the boolean is true and `no` if it is false. + - `to_int()` as above, but returns either `1` or `0` + +### `array` object + +The following methods are defined for all [arrays](Syntax.md#arrays): + + - `length()`, the size of the array + - `contains(item)`, returns `true` if the array contains the object given as argument, `false` otherwise + - `get(index, fallback)`, returns the object at the given index, negative indices count from the back of the array, indexing out of bounds returns the `fallback` value *(added 0.38.0)* or, if it is not specified, causes a fatal error + +You can also iterate over arrays with the [`foreach` statement](https://github.com/mesonbuild/meson/wiki/Syntax#foreach-statements). + +## Returned objects + +These are objects returned by the [functions listed above](#functions). + +### `run result` object + +This object encapsulates the result of trying to compile and run a sample piece of code with [`compiler.run()`](#compiler-object) or [`run_command()`](#run_command). It has the following methods: + +- `compiled()` if true, the compilation succeeded, if false it did not and the other methods return unspecified data +- `returncode()` the return code of executing the compiled binary +- `stdout()` the standard out produced when the binary was run +- `stderr()` the standard error produced when the binary was run + +### `configuration` data object + +This object is returned by [`configuration_data()`](#configuration_data) and encapsulates configuration values to be used for generating configuration files. A more in-depth description can be found in the [the configuration wiki page](Configuration.md) It has three methods: + + - `set(varname, value)`, sets a variable to a given value + - `set10(varname, boolean_value)` is the same as above but the value is either `true` or `false` and will be written as 1 or 0, respectively + - `set_quoted(varname, value)` is same as `set` but quotes the value in double quotes (`"`) + - `has(varname)`, returns `true` if the specified variable is set + - `get(varname, default_value)` returns the value of `varname`, if the value has not been set returns `default_value` if it is defined *(added 0.38.0)* and errors out if not + +They all take the `description` keyword that will be written in the result file. The replacement assumes a file with C syntax. If your generated file is source code in some other language, you probably don't want to add a description field because it most likely will cause a syntax error. + +### `dependency` object + +This object is returned by [`dependency()`](#dependency) and contains an external dependency with the following methods: + + - `found()` which returns whether the dependency was found + - `type_name()` which returns a string describing the type of the dependency, the most common values are `internal` for deps created with `declare_dependencies` and `pkgconfig` for system dependencies obtained with Pkg-config. + - `version()` is the version number as a string, for example `1.2.8` + - `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 + +### `external program` object + +This object is returned by [`find_program()`](#find_program) and contains an external (i.e. not built as part of this project) program and has the following methods: + +- `found()` which returns whether the executable was found +- `path()` which returns an array pointing to the executable (this is an array as opposed to a string because the program might be `['python', 'foo.py']`, for example) + +### `environment` object + +This object is returned by [`environment()`](#environment) and stores detailed information about how environment variables should be set during tests. It should be passed as the `env` keyword argument to tests. It has the following methods. + +- `set(varname, value)` sets environment variable in the first + argument to the value in the second argument, e.g. + `env.set('FOO', 'BAR') sets envvar`FOO`to value`BAR\` +- `append(varname, value)` appends the given value to the old value of + the environment variable, e.g. + `env.append'('FOO', 'BAR', separator : ';')` produces `BOB;BAR` if + `FOO` had the value `BOB` and plain `BAR` if the value was not + defined. If the separator is not specified explicitly, the default + path separator for the host operating system will be used, i.e. ';' + for Windows and ':' for UNIX/POSIX systems. +- `prepend(varname, value)` is the same as `append` except that it + writes to the beginning of the variable + + +### `external library` object + +This object is returned by [`find_library()`](#find_library) and contains an external (i.e. not built as part of this project) library. This object has only one method, `found`, which returns whether the library was found. + +### `generator` object + +This object is returned by [`generator()`](#generator) and contains a generator that is used to transform files from one type to another by an executable (e.g. `idl` files into source code and headers). + +* `process(list_of_files)` takes a list of files, causes them to be processed and returns an object containing the result which can then, for example, be passed into a build target definition. The keyword argument `extra_args`, if specified, will be used to replace an entry `@EXTRA_ARGS@` in the argument list. + +### `subproject` object + +This object is returned by [`subproject()`](#subproject) and is an opaque object representing it. + +- `get_variable(name)` fetches the specified variable from inside the + subproject. This is useful to, for instance, get a [declared + dependency](#declare_dependency) from the subproject. + diff --git a/docs/markdown/Release-notes-for-0.37.0.md b/docs/markdown/Release-notes-for-0.37.0.md new file mode 100644 index 0000000..07fbda2 --- /dev/null +++ b/docs/markdown/Release-notes-for-0.37.0.md @@ -0,0 +1,128 @@ +--- +title: Release 0.37 +short-description: Release notes for 0.37 +... + +# New features + +## Mesontest + +Mesontest is a new testing tool that allows you to run your tests in many different ways. As an example you can run tests multiple times: + + mesontest --repeat=1000 a_test + +or with an arbitrary wrapper executable: + + mesontest --wrap='valgrind --tool=helgrind' a_test + +or under gdb, 1000 times in a row. This is handy for tests that fail spuriously, as when the crash happens you are given the full GDB command line: + + mesontest --repeat=1000 --gdb a_test + +## Mesonrewriter + +Mesonrewrite is an experimental tool to manipulate your build definitions programmatically. It is not installed by default yet but those interested can run it from the source repository. + +As an example, here is how you would add a source file to a build target: + + mesonrewriter add --target=program --filename=new_source.c + +## Shared modules + +The new `shared_module` function allows the creation of shared modules, that is, extension modules such as plugins that are meant to be used solely with `dlopen` rather than linking them to targets. + +## Gnome module + +- Detect required programs and print useful errors if missing + +### gtkdoc + +- Allow passing a list of directories to `src_dir` kwarg +- Add `namespace` kwarg +- Add `mode` kwarg +- Fix `gtkdoc-scangobj` finding local libraries + +### compile_resources + +- Add `gresource_bundle` kwarg to output `.gresource` files +- Add `export` and `install_header` kwargs +- Use depfile support available in GLib >= 2.52.0 + +## i18n module + +- Add `merge_file()` function for creating translated files +- Add `preset` kwarg to included common gettext flags +- Read languages from `LINGUAS` file + +## LLVM IR compilation + +Meson has long had support for compiling assembler (GAS) files. In this release we add support for compiling LLVM IR files in a similar way when building with the Clang compiler. Just add it to the list of files when creating a `library` or `executable` target like any other source file. No special handling is required: + +```meson +executable('some-exe', 'main.c', 'asm-file.S', 'ir-file.ll') +``` + +As always, you can also mix LLVM IR files with C++, C, and Assembly (GAS) sources. + +## ViM indent and syntax files + +We now include filetype, indent, and syntax files for ViM [with the source tree](https://github.com/mesonbuild/meson/tree/master/syntax-highlighting/vim). Please file issues (or pull requests!) for enhancements or if you face any problems using them. + +## Push URLs in .wrap files + +[.wrap files](Using-the-WrapDB.md) for subprojects can now include a separate push URL to allow developers to push changes directly from a subproject git checkout. + +## pkg-config dependencies + +Meson now supports multiple version restrictions while searching for pkg-config dependencies. + +```meson +# Just want a lower limit +dependency('zlib', version : '>1.2.1') +# Want both a lower and an upper limit +dependency('opencv', version : ['>=2.3.0', '<=3.1.0']) +# Want to exclude one specific broken version +dependency('foolite', version : ['>=3.12.1', '!=3.13.99']) +``` + +## Overriding more binaries with environment variables + +You can now specify the binary to be used for the following tools by setting the corresponding environment variable + +| Name | Environment variable | +| ---- | -------------------- | +| pkg-config | PKG_CONFIG | +| readelf | READELF | +| nm | NM | + +## Support for `localstatedir` + +Similar to other options such as `bindir` and `datadir`, you can now specify the `localstatedir` for a project by passing `--localstatedir=dir` to `meson` or `-Dlocalstatedir=dir` to `mesonconf` after configuration. You can also access it from inside the `meson.build` file with `get_option('localstatedir')`. + +## New compiler function `symbols_have_underscore_prefix` + +Checks if the compiler prefixes an underscore to C global symbols with the default calling convention. This is useful when linking to compiled assembly code, or other code that does not have its C symbol mangling handled transparently by the compiler. + +```meson +cc = meson.get_compiler('c') +conf = configuration_data() +if cc.symbols_have_underscore_prefix() + conf.set('SYMBOLS_HAVE_UNDERSCORE', true) +endif +``` + +C symbol mangling is platform and architecture dependent, and a helper function is needed to detect it. Eg: Windows 32-bit prefixes underscore, but 64-bit does not. Linux does not prefix an underscore but OS X does. + +## Vala + +Glib Resources compiled with [`gnome.compile_resources`](Gnome-module.md#compile_resources) that are added to the sources of a Vala build target will now cause the appropriate `--gresources` flag to be passed to the Vala compiler so you don't need to add that yourself to `vala_args:`. + +## Improvements to install scripts + +You can now pass arguments to install scripts added with [`meson.add_install_script()`](Reference-manual.md#meson-object). All arguments after the script name will be passed to the script. + +The `MESON_INSTALL_DESTDIR_PREFIX` environment variable is now set when install scripts are called. This contains the values of the `DESTDIR` environment variable and the `prefix` option passed to Meson joined together. This is useful because both those are usually absolute paths, and joining absolute paths in a cross-platform way is tricky. [`os.path.join` in Python](https://docs.python.org/3/library/os.path.html#os.path.join) will discard all previous path segments when it encounters an absolute path, and simply concatenating them will not work on Windows where absolute paths begin with the drive letter. + +## More install directories + +Added new options `sbindir` and `infodir` that can be used for installation. diff --git a/docs/markdown/Release-notes-for-0.38.0.md b/docs/markdown/Release-notes-for-0.38.0.md new file mode 100644 index 0000000..4c19a91 --- /dev/null +++ b/docs/markdown/Release-notes-for-0.38.0.md @@ -0,0 +1,91 @@ +--- +title: Release 0.38 +short-description: Release notes for 0.38 +... + +# Uninstall target + +Meson allows you to uninstall an install step by invoking the uninstall target. This will remove all files installed as part of install. Note that this does not restore the original files. This also does not undo changes done by custom install scripts (because they can do arbitrary install operations). + +# Support for arbitrary test setups + +Sometimes you need to run unit tests with special settings. For example under Valgrind. Usually this requires extra command line options for the tool. This is supported with the new *test setup* feature. For example to set up a test run with Valgrind, you'd write this in a `meson.build` file: + +```meson +add_test_setup('valgrind', + exe_wrapper : [vg, '--error-exitcode=1', '--leak-check=full'], + timeout_multiplier : 100) +``` + +This tells Meson to run tests with Valgrind using the given options and multiplying the test timeout values by 100. To run this test setup simply issue the following command: + +```console +$ mesontest --setup=valgrind +``` + +# Intel C/C++ compiler support + +As usual, just set `CC=icc CXX=icpc` and Meson will use it as the C/C++ compiler. Currently only Linux is supported. + +# Get values from configuration data objects + +Now it is possible to query values stored in configuration data objects. + +```meson +cdata.set('key', 'value') +cdata.get('key') # returns 'value' +cdata.get('nokey', 'default') # returns 'default' +cdata.get('nokey') # halts with an error +``` + +# Python 3 module support + +Building Python 3 extension modules has always been possible, but it is now even easier: + +```meson +py3_mod = import('python3') +pylib = py3_mod.extension_module('modname', + 'modsource.c', + dependencies : py3_dep) +``` + +# Default options to subprojects + +Projects can specify overriding values for subprojects' `default_options` when invoking a subproject: + +```meson +subproject('foo', default_options : ['optname=overridevalue']) +dependency('some-dep', fallback : ['some_subproject', 'some_dep'], default_options : ['optname=overridevalue']) +``` + +The effect is the same as if the default options were written in the subproject's `project` call. + +# Set targets to be built (or not) by default + +Build targets got a new keyword `build_by_default` which tells whether the target should be built by default when running e.g. `ninja`. Custom targets are not built by default but other targets are. Any target that is tagged as installed or to be built always is also built by default, regardless of the value of this keyword. + +# Add option to mesonconf to wipe cached data. + +Meson caches the results of depencency lookups. Sometimes these may get out of sync with the system state. Mesonconf now has a `--clearcache` option to clear these values so they will be re-searched from the system upon next compile. + +# Can specify file permissions and owner when installing data + +The new `install_mode` keyword argument can be used to specify file permissions and uid/gid of files when doing the install. This allows you to, for example, install suid root scripts. + +# `has_header()` checks are now faster + +When using compilers that implement the [`__has_include()` preprocessor macro](https://clang.llvm.org/docs/LanguageExtensions.html#include-file-checking-macros), the check is now ~40% faster. + +# Array indexing now supports fallback values + +The second argument to the array [`.get()`](https://github.com/mesonbuild/meson/wiki/Reference-manual#array-object) function is now returned if the specified index could not be found +```meson +array = [10, 11, 12, 13] +array.get(0) # this will return `10` +array.get(4) # this will give an error about invalid index +array.get(4, 0) # this will return `0` +``` + +# Silent mode for Mesontest + +The Meson test executor got a new argument `-q` (and `--quiet`) that suppresses all output of successful tests. This makes interactive usage nicer because only errors are printed. diff --git a/docs/markdown/Release-notes-for-0.39.0.md b/docs/markdown/Release-notes-for-0.39.0.md new file mode 100644 index 0000000..705bb80 --- /dev/null +++ b/docs/markdown/Release-notes-for-0.39.0.md @@ -0,0 +1,14 @@ +--- +title: Release 0.39 +short-description: Release notes for 0.39 +... + +The 0.39.0 release turned out to consist almost entirely of bug fixes and minor polishes. + +# New features + +## Extra arguments for tests + +The Meson test executable allows specifying extra command line arguments to pass to test executables. + + mesontest --test-args=--more-debug-info currenttest diff --git a/docs/markdown/Release-notes-for-0.40.0.md b/docs/markdown/Release-notes-for-0.40.0.md new file mode 100644 index 0000000..020030f --- /dev/null +++ b/docs/markdown/Release-notes-for-0.40.0.md @@ -0,0 +1,108 @@ +--- +title: Release 0.40 +short-description: Release notes for 0.40 (unreleased) +... + +**Preliminary, 0.40.0 has not been released yet** + +# New features + +## Outputs of generators can be used in custom targets in the VS backend + +This has been possible with the Ninja backend for a long time but now the Visual Studio backend works too. + +## `compute_int` method in the compiler objects + +This method can be used to evaluate the value of an expression. As an example: + +```meson +cc = meson.get_compiler('c') +two = cc.compute_int('1 + 1') # A very slow way of adding two numbers. +``` + +## Visual Studio 2017 support + +There is now a VS2017 backend (`--backend=vs2017`) as well as a generic VS backend (`--backend=vs`) that autodetects the currently active VS version. + +## Automatic initialization of subprojects that are git submodules + +If you have a directory inside your subprojects directory (usually `subprojects/`) that is a git submodule, meson will automatically initialize it if your build files refer to it. This will be done without needing a wrap file since git contains all the information needed. + +## No download mode for wraps + +Added a new option `wrap-mode` that can be toggled to prevent Meson from downloading dependency projects. Attempting to do so will cause an error. This is useful for distro packagers and other cases where you must explicitly enforce that nothing is downloaded from the net during configuration or build. + +## Overriding options per target + +Build targets got a new keyword argument `override_options` that can be used to override system options. As an example if you have a target that you know can't be built with `-Werror` enabled you can override the value of the option like this: + +```meson +executable('foo', 'foo.c', override_options : ['werror=false']) +``` + +Note that this does not affect project options, only those options that come from Meson (language standards, unity builds etc). + +## Compiler object get define + +Compiler objects got a new method `get_define()` that returns the given preprocessor symbol as a string. + +```meson +cc = meson.get_compiler('c') +one = cc.get_define('__linux__') # returns '1' on Linux hosts +``` + +## Cygwin support + +Meson now works under Cygwin and we have added it to our CI test matrix. + +## Multiple install directories + +Custom targets can produce many output files. Previously it was only possible to install all of them in the same directory, but now you can install each output in its own directory like this: + +```meson +custom_target('two_out', + output : ['diff.h', 'diff.sh'], + command : [creator, '@OUTDIR@'], + install : true, + install_dir : ['dir1', 'dir2']) +``` + +For backwards compatibility and for conciseness, if you only specify one directory all outputs will be installed into it. + +The same feature is also available for Vala build targets. For instance, to install a shared library built by valac, the generated header, and the generated vapi (respectively) into the default locations, you can do: + +```meson +shared_library('valalib', 'mylib.vala', + install : true, + install_dir : [true, true, true]) +``` + +To install any of the three in a custom directory, just pass it as a string instead of `true`. To not install it, pass `false`. You can also pass a single string (as before) and it will cause only the library to be installed, so this is a backwards-compatible change. + +## Can specify method of obtaining dependencies + +Some dependencies have many ways of being provided. As an example Qt can either be detected via `pkg-config` or `qmake`. Until now Meson has had a heuristic for selecting which method to choose but sometimes it does the wrong thing. This can now be overridden with the `method` keyword like this: + +```meson +qt5_dep = dependency('qt5', modules : 'core', method : 'qmake') +``` + +## Link whole contents of static libraries + +The default behaviour of static libraries is to discard all symbols that are not not directly referenced. This may lead to exported symbols being lost. Most compilers support "whole archive" linking that includes all symbols and code of a given static library. This is exposed with the `link_whole` keyword. + +```meson +shared_library('foo', 'foo.c', link_whole : some_static_library) +``` + +Note that Visual Studio compilers only support this functionality on VS 2015 and newer. + +## Unity builds only for subprojects + +Up until now unity builds were either done for every target or none of them. Now unity builds can be specified to be enabled only for subprojects, which change seldom, and not for the master project, which changes a lot. This is enabled by setting the `unity` option to `subprojects`. + +## Running `mesonintrospect` from scripts + +Meson now sets the `MESONINTROSPECT` environment variable in addition to `MESON_SOURCE_ROOT` and other variables when running scripts. It is guaranteed to point to the correct `mesonintrospect` script, which is important when running meson uninstalled from git or when your `PATH`s may not be set up correctly. + +Specifically, the following meson functions will set it: `meson.add_install_script()`, `meson.add_postconf_script()`, `run_command()`, `run_target()`. diff --git a/docs/markdown/Release-notes.md b/docs/markdown/Release-notes.md new file mode 100644 index 0000000..d7de275 --- /dev/null +++ b/docs/markdown/Release-notes.md @@ -0,0 +1 @@ +# Release notes diff --git a/docs/markdown/Release-procedure.md b/docs/markdown/Release-procedure.md new file mode 100644 index 0000000..9168ed8 --- /dev/null +++ b/docs/markdown/Release-procedure.md @@ -0,0 +1,41 @@ +# Release procedure + +**This page is WIP. The following procedure is not yet approved for use** + +# Trunk + +Meson operates under the principle that trunk should (in theory) be always good enough for release. That is, all code merged in trunk must pass all unit tests. Any broken code should either be fixed or reverted immediately. + +People who are willing to tolerate the occasional glitch should be able to use Meson trunk for their day to day development if they so choose. + +# Major releases + +Major releases are currently in the form 0.X.0, where X is an increasing number. We aim to do a major release roughly once a month, though the schedule is not set in stone. Prior to the release there is a stabilisation period of roughly a week. Major changes should not be committed during this time, but instead only small scale fixes. + +# Bugfix releases + +Bugfix releases contain only minor fixes to major releases and are designated by incrementing the last digit of the version number. The criteria for a bug fix release is one of the following: + + - release has a major regression compared to the previous release (making existing projects unbuildable) + - the release has a serious bug causing data loss or equivalent + - other unforeseen major issue + +In these cases a bug fix release can be made. It shall contain _only_ the fix for the issue (or issues) in question and other minor bug fixes. Only changes that have already landed in trunk will be considered for inclusion. No new functionality shall be added. + +# Requesting a bug fix release + +The process for requesting that a bug fix release be made goes roughly as follows: + + - file a bug about the core issue + - file a patch fixing it if possible + - contact the development team and request a bug fix release (IRC is the preferred contact medium) + +The request should contain the following information: + + - the issue in question + - whether it has already caused problems for real projects + - an estimate of how many people and projects will be affected + +There is no need to write a long and complicated request report. Something like the following is sufficient: + +> The latest release has a regression where trying to do Foo using Bar breaks. This breaks all projects that use both, which includes at least [list of affected projects]. This causes problems for X amount of people and because of this we should do a bugfix release. diff --git a/docs/markdown/Reproducible-builds.md b/docs/markdown/Reproducible-builds.md new file mode 100644 index 0000000..e28ca7a --- /dev/null +++ b/docs/markdown/Reproducible-builds.md @@ -0,0 +1,9 @@ +# Reproducible builds + +A reproducible build means the following (as quoted from [the reproducible builds project site](https://reproducible-builds.org/)): + +> Reproducible builds are a set of software development practices that create a verifiable path from human readable source code to the binary code used by computers. + +Roughly what this means is that if two different people compile the project from source, their outputs are bitwise identical to each other. This allows people to verify that binaries downloadable from the net actually come from the corresponding sources and have not, for example, had malware added to them. + +Meson aims to support reproducible builds out of the box with zero additional work (assuming the rest of the build environment is set up for reproducibility). If you ever find a case where this is not happening, it is a bug. Please file an issue with as much information as possible and we'll get it fixed. diff --git a/docs/markdown/Run-targets.md b/docs/markdown/Run-targets.md new file mode 100644 index 0000000..86639ab --- /dev/null +++ b/docs/markdown/Run-targets.md @@ -0,0 +1,36 @@ +# Run targets + +Sometimes you need to have a target that just runs an external command. As an example you might have a build target that reformats your source code, runs `cppcheck` or something similar. In Meson this is accomplished with a so called *run target*. + +The recommended way of doing this is writing the command(s) you want to run to a script file. Here's an example script. + +```bash +#!/bin/sh + +cd "${MESON_SOURCE_ROOT}" +inspector_command -o "${MESON_BUILD_ROOT}/inspection_result.txt" +``` + +Note the two environment variables `MESON_SOURCE_ROOT` and `MESON_BUILD_ROOT`. These are absolute paths to your project's source and build directories and they are automatically set up by Meson. In addition to these Meson also sets up the variable `MESON_SUBDIR`, which points to the subdirectory where the run command was specified. Most commands don't need to set up this. + +Note how the script starts by cd'ing into the source dir. Meson does not guarantee that the script is run in any specific directory. Whether you need to do the same depends on what your custom target wants to do. + +To make this a run target we write it to a script file called `scripts/inspect.sh` and specify it in the top level Meson file like this. + +```meson +run_target('inspector', + command : 'scripts/inspect.sh') +``` + +Run targets are not run by default. To run it run the following command. + +```console +$ ninja inspector +``` + +All additional entries in `run_target`'s `command` array are passed unchanged to the inspector script, so you can do things like this: + +```meson +run_target('inspector', + command : ['scripts/inspect.sh', '--exclude', 'tests']) +``` diff --git a/docs/markdown/Running-Meson.md b/docs/markdown/Running-Meson.md new file mode 100644 index 0000000..5ae407e --- /dev/null +++ b/docs/markdown/Running-Meson.md @@ -0,0 +1,90 @@ +--- +short-description: Building a project with meson +... + +# Running meson + +There are two different ways of invoking Meson. First, you can run it directly from the source tree with the command `/path/to/source/meson.py`. Meson may also be installed in which case the command is simply `meson`. In this manual we only use the latter format for simplicity. + +At the time of writing only a command line version of Meson is available. This means that Meson must be invoked using the terminal. If you wish to use the MSVC compiler, you need to run Meson under "Visual Studio command prompt". + +Configuring the source +== + +Let us assume that we have a source tree that has a Meson build system. This means that at the topmost directory has a file called `meson.build`. We run the following commands to get the build started. + + + cd /path/to/source/root + mkdir build + cd build + meson .. + +First we create a directory to hold all files generated during the build. Then we go into it and invoke Meson, giving it the location of the source root. + +Hint: The syntax of meson is `meson [options] [srcdir] [builddir]`, but you may omit either `srcdir` or `builddir`. Meson will deduce the `srcdir` by the location of `meson.build`. The other one will be your `pwd`. + +Meson then loads the build configuration file and writes the corresponding build backend in the build directory. By default Meson generates a *debug build*, which turns on basic warnings and debug information and disables compiler optimizations. + +You can specify a different type of build with the `--buildtype` command line argument. It can have one of the following values. + +| value | meaning | +| ------ | -------- | +| `plain` | no extra build flags are used, even for compiler warnings, useful for distro packagers and other cases where you need to specify all arguments by yourself | +| `debug` | debug info is generated but the result is not optimized, this is the default | +| `debugoptimized` | debug info is generated and the code is optimized (on most compilers this means `-g -O2`) | +| `release` | full optimization, no debug info | + +The build directory is mandatory. The reason for this is that it simplifies the build process immensely. Meson will not under any circumstances write files inside the source directory (if it does, it is a bug and should be fixed). This means that the user does not need to add a bunch of files to their revision control's ignore list. It also means that you can create arbitrarily many build directories for any given source tree. If we wanted to test building the source code with the Clang compiler instead of the system default, we could just type the following commands. + + cd /path/to/source/root + mkdir buildclang + cd buildclang + CC=clang CXX=clang++ meson .. + +This separation is even more powerful if your code has multiple configuration options (such as multiple data backends). You can create a separate subdirectory for each of them. You can also have build directories for optimized builds, code coverage, static analysis and so on. They are all neatly separated and use the same source tree. Changing between different configurations is just a question of changing to the corresponding directory. + +Unless otherwise mentioned, all following command line invocations are meant to be run in the build directory. + +By default Meson will use the Ninja backend to build your project. If you wish to use any of the other backends, you need to pass the corresponding argument during configuration time. As an example, here is how you would use Meson to generate a Visual studio solution. + + meson <source dir> <build dir> --backend=vs2010 + +You can then open the generated solution with Visual Studio and compile it in the usual way. A list of backends can be obtained with `meson --help`. + +Building the source +== + +If you are not using an IDE, Meson uses the [Ninja build system](http://martine.github.com/ninja/) to actually build the code. To start the build, simply type the following command. + + ninja + +The main usability difference between Ninja and Make is that Ninja will automatically detect the number of CPUs in your computer and parallelize itself accordingly. You can override the amount of parallel processes used with the command line argument `-j <num processes>`. + +It should be noted that after the initial configure step `ninja` is the only command you ever need to type to compile. No matter how you alter your source tree (short of moving it to a completely new location), Meson will detect the changes and regenerate itself accordingly. This is especially handy if you have multiple build directories. Often one of them is used for development (the "debug" build) and others only every now and then (such as a "static analysis" build). Any configuration can be built just by `cd`'ing to the corresponding directory and running Ninja. + +Running tests +== + +Meson provides native support for running tests. The command to do that is simple. + + ninja test + +Meson does not force the use of any particular testing framework. You are free to use GTest, Boost Test, Check or even custom executables. + +Installing +== + +Installing the built software is just as simple. + + ninja install + +By default Meson installs to `/usr/local`. This can be changed by passing the command line argument `--prefix /your/prefix` to Meson during configure time. Meson also supports the `DESTDIR` variable used in e.g. building packages. It is used like this: + + DESTDIR=/path/to/staging ninja install + +Command line help +== + +Meson has a standard command line help feature. It can be accessed with the following command. + + meson --help diff --git a/docs/markdown/Shipping-prebuilt-binaries-as-wraps.md b/docs/markdown/Shipping-prebuilt-binaries-as-wraps.md new file mode 100644 index 0000000..bac19f9 --- /dev/null +++ b/docs/markdown/Shipping-prebuilt-binaries-as-wraps.md @@ -0,0 +1,24 @@ +# Shipping prebuilt binaries as wraps + +A common dependency case, especially on Windows, is the need to provide dependencies as prebuilt binaries rather than Meson projects that you build from scratch. Common reasons include not having access to source code, not having the time and effort to rewrite a legacy system's build definitions to Meson or just the fact that compiling the dependency projects takes too long. + +Packaging a project is straightforward. As an example let's look at a case where the project consists of one static library called `bob` and some headers. To create a binary dependency project we put the static library at the top level and headers in a subdirectory called `include`. The Meson build definition would look like the following. + +```meson +project('binary dep', 'c') + +cc = meson.get_compiler('c') +bin_dep = declare_dependency( + dependencies : cc.find_library('bob', dirs : meson.current_source_dir()), + include_directories : include_directories('include')) +``` + +Now you can use this subproject as if it was a Meson project: + +```meson +project('using dep', 'c') +bob_dep = subproject('bob').get_variable('bin_dep') +executable('prog', 'prog.c', dependencies : bob_dep) +``` + +Note that often libraries compiled with different compilers (or even compiler flags) might not be compatible. If you do this, then you are responsible for verifying that your libraries are compatible, Meson will not check things for you. diff --git a/docs/markdown/Simple-comparison.md b/docs/markdown/Simple-comparison.md new file mode 100644 index 0000000..5ac90e4 --- /dev/null +++ b/docs/markdown/Simple-comparison.md @@ -0,0 +1,47 @@ +# A simple comparison + +In this experiment we generated one thousand C files with contents that looked like this. + +```c +#include<stdio.h> +#include"header.h" + +int func23() { return 0; } +``` + +The function number was different in each file. In addition there was a main C file that just called each function in turn. We then generated build system files for *Meson*, *CMake*, *SCons*, *Premake* and *Autotools* that compiled these files into a single executable. + +With this we measured three different things. The first is configuration time, that is, the time the build system takes to generate necessary build files. This is usually called the *configure step*. The time was measured in seconds. + +The second thing to measure was the build time. This should be limited by the compiler and in the optimal case should be the same for every build system. Four parallel processes were used in this test. + +The third thing we measured was the empty build time. This measures how much time the build system takes to check the states of all source files because if any of them could potentially cause a rebuild. + +Since CMake has two different backends, Make and Ninja, we ran the tests on both of them. All tests were run on a 2011 era Macbook Pro running Ubuntu 13/04. The tests were run multiple times and we always took the fastest time. + +Here are the results for configuration time. + +![Configuration times](images/conftime.png) + +The reason SCons got zero seconds on this test is because you cannot separate configure and build steps. They run as one unit. Autotools is the clear loser of this test as it is over an order of magnitude slower than the second slowest one. This configuration time includes both autogen and configure. All other systems take less than one second to do this setup, which is fast enough for a human being to interpret as instantaneous. + +![Build times](https://raw.githubusercontent.com/wiki/jpakkane/meson/buildtime.png) + +Build times are a bit more even. SCons is the slowest, being almost ten seconds slower than the second slowest. Some of it is work from the configure step but it still has the worst performance. Premake is the fastest Make-based build system narrowly beating out Autotools. Both Ninja-based build systems are faster than all non-Ninja ones with Meson being slightly faster. In practice the difference is minimal. The advantages of Ninja can be seen by comparing CMake's times when using Make or Ninja. It is possible to shave off 3.5 seconds (over 20%) of the total build time just by changing the backend. The project's CMake configuration files don't need any changes. + +![No-op time](https://raw.githubusercontent.com/wiki/jpakkane/meson/emptytime.png) + +Empty build times reflect the performance of regular build times. SCons is again the slowest taking over three seconds compared to Meson, which takes only 0.03 seconds, a difference of two orders of magnitude. Even Autotools, the fastest Make-based system, is almost one order of magnitude slower. Ninja holds the top spots just like in the previous test. + +Conclusions +----- + +Build system performance matters. Even with this extremely simple example we can find differences between various popular build systems. As the project size increases, these differences grow even larger. (The author has witnessed no-op build times of 30 seconds for Make versus less than one second for Ninja when compiling the Clang compiler.) Keeping incremental build times low is one of the major keys of programmer productivity as it allows developers to iterate faster and stay in the creative zone. + +Original scripts +----- + +Those who want to run these experiments themselves can download the scripts here: + +* [Generator script](https://raw.githubusercontent.com/wiki/jpakkane/meson/gen_src.py) +* [Measurement script](https://raw.githubusercontent.com/wiki/jpakkane/meson/measure.py) diff --git a/docs/markdown/Subprojects.md b/docs/markdown/Subprojects.md new file mode 100644 index 0000000..0318e79 --- /dev/null +++ b/docs/markdown/Subprojects.md @@ -0,0 +1,68 @@ +# Subprojects + +Some platforms do not provide a native packaging system. In these cases it is common to bundle all third party libraries in your source tree. This is usually frowned upon because it makes it hard to add these kinds of projects into e.g. those Linux distributions that forbid bundled libraries. + +Meson tries to solve this problem by making it extremely easy to provide both at the same time. The way this is done is that Meson allows you to take any other Meson project and make it a part of your build without (in the best case) any changes to its Meson setup. It becomes a transparent part of the project. The basic idiom goes something like this. + +```meson +dep = dependency('foo', required : false) +if dep.found() + # set up project using external dependency +else + subproject('foo') + # set up rest of project as if foo was provided by this project +endif +``` + +All Meson features of the subproject, such as project options keep working and can be set in the master project. There are a few limitations, the most imporant being that global compiler arguments must be set in the main project before calling subproject. Subprojects must not set global arguments because there is no way to do that reliably over multiple subprojects. To check whether you are running as a subproject, use the `is_subproject` function. + +As an example, suppose we have a simple project that provides a shared library. + +```meson +project('simple', 'c') +i = include_directories('include') +l = shared_library('simple', 'simple.c', include_directories : i, install : true) +``` + +Then we could use that from a master project. First we generate a subdirectory called `subprojects` in the root of the master directory. Then we create a subdirectory called `simple` and put the subproject in that directory. Now the subproject can be used like this. + +```meson +project('master', 'c') +dep = dependency('simple', required : false) +if dep.found() + i = [] + l = [] +else + sp = subproject('simple') # This is a name of a subdirectory in subprojects. + i = sp.get_variable('i') + l = sp.get_variable('l') +endif +exe = executable('prog', 'prog.c', include_directories : i, link_with : l, + deps : dep, install : true) +``` + +With this setup the system dependency is used when it is available, otherwise we fall back on the bundled version. + +It should be noted that this only works for subprojects that are built with Meson. It can not be used with any other build system. The reason is the simple fact that there is no possible way to do this reliably with mixed build systems. + +Subprojects can use other subprojects, but all subprojects must reside in the top level `subprojects` directory. Recursive use of subprojects is not allowed, though, so you can't have subproject `a` that uses subproject `b` and have `b` also use `a`. + +## Subprojects and dependencies + +A common use case is to use subprojects to provide dependencies on platforms that do not provide them out of the box. This is especially common on Windows. Meson makes this easy while at the same time using system dependencies if are available. The way to do this is to set up a subproject that builds the dependency and has an internal dependency declared like this: + +```meson +proj_dep = declare_dependency(...) +``` + +Then you can use the subproject in the master project like this: + +```meson +sp_dep = dependency('subproj_pkgconfig_name', fallback : ['subproj_name', 'proj_dep'] +``` + +This uses the system dependency when available and the self built version if not. If you want to always use the subproject, that is also possible, just use `subproject` and `get_variable` as discussed above to get the dependency object. + +# Obtaining subprojects + +Meson ships with a dependency system to automatically obtain dependency subprojects. It is documented in the [Wrap dependency system manual](Wrap dependency system manual). diff --git a/docs/markdown/Syntax.md b/docs/markdown/Syntax.md new file mode 100644 index 0000000..6f43887 --- /dev/null +++ b/docs/markdown/Syntax.md @@ -0,0 +1,320 @@ +--- +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. Apart from line ending whitespace has no syntactical 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. + +```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. + +```meson +var1 = [1, 2, 3] +var2 = var1 +var2 += [4] +# var2 is now [1, 2, 3, 4] +# var1 is still [1, 2, 3] +``` + +Numbers +-- + +Meson supports only integer numbers. They are declared simply by writing them out. Basic arithmetic operations are supported. + +```meson +x = 1 + 2 +y = 3 * 4 +d = 5 % 3 # Yields 2. +``` + +Strings can be converted to a number like this: + +```meson +string_var = '42' +num = var1.to_int() +``` + +Booleans +-- + +A boolean is either `true` or `false`. + +```meson +truth = true +``` + +Strings +-- + +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. + +#### Strings running over multiple lines + +Strings running over multiple lines can be declared with three single quotes, like this: + +```meson +multiline_string = '''#include <foo.h> +int main (int argc, char ** argv) { + return FOO_SUCCESS; +}''' +``` + +This can also be combined with the string formatting functionality described below. + +#### String formatting + +Strings can be built using the string formatting functionality. + +```meson +template = 'string: @0@, number: @1@, bool: @2@' +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. + +#### String methods + +Strings also support a number of other methods that return transformed copies. + +**.strip()** + +```meson +# Similar to the Python str.strip(). Removes leading/ending spaces and newlines +define = ' -Dsomedefine ' +stripped_define = target.strip() +# 'stripped_define' now has the value '-Dsomedefine' +``` + +**.to_upper()**, **.to_lower()** + +```meson +target = 'x86_FreeBSD' +upper = target.to_upper() # t now has the value 'X86_FREEBSD' +lower = target.to_lower() # t now has the value 'x86_freebsd' +``` + +**.to_int()** + +```meson +version = '1' +# Converts the string to an int and throws an error if it can't be +ver_int = version.to_int() +``` + +**.contains()**, **.startswith()**, **.endswith()** + +```meson +target = 'x86_FreeBSD' +is_fbsd = target.to_lower().contains('freebsd') +# is_fbsd now has the boolean value 'true' +is_x86 = target.startswith('x86') # boolean value 'true' +is_bsd = target.to_lower().endswith('bsd') # boolean value 'true' +``` + +**.split()**, **.join()** + +```meson +# Similar to the Python str.split() +components = 'a b c d '.split() +# components now has the value ['a', 'b', 'c', 'd'] +components = 'a b c d '.split(' ') +# components now has the value ['a', 'b', '', '', 'c', 'd', ''] + +# Similar to the Python str.join() +output = ' '.join(['foo', 'bar']) +# Output value is 'foo bar' +pathsep = ':' +path = pathsep.join(['/usr/bin', '/bin', '/usr/local/bin']) +# path now has the value '/usr/bin:/bin:/usr/local/bin' + +# For joining paths, you should use join_paths() +# This has the advantage of being cross-platform +path = join_paths(['/usr', 'local', 'bin']) +# path now has the value '/usr/local/bin' + +# Example to set an API version for use in library(), install_header(), etc +project('project', 'c', version: '0.2.3') +version_array = meson.project_version().split('.') +# version_array now has the value ['0', '2', '3'] +api_version = '.'.join([version_array[0], version_array[1]]) +# api_version now has the value '0.2' + +# We can do the same with .format() too: +api_version = '@0@.@1@'.format(version_array[0], version_array[1]) +# api_version now (again) has the value '0.2' +``` + +**.underscorify()** + +```meson +name = 'Meson Docs.txt#Reference-manual' +# Replaces all characters other than `a-zA-Z0-9` with `_` (underscore) +# Useful for substituting into #defines, filenames, etc. +underscored = name.underscorify() +# underscored now has the value 'Meson_Docs_txt_Reference_manual' +``` + +**.version_compare()** + +```meson +version = '1.2.3' +# Compare version numbers semantically +is_new = version.version_compare('>=2.0') +# is_new now has the boolean value false +# Supports the following operators: '>', '<', '>=', '<=', '!=', '==', '=' +``` + +Arrays +-- + +Arrays are delimited by brackets. An array can contain an arbitrary number of objects of any type. + +```meson +my_array = [1, 2, 'string', some_obj] +``` + +You can add additional items to an array like this: + +```meson +my_array += [ 'foo', 3, 4, another_obj ] +``` + +#### Array methods + +The following methods are defined for all arrays: + + - `length`, the size of the array + - `contains`, returns `true` if the array contains the object given as argument, `false` otherwise + - `get`, returns the object at the given index, negative indices count from the back of the array, indexing out of bounds is a fatal error + +Function calls +-- + +Meson provides a set of usable functions. The most common use case is creating build objects. + +```meson +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. + +```meson +myobj = some_function() +myobj.do_something('now') +``` + +If statements +-- + +If statements work just like in other languages. + +```meson +var1 = 1 +var2 = 2 +if var1 == var2 # Evaluates to false + something_broke() +elif var3 == var2 + something_else_broke() +else + everything_ok() +endif + +opt = get_option('someoption') +if opt == 'foo' + do_something() +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. + +```meson +progs = [['prog1', ['prog1.c', 'foo.c']], + ['prog2', ['prog2.c', 'bar.c']]] + +foreach p : progs + exe = executable(p[0], p[1]) + test(p[0], exe) +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. + +Logical operations +-- + +Meson has the standard range of logical operations. + +```meson +if a and b + # do something +endif +if c or d + # do something +endif +if not e + # do something +endif +if not (f or g) + # do something +endif +``` + +Logical operations work only on boolean values. + +Comments +-- + +A comment starts with the `#` character and extends until the end of the line. + +```meson +some_function() # This is a comment +some_other_function() +``` + +Ternary operator +-- + +The ternary operator works just like in other languages. + +```meson +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. + +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. + +```meson +test_data_dir = 'data' +subdir('tests') +``` diff --git a/docs/markdown/Threads.md b/docs/markdown/Threads.md new file mode 100644 index 0000000..d4f1bca --- /dev/null +++ b/docs/markdown/Threads.md @@ -0,0 +1,14 @@ +# Threads + +Meson has a very simple notational shorthand for enabling thread support on your build targets. First you obtain the thread dependency object like this: + +```meson +thread_dep = dependency('threads') +``` + +And then you just use it in a target like this: + +```meson +executable('threadedprogram', ... + dependencies : thread_dep) +``` diff --git a/docs/markdown/Trial-conversions.md b/docs/markdown/Trial-conversions.md new file mode 100644 index 0000000..64d5a0a --- /dev/null +++ b/docs/markdown/Trial-conversions.md @@ -0,0 +1,22 @@ +--- +title: Trial conversions +... + +# Trial conversions of existing projects + +To verify Meson's suitability for different types of projects, its developers do experimental build system conversions. In all simplicity it means that random projects are chosen and their build system is rewritten in Meson. Usually these are not fully polished ports, but should contain most of the work necessary to use Meson as the new build system. + +Here is a list of projects that have had a build system port done. + +* [Python 3](https://mail.python.org/pipermail/python-dev/2013-June/126748.html) +* [Glib](https://mail.gnome.org/archives/gtk-devel-list/2013-August/msg00001.html) +* [QtCreator](http://lists.qt-project.org/pipermail/qt-creator/2014-May/003584.html), and a [followup](http://lists.qt-project.org/pipermail/qt-creator/2014-May/003598.html) on unity builds +* [SDL 2](http://forums.libsdl.org/viewtopic.php?t=10093&sid=8cf1d6c83d4d73fe6cfbb7cbb16b3d28) +* [Mesa3D](http://lists.freedesktop.org/archives/mesa-dev/2014-July/064160.html) +* [Mame](http://www.mameworld.info/ubbthreads/showthreaded.php?Cat=&Number=332119&page=0&view=expanded&sb=5&o=&fpart=1&vc=1) +* [Firefox NSPR](https://groups.google.com/forum/#!topic/mozilla.dev.builds/daS3DK2F1MQ) +* [Wayland](http://lists.freedesktop.org/archives/wayland-devel/2015-February/020124.html) + +## More from Wrapdb + +The [Meson Wrap database](http://wrapdb.mesonbuild.com) contains several projects that have been converted into Meson and are ready to use. diff --git a/docs/markdown/Tutorial.md b/docs/markdown/Tutorial.md new file mode 100644 index 0000000..524861d --- /dev/null +++ b/docs/markdown/Tutorial.md @@ -0,0 +1,123 @@ +--- +short-description: Simplest tutorial +... + +# Tutorial + +This page shows from the ground up how to create a Meson build definition for a simple project. Then we expand it to use external dependencies to show how easily they can be integrated into your project. + +The humble beginning +----- + +Let's start with the most basic of programs, the classic hello example. First we create a file `main.c` which holds the source. It looks like this. + +```c +#include<stdio.h> + +int main(int argc, char **argv) { + printf("Hello there.\n"); + return 0; +} +``` + +Then we create a Meson build description and put it in a file called `meson.build` in the same directory. Its contents are the following. + +```meson +project('tutorial', 'c') +executable('demo', 'main.c') +``` + +That is all. We are now ready to build our application. First we need to initialise the build by going into the source directory and issuing the following commands. + +```console +$ meson build +``` + +We create a separate build directory to hold all of the compiler output. Meson is different from some other build systems in that it does not permit in-source builds. You must always create a separate build directory. Common convention is to put the default build directory in a subdirectory of your toplevel source directory. + +When Meson is run it prints the following output. + + The Meson build system + version: 0.13.0-research + Source dir: /home/jpakkane/mesontutorial + Build dir: /home/jpakkane/mesontutorial/build + Build type: native build + Project name is "tutorial". + Using native c compiler "ccache cc". (gcc 4.8.2) + Creating build target "demo" with 1 files. + +Now we are ready to build our code. + +``` +$ cd build +$ ninja +``` + +Once that is done we can run the resulting binary. + +```console +$ ./demo +``` + +This produces the expected output. + + Hello there. + +Adding dependencies +----- + +Just printing text is a bit old fashioned. Let's update our program to create a graphical window instead. We'll use the [GTK+](https://gtk.org) widget toolkit. First we edit the main file to use Gtk. The new version looks like this. + +```c +#include<gtk/gtk.h> + +int main(int argc, char **argv) { + GtkWidget *win; + gtk_init(&argc, &argv); + win = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(win), "Hello there"); + g_signal_connect(win, "destroy", G_CALLBACK(gtk_main_quit), NULL); + gtk_widget_show(win); + gtk_main(); +} +``` + +Then we edit the Meson file, instructing it to find and use the Gtk libraries. + +```meson +project('tutorial', 'c') +gtkdep = dependency('gtk+-3.0') +executable('demo', 'main.c', dependencies : gtkdep) +``` + +Now we are ready to build. The thing to notice is that we do *not* need to recreate our build directory, run any sort of magical commands or the like. Instead we just type the exact same command as if we were rebuilding our code without any build system changes. + +``` +$ ninja +``` + +Once you have set up your build directory the first time, you don't ever need to run the `meson` command again. You always just run `ninja`. Meson will automatically detect when you have done changes to build definitions and will take care of everything so users don't have to care. In this case the following output is produced. + + [1/1] Regenerating build files + The Meson build system + version: 0.13.0-research + Source dir: /home/jpakkane/mesontutorial + Build dir: /home/jpakkane/mesontutorial/build + Build type: native build + Project name is "tutorial". + Using native c compiler "ccache cc". (gcc 4.8.2) + Found pkg-config version 0.26. + Dependency gtk+-3.0 found: YES + Creating build target "demo" with 1 files. + [1/2] Compiling c object demo.dir/main.c.o + [2/2] Linking target demo + +Note how Meson noticed that the build definition has changed and reran itself automatically. The program is now ready to be run: + +``` +$ ./demo +``` + +This creates the following GUI application. + +![Gtk sample application screenshot](images/gtksample.png) diff --git a/docs/markdown/Unit-tests.md b/docs/markdown/Unit-tests.md new file mode 100644 index 0000000..d5ef77e --- /dev/null +++ b/docs/markdown/Unit-tests.md @@ -0,0 +1,104 @@ +# Unit tests + +Meson comes with a fully functional unit test system. To use it simply build an executable and then use it in a test. + +```meson +e = executable('prog', 'testprog.c') +test('name of test', e) +``` + +You can add as many tests as you want. They are run with the command `ninja test`. + +Meson captures the output of all tests and writes it in the log file `meson-logs/testlog.txt`. + +Test parameters +-- + +Some tests require the use of command line arguments or environment variables. These are simple to define. + +```meson +test('command line test', exe, args : ['first', 'second']) +test('envvar test', exe2, env : ['key1=value1', 'key2=value2']) +``` + +Note how you need to specify multiple values as an array. + +Coverage +-- + +If you enable coverage measurements by giving Meson the command line flag `-Db_coverage=true`, you can generate coverage reports. Meson will autodetect what coverage generator tools you have installed and will generate the corresponding targets. These targets are `coverage-xml` and `coverage-text` which are both provided by [Gcovr](https://software.sandia.gov/trac/fast/wiki/gcovr) and `coverage-html`, which requires [Lcov](http://ltp.sourceforge.net/coverage/lcov.php) and [GenHTML](http://linux.die.net/man/1/genhtml). + +The the output of these commands is written to the log directory `meson-logs` in your build directory. + +Parallelism +-- + +To reduce test times, Meson will by default run multiple unit tests in parallel. It is common to have some tests which can not be run in parallel because they require unique hold on some resource such as a file or a dbus name. You have to specify these tests with a keyword argument. + +```meson +test('unique test', t, is_parallel : false) +``` + +Meson will then make sure that no other unit test is running at the same time. Non-parallel tests take longer to run so it is recommended that you write your unit tests to be parallel executable whenever possible. + +By default Meson uses as many concurrent processes as there are cores on the test machine. You can override this with the environment variable `MESON_TESTTHREADS` like this. + +```console +$ MESON_TESTTHREADS=5 ninja test +``` + +## Skipped tests + +Sometimes a test can only determine at runtime that it can not be run. The GNU standard approach in this case is to exit the program with error code 77. Meson will detect this and report these tests as skipped rather than failed. This behaviour was added in version 0.37.0. + +## Testing tool + +In version 0.37.0 a new tool called `mesontest` was added. The goal of this tool is to provide a simple way to run tests in a variety of different ways. The tool is designed to be run in the build directory. + +The simplest thing to do is just to run all tests, which is equivalent to running `ninja test`. + +```console +$ mesontest +``` + +You can also run only a single test by giving its name: + +```console +$ mesontest testname +``` + +Sometimes you need to run the tests multiple times, which is done like this: + +```console +$ mesontest --repeat=10 +``` + +Invoking tests via a helper executable such as Valgrind can be done with the `--wrap` argument + +```console +$ mesontest --wrap=valgrind testname +``` + +Arguments to the wrapper binary can be given like this: + +```console +$ mesontest --wrap='valgrind --tool=helgrind' testname +``` + +Meson also supports running the tests under gdb. Just doing this: + +```console +$ mesontest --gdb testname +``` + +Mesontest will launch gdb all set up to run the test. Just type `run` in the gdb command prompt to start the program. + +The second use case is a test that segfaults only rarely. In this case you can invoke the following command: + +```console +$ mesontest --gdb --repeat=10000 testname +``` + +This runs the test up to 10 000 times under gdb automatically. If the program crashes, gdb will halt and the user can debug the application. Note that testing timeouts are disabled in this case so mesontest will not kill gdb while the developer is still debugging it. The downside is that if the test binary freezes, the test runner will wait forever. + +For further information see the command line help of Mesontest by running `mesontest -h`. diff --git a/docs/markdown/Unity-builds.md b/docs/markdown/Unity-builds.md new file mode 100644 index 0000000..f1f718e --- /dev/null +++ b/docs/markdown/Unity-builds.md @@ -0,0 +1,15 @@ +# Unity builds + +Unity builds are a technique for cutting down build times. The way it works is relatively straightforward. Suppose we have source files `src1.c`, `src2.c` and `src3.c`. Normally we would run the compiler three times, once for each file. In a unity build we instead compile all these sources in a single unit. The simplest approach is to create a new source file that looks like this. + +```c +#include<src1.c> +#include<src2.c> +#include<src3.c> +``` + +This is then compiled rather than the individual files. The exact speedup depends on the code base, of course, but it is not uncommon to obtain more than 50% speedup in compile times. This happens even though the Unity build uses only one CPU whereas individual compiles can be run in parallel. Unity builds can also lead to faster code, because the compiler can do more aggressive optimizations (e.g. inlining). + +The downside is that incremental builds are as slow as full rebuilds (because that is what they are). Unity compiles also use more memory, which may become an issue in certain scenarios. There may also be some bugs in the source that need to be fixed before Unity compiles work. As an example, if both `src1.c` and `src2.c` contain a static function or variable of the same name, there will be a clash. + +Meson has built-in support for unity builds. To enable them, just pass the `--unity` command line argument or enable unity builds with the GUI. No code changes are necessary apart from the potential clash issue discussed above. Meson will automatically generate all the necessary inclusion files for you. diff --git a/docs/markdown/Use-of-Python.md b/docs/markdown/Use-of-Python.md new file mode 100644 index 0000000..1803503 --- /dev/null +++ b/docs/markdown/Use-of-Python.md @@ -0,0 +1,21 @@ +# Use of Python + +Meson is implemented in Python. This has both positive and negative sides. The main thing people seem to be mindful about is the dependency on Python to build source code. This page discusses various aspects of this problem. + +# Dependency hell + +There have been many Python programs that are difficult to maintain on multiple platforms. The reasons come mostly from dependencies. The program may use dependencies that are hard to compile on certain platforms, are outdated, conflict with other dependencies, not available on a given Python version and so on. + +Meson avoids dependency problems with one simple rule: Meson is not allowed to have any dependencies outside the Python basic library. The only thing you need is Python 3 (and possibly Ninja). + +## Reimplementability + +Meson has been designed in such a way that the implementation language is never exposed in the build definitions. This makes it possible (and maybe even easy) to reimplement Meson in any other programming language. There are currently no plans to reimplement Meson, but we will make sure that Python is not exposed inside the build definitions. + +## Cross platform tooling + +There is no one technical solution or programming language that works natively on all operating systems currently in use. When Autotools was designed in the late 80s, Unix shell was available pretty much anywhere. This is no longer the case. + +It is also the case that as any project gets larger, sooner or later it requires code generation, scripting or other tooling. This seems to be inevitable. Because there is no scripting language that would be available everywhere, these tools either need to be rewritten for each platform (which is a lot of work and is prone to errors) or the project needs to take a dependency on _something_. + +Any project that uses Meson (at least the current version) can rely on the fact that Python 3 will always be available, because you can't compile the project without it. All tooling can then be done in Python 3 with the knowledge that it will run on any platform without any extra dependencies (modulo the usual porting work). This reduces maintenance effort on multiplatform projects by a fair margin. diff --git a/docs/markdown/Users.md b/docs/markdown/Users.md new file mode 100644 index 0000000..1796c7c --- /dev/null +++ b/docs/markdown/Users.md @@ -0,0 +1,36 @@ +--- +title: Users +... + +# List of projects using Meson + +If you have a project that uses Meson that you want to add to this list, let us know and we'll add it. + + - [AQEMU](https://github.com/tobimensch/aqemu), a Qt GUI for QEMU virtual machines, since version 0.9.3 + - [Arduino sample project](https://github.com/jpakkane/mesonarduino) + - [Emeus](https://github.com/ebassi/emeus), Constraint based layout manager for Gtk + - [GLib](https://github.com/centricular/glib/), cross-platform C library used by GTK+ (not merged 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 + - [Gnome Recipes](https://github.com/matthiasclasen/gr), application for cooking recipes + - [Gnome Software](https://git.gnome.org//browse/gnome-software), an app store for Gnome + - [Gnome Twitch](https://github.com/vinszent/gnome-twitch), an app for viewing Twitch streams on Gnome desktop + - [Graphene](http://ebassi.github.io/graphene/), a thin type library for graphics + - [Grilo](https://mail.gnome.org/archives/grilo-list/2017-February/msg00000.html) and [Grilo plugins](https://git.gnome.org/browse/grilo-plugins/commit/?id=ea047c4fb63e90268eb795ed91a09a2be5068a4c), the Grilo multimedia framework + - [GStreamer](https://cgit.freedesktop.org/gstreamer/gstreamer/), multimedia framework (not the default yet) + - [GTK+](https://git.gnome.org/browse/gtk+/log/?h=wip/meson), the multi-platform toolkit used by GNOME (not merged yet) + - [Json-glib](https://git.gnome.org/browse/json-glib), GLib-based JSON manipulation library + - [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 + - [Lightdm-Webkit2-Greeter](https://github.com/Antergos/lightdm-webkit2-greeter) + - [Kiwix libraries](https://github.com/kiwix/kiwix-lib) + - [Nautilus](https://git.gnome.org/browse/nautilus/commit/?id=ed5652c89ac0654df2e82b54b00b27d51c825465) the Gnome file manager + - [Parzip](https://github.com/jpakkane/parzip), a multithreaded reimplementation of Zip + - [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 merged 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) + - [ZStandard](https://github.com/facebook/zstd/commit/4dca56ed832c6a88108a2484a8f8ff63d8d76d91) a compression algorithm developed at Facebook (not used by default) diff --git a/docs/markdown/Using-multiple-build-directories.md b/docs/markdown/Using-multiple-build-directories.md new file mode 100644 index 0000000..cabd64f --- /dev/null +++ b/docs/markdown/Using-multiple-build-directories.md @@ -0,0 +1,49 @@ +# Using multiple build directories + +One of the main design goals of Meson has been to build all projects out-of-source. This means that *all* files generated during the build are placed in a separate subdirectory. This goes against common Unix tradition where you build your projects in-source. Building out of source gives two major advantages. + +First of all this makes for very simple `.gitignore` files. In classical build systems you may need to have tens of lines of definitions, most of which contain wildcards. When doing out of source builds all of this busywork goes away. A common ignore file for a Meson project only contains a few lines that are the build directory and IDE project files. + +Secondly this makes it very easy to clean your projects: just delete the build subdirectory and you are done. There is no need to guess whether you need to run `make clean`, `make distclean`, `make mrproper` or something else. When you delete a build subdirectory there is no possible way to have any lingering state from your old builds. + +The true benefit comes from somewhere else, though. + +## Multiple build directories for the same source tree ## + +Since a build directory is fully self contained and treats the source tree as a read-only piece of data, it follows that you can have arbitrarily many build trees for any source tree at the same time. Since all build trees can have different configuration, this is extremely powerful. Now you might be wondering why one would want to have multiple build setups at the same time. Let's examine this by setting up a hypothetical project. + +The first thing to do is to set up the default build, that is, the one we are going to use over 90% of the time. In this we use the system compiler and build with debug enabled and no optimizations so it builds as fast as possible. This is the default project type for Meson, so setting it up is simple. + + mkdir build + meson build + +Another common setup is to build with debug and optimizations to, for example, run performance tests. Setting this up is just as simple. + + mkdir buildopt + meson --buildtype=debugoptimized + +For systems where the default compiler is GCC, we would like to compile with Clang, too. So let's do that. + + mkdir buildclang + CC=clang CXX=clang++ meson buildclang + +You can add cross builds, too. As an example, let's set up a Linux -> Windows cross compilation build using mingw. + + mkdir buildwine + meson --cross-file=mingw-cross.txt buildwine + +The cross compilation file sets up Wine so that not only can you compile your application, you can also run the unit test suite just by issuing the command `ninja test`. + +To compile any of these build types, just cd into the corresponding build directory and run `ninja` or instruct your IDE to do the same. Note that once you have set up your build directory once, you can just run Ninja and Meson will ensure that the resulting build is fully up to date according to the source. Even if you have not touched one of the directories in weeks and have done major changes to your build configuration, Meson will detect this and bring the build directory up to date (or print an error if it can't do that). This allows you to do most of your work in the default directory and use the others every now and then without having to babysit your build directories. + +## Specialised uses ## + +Separate build directories allows easy integration for various different kinds of tools. As an example, Clang comes with a static analyzer. It is meant to be run from scratch on a given source tree. The steps to run it with Meson are very simple. + + rm -rf buildscan + mkdir buildscan + scan-build meson buildscan + cd buildscan + scan-build ninja + +These commands are the same for every single Meson project, so they could even be put in a script turning static analysis into a single command. diff --git a/docs/markdown/Using-the-WrapDB.md b/docs/markdown/Using-the-WrapDB.md new file mode 100644 index 0000000..b6f1e11 --- /dev/null +++ b/docs/markdown/Using-the-WrapDB.md @@ -0,0 +1,28 @@ +# Using the wrapDB + +The Wrap database is a web service that provides Meson build definitions to projects that do not have it natively. Using it is simple. The service can be found [here](http://wrapdb.mesonbuild.com). + +The front page lists all projects that are on the service. Select the one you want and click it. The detail page lists available versions by branch and revision id. The branch names come from upstream releases and revision ids are version numbers internal to the database. Whenever the packaging is updated a new revision is released to the service a new revision with a bigger revision id is added. Usually you want to select the newest branch with the highest revision id. + +You can get the actual wrap file which tells Meson how to fetch the project by clicking on the download link on the page. As an example, the wrap file for [zlib-1.2.8, revision 4](http://wrapdb.mesonbuild.com/v1/projects/zlib/1.2.8/4/get_wrap) looks like this. You can find detailed documentation about it in [the Wrap manual](Wrap-dependency-system-manual.md). + + [wrap-file] + directory = zlib-1.2.8 + + source_url = http://zlib.net/zlib-1.2.8.tar.gz + source_filename = zlib-1.2.8.tar.gz + source_hash = 36658cb768a54c1d4dec43c3116c27ed893e88b02ecfcb44f2166f9c0b7f2a0d + + patch_url = http://wrapdb.mesonbuild.com/v1/projects/zlib/1.2.8/4/get_zip + patch_filename = zlib-1.2.8-4-wrap.zip + patch_hash = 2327a42c8f73a4289ee8c9cd4abc43b324d0decc28d6e609e927f0a50321af4a + +Add this file to your project with the name `subprojects/zlib.wrap`. Then you can use it in your `meson.build` file with this directive: + + zproj = subproject('zlib') + +When Meson encounters this it will automatically download, unpack and patch the source files. + +## Contributing build definitions + +The contents of the Wrap database are tracked in git repos of the [Mesonbuild project](https://github.com/mesonbuild). The actual process is simple and described in [submission documentation](https://github.com/mesonbuild/wrapweb/wiki). diff --git a/docs/markdown/Using-with-Visual-Studio.md b/docs/markdown/Using-with-Visual-Studio.md new file mode 100644 index 0000000..2768ea4 --- /dev/null +++ b/docs/markdown/Using-with-Visual-Studio.md @@ -0,0 +1,16 @@ +--- +short-description: How to use meson in Visual Studio +... + +# Using with Visual Studio + +In order to generate Visual Studio projects, Meson needs to know the settings of your installed version of Visual Studio. The only way to get this information is to run Meson under the Visual Studio Command Prompt. The steps to set it up are as follows: + +1. Click on start menu and select "Visual Studio 2015 Command Prompt" +1. cd into your source directory +1. mkdir build +1. python3 path/to/meson.py build --backend vs2015 + +If you wish to use the Ninja backend instead of vs2015, pass `--backend ninja`. At the time of writing the Ninja backend is more mature than the VS backend so you might want to use it for serious work. + +This assumes Python3 is in your `PATH`, which is highly recommended. diff --git a/docs/markdown/Using-wraptool.md b/docs/markdown/Using-wraptool.md new file mode 100644 index 0000000..4e5eb05 --- /dev/null +++ b/docs/markdown/Using-wraptool.md @@ -0,0 +1,59 @@ +# 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. + +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: + + # wraptool list + box2d + enet + gtest + libjpeg + liblzma + libpng + libxml2 + lua + ogg + sqlite + vorbis + zlib + +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: + + # 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. + +## 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. + + # wraptool install libjpeg + Installed libjpeg branch 9a revision 2 + +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. + + # wraptool status + Subproject status + 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: + + # wraptool.py update zlib + Updated zlib to branch 1.2.8 revision 4 + +Wraptool can do other things besides these. Documentation for these can be found in the command line help, which can be accessed by `wraptool --help`. diff --git a/docs/markdown/Vala.md b/docs/markdown/Vala.md new file mode 100644 index 0000000..00df371 --- /dev/null +++ b/docs/markdown/Vala.md @@ -0,0 +1,78 @@ +--- +title: Vala +... + +# Compiling Vala applications + +Meson has support for compiling Vala programs. A skeleton Vala file looks like this. + +```meson +project('valaprog', ['vala', 'c']) + +glib = dependency('glib-2.0') +gobject = dependency('gobject-2.0') + +executable('valaprog', 'prog.vala', + dependencies : [glib, gobject]) +``` + +You must always specify `glib` and `gobject` as dependencies, because all Vala applications use them. + +## Using a custom VAPI + +When dealing with libraries that are not providing Vala bindings, you can point --vapidir to a directory relative to meson.current_source_dir containing the binding and include a --pkg flag. + +```meson +glib = dependency('glib-2.0') +gobject = dependency('gobject-2.0') +foo = dependency('foo') + +executable('app', + dependencies: [glib, gobject, foo] + vala_args: ['--pkg=foo', '--vapidir=' + meson.current_source_dir()]) +``` + +## GObject Introspection + +To generate GObject Introspection metadata, the --gir flags has to be set explicitly in vala_args. + +```meson +foo_lib = library('foo', + dependencies: [glib, gobject], + vala_args: ['--gir=Foo-1.0.gir']) +``` + +For the typelib, use a custom_target depending on the library: + +```meson + g_ir_compiler = find_program('g_ir_compiler') + custom_target('foo-typelib', + command: [g_ir_compiler, '--output', '@OUTPUT@', meson.current_build_dir() + '/foo@sha/Foo-1.0.gir'], + output: 'Foo-1.0.typelib', + depends: foo_lib, + install: true, + install_dir: get_option('libdir') + '/girepository-1.0') +``` + +## Installing VAPI and GIR files + +To install generated VAPI and GIR files, it is necessary to add a custom install script. + +```meson +meson.add_install_script('install.sh') +``` + +```bash +#!/bin/sh + +mkdir -p "${DESTDIR}${MESON_INSTALL_PREFIX}/share/vala/vapi" +mkdir -p "${DESTDIR}${MESON_INSTALL_PREFIX}/share/gir-1.0" + +install -m 0644 \ + "${MESON_BUILD_ROOT}/foo-1.0.vapi" \ + $"{DESTDIR}${MESON_INSTALL_PREFIX}/share/vala/vapi" + +install -m 0644 \ + "${MESON_BUILD_ROOT}/foo@sha/Foo-1.0.gir" \ + "${DESTDIR}${MESON_INSTALL_PREFIX}/share/gir-1.0" +``` diff --git a/docs/markdown/Videos.md b/docs/markdown/Videos.md new file mode 100644 index 0000000..ab128c6 --- /dev/null +++ b/docs/markdown/Videos.md @@ -0,0 +1,37 @@ +--- +short-description: Videos about Meson +... + +# Videos + +## An overview of meson + +(from Linux.conf.au 2015 -- Auckland, New Zealand) + +<div class="video-container"> +<iframe width="854" height="480" src="https://www.youtube.com/embed/KPi0AuVpxLI" frameborder="0" allowfullscreen></iframe> +</div> + +## Talks about design, goals behind Meson's multiplatform dependency system was held + +(From Linux.conf.au 2016 -- Geelong, Australia) + +<div class="video-container"> +<iframe width="854" height="480" src="https://www.youtube.com/embed/CTJtKtQ8R5k" frameborder="0" allowfullscreen></iframe> +</div> + +## Features and benefits of Meson's multiplatform support for building and dependencies] + +(Libre Application Summit 2016 talk _New world, new tools_ explored further) + +<div class="video-container"> +<iframe width="854" height="480" src="https://www.youtube.com/embed/0-gx1qU2pPo" frameborder="0" allowfullscreen></iframe> +</div> + +## The first ever public presentation on Meson + +(lightning talk at FOSDEM 2014) + +<video width="854" height="480" controls> + < <source src=http://mirror.onet.pl/pub/mirrors/video.fosdem.org/2014/H2215_Ferrer/Sunday/Introducing_the_Meson_build_system.webm> +</video> diff --git a/docs/markdown/Windows-module.md b/docs/markdown/Windows-module.md new file mode 100644 index 0000000..b2b5145 --- /dev/null +++ b/docs/markdown/Windows-module.md @@ -0,0 +1,12 @@ +# Windows module + +This module provides functionality used to build applications for Windows. + +## Methods + +### compile_resources + +Compiles Windows `rc` files specified in the positional arguments. Returns an opaque object that you put in the list of sources for the target you want to have the resources in. This method has the following keyword argument. + + - `args` lists extra arguments to pass to the resource compiler + - `include_directories` which does the same thing as it does on target declarations: specifies header search directories diff --git a/docs/markdown/Wrap-best-practices-and-tips.md b/docs/markdown/Wrap-best-practices-and-tips.md new file mode 100644 index 0000000..cebc779 --- /dev/null +++ b/docs/markdown/Wrap-best-practices-and-tips.md @@ -0,0 +1,63 @@ +# Wrap best practices and tips + +There are several things you need to take into consideration when writing a Meson build definition for a project. This is especially true when the project will be used as a subproject. This page lists a few things to consider when writing your definitions. + +## Do not put config.h in external search path + +Many projects use a `config.h` header file that they use for configuring their project internally. These files are never installed to the system header files so there are no inclusion collisions. This is not the case with subprojects, your project tree may have an arbitrary number of configuration files, so we need to ensure they don't clash. + +The basic problem is that the users of the subproject must be able to include subproject headers without seeing its `config.h` file. The most correct solution is to rename the `config.h` file into something unique, such as `foobar-config.h`. This is usually not feasible unless you are the maintainer of the subproject in question. + +The pragmatic solution is to put the config header in a directory that has no other header files and then hide that from everyone else. One way is to create a top level subdirectory called `internal` and use that to build your own sources, like this: + +```meson +subdir('internal') # create config.h in this subdir +internal_inc = include_directories('internal') +shared_library('foo', 'foo.c', include_directories : internal_inc) +``` + +Many projects keep their `config.h` in the top level directory that has no other source files in it. In that case you don't need to move it but can just do this instead: + +```meson +internal_inc = include_directories('.') # At top level meson.build +``` + +## Make libraries buildable both as static and shared + +Some platforms (e.g. iOS) requires linking everything in your main app statically. In other cases you might want shared libraries. They are also faster during development due to Meson's relinking optimization. However building both library types on all builds is slow and wasteful. + +Your project should provide a toggle specifying which type of library it should build. As an example if you have a Meson option called `shared_lib` then you could do this: + +```meson +if get_option('shared_lib') + libtype = 'shared_library' +else + libtype = 'static_library' +endif + +mylib = build_target('foo', 'foo.c', + target_type : libtype) +``` + +## Declare generated headers explicitly + +Meson's Ninja backend works differently from Make and other systems. Rather than processing things directory per directory, it looks at the entire build definition at once and runs the individual compile jobs in what might look to the outside as a random order. + +The reason for this is that this is much more efficient so your builds finish faster. The downside is that you have to be careful with your dependencies. The most common problem here is headers that are generated at compile time with e.g. code generators. If these headers are needed when building code that uses these libraries, the compile job might be run before the code generation step. The fix is to make the dependency explicit like this: + +```meson +myheader = custom_target(...) +mylibrary = shared_library(...) +mydep = declare_dependency(link_with : mylibrary, + include_directories : include_directories(...), + sources : myheader) +``` + +And then you can use the dependency in the usual way: + +```meson +executable('dep_using_exe', 'main.c', + dependencies : mydep) +``` + +Meson will ensure that the header file has been built before compiling `main.c`. diff --git a/docs/markdown/Wrap-dependency-system-manual.md b/docs/markdown/Wrap-dependency-system-manual.md new file mode 100644 index 0000000..13765fc --- /dev/null +++ b/docs/markdown/Wrap-dependency-system-manual.md @@ -0,0 +1,121 @@ +# Wrap dependency system manual + +One of the major problems of multiplatform development is wrangling all your dependencies. This is easy on Linux where you can use system packages but awkward on other platforms. Most of those do not have a package manager at all. This has been worked around by having third party package managers. They are not really a solution for end user deployment, because you can't tell them to install a package manager just to use your app. On these platforms you must produce self-contained applications. + +The traditional approach to this has been to bundle dependencies inside your own project. Either as prebuilt libraries and headers or by embedding the source code inside your source tree and rewriting your build system to build them as part of your project. + +This is both tedious and error prone because it is always done by hand. The Wrap dependency system of Meson aims to provide an automated way to do this. + +## How it works + +Meson has a concept of [subprojects](Subprojects.md). They are a way of nesting one Meson project inside another. Any project that builds with Meson can detect that it is built as a subproject and build itself in a way that makes it easy to use (usually this means as a static library). + +To use this kind of a project as a dependency you could just copy and extract it inside your project's `subprojects` directory. However there is a simpler way. You can specify a Wrap file that tells Meson how to download it for you. An example wrap file would look like this and should be put in `subprojects/foobar.wrap`: + +```ini +[wrap-file] +directory = libfoobar-1.0 + +source_url = http://example.com/foobar-1.0.tar.gz +source_filename = foobar-1.0.tar.gz +source_hash = 5ebeea0dfb75d090ea0e7ff84799b2a7a1550db3fe61eb5f6f61c2e971e57663 +``` + +If you then use this subproject in your build, Meson will automatically download and extract it during build. This makes subproject embedding extremely easy. + +Unfortunately most software projects in the world do not build with Meson. Because of this Meson allows you to specify a patch url. This works in much the same way as Debian's distro patches. That is, they 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. + +``` +[wrap-file] +directory = libfoobar-1.0 + +source_url = http://upstream.example.com/foobar-1.0.tar.gz +source_filename = foobar-1.0.tar.gz +source_hash = 5ebeea0dfb75d090ea0e7ff84799b2a7a1550db3fe61eb5f6f61c2e971e57663 + +patch_url = https://myserver.example.com/libfoobar-meson.tar.gz +patch_filename = libfoobar-meson.tar.gz +patch_hash = 8c9d00702d5fe4a6bf25a36b821a332f6b2dfd117c66fe818b88b23d604635e9 +``` + +In this example the Wrap manager would download the patch and unzip it in libfoobar's directory. + +This approach makes it extremely simple to embed dependencies that require build system changes. You can write the Meson build definition for the dependency in total isolation. This is a lot better than doing it inside your own source tree, especially if it contains hundreds of thousands of lines of code. Once you have a working build definition, just zip up the Meson build files (and others you have changed) and put them somewhere where you can download them. + +## Branching subprojects directly from git + +The above mentioned scheme assumes that your subproject is working off 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. + +``` +[wrap-git] +directory=samplesubproject +url=https://github.com/jpakkane/samplesubproject.git +revision=head +``` + +The format is straightforward. The only thing to note is the revision element that can have one of two values. The first is `head` which will cause Meson to track the master head (doing a repull whenever the build definition is altered). The second type is a commit hash. In this case Meson will use the commit specified (with `git checkout [hash id]`). + +Note that in this case you cannot specify an extra patch file to use. The git repo must contain all necessary Meson build definitions. + +Usually you would use subprojects as read only. However in some cases you want to do commits to subprojects and push them upstream. For these cases you can specify the upload url by adding the following at the end of your wrap file: + +```ini +push-url=git@git.example.com:projects/someproject.git # Supported since version 0.37.0 +``` + +## Using wrapped projects + +To use a subproject simply do this in your top level `meson.build`. + +```meson +foobar_sp = subproject('foobar') + +Usually dependencies consist of some header files plus a library to link against. To do this you would declare this internal dependency like this: + +```meson +foobar_dep = declare_dependency(link_with : mylib, + include_directories : myinc) +``` + +Then in your main project you would use them like this: + +```meson +executable('toplevel_exe', 'prog.c', + dependencies : foobar_sp.get_variable('foobar_dep')) +``` + +Note that the subproject object is *not* used as the dependency, but rather you need to get the declared dependency from it with `get_variable` because a subproject may have multiple declared dependencies. + +## Toggling between distro packages and embedded source + +When building distro packages it is very important that you do not embed any sources. Some distros have a rule forbidding embedded dependencies so your project must be buildable without them or otherwise the packager will hate you. + +Doing this with Meson and Wrap is simple. Here's how you would use distro packages and fall back to embedding if the dependency is not available. + +```meson +foobar_dep = dependency('foobar', required : false) + +if not foobar_dep.found() + foobar_subproj = subproject('foobar') + # the subproject defines an internal dependency with + # the command declare_dependency(). + foobar_dep = foobar_subproj.get_variable('foobar_dep') +endif + +executable('toplevel_exe', 'prog.c', + dependencies : foobar_dep) +``` + +Because this is such a common operation, Meson provides a shortcut for this use case. + +```meson +foobar_dep = dependency('foobar', fallback : ['foobar', 'foobar_dep']) +``` + +The `fallback` keyword argument takes two items, the name of the subproject and the name of the variable that holds the dependency. If you need to do something more complicated, such as extract several different variables, then you need to do it yourself with the manual method described above. + +With this setup when foobar is provided by the system, we use it. When that is not the case we use the embedded version. Note that `foobar_dep` can point to an external or an internal dependency but you don't have to worry about their differences. Meson will take care of the details for you. + +## Getting wraps + +Usually you don't want to write your wraps by hand. There is an online repository called [WrapDB](Using-the-WrapDB.md) that provides many dependencies ready to use. diff --git a/docs/markdown/Wrap-review-guidelines.md b/docs/markdown/Wrap-review-guidelines.md new file mode 100644 index 0000000..b211d91 --- /dev/null +++ b/docs/markdown/Wrap-review-guidelines.md @@ -0,0 +1,19 @@ +# Wrap review guidelines + +In order to get a package in the Wrap database it must be reviewed and accepted by someone with admin rights. Here is a list of items to check in the review. If some item is not met it does not mean that the package is rejected. What should be done will be determined on a case-by-case basis. Similarly meeting all these requirements does not guarantee that the package will get accepted. Use common sense. + +## Checklist ## + +Reviewer: copypaste this to MR discussion box and tick all boxes that apply. + + - [ ] project() has version string + - [ ] project() has license string + - [ ] if new project, master has tagged commit as only commit + - [ ] if new branch, it is branched from master + - [ ] contains a readme.txt + - [ ] contains an upstream.wrap file + - [ ] download link points to authoritative upstream location + - [ ] wrap repository contains only build system files + - [ ] merge request is pointed to correct target branch (not master) + - [ ] wrap works + - [ ] repo does not have useless top level directory (i.e. libfoobar-1.0.0) diff --git a/docs/markdown/_Sidebar.md b/docs/markdown/_Sidebar.md new file mode 100644 index 0000000..89fc523 --- /dev/null +++ b/docs/markdown/_Sidebar.md @@ -0,0 +1,14 @@ +## Quick References + +* [Functions](Reference-manual.md) +* [Options](Build-options.md) +* [Configuration](Configuration.md) +* [Dependencies](Dependencies.md) +* [Tests](Unit-tests.md) +* [Syntax](Syntax.md) + +### [Modules](https://github.com/mesonbuild/meson/wiki/Module-reference.md) + +* [gnome](Gnome-module.md) +* [i18n](i18n-module.md) +* [pkgconfig](Pkgconfig-module.md) diff --git a/docs/markdown/fallback-wraptool.md b/docs/markdown/fallback-wraptool.md new file mode 100644 index 0000000..fc3cc02 --- /dev/null +++ b/docs/markdown/fallback-wraptool.md @@ -0,0 +1,31 @@ +--- +title: fallback wraptool +... + +# In case of emergency + +In case wraptool is down we have created a backup script that you can use to download wraps directly from the Github repos. It is not as slick and may have bugs but at least it will allow you to use wraps. + +## Using it + +Currently the emergency tool is only in Meson trunk so you need a git checkout to use it. It also does not on releases older than 0.32.0 because they had a bug. (A workaround for older versions is to delete existing `foobar.wrap` files if you have them.) + +To list all available wraps: + + ghwt.py list + +To install a wrap, go to your source root, make sure that the `subprojects` directory exists and run this command: + + ghwt.py install <projectname> + +This will stage the subproject ready to use. If you have multiple subprojects you need to download them all manually. + +## How to upgrade an existing dir/fix broken state/any other problem + +Nuke the contents of `subprojects` and start again. + +## Known issues + +Some repositories show up in the list but are not installable. They would not show up in the real wrapdb because they are works in progress. + +Github web API limits the amount of queries you can do to 60/hour. If you exceed that you need to wait for the timer to reset. diff --git a/docs/markdown/howtox.md b/docs/markdown/howtox.md new file mode 100644 index 0000000..d40e8cd --- /dev/null +++ b/docs/markdown/howtox.md @@ -0,0 +1,160 @@ +# How do I do X in Meson? + +This page lists code snippets for common tasks. These are written mostly using the C compiler, but the same approach should work on almost all other compilers. + +# Set compiler + +When first running Meson, set it in an environment variable. + +```console +$ CC=mycc meson <options> +``` + +# Set default C/C++ language version + +```meson +project('myproj', 'c', 'cpp', + default_options : ['c_std=c11', 'cpp_std=c++11']) +``` + +# Enable threads + +Lots of people seem to do this manually with `find_library('phtread')` or something similar. Do not do that. It is not portable. Instead do this. + +```meson +thread_dep = dependency('threads') +executable(..., dependencies : thread_dep) +``` + +# Set extra compiler and linker flags from the outside (when e.g. building distro packages) + +The behaviour is the same as with other build systems, with environment variables during first invocation. + +```console +$ CFLAGS=-fsomething LDFLAGS=-Wl,--linker-flag meson <options> +``` + +# Use an argument only with a specific compiler + +First check which arguments to use. + +```meson +if meson.get_compiler('c').get_id() == 'clang' + extra_args = ['-fclang-flag'] +else + extra_args = [] +endif +``` + +Then use it in a target. + +```meson +executable(..., c_args : extra_args) +``` + +If you want to use the arguments on all targets, then do this. + +```meson +if meson.get_compiler('c').get_id() == 'clang' + add_global_arguments('-fclang-flag', language : 'c') +endif +``` + +# Set a command's output to configuration + +```meson +txt = run_command('script', 'argument').stdout().strip() +cdata = configuration_data() +cdata.set('SOMETHING', txt) +configure_file(...) +``` + +# Generate a runnable script with `configure_file` + +`configure_file` preserves metadata so if your template file has execute permissions, the generated file will have them too. + +## Producing a coverage report + +First initialise the build directory with this command. + +```console +$ meson <other flags> -Db_coverage=true +``` + +Then issue the following commands. + +```console +$ ninja +$ ninja test +$ ninja coverage-html (or coverage-xml) +``` + +The coverage report can be found in the meson-logs subdirectory. + +## Add some optimization to debug builds ## + +By default the debug build does not use any optimizations. This is the desired approach most of the time. However some projects benefit from having some minor optimizations enabled. Gcc even has a specific compiler flag `-Og` for this. To enable its use, just issue the following command. + +```console +$ mesonconf -Dc_args=-Og +``` + +This causes all subsequent builds to use this command line argument. + +## Use address sanitizer + +Clang comes with a selection of analysis tools such as the [address sanitizer](http://clang.llvm.org/docs/AddressSanitizer.html). Meson has native support for these with the `b_sanitize` option. + +```console +$ meson <other options> -Db_sanitize=address +``` + +After this you just compile your code and run the test suite. Address sanitizer will abort executables which have bugs so they show up as test failures. + +## Use Clang static analyzer + +Install scan-build and configure your project. Then do this: + +```console +$ ninja scan-build +``` + +## Use profile guided optimization + +Using profile guided optimization with GCC is a two phase operation. First we set up the project with profile measurements enabled and compile it. + +```console +$ meson <Meson options, such as --buildtype=debugoptimized> -Db_pgo=generate +$ ninja -C builddir +``` + +Then we need to run the program with some representative input. This step depends on your project. + +Once that is done we change the compiler flags to use the generated information and rebuild. + +```console +$ mesonconf -Db_pgo=use +$ ninja +``` + +After these steps the resulting binary is fully optimized. + +## Add math library (`-lm`) portably + +Some platforms (e.g. Linux) have a standalone math library. Other platforms (pretty much everyone else) do not. How to specify that `m` is used only when needed? + +```meson +cc = meson.get_compiler('c') +m_dep = cc.find_library('m', required : false) +executable(..., dependencies : m_dep) +``` + +## Install an executable to `libexecdir` + +```meson +executable(..., install : true, install_dir : get_option('libexecdir')) +``` + +---- + +[Wiki home](index.md) diff --git a/docs/markdown/i18n-module.md b/docs/markdown/i18n-module.md new file mode 100644 index 0000000..b4e40d7 --- /dev/null +++ b/docs/markdown/i18n-module.md @@ -0,0 +1,30 @@ +# I18n module + +This module provides internationalisation and localisation functionality. + +## Usage + +To use this module, just do: **`i18n = import('i18n')`**. The following functions will then be available as methods on the object with the name `i18n`. You can, of course, replace the name `i18n` with anything else. + +### i18n.gettext() + +Sets up gettext localisation so that translations are built and placed into their proper locations during install. Takes one positional argument which is the name of the gettext module. + +* `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. +* `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 +* `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 +* `args`: list of extra arguments to pass to `xgettext` when generating the pot file + +This function also defines targets for maintainers to use: +**Note**: These output to the source directory + +* `<project_id>-pot`: runs `xgettext` to regenerate the pot file + +### i18n.merge_file() + +This merges translations into a text file using `msgfmt`. See [custom_target](https://github.com/mesonbuild/meson/wiki/Reference%20manual#custom_target) for normal keywords. In addition it accepts these keywords: + +* `po_dir`: directory containing translations, relative to current directory +* `type`: type of file, valid options are `'xml'` (default) and `'desktop'` + +*Added 0.37.0* diff --git a/docs/markdown/index.md b/docs/markdown/index.md new file mode 100644 index 0000000..63bfd55 --- /dev/null +++ b/docs/markdown/index.md @@ -0,0 +1,33 @@ +--- +render-subpages: false +... + +# The Meson Build system + +## Overview + +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. + +## Features + +* multiplatform support for Linux, OSX, Windows, Gcc, Clang, Visual Studio and others +* supported languages include C, C++, Fortran, Java, Rust +* build definitions in a very readable and user friendly non-turing complete DSL +* cross compilation for many operating systems as well as bare metal +* optimized for extremely fast full and incremental builds without sacrificing correctness +* built-in multiplatform dependency provider that works together with distro packages +* fun! + +## 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). + +The second way is via IRC. The channel to use is <tt>#mesonbuild</tt> at [Freenode](https://freenode.net/). + +## Development + +All development on Meson is done on [Github project](https://github.com/mesonbuild/meson). For further info look into the <tt>contributing.txt</tt> file that comes with Meson's source checkout. + +You do not need to sign a CLA to contribute to Meson. diff --git a/docs/markdown/legal.md b/docs/markdown/legal.md new file mode 100644 index 0000000..f8f01bc --- /dev/null +++ b/docs/markdown/legal.md @@ -0,0 +1,6 @@ +# Legal information + +Meson is copyrighted by all members of the Meson development team. For details see the <tt>authors.txt</tt> file that comes with the source code. Meson is licensed under the [Apache 2 license](https://www.apache.org/licenses/LICENSE-2.0). + +Meson is a registered trademark of Jussi Pakkanen. + diff --git a/docs/markdown/tmp.json b/docs/markdown/tmp.json new file mode 100644 index 0000000..190d12f --- /dev/null +++ b/docs/markdown/tmp.json @@ -0,0 +1,29 @@ +{ + "functions": { + "add_global_arguments": { + "doc": ["Adds the positional arguments to the compiler command line for the language specified in `language` keyword argument. Note that there is no way to remove an argument set in this way.", + "If you have an argument that is only used in a subset of targets, you have to specify it in per-target flags.", + "The arguments are used in all compiler invocations with the exception of compile tests, because you might need to run a compile test with and without the argument in question. For this reason only the arguments explicitly specified are used during compile tests.", + "**Note:** Usually you should use `add_project_arguments` instead, because that works even when you project is used as a subproject.", + "**Note:** You must pass always arguments individually `arg1, arg2, ...` rather than as a string `'arg1 arg2', ...`"] + "arguments": [ + {"name": "args1", "doc": "Some argument"} + ] + } + } + "objects": [ + "meson": { + "doc": ["The `meson` object allows you to introspect various properties of the system. This object is always mapped in the `meson` variable. It has the following methods."] + "methods": [ + "get_compiler": { + "arguments": [ + {"name": "language", "doc": "returns [an object describing a compiler](#compiler-object), takes one positional argument which is the language to use. ", + "It also accepts one keyword argument, `native` which when set to true makes Meson return the compiler for the build machine (the \"native\" compiler)", + "and when false it returns the host compiler (the \"cross\" compiler). If `native` is omitted, Meson returns the \"cross\" compiler if we're currently", + " cross-compiling and the \"native\" compiler if we're not."} + ] + } + ] + } + ] +} diff --git a/docs/sitemap.txt b/docs/sitemap.txt new file mode 100644 index 0000000..a034d60 --- /dev/null +++ b/docs/sitemap.txt @@ -0,0 +1,85 @@ +index.md + Getting-meson.md + Quick-guide.md + Tutorial.md + Manual.md + Overview.md + Running-Meson.md + Using-with-Visual-Studio.md + Meson-sample.md + Syntax.md + Build-targets.md + Include-directories.md + Installing.md + Adding-arguments.md + Configuration.md + Compiler-properties.md + Dependencies.md + Threads.md + External-commands.md + Precompiled-headers.md + Unity-builds.md + Feature-autodetection.md + Generating-sources.md + Unit-tests.md + Cross-compilation.md + Localisation.md + Build-options.md + Subprojects.md + Modules.md + i18n-module.md + Pkgconfig-module.md + Python-3-module.md + Qt4-module.md + Qt5-module.md + RPM-module.md + Windows-module.md + Gnome-module.md + Java.md + Vala.md + IDE-integration.md + Custom-build-targets.md + Build-system-converters.md + Configuring-a-build-directory.md + Run-targets.md + Creating-OSX-packages.md + Creating-Linux-binaries.md + Reference-manual.md + FAQ.md + Reproducible-builds.md + howtox.md + Wrap-dependency-system-manual.md + fallback-wraptool.md + Adding-new-projects-to-wrapdb.md + Using-the-WrapDB.md + Using-wraptool.md + Wrap-best-practices-and-tips.md + Wrap-review-guidelines.md + Shipping-prebuilt-binaries-as-wraps.md + Release-notes.md + Release-notes-for-0.40.0.md + Release-notes-for-0.39.0.md + Release-notes-for-0.38.0.md + Release-notes-for-0.37.0.md + Additionnal.md + Release-procedure.md + Performance-comparison.md + ARM-performance-test.md + Simple-comparison.md + Comparisons.md + Conference-presentations.md + Contact-information.md + Continuous-Integration.md + Design-rationale.md + IndepthTutorial.md + In-the-press.md + Meson-design-rationale:-A-proposal-for-a-better-cross-platform-build-system.md + Pkg-config-files.md + Playground.md + Porting-from-autotools.md + Trial-conversions.md + Use-of-Python.md + Users.md + Using-multiple-build-directories.md + legal.md + Videos.md diff --git a/docs/theme/extra/images/favicon.png b/docs/theme/extra/images/favicon.png Binary files differnew file mode 100644 index 0000000..5e7b941 --- /dev/null +++ b/docs/theme/extra/images/favicon.png diff --git a/docs/theme/extra/images/meson_logo.png b/docs/theme/extra/images/meson_logo.png Binary files differnew file mode 100644 index 0000000..2720af5 --- /dev/null +++ b/docs/theme/extra/images/meson_logo.png diff --git a/docs/theme/extra/prism_components/prism-meson.js b/docs/theme/extra/prism_components/prism-meson.js new file mode 100644 index 0000000..242af19 --- /dev/null +++ b/docs/theme/extra/prism_components/prism-meson.js @@ -0,0 +1,16 @@ +Prism.languages.meson= { + 'triple-quoted-string': { + 'pattern': /'''[\s\S]*?'''/, + 'alias': 'string' + }, + 'comment': /#.*/, + 'string': /'(?:\\'|[^'])*'/, + 'number': /\b\d+(?:\.\d+)?\b/, + 'keyword': /\b(?:if|else|elif|endif|foreach|endforeach)\b/, + 'function': /(?=\.|\b)[a-zA-Z_]+\s*(?=\()/, + 'boolean': /\b(?:true|false)\b/, + 'builtin': /\b(?:meson|host_machine|target_machine|build_machine)(?=\.)/, + 'operator': /(?:[<>=*+\-/!]?=|%|\/|\*|-|\+|\b(?:or|and|not)\b)/, + 'punctuation': /[(),[\]]/ + // TODO: Handle ternary ?: +};
\ No newline at end of file diff --git a/docs/theme/extra/prism_components/prism-meson.min.js b/docs/theme/extra/prism_components/prism-meson.min.js new file mode 100644 index 0000000..7bf90e0 --- /dev/null +++ b/docs/theme/extra/prism_components/prism-meson.min.js @@ -0,0 +1 @@ +Prism.languages.meson={"triple-quoted-string":{pattern:/'''[\s\S]*?'''/,alias:"string"},comment:/#.*/,string:/'(?:\\'|[^'])*'/,number:/\b\d+(?:\.\d+)?\b/,keyword:/\b(?:if|else|elif|endif|foreach|endforeach)\b/,"function":/(?=\.|\b)[a-zA-Z_]+\s*(?=\()/,"boolean":/\b(?:true|false)\b/,builtin:/\b(?:meson|host_machine|target_machine|build_machine)(?=\.)/,operator:/(?:[<>=*+\-\/!]?=|%|\/|\*|-|\+|\b(?:or|and|not)\b)/,punctuation:/[(),[\]]/};
\ No newline at end of file diff --git a/docs/theme/extra/templates/brand-logo.html b/docs/theme/extra/templates/brand-logo.html new file mode 100644 index 0000000..7a12347 --- /dev/null +++ b/docs/theme/extra/templates/brand-logo.html @@ -0,0 +1 @@ +<img src="assets/images/meson_logo.png" alt=Home> diff --git a/docs/theme/extra/templates/extra_head.html b/docs/theme/extra/templates/extra_head.html new file mode 100644 index 0000000..012f325 --- /dev/null +++ b/docs/theme/extra/templates/extra_head.html @@ -0,0 +1,3 @@ +<title>The MesonĀ® Build System</title> +<link rel="icon" type="image/png" href="assets/images/favicon.png"> +<link rel="shortcut icon" href="assets/images/favicon.png"> diff --git a/docs/theme/extra/templates/navbar_center.html b/docs/theme/extra/templates/navbar_center.html new file mode 100644 index 0000000..9934be7 --- /dev/null +++ b/docs/theme/extra/templates/navbar_center.html @@ -0,0 +1 @@ +<p><b>The Meson Build System</b></p> diff --git a/docs/theme/extra/templates/navbar_links.html b/docs/theme/extra/templates/navbar_links.html new file mode 100644 index 0000000..8a3f515 --- /dev/null +++ b/docs/theme/extra/templates/navbar_links.html @@ -0,0 +1,39 @@ +@require(page) + +<li class="dropdown"> + <a class="dropdown-toggle" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> + Modules <span class="caret"></span> + </a> + <ul class="dropdown-menu" id="modules-menu"> + @for tup in (("Gnome-module.html","GNOME"), \ + ("i18n-module.html","i18n"), \ + ("Pkgconfig-module.html","Pkgconfig"), \ + ("Python-3-module.html","Python 3"), \ + ("Qt4-module.html","Qt4"), \ + ("Qt5-module.tml","Qt5"), \ + ("RPM-module.html","RPM"), \ + ("Windows-module.html","Windows")): + <li> + <a href="@tup[0]">@tup[1]</a> + </li> + @end + </ul> +</li> +\ +<li class="dropdown"> + <a class="dropdown-toggle" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> + Quick References <span class="caret"></span> + </a> + <ul class="dropdown-menu" id="quick-refs-menu"> + @for tup in (("Reference-manual.html", "Functions"), \ + ("Build-options.html", "Options"), \ + ("Configuration.html", "Configuration"), \ + ("Dependencies.html", "Dependencies"), \ + ("Unit-tests.html", "Tests"), \ + ("Syntax.html", "Syntax")): + <li> + <a href="@tup[0]">@tup[1]</a> + </li> + @end + </ul> +</li> |