diff options
68 files changed, 2896 insertions, 883 deletions
diff --git a/ciimage/Dockerfile b/ciimage/Dockerfile index 3789e8d..2691900 100644 --- a/ciimage/Dockerfile +++ b/ciimage/Dockerfile @@ -9,5 +9,8 @@ RUN apt-get -y update && apt-get -y upgrade \ && apt-get -y install llvm libsdl2-dev \ && apt-get -y install python3-pip libxml2-dev libxslt1-dev cmake libyaml-dev \ && apt-get -y install openmpi-bin libopenmpi-dev \ +&& apt-get -y install libboost-log-dev \ && apt-get -y install libvulkan-dev libpcap-dev \ +&& apt-get -y install gcovr lcov \ +&& apt-get -y install gtk-sharp2 gtk-sharp2-gapi libglib2.0-cil-dev \ && python3 -m pip install hotdoc codecov diff --git a/docs/markdown/ARM-performance-test.md b/docs/markdown/ARM-performance-test.md index 7e42fb3..4be6e4a 100644 --- a/docs/markdown/ARM-performance-test.md +++ b/docs/markdown/ARM-performance-test.md @@ -1,10 +1,21 @@ # 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). +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 ------ @@ -13,25 +24,58 @@ The first thing we measured was the time it took to run the configure step.  -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. +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. +Then we measured the build times. Two parallel compilation processes +were used for both systems.  -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. +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.  -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. +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.  -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. +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. +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 index 0bf5944..e314102 100644 --- a/docs/markdown/Adding-arguments.md +++ b/docs/markdown/Adding-arguments.md @@ -4,22 +4,38 @@ short-description: Adding compiler arguments # Adding arguments -Often you need to specify extra compiler arguments. Meson provides two different ways to achieve this: global arguments and per-target 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. +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.md). - -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. +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.md). + +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 -- @@ -30,7 +46,8 @@ Per target arguments are just as simple to define. 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. +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: diff --git a/docs/markdown/Adding-new-projects-to-wrapdb.md b/docs/markdown/Adding-new-projects-to-wrapdb.md index e14e0ac..4420de5 100644 --- a/docs/markdown/Adding-new-projects-to-wrapdb.md +++ b/docs/markdown/Adding-new-projects-to-wrapdb.md @@ -1,18 +1,35 @@ # 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.** +**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. +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. +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`. +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 @@ -61,13 +78,21 @@ First you need to fork the repository to your own page. Then you can create the 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. +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. +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. +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 diff --git a/docs/markdown/Build-options.md b/docs/markdown/Build-options.md index 6029a2c..54905d5 100644 --- a/docs/markdown/Build-options.md +++ b/docs/markdown/Build-options.md @@ -4,7 +4,11 @@ short-description: Build options to configure project properties # 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. +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. @@ -14,7 +18,14 @@ 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. +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. @@ -22,13 +33,19 @@ These options are accessed in Meson code with the `get_option` function. 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: +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: +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 index 18e7470..1c0b4fc 100644 --- a/docs/markdown/Build-system-converters.md +++ b/docs/markdown/Build-system-converters.md @@ -4,10 +4,24 @@ short-description: Converting other build systems to Meson # 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. +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. +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 finalize the conversion. To make this task as simple as possible, the converter script will transfer all comments from the CMake definition into Meson definition. +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 finalize 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 index 4153e97..e48de12 100644 --- a/docs/markdown/Build-targets.md +++ b/docs/markdown/Build-targets.md @@ -4,7 +4,13 @@ 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. +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. @@ -13,14 +19,16 @@ 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. +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. +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') @@ -28,7 +36,9 @@ 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. +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. @@ -40,15 +50,25 @@ 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. +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. +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. +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', ...) @@ -56,6 +76,13 @@ 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. +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. +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 index eb0e4dd..3c526ad 100644 --- a/docs/markdown/Comparisons.md +++ b/docs/markdown/Comparisons.md @@ -4,17 +4,25 @@ title: Comparisons # 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. +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. +Excellent support for legacy Unix platforms, large selection of +existing modules. ### Cons ### -Needlessly slow, complicated, hard to use correctly, unreliable, painful to debug, incomprehensible for most people, poor support for non-Unix platforms (especially Windows). +Needlessly slow, complicated, hard to use correctly, unreliable, +painful to debug, incomprehensible for most people, poor support for +non-Unix platforms (especially Windows). ## CMake ## @@ -24,7 +32,8 @@ 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. +The scripting language is cumbersome to work with. Some simple things +are more complicated than necessary. ## SCons ## @@ -34,7 +43,11 @@ 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. +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 @@ -44,14 +57,22 @@ 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). +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.md), 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. +The fastest build system [see +measurements](Performance-comparison.md), 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. +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 index 1765bef..5978b5d 100644 --- a/docs/markdown/Compiler-properties.md +++ b/docs/markdown/Compiler-properties.md @@ -1,16 +1,25 @@ # 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. +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. +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 thoroughly explained on the page on [cross compilation](Cross-compilation.md). But if you just want to know the operating system your code will run on, issue this command: +This is a bit complex and more thoroughly explained on the page on +[cross compilation](Cross-compilation.md). But if you just want to +know the operating system your code will run on, issue this command: ```meson host_machine.system() @@ -19,7 +28,9 @@ 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. +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 | | ----- | ---------------- | @@ -42,7 +53,9 @@ The compiler object has a method called `get_id`, which returns a lower case str 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: +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> @@ -56,15 +69,18 @@ Then we can run the test. 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. +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: +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> @@ -79,9 +95,9 @@ 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. +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 @@ -100,7 +116,9 @@ int main(int argc, char **argv) { 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`. +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 | ------ | ------------ @@ -121,7 +139,11 @@ 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. +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') @@ -132,20 +154,31 @@ 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. +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. +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. +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 doesn't 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` +Just having a header doesn't 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>') @@ -156,7 +189,9 @@ 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`. +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>') @@ -167,7 +202,10 @@ 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. +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. @@ -175,10 +213,13 @@ 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. +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. +*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/Configuration.md b/docs/markdown/Configuration.md index 70649d7..9db6370 100644 --- a/docs/markdown/Configuration.md +++ b/docs/markdown/Configuration.md @@ -4,7 +4,11 @@ short-description: Build-time configuration options # 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. +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: @@ -22,15 +26,22 @@ and that the contents of `config.h.in` are #define VERSION_STR "@version@" ``` -Meson will then create a file called `config.h` in the corresponding build directory whose contents are the following. +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. +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 being passed to the `configure_file` +function. That is, after it has been used once to generate output 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. +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 @@ -43,20 +54,24 @@ The replacement that happens depends on what the value and type of TOKEN is: /* 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: +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: +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. +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) @@ -70,7 +85,9 @@ 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: +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" @@ -81,7 +98,8 @@ 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. +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') @@ -93,3 +111,44 @@ Will produce: /* Set BAR if it is available */ #define BAR ``` + +# A full example + +Generating and using a configuration file requires the following steps: + + - generate the file + - create an include directory object for the directory that holds the file + - use it in a target + +We are going to use the traditional approach of generating a header +file in the top directory. The common name is `config.h` but we're +going to use an unique name. This avoids the problem of accidentally +including the wrong header file when building a project with many +subprojects. + +At the top level we generate the file: + +```meson +configure_file(input : 'projconfig.h.in', + output : 'projconfig.h', + configuration : cdata_object) +``` + +Immediately afterwards we generate the include object. + +```meson +configuration_inc = include_directories('.') +``` + +Finally we specify this in a target that can be in any subdirectory. + +```meson +executable(..., include_directories : configuration_inc) +``` + +Now any source file in this target can include the configuration +header like this: + +```c +#include<projconfig.h> +``` diff --git a/docs/markdown/Configuring-a-build-directory.md b/docs/markdown/Configuring-a-build-directory.md index c7aa913..edf3d97 100644 --- a/docs/markdown/Configuring-a-build-directory.md +++ b/docs/markdown/Configuring-a-build-directory.md @@ -4,11 +4,18 @@ short-description: Configuring a pre-generated build directory # 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. +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. +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. +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 @@ -43,8 +50,14 @@ You invoke `mesonconf` by giving it the location of your build dir. If omitted, 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. +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. +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 index 4075573..87a76a5 100644 --- a/docs/markdown/Contact-information.md +++ b/docs/markdown/Contact-information.md @@ -1,7 +1,14 @@ # Contact information -For general discussion and questions, it is strongly recommended that you use the [mailing list](https://groups.google.com/forum/#!forum/mesonbuild). +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). +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*). +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 index 68d6138..96e8e5d 100644 --- a/docs/markdown/Continuous-Integration.md +++ b/docs/markdown/Continuous-Integration.md @@ -1,14 +1,21 @@ # Continuous Integration -Here you will find snippets to use Meson with various CI such as Travis and AppVeyor. +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. +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. +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). +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 @@ -39,7 +46,8 @@ script: ## 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. +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 diff --git a/docs/markdown/Creating-Linux-binaries.md b/docs/markdown/Creating-Linux-binaries.md index 3c48122..8ca3ef0 100644 --- a/docs/markdown/Creating-Linux-binaries.md +++ b/docs/markdown/Creating-Linux-binaries.md @@ -4,20 +4,34 @@ short-description: Creating universal Linux binaries # 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. +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. +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: +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. Copy-paste the following into `install_gcc.sh` and execute it. +Then create a `src` subdirectory in your home directory. Copy-paste +the following into `install_gcc.sh` and execute it. ```bash #!/bin/sh @@ -46,21 +60,46 @@ 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. +Old distros might have too old versions of some tools. For Meson this +could nclude 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](Wrap-dependency-system-manual.md) might be of use here. 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. +You want to embed and statically link every dependency you can +(especially C++ dependencies). Meson's [Wrap package +manager](Wrap-dependency-system-manual.md) might be of use here. 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: +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). +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: @@ -70,7 +109,11 @@ meson.add_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: +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 @@ -86,4 +129,6 @@ Install it with this Meson snippet: 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`. +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 index 4a4612e..14b2af8 100644 --- a/docs/markdown/Creating-OSX-packages.md +++ b/docs/markdown/Creating-OSX-packages.md @@ -4,15 +4,27 @@ short-description: Tools to create OS X packages # 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. +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). +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. +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: +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) @@ -27,18 +39,29 @@ $ meson --prefix=/tmp/myapp.app \ <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. +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. +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. +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: +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 @@ -53,17 +76,25 @@ install it with this: 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`. +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. +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. +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.add_install_script('install_script.sh') ``` -The install script does two things. First it copies the whole framework into our bundle. +The install script does two things. First it copies the whole +framework into our bundle. ```console $ mkdir -p ${MESON_INSTALL_PREFIX}/Contents/Frameworks @@ -71,7 +102,10 @@ $ 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: +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 \ @@ -79,22 +113,48 @@ $ install_name_tool -change @rpath/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. +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. +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. +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. +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. +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. +`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. +`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. +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/Creating-releases.md b/docs/markdown/Creating-releases.md index b0149a6..0ec41d1 100644 --- a/docs/markdown/Creating-releases.md +++ b/docs/markdown/Creating-releases.md @@ -4,12 +4,27 @@ short-description: Creating releases # Creating releases -In addition to development, almost all projects provide periodical source releases. These are standalone packages (usually either in tar or zip format) of the source code. They do not contain any revision control metadata, only the source code. +In addition to development, almost all projects provide periodical +source releases. These are standalone packages (usually either in tar +or zip format) of the source code. They do not contain any revision +control metadata, only the source code. -Meson provides a simple way of generating these. It consists of a single command: +Meson provides a simple way of generating these. It consists of a +single command: ninja dist -This creates a file called `projectname-version.tar.xz` in the build tree subdirectory `meson-dist`. This archive contains the full contents of the latest commit in revision control including all the submodules. All revision control metadata is removed. Meson then takes this archive and tests that it works by doing a full compile + test + install cycle. If all these pass, Meson will then create a SHA-256 checksum file next to the archive. +This creates a file called `projectname-version.tar.xz` in the build +tree subdirectory `meson-dist`. This archive contains the full +contents of the latest commit in revision control including all the +submodules. All revision control metadata is removed. Meson then takes +this archive and tests that it works by doing a full compile + test + +install cycle. If all these pass, Meson will then create a SHA-256 +checksum file next to the archive. -**Note**: Meson behaviour is different from Autotools. The Autotools "dist" target packages up the current source tree. Meson packages the latest revision control commit. The reason for this is that it prevents developers from doing accidental releases where the distributed archive does not match any commit in revision control (especially the one tagged for the release). +**Note**: Meson behaviour is different from Autotools. The Autotools +"dist" target packages up the current source tree. Meson packages +the latest revision control commit. The reason for this is that it +prevents developers from doing accidental releases where the +distributed archive does not match any commit in revision control +(especially the one tagged for the release). diff --git a/docs/markdown/Cross-compilation.md b/docs/markdown/Cross-compilation.md index b7ef354..e232033 100644 --- a/docs/markdown/Cross-compilation.md +++ b/docs/markdown/Cross-compilation.md @@ -4,28 +4,64 @@ short-description: Setting up cross-compilation # 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 +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 platform. 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. +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 platform. 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: +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] @@ -36,9 +72,17 @@ 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 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: +The next section lists properties of the cross compiler and thus of +the target system. It looks like this: ```ini [properties] @@ -56,16 +100,40 @@ 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'`). - -One important thing to note, if you did not define an `exe_wrapper` in the previous section, is that Meson will make a best-effort guess at whether it can run the generated binaries on the build machine. It determines whether this is possible by looking at the `system` and `cpu_family` of build vs host. There will however be cases where they do match up, but the build machine is actually not compatible with the host machine. Typically this will happen if the libc used by the build and host machines are incompatible, or the code relies on kernel features not available on the build machine. One concrete example is a macOS build machine producing binaries for an iOS Simulator x86-64 host. They're both `darwin` and the same architecture, but their binaries are not actually compatible. In such cases you may use the `needs_exe_wrapper` property to override the auto-detection: +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'`). + +One important thing to note, if you did not define an `exe_wrapper` in +the previous section, is that Meson will make a best-effort guess at +whether it can run the generated binaries on the build machine. It +determines whether this is possible by looking at the `system` and +`cpu_family` of build vs host. There will however be cases where they +do match up, but the build machine is actually not compatible with the +host machine. Typically this will happen if the libc used by the build +and host machines are incompatible, or the code relies on kernel +features not available on the build machine. One concrete example is a +macOS build machine producing binaries for an iOS Simulator x86-64 +host. They're both `darwin` and the same architecture, but their +binaries are not actually compatible. In such cases you may use the +`needs_exe_wrapper` property to override the auto-detection: ```ini [properties] needs_exe_wrapper = true ``` -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. +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] @@ -75,11 +143,26 @@ 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. +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 @@ -90,20 +173,24 @@ Once you have the cross file, starting a build is simple $ meson srcdir builddir --cross-file cross_file.txt ``` -Once configuration is done, compilation is started by invoking Ninja in the usual way. +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. +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. +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. +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) @@ -115,7 +202,10 @@ 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. +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) @@ -125,22 +215,35 @@ You can then take `native_exe` and use it as part of a generator rule or anythin ## 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: +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. +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. +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: +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] diff --git a/docs/markdown/Custom-build-targets.md b/docs/markdown/Custom-build-targets.md index a425f8c..8bd31db 100644 --- a/docs/markdown/Custom-build-targets.md +++ b/docs/markdown/Custom-build-targets.md @@ -4,7 +4,10 @@ short-description: Build targets for custom languages or corner-cases # 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. +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') @@ -20,12 +23,21 @@ mytarget = custom_target('targetname', 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. +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: +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` +* 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 index faf4102..9050696 100644 --- a/docs/markdown/Dependencies.md +++ b/docs/markdown/Dependencies.md @@ -4,14 +4,22 @@ short-description: Dependencies for external libraries and frameworks # 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. +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. +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: @@ -19,7 +27,8 @@ If you have multiple dependencies, pass them as an array: 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. +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) @@ -30,26 +39,39 @@ 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. +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. +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. +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. +You can call `dependency` multiple times with different modules and +use those to link against your targets. -If your boost headers or libraries are in non-standard locations you can set the BOOST_ROOT, BOOST_INCLUDEDIR, and/or BOOST_LIBRARYDIR environment variables. +If your boost headers or libraries are in non-standard locations you +can set the BOOST_ROOT, BOOST_INCLUDEDIR, and/or BOOST_LIBRARYDIR +environment variables. ## GTest and GMock ## -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. +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. ## MPI ## @@ -60,15 +82,17 @@ language-specific, you must specify the requested language using the * `dependency('mpi', language='cpp')` for the C++ MPI headers and libraries * `dependency('mpi', language='fortran')` for the Fortran MPI headers and libraries -Meson prefers pkg-config for MPI, but if your MPI implementation does not -provide them, it will search for the standard wrapper executables, `mpic`, -`mpicxx`, `mpic++`, `mpifort`, `mpif90`, `mpif77`. If these are not in your -path, they can be specified by setting the standard environment variables -`MPICC`, `MPICXX`, `MPIFC`, `MPIF90`, or `MPIF77`, during configuration. +Meson prefers pkg-config for MPI, but if your MPI implementation does +not provide them, it will search for the standard wrapper executables, +`mpic`, `mpicxx`, `mpic++`, `mpifort`, `mpif90`, `mpif77`. If these +are not in your path, they can be specified by setting the standard +environment variables `MPICC`, `MPICXX`, `MPIFC`, `MPIF90`, or +`MPIF77`, during configuration. ## Qt5 ## -Meson has native Qt5 support. Its usage is best demonstrated with an example. +Meson has native Qt5 support. Its usage is best demonstrated with an +example. ```meson qt5_mod = import('qt5') @@ -88,7 +112,15 @@ q5exe = executable('qt5test', 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. +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. ## Pcap @@ -102,7 +134,9 @@ pcap_dep = dependency('pcap', version : '>=1.0') ## 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: +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(...) @@ -111,4 +145,5 @@ 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. +This declares a dependency that adds the given include directories and +static library to any target you use it in. diff --git a/docs/markdown/Design-rationale.md b/docs/markdown/Design-rationale.md index 611b7f4..269f688 100644 --- a/docs/markdown/Design-rationale.md +++ b/docs/markdown/Design-rationale.md @@ -5,76 +5,174 @@ 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. +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. +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 copy-paste 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. +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 copy-paste +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. +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? +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. +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. +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. +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. +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. +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. +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. +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. +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](https://ninja-build.org/), which is extremely fast. The backend code is abstracted away from the core, so other backends can be added with relatively little effort. +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](https://ninja-build.org/), 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. +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. @@ -83,9 +181,15 @@ 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. +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. +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') @@ -102,9 +206,13 @@ 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. +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. +Here's a slightly more complicated definition. It should still be +understandable. ```meson project('build library', 'c') @@ -114,20 +222,37 @@ 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`. +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. +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. +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. +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. +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 index f597b0c..9336ec3 100644 --- a/docs/markdown/External-commands.md +++ b/docs/markdown/External-commands.md @@ -4,7 +4,8 @@ short-description: Running external commands # 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. +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') @@ -15,6 +16,19 @@ 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`. +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`. +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/Gnome-module.md b/docs/markdown/Gnome-module.md index 0e24bb0..e81875a 100644 --- a/docs/markdown/Gnome-module.md +++ b/docs/markdown/Gnome-module.md @@ -1,68 +1,121 @@ # GNOME module -This module provides helper tools for build operations needed when building Gnome/GLib programs. +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. +**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. +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. +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. + +* `c_name`: passed to the resource compiler as an argument after + `--c-name` -* `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` * `dependencies`: extra targets to depend upon for building -* `export`: (*Added 0.37.0*) if true, export the symbols of the generated sources -* `gresource_bundle`: (*Added 0.37.0*) if true, output a `.gresource` file instead of source -* `install_header`: (*Added 0.37.0*) if true, install the header file + +* `export`: (*Added 0.37.0*) if true, export the symbols of the + generated sources + +* `extra_args`: extra command line arguments to pass to the resource + +* `gresource_bundle`: (*Added 0.37.0*) if true, output a `.gresource` + file instead of source + * `install`: (*Added 0.37.0*) if true, install the gresource file -* `install_dir`: (*Added 0.37.0*) location to install the header or bundle depending on previous options -* `extra_args`: extra command line arguments to pass to the resource compiler -Returns an array containing: `[c_source, header_file]` or `[gresource_bundle]` +* `install_dir`: (*Added 0.37.0*) location to install the header or + bundle depending on previous options + +* `install_header`: (*Added 0.37.0*) if true, install the header file + +* `source_dir`: a list of subdirectories where the resource compiler + should look up the files, relative to the location of the XML file + + compiler + +Returns an array containing: `[c_source, header_file]` or +`[gresource_bundle]` ### 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. +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. + +* `dependencies`: deps to use during introspection scanning + +* `extra_args`: command line arguments to pass to gir compiler + +* `export_packages`: extra packages the gir file exports * `sources`: the list of sources to be scanned for gir data + * `nsversion`: namespace version -* `namespace`: the namespace for this gir object which determines output files -* `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 + +* `namespace`: the namespace for this gir object which determines + output files + +* `identifier_prefix`: the identifier prefix for the gir object, + e.g. `Gtk` + * `includes`: list of gir names to be included, can also be a GirTarget -* `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]` +* `install_dir_gir`: (*Added 0.35.0*) which directory to install the + gir file into + +* `install_dir_typelib`: (*Added 0.35.0*) which directory to install + the typelib file into + +* `link_with`: list of libraries to link with + +* `symbol_prefix`: the symbol prefix for the gir object, e.g. `gtk` + +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. +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 +* `extra_args`: (*Added 0.42.0*) additional command line arguments to + pass * `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 +* `nostdinc`: if true, don't include the standard marshallers from + glib +* `internal`: if true, mark generated sources as internal to + `glib-genmarshal` (*Requires GLib 2.54*) +* `prefix`: the prefix to use for symbols * `skip_source`: if true, skip source location comments +* `stdinc`: if true, include the standard marshallers from glib +* `sources`: the list of sources to use as inputs * `valist_marshallers`: if true, generate va_list marshallers -* `extra_args`: (*Added 0.42.0*) additional command line arguments to pass - to `glib-genmarshal` (*Requires GLib 2.54*) *Added 0.35.0* @@ -70,23 +123,31 @@ 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. +Generates enum files for GObject using the `glib-mkenums` tool. The +first argument is the base name of the output files. -This method is essentially a wrapper around the `glib-mkenums` tool's command line API. It is the most featureful method for enum creation. +This method is essentially a wrapper around the `glib-mkenums` tool's +command line API. It is the most featureful method for enum creation. -Typically you either provide template files or you specify the various template sections manually as strings. +Typically you either provide template files or you specify the various +template sections manually as strings. -Most libraries and applications will be using the same standard template with only minor tweaks, in which case the `gnome.mkenums_simple()` convenience method can be used instead. +Most libraries and applications will be using the same standard +template with only minor tweaks, in which case the +`gnome.mkenums_simple()` convenience method can be used instead. -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`. +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 +* `comments`: comment passed to the command * `h_template`: template to use for generating the header +* `identifier_prefix`: prefix to use for the identifiers * `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 +* `sources`: the list of sources to make enums with * `symbol_prefix`: prefix to use for the symbols * `eprod`: enum text * `fhead`: file header @@ -101,24 +162,31 @@ Returns an array of two elements which are: `[c_source, header_file]` ### gnome.mkenums_simple() -Generates enum `.c` and `.h` files for GObject using the `glib-mkenums` tool -with the standard template used by most GObject-based C libraries. 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_simple`. - -* `sources`: the list of sources to make enums with +Generates enum `.c` and `.h` files for GObject using the +`glib-mkenums` tool with the standard template used by most +GObject-based C libraries. 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_simple`. + +* `body_prefix`: additional prefix at the top of the body file, + e.g. for extra includes +* `decorator`: optional decorator for the function declarations, + e.g. `GTK_AVAILABLE` or `GST_EXPORT` +* `function_prefix`: additional prefix for function names, e.g. in + case you want to add a leading underscore to functions used only + internally +* `header_prefix`: additional prefix at the top of the header file, + e.g. for extra includes (which may be needed if you specify a + decorator for the function declarations) * `install_header`: if true, install the generated header * `install_dir`: directory to install the header * `identifier_prefix`: prefix to use for the identifiers +* `sources`: the list of sources to make enums with * `symbol_prefix`: prefix to use for the symbols -* `header_prefix`: additional prefix at the top of the header file, e.g. for extra includes (which may be needed if you specify a decorator for the function declarations) -* `decorator`: optional decorator for the function declarations, e.g. `GTK_AVAILABLE` or `GST_EXPORT` -* `function_prefix`: additional prefix for function names, e.g. in case you want to add a leading underscore to functions used only internally -* `body_prefix`: additional prefix at the top of the body file, e.g. for extra includes Example: @@ -144,68 +212,87 @@ 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. +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. +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. +Returns an opaque object containing the source files. Add it to a top +level target's source list. ### gnome.generate_vapi() -Creates a VAPI file from gir. The first argument is the name of the library. +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 * `install`: if true, install the VAPI file * `install_dir`: location to install the VAPI file (defaults to datadir/vala/vapi) +* `metadata_dirs`: extra directories to include for metadata files +* `packages`: VAPI packages that are depended upon +* `sources`: the gir source to generate the VAPI from +* `vapi_dirs`: extra directories to include for VAPI files -Returns a custom dependency that can be included when building other VAPI or Vala binaries. +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. +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`. +This also creates two targets for translations +`help-$project-update-po` and `help-$project-pot`. -* `sources`: list of pages +* `languages`: list of languages for translations * `media`: list of media such as images +* `sources`: list of pages * `symlink_media`: if media should be symlinked not copied (defaults to `true` since 0.42.0) -* `languages`: list of languages for translations -Note that very old versions of yelp may not support symlinked media; At least 3.10 should work. +Note that very old versions of yelp may not support symlinked media; +At least 3.10 should work. *Added 0.36.0* ### gnome.gtkdoc() -Compiles and installs gtkdoc documentation into `prefix/share/gtk-doc/html`. Takes one positional argument: The name of the module. +Compiles and installs gtkdoc documentation into +`prefix/share/gtk-doc/html`. Takes one positional argument: The name +of the module. -* `main_xml`: specifies the main XML file -* `main_sgml`: equal to `main_xml` -* `src_dir`: include_directories to include +* `content_files`: a list of content files * `dependencies`: a list of dependencies -* `install`: if true, installs the generated docs -* `install_dir`: the directory to install the generated docs relative to the gtk-doc html dir or an absolute path (default: module name) -* `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` +* `gobject_typesfile`: a list of type files +* `ignore_headers`: a list of header files to ignore * `html_assets`: a list of assets for the HTML pages -* `content_files`: a list of content files +* `html_args` a list of arguments to pass to `gtkdoc-mkhtml` +* `install`: if true, installs the generated docs +* `install_dir`: the directory to install the generated docs relative + to the gtk-doc html dir or an absolute path (default: module name) +* `main_xml`: specifies the main XML file +* `main_sgml`: equal to `main_xml` * `mkdb_args`: a list of arguments to pass to `gtkdoc-mkdb` -* `ignore_headers`: a list of header files to ignore +* `scan_args`: a list of arguments to pass to `gtkdoc-scan` +* `scanobjs_args`: a list of arguments to pass to `gtkdoc-scangobj` +* `src_dir`: include_directories to include -This creates a `$module-doc` target that can be ran to build docs and normally these are only built on install. +This creates a `$module-doc` target that can be ran to build docs and +normally these are only built on install. ### 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. +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/Manual.md b/docs/markdown/Manual.md index 0c126c0..988efa1 100644 --- a/docs/markdown/Manual.md +++ b/docs/markdown/Manual.md @@ -4,4 +4,6 @@ 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. +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/Overview.md b/docs/markdown/Overview.md index c9acda5..7bee937 100644 --- a/docs/markdown/Overview.md +++ b/docs/markdown/Overview.md @@ -4,19 +4,55 @@ 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 should 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. +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 should 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 needless 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. +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 needless 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/Pkgconfig-module.md b/docs/markdown/Pkgconfig-module.md index 2424421..8814d19 100644 --- a/docs/markdown/Pkgconfig-module.md +++ b/docs/markdown/Pkgconfig-module.md @@ -1,24 +1,42 @@ # Pkgconfig module -This module is a simple generator for [pkg-config](https://pkg-config.freedesktop.org/) files. +This module is a simple generator for +[pkg-config](https://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. +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. +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` +- `extra_cflags` a list of extra compiler flags to be added to the + `Cflags` field after the header search path +- `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` +- `install_dir` the directory to install to, defaults to the value of + option `libdir` followed by `/pkgconfig` +- `libraries` a list of built libraries (usually results of + shared_library) that the user needs to link against +- `libraries_private` list of strings to put in the + `Libraries.private` field +- `name` the name of this library +- `subdirs` which subdirs of `include` should be added to the header + search path, for example if you install headers into + `${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` -- `extra_cflags` a list of extra compiler flags to be added to the `Cflags` field after the header search path -- `variables` a list of strings with custom variables to add to the generated file. The strings must be in the form `name=value` and may reference other pkgconfig variables, e.g. `datadir=${prefix}/share`. The names `prefix`, `libdir` and `installdir` are reserved and may not be used. +- `requires_private` list of strings to put in the `Requires.private` + field +- `variables` a list of strings with custom variables to add to the + generated file. The strings must be in the form `name=value` and may + reference other pkgconfig variables, + e.g. `datadir=${prefix}/share`. The names `prefix`, `libdir` and + `installdir` are reserved and may not be used. +- `version` a string describing the version of this library diff --git a/docs/markdown/Porting-from-autotools.md b/docs/markdown/Porting-from-autotools.md index 91ed5d2..5786e0e 100644 --- a/docs/markdown/Porting-from-autotools.md +++ b/docs/markdown/Porting-from-autotools.md @@ -578,7 +578,7 @@ introspection_sources = [ 'as-tag.c', 'as-tag.h', 'as-utils.c', - 'as-utils.h'] + 'as-utils.h', 'as-version.h'] gnome.generate_gir(asglib, diff --git a/docs/markdown/Precompiled-headers.md b/docs/markdown/Precompiled-headers.md index feac7f0..22fd762 100644 --- a/docs/markdown/Precompiled-headers.md +++ b/docs/markdown/Precompiled-headers.md @@ -4,11 +4,22 @@ short-description: Using precompiled headers to reduce compilation time # 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. +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> @@ -16,7 +27,13 @@ A precompiled header file is relatively simple. It is a header file that contain #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. +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 -- @@ -33,15 +50,23 @@ 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. +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 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. +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, @@ -51,7 +76,11 @@ executable('multilang', sources : srclist, Using precompiled headers with MSVC -- -MSVC is a bit trickier, because in addition to the header file, it also requires a corresponding 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: +MSVC is a bit trickier, because in addition to the header file, it +also requires a corresponding 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) @@ -68,6 +97,9 @@ 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. +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. +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 index 2a33ba8..fa1d78e 100644 --- a/docs/markdown/Python-3-module.md +++ b/docs/markdown/Python-3-module.md @@ -1,16 +1,22 @@ # Python 3 module -This module provides support for dealing with Python 3. It has the following methods. +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. +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). +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* @@ -22,6 +28,7 @@ Returns a string with the Python language version such as `3.5`. ## sysconfig_path -Returns the Python sysconfig path without prefix, such as `lib/python3.6/site-packages`. +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 index 77e271d..4be1be5 100644 --- a/docs/markdown/Qt4-module.md +++ b/docs/markdown/Qt4-module.md @@ -1,3 +1,4 @@ # 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). +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 index 64d2920..7082309 100644 --- a/docs/markdown/Qt5-module.md +++ b/docs/markdown/Qt5-module.md @@ -1,10 +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. +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: +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') @@ -15,4 +20,6 @@ executable('myprog', 'main.cpp', 'myclass.cpp', moc_files, ``` -The 'modules' argument is used to include Qt modules in the project. See the Qt documentation for the [list of modules](http://doc.qt.io/qt-5/qtmodules.html). +The 'modules' argument is used to include Qt modules in the project. +See the Qt documentation for the [list of +modules](http://doc.qt.io/qt-5/qtmodules.html). diff --git a/docs/markdown/Quick-guide.md b/docs/markdown/Quick-guide.md index 32e2b7d..938c3ed 100644 --- a/docs/markdown/Quick-guide.md +++ b/docs/markdown/Quick-guide.md @@ -5,7 +5,9 @@ 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`. +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 -- @@ -15,7 +17,8 @@ Meson has two main dependencies. * [Python 3](https://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. +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: @@ -29,14 +32,18 @@ The best way to get Meson is to `pip install` it for your user $ 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. +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. +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. +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 @@ -45,16 +52,33 @@ $ 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. +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. +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 @@ -64,8 +88,14 @@ $ ninja -C builddir test $ DESTDIR=/path/to/staging/root ninja -C builddir 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. +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`. +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. +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 index 3939937..cab6d96 100644 --- a/docs/markdown/RPM-module.md +++ b/docs/markdown/RPM-module.md @@ -1,10 +1,16 @@ # 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 top level `meson.build` file) add these two lines. +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 top level `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. +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 index 84b3e80..91f7edd 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -2,7 +2,9 @@ ## 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). +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() @@ -11,13 +13,24 @@ The following functions are available in build files. Click on each to see the d 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. +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. +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:** 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', ...` +**Note:** You must pass always arguments individually `arg1, arg2, + ...` rather than as a string `'arg1 arg2', ...` ### add_global_link_arguments() @@ -33,7 +46,9 @@ Like `add_global_arguments` but the arguments are passed to the linker. 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: +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') @@ -42,7 +57,10 @@ if compiling_for_osx 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. +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() @@ -50,7 +68,9 @@ Takes one keyword argument, `required`. It defaults to `true`, which means that 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. +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() @@ -66,16 +86,20 @@ Like `add_project_arguments` but the arguments are passed to the linker. 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: +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: +- `env` an [environment object](#environment-object) to use a custom environment - `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. +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() @@ -83,11 +107,15 @@ Note that all these options are also available while running the `mesontest` scr void benchmark(name, executable, ...) ``` -Creates a benchmark item that will be run when the benchmark target is run. The behavior of this function is identical to `test` with the exception that there is no `is_parallel` keyword, because benchmarks are never run in parallel. +Creates a benchmark item that will be run when the benchmark target is +run. The behavior 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: +Creates a build target whose type can be set dynamically with the +`target_type` keyword argument. This declaration: ```meson executable(<arguments and keyword arguments>) @@ -99,7 +127,10 @@ is equivalent to this: 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. +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() @@ -107,7 +138,9 @@ The object returned by `build_target` and all convenience wrappers for `build_ta 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`. +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() @@ -115,20 +148,36 @@ Creates an empty configuration object. You should add your configuration with [i generated_file = configure_file(...) ``` -This function can run in two modes depending on the keyword arguments passed to it. +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 [`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. +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 (since v0.41.0, may contain `@PLAINNAME@` or `@BASENAME@` substitutions). 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 -- `capture` when this argument is set to true, Meson captures `stdout` of the `command` and writes it to the target file specified as `output`. Available since v0.41.0. -- `install_dir` the subdirectory to install the generated file to (e.g. `share/myproject`), if omitted the file is not installed. +- `capture` when this argument is set to true, Meson captures `stdout` + of the `command` and writes it to the target file specified as + `output`. Available since v0.41.0. +- `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 +- `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. +- `install_dir` the subdirectory to install the generated file to + (e.g. `share/myproject`), if omitted the file is not installed. +- `output` the output file name (since v0.41.0, may contain + `@PLAINNAME@` or `@BASENAME@` substitutions). In configuration mode, + the permissions of the input file (if it is specified) are copied to + the output file. ### custom_target() @@ -136,30 +185,63 @@ These are all the supported keyword arguments: customtarget 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. - +Create a custom top level build target. The only positional argument +is the name of this target and the keyword arguments are the +following. + +- `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 +- `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. +- `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) +- `depend_files` files ([`string`](#string-object), + [`files()`](#files), or [`configure_file()`](#configure_file)) that + this target depends on but are not listed in the `command` keyword + argument. Useful for adding regen dependencies. +- `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. +- `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 - `input` list of source files. As of 0.41.0 the list will be flattened. -- `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` keyword argument. 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` keyword argument accept the following special string substitutions: +- `output` list of output files -- `@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 behavior is the same as `@INPUT@`. +The list of strings passed to the `command` keyword argument 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 behavior 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` -The returned object also has methods that are documented in the [object methods section](#custom-target-object) below. +The returned object also has methods that are documented in the +[object methods section](#custom-target-object) below. ### declare_dependency() @@ -167,14 +249,21 @@ The returned object also has methods that are documented in the [object methods 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. +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 + - `dependencies`, other dependencies needed to use this dependency + - `include_directories`, the directories to add to header search path - `link_args`, link arguments to use + - `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) - `version`, the version of this dependency, such as `1.2.3` ### dependency() @@ -183,19 +272,47 @@ This function returns a [dependency object](#dependency-object) that behaves lik dependency_object dependency(*dependency_name*, ...) ``` -Finds an external dependency (usually a library installed on your system) with the given name with `pkg-config` if possible and with [library-specific fallback detection logic](Dependencies.md) otherwise. This function 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 keyword argument, 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) -- `language` *(added 0.42.0)* defines what language-specific dependency to find if it's available for multiple languages. - -The returned object also has methods that are documented in the [object methods section](#dependency-object) below. +Finds an external dependency (usually a library installed on your +system) with the given name with `pkg-config` if possible and with +[library-specific fallback detection logic](Dependencies.md) +otherwise. This function supports the following keyword arguments: + +- `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) +- `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). +- `language` *(added 0.42.0)* defines what language-specific + dependency to find if it's available for multiple languages. +- `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) +- `modules` specifies submodules to use for dependencies such as Qt5 + or Boost. +- `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. +- `required`, when set to false, Meson will proceed with the build + even if the dependency is not found +- `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) +- `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 + keyword argument, such as: `['>=3.14.0', '<=4.1.0']`. + +The returned object also has methods that are documented in the +[object methods section](#dependency-object) below. ### error() @@ -219,47 +336,110 @@ Returns an empty [environment variable object](#environment-object). buildtarget 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: +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 behavior 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). +- 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 behavior 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, If passed a list this list will be flattened as of 0.41.0. -- `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. As of 0.41.0 if passed a list that list will be flattened. - `<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` strings, files, or custom targets 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) +- `<languagename>_args` compiler flags to use for the given language; + eg: `cpp_args` for C++ +- `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 +- `build_rpath` a string to add to target's rpath definition in the + build dir, but which will be removed on install +- `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) +- `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) +- `gui_app` when set to true flags this target as a GUI application on + platforms where this makes a difference (e.g. Windows) +- `link_args` flags to use during linking. You can use UNIX-style + flags here for all platforms. +- `link_depends` strings, files, or custom targets the link step + depends on such as a symbol visibility map. The purpose is to + automaticallytrigger a re-link (but not a re-compile) of the target + when this file changes. +- `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. As of 0.41.0 if passed a list that list will be flattened. +- `link_with`, one or more shared or static libraries (built by this + project) that this target should be linked with, If passed a list + this list will be flattened as of 0.41.0. +- `implib` when set to true, an import library is generated for the + executable (the name of the import library is based on *exe_name*). + Alternatively, when set to a string, that gives the base name for + the import library. The import library is used when the returned + build target object appears in `link_with:` elsewhere. Only has any + effect on platforms where that is meaningful (e.g. Windows). Since + 0.42.0 +- `implicit_include_directories` is a boolean telling whether Meson + adds the current source and build directories to the include path, + defaults to `true`, since 0.42.0 +- `include_directories` one or more objects created with the + `include_directories` function - `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) -- `build_rpath` a string to add to target's rpath definition in the build dir, but which will be removed on install -- `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 -- `implib` when set to true, an import library is generated for the executable (the name of the import library is based on *exe_name*). Alternatively, when set to a string, that gives the base name for the import library. The import library is used when the returned build target object appears in `link_with:` elsewhere. Only has any effect on platforms where that is meaningful (e.g. Windows). Since 0.42.0 -- `implicit_include_directories` is a boolean telling whether Meson adds the current source and build directories to the include path, defaults to `true`, since 0.42.0 - -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:` keyword argument. - -The returned object also has methods that are documented in the [object methods section](#build-target-object) below. +- `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'`. +- `install_rpath` a string to set the target's rpath to after install + (but *not* before that) +- `objects` list of prebuilt object files (usually for third party + 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. +- `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:` keyword +argument. + +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)`. +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() @@ -267,27 +447,46 @@ This function is deprecated and in the 0.31.0 release it was moved to [the compi 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. +`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. -`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. +`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. Keyword arguments are the following: -- `required` By default, `required` is set to `true` and Meson will abort if no program can be found. If `required` is set to `false`, Meson continue even if none of the programs can be found. You can then use the `.found()` method on the returned object to check whether it was found or not. +- `required` By default, `required` is set to `true` and Meson will + abort if no program can be found. If `required` is set to `false`, + Meson continue even if none of the programs can be found. You can + then use the `.found()` method on the returned object to check + whether it was found or not. -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. +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. -If you need to check for a program in a non-standard location, you can just pass an absolute path to `find_program`, e.g. -``` -setcap = find_program('setcap', '/usr/sbin/setcap', '/sbin/setcap', required : false) -``` +If you need to check for a program in a non-standard location, you can +just pass an absolute path to `find_program`, e.g. ``` setcap = +find_program('setcap', '/usr/sbin/setcap', '/sbin/setcap', required : +false) ``` + +It is also possible to pass an array to `find_program` in case you +need to construct the set of paths to search on the fly: -It is also possible to pass an array to `find_program` in case you need to construct the set of paths to search on the fly: ``` setcap = find_program(['setcap', '/usr/sbin/setcap', '/sbin/setcap'], required : false) ``` -The returned object also has methods that are documented in the [object methods section](#external-program-object) below. +The returned object also has methods that are documented in the +[object methods section](#external-program-object) below. ### files() @@ -295,7 +494,14 @@ The returned object also has methods that are documented in the [object methods 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: +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') @@ -312,27 +518,42 @@ Meson will then do the right thing. ### generator() ``` meson - generator_object gen(*executable*, ...) + generator_object generator(*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 keyword arguments accept the following special substitutions: +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 +- `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 +- `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 + +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 keyword arguments 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` keyword argument *must* be constructed using one or both of these two substitutions. +Each string passed to the `outputs` keyword argument *must* be +constructed using one or both of these two substitutions. -In addition to the above substitutions, the `arguments` keyword argument also accepts the following: +In addition to the above substitutions, the `arguments` keyword +argument also accepts the following: - `@OUTPUT@`: the full path to the output file - `@INPUT@`: the full path to the input file @@ -340,9 +561,16 @@ In addition to the above substitutions, the `arguments` keyword argument also ac - `@CURRENT_SOURCE_DIR@`: this is the directory where the currently processed meson.build is located in - `@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@`. +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. +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() @@ -358,7 +586,12 @@ Obtains the value of the [project build option](Build-options.md) specified in t 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. +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() @@ -366,7 +599,9 @@ This function can be used to dynamically obtain a variable. `res = get_variable( 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. +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') @@ -379,13 +614,22 @@ Imports the given extension module. Returns an opaque object that can be used to 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. +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). +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. +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`: +For example, with the following source tree layout in +`/home/user/project.git`: `meson.build`: ```meson @@ -425,10 +669,16 @@ This function has one keyword argument `is_system` which, if set, flags the spec void install_data(list_of_files, ...) ``` -Installs files from the source tree that are listed as positional arguments. The following keyword arguments are supported: +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_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 @@ -444,9 +694,16 @@ Installs files from the source tree that are listed as positional arguments. The 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`. +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`: +For example, this will install `common.h` and `kola.h` into +`/{prefix}/include`: ```meson install_headers('common.h', 'proj/kola.h') @@ -470,7 +727,11 @@ install_headers('common.h', 'proj/kola.h', install_dir : 'cust', subdir : 'mypro 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. +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() @@ -478,15 +739,21 @@ Installs the specified man files from the source tree into system's man director void install_subdir(subdir_name, install_dir : ..., exclude_files : ..., exclude_directories : ...) ``` -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 behavior is undefined. +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 behavior is +undefined. The following keyword arguments are supported: -- `install_dir`: the location to place the installed subdirectory. - `exclude_files`: a list of file names that should not be installed. Names are interpreted as paths relative to the `subdir_name` location. - `exclude_directories`: a list of directory names that should not be installed. Names are interpreted as paths relative to the `subdir_name` location. +- `install_dir`: the location to place the installed subdirectory. ### is_variable() @@ -502,7 +769,10 @@ Returns true if a variable of the given name exists and false otherwise. jar_object jar(name, list_of_sources, ...) ``` -Build a jar from the specified Java source files. Keyword arguments are the same as [`executable`](#executable)'s, with the addition of `main_class` which specifies the main class to execute when running the jar with `java -jar file.jar`. +Build a jar from the specified Java source files. Keyword arguments +are the same as [`executable`](#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() @@ -510,7 +780,10 @@ Build a jar from the specified Java source files. Keyword arguments are the same 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`. +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* @@ -520,12 +793,22 @@ Joins the given strings into a file system path segment. For example `join_paths 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. +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 additions: -- `name_prefix` the string that will be used as the suffix for the target by overriding the default (only used for libraries). By default this is `lib` on all platforms and compilers except with MSVC where it is omitted. -- `rust_crate_type` specifies the crate type for Rust libraries. Defaults to `dylib` for shared libraries and `rlib` for static libraries. +- `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. +- `rust_crate_type` specifies the crate type for Rust + libraries. Defaults to `dylib` for shared libraries and `rlib` for + static libraries. `static_library` and `shared_library` also accept these keyword arguments. @@ -543,21 +826,55 @@ This function prints its argument to stdout. 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 first argument to this function must be a string defining the name +of this project. It is followed by programming languages that the +project uses. Supported values for languages are `c`, `cpp` (for +`C++`), `objc`, `objcpp`, `fortran`, `java`, `cs` (for `C#`) and +`vala`. In versions before `0.40.0` you must have at least one +language listed. -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_. +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`. - - - `license` takes a string or array of strings describing the license(s) the code is under. 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. + - `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. + + + - `license` takes a string or array of strings describing the + license(s) the code is under. 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. + + - `meson_version` takes a string describing which Meson version the + project requires. Usually something like `>0.28.0`. + + - `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. + + - `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()`. ### run_command() @@ -565,7 +882,13 @@ Project supports the following keyword arguments. runresult run_command(command, list_of_args) ``` -Runs the command specified in positional arguments. Returns [an opaque object](#run-result-object) containing the result of the invocation. The script is run from an *unspecified* directory, and 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. +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 @@ -573,12 +896,24 @@ Runs the command specified in positional arguments. Returns [an opaque object](# 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) +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() @@ -586,7 +921,8 @@ The script is run from an *unspecified* directory, and Meson will set three envi void set_variable(variable_name, value) ``` -Assigns a value to the given variable name. Calling `set_variable('foo', bar)` is equivalent to `foo = bar`. +Assigns a value to the given variable name. Calling +`set_variable('foo', bar)` is equivalent to `foo = bar`. ### shared_library() @@ -594,11 +930,26 @@ Assigns a value to the given variable name. Calling `set_variable('foo', bar)` i 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, a File object, or Custom Target for a Microsoft module definition file for controlling symbol exports, etc., on platforms where that is possible (e.g. Windows). +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. + +- `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`. +- `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). +- `vs_module_defs` a string, a File object, or Custom Target for a + Microsoft module definition file for controlling symbol exports, + etc., on platforms where that is possible (e.g. Windows). ### shared_module() @@ -606,9 +957,12 @@ Builds a shared library with the given sources. Positional and keyword arguments 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). +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. +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* @@ -618,9 +972,14 @@ This is useful for building modules that will be `dlopen()`ed and hence may cont 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: +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. + - `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() @@ -628,9 +987,15 @@ Builds a static library with the given sources. Positional and keyword arguments 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()`. +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. +Note that this means that each `meson.build` file in a source tree can +and must only be executed once. ### subproject() @@ -638,12 +1003,28 @@ Note that this means that each `meson.build` file in a source tree can and must 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) - -Note that you can use the returned [subproject object](#subproject-object) to access any variable in the subproject. However, if you want to use a dependency object from inside a subproject, an easier way is to use the `fallback:` keyword argument to [`dependency()`](#dependency). +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: + + - `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) + - `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` + +Note that you can use the returned [subproject +object](#subproject-object) to access any variable in the +subproject. However, if you want to use a dependency object from +inside a subproject, an easier way is to use the `fallback:` keyword +argument to [`dependency()`](#dependency). ### test() @@ -651,16 +1032,33 @@ Note that you can use the returned [subproject object](#subproject-object) to ac void test(name, executable, ...) ``` -Defines a 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. +Defines a 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`. +- `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() @@ -668,15 +1066,27 @@ Defined tests can be run in a backend-agnostic way by calling `mesontest` inside customtarget 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`. +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`. +- `command` string list with the command to execute, see + [`custom_target`](#custom_target) for details on how this command + must be specified +- `fallback` version number to use when no revision control + information is present, such as when building from a release tarball + (defaults to `meson.project_version()`) - `input` file to modify (e.g. `version.c.in`) (required) - `output` file to write the results to (e.g. `version.c`) (required) -- `fallback` version number to use when no revision control information is present, such as when building from a release tarball (defaults to `meson.project_version()`) -- `command` string list with the command to execute, see [`custom_target`](#custom_target) for details on how this command must be specified -- `replace_string` string in the input file to substitute with the commit information (defaults to `@VCS_TAG@`) +- `replace_string` string in the input file to substitute with the + commit information (defaults to `@VCS_TAG@`) -Meson will read the contents of `input`, substitute the `replace_string` with the detected revision number, and write the result to `output`. This method returns an opaque [`custom_target`](#custom_target) object that can be used as source. If you desire more specific behavior than what this command provides, you should use `custom_target`. +Meson will read the contents of `input`, substitute the +`replace_string` with the detected revision number, and write the +result to `output`. This method returns an opaque +[`custom_target`](#custom_target) object that can be used as +source. If you desire more specific behavior than what this command +provides, you should use `custom_target`. ## Built-in objects @@ -684,35 +1094,92 @@ 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`, `vs2017`, or `xcode`. - -- `is_cross_build()` returns `true` if the current build is a [cross build](Cross-compilation.md) and `false` otherwise. - -- `is_unity()` returns `true` when doing a [unity build](Unity-builds.md) (multiple sources are combined before compilation to reduce build time) 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`, `MESON_INSTALL_DESTDIR_PREFIX`, and `MESONINTROSPECT` set. All additional arguments are passed as parameters. - - To determine the installation location, the script should use the `DESTDIR`, `MESON_INSTALL_PREFIX`, `MESON_INSTALL_DESTDIR_PREFIX` variables. `DESTDIR` will be set only if it is inherited from the outside environment. `MESON_INSTALL_PREFIX` is always set and has the value of the `prefix` option passed to Meson. `MESON_INSTALL_DESTDIR_PREFIX` is always set and contains `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. - - `MESONINTROSPECT` contains the path to the `mesonintrospect` executable that corresponds to the `meson` executable that was used to configure the build. (This might be a different path then the first `mesonintrospect` executable found in `PATH`.) It can be used to query build configuration. - -- `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 with the absolute path 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. +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. + +- `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`, + `MESON_INSTALL_DESTDIR_PREFIX`, and `MESONINTROSPECT` set. All + additional arguments are passed as parameters. + +- `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. + +- `backend()` *(added 0.37.0)* returns a string representing the + current backend: `ninja`, `vs2010`, `vs2015`, `vs2017`, or `xcode`. + +- `build_root()` returns a string with the absolute path to the build + root directory. + +- `current_build_dir()` returns a string with the absolute path to the + current build directory. + +- `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()`. + +- `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. + +- `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. + +- `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). + +- `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. + +- `is_cross_build()` returns `true` if the current build is a [cross + build](Cross-compilation.md) and `false` otherwise. + +- `is_subproject()` returns `true` if the current project is being + built as a subproject of some other project and `false` otherwise. + +- `is_unity()` returns `true` when doing a [unity + build](Unity-builds.md) (multiple sources are combined before + compilation to reduce build time) and `false` otherwise. + + To determine the installation location, the script should use the + `DESTDIR`, `MESON_INSTALL_PREFIX`, `MESON_INSTALL_DESTDIR_PREFIX` + variables. `DESTDIR` will be set only if it is inherited from the + outside environment. `MESON_INSTALL_PREFIX` is always set and has + the value of the `prefix` option passed to + Meson. `MESON_INSTALL_DESTDIR_PREFIX` is always set and contains + `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. + + `MESONINTROSPECT` contains the path to the `mesonintrospect` + executable that corresponds to the `meson` executable that was used + to configure the build. (This might be a different path then the + first `mesonintrospect` executable found in `PATH`.) It can be used + to query build configuration. + +- `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()`. - `project_version()` returns the version string specified in `project` function call. @@ -720,96 +1187,253 @@ The `meson` object allows you to introspect various properties of the system. Th - `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. +### `build_machine` object -- `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. +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: -### `build_machine` object +- `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. -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: +- `system()` returns the operating system name, such as `windows` (all + versions of Windows), `linux` (all Linux distros), `darwin` (all + versions of OS X/macOS), `cygwin` (for Cygwin), and `bsd` (all *BSD + OSes). -- `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/macOS), `cygwin` (for Cygwin), and `bsd` (all *BSD OSes). -- `endian()` returns `big` on big-endian systems and `little` on little-endian systems. +- `endian()` returns `big` on big-endian systems and `little` on + little-endian systems. -Currently, these values are populated using [`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, or if your OS is not in the above list, please file [a bug report](https://github.com/mesonbuild/meson/issues/new) with details and we'll look into it. +Currently, these values are populated using +[`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, or if your OS is not in the above list, please file [a +bug report](https://github.com/mesonbuild/meson/issues/new) with +details and we'll look into it. ### `host_machine` object -Provides information about the host machine — the machine on which the compiled binary will run. See [Cross-compilation](Cross-compilation.md). +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) +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. +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). +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). +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. +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. ### `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: +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: + +- `alignment(typename)` returns the alignment of the type specified in + the positional argument, you can specify external dependencies to + use with `dependencies` keyword argument. + +- `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. + +- `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. + +- `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. + +- `get_define(definename)` returns the given preprocessor symbol's + value as a string or empty string if it is not defined. + +- `get_id()` returns a string identifying the compiler. For example, + `gcc`, `msvc`, [and more](Compiler-properties.md#compiler-id). + +- `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. + +- `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_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_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_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_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_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. + +- `has_type(typename)` returns true if the specified token is a type, + you can specify external dependencies to use with `dependencies` + keyword argument. + +- `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. + +- `symbols_have_underscore_prefix()` returns `true` if the C symbol + mangling is one underscore (`_`) prefixed to the symbol, available + since 0.37.0. + +- `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. -- `get_id()` returns a string identifying the compiler. For example, `gcc`, `msvc`, [and more](Compiler-properties.md#compiler-id). - `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 keyword argument is not passed to those methods, no message will be printed about the check. +- `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`. + +- `include_directories` specifies extra directories for header + searches. *(added 0.38.0)* + +- `name` the name to use for printing a message about the compiler + check. Supported by the methods `compiles()`, `links()`, and + `run()`. If this keyword argument 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`. + +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> -- `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`. +### `string` object -- `include_directories` specifies extra directories for header searches. *(added 0.38.0)* +All [strings](Syntax.md#strings) have the following methods. Strings +are immutable, all operations return their results as a new string. -- `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`. +- `contains(string)` returns true if string contains the string + specified as the argument -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. +- `endswith(string)` returns true if string ends with the string + specified as the argument -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> +- `format()` formats text, see the [Syntax + manual](Syntax.md#string-formatting) for usage info -### `string` object +- `join(list_of_strings)` is the opposite of split, for example + `'.'.join(['a', 'b', 'c']` yields `'a.b.c'` + +- `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 + +- `strip()` removes whitespace at the beginning and end of the string -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` +- `to_int` returns the string converted to an integer (error if string + is not a number) + +- `to_lower()` creates a lower case version of the string + +- `to_upper()` creates an upper case version of the string + +- `underscorify()` creates a string where every non-alphabetical + non-number character is replaced with `_` + +- `version_compare(comparison_string)` does semantic version + comparison, if `x = '1.2.3'` then `x.version_compare('>1.0.0')` + returns `true` ### `Number` object @@ -822,18 +1446,30 @@ All [strings](Syntax.md#strings) have the following methods. Strings are immutab 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` +- `to_int()` as above, but returns either `1` or `0` + +- `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. ### `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 +- `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). +- `length()`, the size of the array + +You can also iterate over arrays with the [`foreach` +statement](https://github.com/mesonbuild/meson/wiki/Syntax#foreach-statements). ## Returned objects @@ -841,81 +1477,143 @@ These are objects returned by the [functions listed above](#functions). ### `build target` object -A build target is either an [executable](#executable), [shared](#shared_library), [static library](#static_library) or [shared module](#shared_module). - -- `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. +A build target is either an [executable](#executable), +[shared](#shared_library), [static library](#static_library) or +[shared module](#shared_module). -- `extract_all_objects()` is same as above but returns all object files generated by this target +- `extract_all_objects()` is same as `extract_objects` 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 +- `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. - `full_path()` returns a full path pointing to the result target file +- `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 + + ### `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: +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: + +- `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 - - `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 +- `has(varname)`, returns `true` if the specified variable is set -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. +- `merge_from(other)` takes as argument a different configuration data + object and copies all entries from that object to the current + object, available since 0.42.0 + +- `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 (`"`) + +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. ### `custom target` object -This object is returned by [`custom_target`](#custom_target) and contains a target with the following methods: +This object is returned by [`custom_target`](#custom_target) and +contains a target with the following methods: - `full_path()` returns a full path pointing to the result target file ### `dependency` object -This object is returned by [`dependency()`](#dependency) and contains an external dependency with the following methods: +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. + + - `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 + + - `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: +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) + +- `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. +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. + +- `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. -- `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 +- `prepend(varname, value)` is the same as `append` except that it + writes to the beginning of the variable +- `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\` ### `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. +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). +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. +* `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. +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 @@ -923,9 +1621,12 @@ This object is returned by [`subproject()`](#subproject) and is an opaque object ### `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: +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 +- `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 +- `stderr()` the standard error produced when the command was run +- `stdout()` the standard out produced when the command was run diff --git a/docs/markdown/Reproducible-builds.md b/docs/markdown/Reproducible-builds.md index e28ca7a..1e00fea 100644 --- a/docs/markdown/Reproducible-builds.md +++ b/docs/markdown/Reproducible-builds.md @@ -1,9 +1,20 @@ # Reproducible builds -A reproducible build means the following (as quoted from [the reproducible builds project site](https://reproducible-builds.org/)): +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. +> 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. +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. +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/Tutorial.md b/docs/markdown/Tutorial.md index b8e268e..c555abc 100644 --- a/docs/markdown/Tutorial.md +++ b/docs/markdown/Tutorial.md @@ -4,12 +4,17 @@ 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. +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. +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> @@ -20,20 +25,27 @@ int main(int argc, char **argv) { } ``` -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. +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 initialize the build by going into the source directory and issuing the following commands. +That is all. We are now ready to build our application. First we need +to initialize the build by going into the source directory and issuing +the following commands. ```console $ meson builddir ``` -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 top level source directory. +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 top level source directory. When Meson is run it prints the following output. @@ -66,7 +78,10 @@ This produces the expected output. 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. +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> @@ -82,7 +97,8 @@ int main(int argc, char **argv) { } ``` -Then we edit the Meson file, instructing it to find and use the GTK+ libraries. +Then we edit the Meson file, instructing it to find and use the GTK+ +libraries. ```meson project('tutorial', 'c') @@ -90,13 +106,20 @@ 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. +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. +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 @@ -112,7 +135,8 @@ Once you have set up your build directory the first time, you don't ever need to [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: +Note how Meson noticed that the build definition has changed and reran +itself automatically. The program is now ready to be run: ``` $ ./demo diff --git a/docs/markdown/Users.md b/docs/markdown/Users.md index 6c6a368..46c2654 100644 --- a/docs/markdown/Users.md +++ b/docs/markdown/Users.md @@ -21,7 +21,7 @@ If you have a project that uses Meson that you want to add to this list, let us - [Graphene](https://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+/), the multi-platform toolkit used by GNOME (not the default yet) + - [GTK+](https://git.gnome.org/browse/gtk+/), the multi-platform toolkit used by GNOME - [GtkDApp](https://gitlab.com/csoriano/GtkDApp), an application template for developing Flatpak apps with Gtk+ and D - [HexChat](https://github.com/hexchat/hexchat), a cross-platform IRC client in C - [Json-glib](https://git.gnome.org/browse/json-glib), GLib-based JSON manipulation library @@ -42,3 +42,5 @@ If you have a project that uses Meson that you want to add to this list, let us - [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) + +Note that a more up-to-date list of GNOME projects that use Meson can be found here: https://wiki.gnome.org/Initiatives/GnomeGoals/MesonPorting diff --git a/docs/markdown/Windows-module.md b/docs/markdown/Windows-module.md index b2b5145..1d4b9bf 100644 --- a/docs/markdown/Windows-module.md +++ b/docs/markdown/Windows-module.md @@ -1,12 +1,17 @@ # Windows module -This module provides functionality used to build applications for Windows. +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. +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 +- `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 index cebc779..d7bd150 100644 --- a/docs/markdown/Wrap-best-practices-and-tips.md +++ b/docs/markdown/Wrap-best-practices-and-tips.md @@ -1,14 +1,29 @@ # 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. +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. +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 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: +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 @@ -16,7 +31,9 @@ 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: +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 @@ -24,9 +41,15 @@ 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. +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: +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') @@ -41,9 +64,18 @@ mylib = build_target('foo', 'foo.c', ## 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. +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: +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(...) @@ -61,3 +93,74 @@ executable('dep_using_exe', 'main.c', ``` Meson will ensure that the header file has been built before compiling `main.c`. + +## Avoid exposing compilable source files in declare_dependency + +The main use for the `sources` argument in `declare_dependency` is to +construct the correct dependency graph for the backends, as +demonstrated in the previous section. It is extremely important to +note that it should *not* be used to directly expose compilable +sources (`.c`, `.cpp`, etc.) of dependencies, and should rather only +be used for header/config files. The following example will illustrate +what can go wrong if you accidentally expose compilable source files. + +So you've read about unity builds and how Meson natively supports +them. You decide to expose the sources of dependencies in order to +have unity builds that include their dependencies. For your support +library you do + +```meson +my_support_sources = files(...) + +mysupportlib = shared_library( + ... + sources : my_support_sources, + ...) +mysupportlib_dep = declare_dependency( + ... + link_with : mylibrary, + sources : my_support_sources, + ...) +``` + +And for your main project you do: + +```meson +mylibrary = shared_library( + ... + dependencies : mysupportlib_dep, + ...) +myexe = executable( + ... + link_with : mylibrary, + dependencies : mysupportlib_dep, + ...) +``` + +This is extremely dangerous. When building, `mylibrary` will build and +link the support sources `my_support_sources` into the resulting +shared library. Then, for `myexe`, these same support sources will be +compiled again, will be linked into the resulting executable, in +addition to them being already present in `mylibrary`. This can +quickly run afoul of the [One Definition Rule +(ODR)](https://en.wikipedia.org/wiki/One_Definition_Rule) in C++, as +you have more than one definition of a symbol, yielding undefined +behavior. While C does not have a strict ODR rule, there is no +language in the standard which guarantees such behavior to +work. Violations of the ODR can lead to weird idiosyncratic failures +such as segfaults. In the overwhelming number of cases, exposing +library sources via the `sources` argument in `declare_dependency` is +thus incorrect. If you wish to get full cross-library performance, +consider building `mysupportlib` as a static library instead and +employing LTO. + +There are exceptions to this rule. If there are some natural +constraints on how your library is to be used, you can expose +sources. For instance, the WrapDB module for GoogleTest directly +exposes the sources of GTest and GMock. This is valid, as GTest and +GMock will only ever be used in *terminal* link targets. A terminal +target is the final target in a dependency link chain, for instance +`myexe` in the last example, whereas `mylibrary` is an intermediate +link target. For most libraries this rule is not applicable though, as +you cannot in general control how others consume your library, and as +such should not expose sources. diff --git a/docs/markdown/Wrap-dependency-system-manual.md b/docs/markdown/Wrap-dependency-system-manual.md index fc41b61..a850896 100644 --- a/docs/markdown/Wrap-dependency-system-manual.md +++ b/docs/markdown/Wrap-dependency-system-manual.md @@ -1,16 +1,36 @@ # 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. +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). +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`: +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] @@ -21,9 +41,16 @@ 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. +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. +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] @@ -38,13 +65,23 @@ 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. +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. +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. +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] @@ -53,11 +90,20 @@ 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]`). +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. +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: +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 @@ -71,7 +117,9 @@ To use a subproject simply do this in your top level `meson.build`. 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: +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, @@ -85,13 +133,21 @@ 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. +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. +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. +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) @@ -107,16 +163,27 @@ executable('toplevel_exe', 'prog.c', dependencies : foobar_dep) ``` -Because this is such a common operation, Meson provides a shortcut for this use case. +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. +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. +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. +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 index beda0c2..39acadc 100644 --- a/docs/markdown/Wrap-review-guidelines.md +++ b/docs/markdown/Wrap-review-guidelines.md @@ -1,6 +1,11 @@ # 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. +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 ## diff --git a/docs/markdown/i18n-module.md b/docs/markdown/i18n-module.md index 172f73e..5e6004a 100644 --- a/docs/markdown/i18n-module.md +++ b/docs/markdown/i18n-module.md @@ -4,16 +4,33 @@ 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. +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. +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 +* `args`: list of extra arguments to pass to `xgettext` when + generating the pot file + +* `data_dirs`: (*Added 0.36.0*) list of directories to be set for + `GETTEXTDATADIRS` env var (Requires gettext 0.19.8+), used for local + its files + +* `languages`: list of languages that are to be generated. As of + 0.37.0 this is optional and the + [LINGUAS](https://www.gnu.org/software/gettext/manual/html_node/po_002fLINGUAS.html) + file is read. + +* `preset`: (*Added 0.37.0*) name of a preset list of arguments, + current option is `'glib'`, see + [source](https://github.com/mesonbuild/meson/blob/master/mesonbuild/modules/i18n.py) + for for their value This function also defines targets for maintainers to use: **Note**: These output to the source directory @@ -24,10 +41,13 @@ This function also defines targets for maintainers to use: ### 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: +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: +* `data_dirs`: (*Added 0.41.0*) list of directories for its files (See + also `i18n.gettext()`) * `po_dir`: directory containing translations, relative to current directory -* `data_dirs`: (*Added 0.41.0*) list of directories for its files (See also `i18n.gettext()`) * `type`: type of file, valid options are `'xml'` (default) and `'desktop'` *Added 0.37.0* diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index f967de0..4dbf41c 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -20,10 +20,11 @@ from .. import mlog from .. import compilers import json import subprocess -from ..mesonlib import MesonException, get_meson_script +from ..mesonlib import MesonException from ..mesonlib import get_compiler_for_source, classify_unity_sources from ..compilers import CompilerArgs from collections import OrderedDict +import shlex class CleanTrees: ''' @@ -771,7 +772,8 @@ class Backend: def run_postconf_scripts(self): env = {'MESON_SOURCE_ROOT': self.environment.get_source_dir(), 'MESON_BUILD_ROOT': self.environment.get_build_dir(), - 'MESONINTROSPECT': get_meson_script(self.environment, 'mesonintrospect')} + 'MESONINTROSPECT': ' '.join([shlex.quote(x) for x in self.environment.get_build_command() + ['introspect']]), + } child_env = os.environ.copy() child_env.update(env) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 0587cff..dce3b80 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -25,7 +25,7 @@ from .. import compilers from ..compilers import CompilerArgs from ..linkers import ArLinker from ..mesonlib import File, MesonException, OrderedSet -from ..mesonlib import get_meson_script, get_compiler_for_source +from ..mesonlib import get_compiler_for_source from .backends import CleanTrees, InstallData from ..build import InvalidArguments @@ -520,8 +520,7 @@ int dummy; # All targets are built from the build dir self.environment.get_build_dir(), capture=ofilenames[0] if target.capture else None) - cmd = [sys.executable, self.environment.get_build_command(), - '--internal', 'exe', exe_data] + cmd = self.environment.get_build_command() + ['--internal', 'exe', exe_data] cmd_type = 'meson_exe.py custom' else: cmd_type = 'custom' @@ -537,7 +536,7 @@ int dummy; self.processed_targets[target.name + target.type_suffix()] = True def generate_run_target(self, target, outfile): - cmd = [sys.executable, self.environment.get_build_command(), '--internal', 'commandrunner'] + cmd = self.environment.get_build_command() + ['--internal', 'commandrunner'] deps = self.unwrap_dep_list(target) arg_strings = [] for i in target.args: @@ -555,8 +554,7 @@ int dummy; elem = NinjaBuildElement(self.all_outputs, 'meson-' + target.name, 'CUSTOM_COMMAND', []) cmd += [self.environment.get_source_dir(), self.environment.get_build_dir(), - target.subdir, - get_meson_script(self.environment, 'mesonintrospect')] + target.subdir] + self.environment.get_build_command() texe = target.command try: texe = texe.held_object @@ -594,12 +592,11 @@ int dummy; def generate_coverage_rules(self, outfile): e = NinjaBuildElement(self.all_outputs, 'meson-coverage', 'CUSTOM_COMMAND', 'PHONY') - e.add_item('COMMAND', [sys.executable, - self.environment.get_build_command(), - '--internal', 'coverage', - self.environment.get_source_dir(), - self.environment.get_build_dir(), - self.environment.get_log_dir()]) + e.add_item('COMMAND', self.environment.get_build_command() + + ['--internal', 'coverage', + self.environment.get_source_dir(), + self.environment.get_build_dir(), + self.environment.get_log_dir()]) e.add_item('description', 'Generates coverage reports.') e.write(outfile) # Alias that runs the target defined above @@ -629,7 +626,7 @@ int dummy; added_rule = True htmloutdir = os.path.join(self.environment.get_log_dir(), 'coveragereport') covinfo = os.path.join(self.environment.get_log_dir(), 'coverage.info') - phony_elem = NinjaBuildElement(self.all_outputs, 'coverage-html', 'phony', os.path.join(htmloutdir, 'index.html')) + phony_elem = NinjaBuildElement(self.all_outputs, 'meson-coverage-html', 'phony', os.path.join(htmloutdir, 'index.html')) phony_elem.write(outfile) # Alias that runs the target defined above self.create_target_alias('meson-coverage-html', outfile) @@ -659,12 +656,11 @@ int dummy; d = InstallData(self.environment.get_source_dir(), self.environment.get_build_dir(), self.environment.get_prefix(), - strip_bin, - get_meson_script(self.environment, 'mesonintrospect')) + strip_bin, self.environment.get_build_command() + ['introspect']) elem = NinjaBuildElement(self.all_outputs, 'meson-install', 'CUSTOM_COMMAND', 'PHONY') elem.add_dep('all') elem.add_item('DESC', 'Installing files.') - elem.add_item('COMMAND', [sys.executable, self.environment.get_build_command(), '--internal', 'install', install_data_file]) + elem.add_item('COMMAND', self.environment.get_build_command() + ['--internal', 'install', install_data_file]) elem.add_item('pool', 'console') self.generate_depmf_install(d) self.generate_target_install(d) @@ -844,7 +840,7 @@ int dummy; def generate_tests(self, outfile): self.serialize_tests() - cmd = [sys.executable, '-u', self.environment.get_build_command(), 'test', '--no-rebuild'] + cmd = self.environment.get_build_command(True) + ['test', '--no-rebuild'] if not self.environment.coredata.get_builtin_option('stdsplit'): cmd += ['--no-stdsplit'] if self.environment.coredata.get_builtin_option('errorlogs'): @@ -858,7 +854,7 @@ int dummy; self.create_target_alias('meson-test', outfile) # And then benchmarks. - cmd = [sys.executable, '-u', self.environment.get_build_command(), 'test', '--benchmark', '--logbase', + cmd = self.environment.get_build_command(True) + ['test', '--benchmark', '--logbase', 'benchmarklog', '--num-processes=1', '--no-rebuild'] elem = NinjaBuildElement(self.all_outputs, 'meson-benchmark', 'CUSTOM_COMMAND', ['all', 'PHONY']) elem.add_item('COMMAND', cmd) @@ -896,13 +892,12 @@ int dummy; outfile.write(' depfile = $DEPFILE\n') outfile.write(' restat = 1\n\n') outfile.write('rule REGENERATE_BUILD\n') - c = (ninja_quote(quote_func(sys.executable)), - ninja_quote(quote_func(self.environment.get_build_command())), - '--internal', + c = [ninja_quote(quote_func(x)) for x in self.environment.get_build_command()] + \ + ['--internal', 'regenerate', ninja_quote(quote_func(self.environment.get_source_dir())), - ninja_quote(quote_func(self.environment.get_build_dir()))) - outfile.write(" command = %s %s %s %s %s %s --backend ninja\n" % c) + ninja_quote(quote_func(self.environment.get_build_dir()))] + outfile.write(" command = " + ' '.join(c) + ' --backend ninja\n') outfile.write(' description = Regenerating build files.\n') outfile.write(' generator = 1\n\n') outfile.write('\n') @@ -972,7 +967,7 @@ int dummy; compiler = target.compilers['cs'] rel_srcs = [s.rel_to_builddir(self.build_to_src) for s in src_list] deps = [] - commands = target.extra_args.get('cs', []) + commands = CompilerArgs(compiler, target.extra_args.get('cs', [])) commands += compiler.get_buildtype_args(buildtype) if isinstance(target, build.Executable): commands.append('-target:exe') @@ -992,11 +987,25 @@ int dummy; outputs = [outname_rel, outname_rel + '.mdb'] else: outputs = [outname_rel] + generated_sources = self.get_target_generated_sources(target) + for rel_src in generated_sources.keys(): + dirpart, fnamepart = os.path.split(rel_src) + if rel_src.lower().endswith('.cs'): + rel_srcs.append(rel_src) + deps.append(rel_src) + + for dep in target.get_external_deps(): + commands.extend_direct(dep.get_link_args()) + commands += self.build.get_project_args(compiler, target.subproject) + commands += self.build.get_global_args(compiler) + elem = NinjaBuildElement(self.all_outputs, outputs, 'cs_COMPILER', rel_srcs) elem.add_dep(deps) elem.add_item('ARGS', commands) elem.write(outfile) + self.generate_generator_list_rules(target, outfile) + def generate_single_java_compile(self, src, target, compiler, outfile): args = [] args += compiler.get_buildtype_args(self.get_option_for_target('buildtype', target)) @@ -1500,13 +1509,13 @@ int dummy; outfile.write(description) outfile.write('\n') outfile.write('\n') + args = [ninja_quote(quote_func(x)) for x in self.environment.get_build_command()] + \ + ['--internal', + 'symbolextractor', + '$in', + '$out'] symrule = 'rule SHSYM\n' - symcmd = ' command = "%s" "%s" %s %s %s %s $CROSS\n' % (ninja_quote(sys.executable), - self.environment.get_build_command(), - '--internal', - 'symbolextractor', - '$in', - '$out') + symcmd = ' command = ' + ' '.join(args) + ' $CROSS\n' synstat = ' restat = 1\n' syndesc = ' description = Generating symbol file $out.\n' outfile.write(symrule) @@ -1564,8 +1573,7 @@ int dummy; def generate_swift_compile_rules(self, compiler, outfile): rule = 'rule %s_COMPILER\n' % compiler.get_language() - full_exe = [ninja_quote(sys.executable), - ninja_quote(self.environment.get_build_command()), + full_exe = [ninja_quote(x) for x in self.environment.get_build_command()] + [ '--internal', 'dirchanger', '$RUNDIR'] @@ -1833,7 +1841,9 @@ rule FORTRAN_DEP_HACK continue filename = s.absolute_path(self.environment.get_source_dir(), self.environment.get_build_dir()) - with open(filename) as f: + # Some Fortran editors save in weird encodings, + # but all the parts we care about are in ASCII. + with open(filename, errors='ignore') as f: for line in f: modmatch = modre.match(line) if modmatch is not None: @@ -2487,9 +2497,7 @@ rule FORTRAN_DEP_HACK e = NinjaBuildElement(self.all_outputs, 'meson-clean-ctlist', 'CUSTOM_COMMAND', 'PHONY') d = CleanTrees(self.environment.get_build_dir(), trees) d_file = os.path.join(self.environment.get_scratch_dir(), 'cleantrees.dat') - e.add_item('COMMAND', [sys.executable, - self.environment.get_build_command(), - '--internal', 'cleantrees', d_file]) + e.add_item('COMMAND', self.environment.get_build_command() + ['--internal', 'cleantrees', d_file]) e.add_item('description', 'Cleaning custom target directories.') e.write(outfile) # Alias that runs the target defined above @@ -2530,13 +2538,10 @@ rule FORTRAN_DEP_HACK def generate_dist(self, outfile): elem = NinjaBuildElement(self.all_outputs, 'meson-dist', 'CUSTOM_COMMAND', 'PHONY') elem.add_item('DESC', 'Creating source packages') - elem.add_item('COMMAND', [sys.executable, - self.environment.get_build_command(), - '--internal', 'dist', - self.environment.source_dir, - self.environment.build_dir, - sys.executable, - self.environment.get_build_command()]) + elem.add_item('COMMAND', self.environment.get_build_command() + + ['--internal', 'dist', + self.environment.source_dir, + self.environment.build_dir] + self.environment.get_build_command()) elem.add_item('pool', 'console') elem.write(outfile) # Alias that runs the target defined above @@ -2544,17 +2549,16 @@ rule FORTRAN_DEP_HACK # For things like scan-build and other helper tools we might have. def generate_utils(self, outfile): - cmd = [sys.executable, self.environment.get_build_command(), - '--internal', 'scanbuild', self.environment.source_dir, self.environment.build_dir, - sys.executable, self.environment.get_build_command()] + self.get_user_option_args() + cmd = self.environment.get_build_command() + \ + ['--internal', 'scanbuild', self.environment.source_dir, self.environment.build_dir] + \ + self.environment.get_build_command() + self.get_user_option_args() elem = NinjaBuildElement(self.all_outputs, 'meson-scan-build', 'CUSTOM_COMMAND', 'PHONY') elem.add_item('COMMAND', cmd) elem.add_item('pool', 'console') elem.write(outfile) # Alias that runs the target defined above self.create_target_alias('meson-scan-build', outfile) - cmd = [sys.executable, self.environment.get_build_command(), - '--internal', 'uninstall'] + cmd = self.environment.get_build_command() + ['--internal', 'uninstall'] elem = NinjaBuildElement(self.all_outputs, 'meson-uninstall', 'CUSTOM_COMMAND', 'PHONY') elem.add_item('COMMAND', cmd) elem.add_item('pool', 'console') diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py index 4832f7e..00ee34a 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -24,7 +24,7 @@ from .. import mlog from .. import compilers from ..build import BuildTarget from ..compilers import CompilerArgs -from ..mesonlib import MesonException, File, get_meson_script +from ..mesonlib import MesonException, File from ..environment import Environment def autodetect_vs_version(build): @@ -413,8 +413,8 @@ class Vs2010Backend(backends.Backend): cmd = [sys.executable, os.path.join(self.environment.get_script_dir(), 'commandrunner.py'), self.environment.get_build_dir(), self.environment.get_source_dir(), - self.get_target_dir(target), - get_meson_script(self.environment, 'mesonintrospect')] + self.get_target_dir(target)] + \ + self.environment.get_build_command() for i in cmd_raw: if isinstance(i, build.BuildTarget): cmd.append(os.path.join(self.environment.get_build_dir(), self.get_target_filename(i))) @@ -447,8 +447,7 @@ class Vs2010Backend(backends.Backend): # All targets run from the target dir tdir_abs, capture=ofilenames[0] if target.capture else None) - wrapper_cmd = [sys.executable, self.environment.get_build_command(), - '--internal', 'exe', exe_data] + wrapper_cmd = self.environment.get_build_command() + ['--internal', 'exe', exe_data] ET.SubElement(customstep, 'Command').text = ' '.join(self.quote_arguments(wrapper_cmd)) ET.SubElement(customstep, 'Outputs').text = ';'.join(ofilenames) ET.SubElement(customstep, 'Inputs').text = ';'.join([exe_data] + srcs + depend_files) @@ -1093,10 +1092,7 @@ class Vs2010Backend(backends.Backend): ET.SubElement(midl, 'TypeLibraryName').text = '%(Filename).tlb' ET.SubElement(midl, 'InterfaceIdentifierFilename').text = '%(Filename)_i.c' ET.SubElement(midl, 'ProxyFileName').text = '%(Filename)_p.c' - regen_command = [sys.executable, - self.environment.get_build_command(), - '--internal', - 'regencheck'] + regen_command = self.environment.get_build_command() + ['--internal', 'regencheck'] private_dir = self.environment.get_scratch_dir() cmd_templ = '''setlocal "%s" "%s" @@ -1176,10 +1172,7 @@ if %%errorlevel%% neq 0 goto :VCEnd''' postbuild = ET.SubElement(action, 'PostBuildEvent') ET.SubElement(postbuild, 'Message') # FIXME: No benchmarks? - test_command = [sys.executable, - self.environment.get_build_command(), - 'test', - '--no-rebuild'] + test_command = self.environment.get_build_command() + ['test', '--no-rebuild'] if not self.environment.coredata.get_builtin_option('stdsplit'): test_command += ['--no-stdsplit'] if self.environment.coredata.get_builtin_option('errorlogs'): diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 3c993ac..5077a6e 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -1041,8 +1041,11 @@ class ClangCompiler: return get_gcc_soname_args(gcc_type, prefix, shlib_name, suffix, path, soversion, is_shared_module) def has_multi_arguments(self, args, env): + myargs = ['-Werror=unknown-warning-option', '-Werror=unused-command-line-argument'] + if mesonlib.version_compare(self.version, '>=3.6.0'): + myargs.append('-Werror=ignored-optimization-argument') return super().has_multi_arguments( - ['-Werror=unknown-warning-option', '-Werror=unused-command-line-argument'] + args, + myargs + args, env) def has_function(self, funcname, prefix, env, extra_args=None, dependencies=None): diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index e9effc6..0112fd3 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -142,7 +142,7 @@ class BoostDependency(ExternalDependency): def validate_requested(self): for m in self.requested_modules: - if m not in self.src_modules: + if m not in self.src_modules and m not in self.lib_modules and m + '-mt' not in self.lib_modules_mt: msg = 'Requested Boost module {!r} not found' raise DependencyException(msg.format(m)) diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index d4af9be..0b2a159 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -19,6 +19,7 @@ from .linkers import ArLinker, VisualStudioLinker from . import mesonlib from .mesonlib import EnvironmentException, Popen_safe from . import mlog +import sys from . import compilers from .compilers import ( @@ -361,8 +362,15 @@ class Environment: def get_coredata(self): return self.coredata - def get_build_command(self): - return self.meson_script_launcher + def get_build_command(self, unbuffered=False): + # If running an executable created with cx_freeze, + # Python might not be installed so don't prefix + # the command with it. + if sys.executable.endswith('meson.exe'): + return [sys.executable] + if unbuffered: + [sys.executable, '-u', self.meson_script_launcher] + return [sys.executable, self.meson_script_launcher] def is_header(self, fname): return is_header(fname) @@ -503,6 +511,24 @@ class Environment: if isinstance(compiler, str): compiler = [compiler] if 'cl' in compiler or 'cl.exe' in compiler: + # Watcom C provides it's own cl.exe clone that mimics an older + # version of Microsoft's compiler. Since Watcom's cl.exe is + # just a wrapper, we skip using it if we detect its presence + # so as not to confuse Meson when configuring for MSVC. + # + # Additionally the help text of Watcom's cl.exe is paged, and + # the binary will not exit without human intervention. In + # practice, Meson will block waiting for Watcom's cl.exe to + # exit, which requires user input and thus will never exit. + if 'WATCOM' in os.environ: + def sanitize(p): + return os.path.normcase(os.path.abspath(p)) + + watcom_cls = [sanitize(os.path.join(os.environ['WATCOM'], 'BINNT', 'cl')), + sanitize(os.path.join(os.environ['WATCOM'], 'BINNT', 'cl.exe'))] + found_cl = sanitize(shutil.which('cl')) + if found_cl in watcom_cls: + continue arg = '/?' else: arg = '--version' @@ -531,10 +557,14 @@ class Environment: cls = ClangCCompiler if lang == 'c' else ClangCPPCompiler return cls(ccache + compiler, version, cltype, is_cross, exe_wrap) if 'Microsoft' in out or 'Microsoft' in err: - # Visual Studio prints version number to stderr but - # everything else to stdout. Why? Lord only knows. + # Latest versions of Visual Studio print version + # number to stderr but earlier ones print version + # on stdout. Why? Lord only knows. + # Check both outputs to figure out version. version = search_version(err) - if not err or not err.split('\n')[0]: + if version == 'unknown version': + version = search_version(out) + if version == 'unknown version': m = 'Failed to detect MSVC compiler arch: stderr was\n{!r}' raise EnvironmentException(m.format(err)) is_64 = err.split('\n')[0].endswith(' x64') diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 5fa0878..313f430 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -21,7 +21,7 @@ from . import optinterpreter from . import compilers from .wrap import wrap, WrapMode from . import mesonlib -from .mesonlib import FileMode, Popen_safe, get_meson_script +from .mesonlib import FileMode, Popen_safe from .dependencies import ExternalProgram from .dependencies import InternalDependency, Dependency, DependencyException from .interpreterbase import InterpreterBase @@ -31,7 +31,7 @@ from .interpreterbase import InterpreterObject, MutableInterpreterObject from .modules import ModuleReturnValue import os, sys, shutil, uuid -import re +import re, shlex from collections import namedtuple import importlib @@ -88,7 +88,8 @@ class RunProcess(InterpreterObject): env = {'MESON_SOURCE_ROOT': source_dir, 'MESON_BUILD_ROOT': build_dir, 'MESON_SUBDIR': subdir, - 'MESONINTROSPECT': mesonintrospect} + 'MESONINTROSPECT': ' '.join([shlex.quote(x) for x in mesonintrospect]), + } if in_builddir: cwd = os.path.join(build_dir, subdir) else: @@ -97,7 +98,13 @@ class RunProcess(InterpreterObject): child_env.update(env) mlog.debug('Running command:', ' '.join(command_array)) try: - return Popen_safe(command_array, env=child_env, cwd=cwd) + p, o, e = Popen_safe(command_array, env=child_env, cwd=cwd) + mlog.debug('--- stdout----') + mlog.debug(o) + mlog.debug('----stderr----') + mlog.debug(e) + mlog.debug('') + return p, o, e except FileNotFoundError: raise InterpreterException('Could not execute command "%s".' % ' '.join(command_array)) @@ -1231,6 +1238,7 @@ lang_arg_kwargs = set(['c_args', 'objcpp_args', 'rust_args', 'vala_args', + 'cs_args', ]) vala_kwargs = set(['vala_header', 'vala_gir', 'vala_vapi']) @@ -1269,9 +1277,7 @@ build_target_common_kwargs = ( rust_kwargs | cs_kwargs) -exe_kwargs = set() -exe_kwargs.update(build_target_common_kwargs) - +exe_kwargs = (build_target_common_kwargs) | {'implib'} shlib_kwargs = (build_target_common_kwargs) | {'version', 'soversion'} shmod_kwargs = shlib_kwargs stlib_kwargs = shlib_kwargs @@ -1607,7 +1613,7 @@ class Interpreter(InterpreterBase): else: raise InterpreterException('Arguments ' + m.format(a)) return RunProcess(cmd, expanded_args, srcdir, builddir, self.subdir, - get_meson_script(self.environment, 'mesonintrospect'), in_builddir) + self.environment.get_build_command() + ['introspect'], in_builddir) @stringArgs def func_gettext(self, nodes, args, kwargs): @@ -2190,16 +2196,15 @@ class Interpreter(InterpreterBase): else: vcs_cmd = [' '] # executing this cmd will fail in vcstagger.py and force to use the fallback string # vcstagger.py parameters: infile, outfile, fallback, source_dir, replace_string, regex_selector, command... - kwargs['command'] = [sys.executable, - self.environment.get_build_command(), - '--internal', - 'vcstagger', - '@INPUT0@', - '@OUTPUT0@', - fallback, - source_dir, - replace_string, - regex_selector] + vcs_cmd + kwargs['command'] = self.environment.get_build_command() + \ + ['--internal', + 'vcstagger', + '@INPUT0@', + '@OUTPUT0@', + fallback, + source_dir, + replace_string, + regex_selector] + vcs_cmd kwargs.setdefault('build_always', True) return self.func_custom_target(node, [kwargs['output']], kwargs) diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index d48625f..9a019c6 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -182,15 +182,6 @@ class File: def relative_name(self): return os.path.join(self.subdir, self.fname) -def get_meson_script(env, script): - ''' - Given the path of `meson.py`/`meson`, get the path of a meson script such - as `mesonintrospect` or `mesontest`. - ''' - meson_py = env.get_build_command() - (base, ext) = os.path.splitext(meson_py) - return os.path.join(os.path.dirname(base), script + ext) - def get_compiler_for_source(compilers, src): for comp in compilers: if comp.can_compile(src): diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py index ed23f52..ab14b15 100644 --- a/mesonbuild/mesonmain.py +++ b/mesonbuild/mesonmain.py @@ -113,13 +113,14 @@ class MesonApp: priv_dir = os.path.join(build_dir, 'meson-private/coredata.dat') if os.path.exists(priv_dir): if not handshake: - msg = '''Trying to run Meson on a build directory that has already been configured. + print('''Trying to run Meson on a build directory that has already been configured. If you want to build it, just run your build command (e.g. ninja) inside the build directory. Meson will autodetect any changes in your setup and regenerate -itself as required. +itself as required. Though it shouldn't be necessary, running ninja reconfigure +will force Meson to regenerate the build files. -If you want to change option values, use the mesonconf tool instead.''' - raise RuntimeError(msg) +If you want to change option values, use meson configure instead.''') + sys.exit(0) else: if handshake: raise RuntimeError('Something went terribly wrong. Please file a bug.') @@ -135,6 +136,12 @@ If you want to change option values, use the mesonconf tool instead.''' def generate(self): env = environment.Environment(self.source_dir, self.build_dir, self.meson_script_launcher, self.options, self.original_cmd_line_args) mlog.initialize(env.get_log_dir()) + try: + self._generate(env) + finally: + mlog.shutdown() + + def _generate(self, env): mlog.debug('Build started at', datetime.datetime.now().isoformat()) mlog.debug('Python binary:', sys.executable) mlog.debug('Python system:', platform.system()) diff --git a/mesonbuild/mlog.py b/mesonbuild/mlog.py index 82ee6ba..659c8f5 100644 --- a/mesonbuild/mlog.py +++ b/mesonbuild/mlog.py @@ -31,7 +31,9 @@ def initialize(logdir): def shutdown(): global log_file if log_file is not None: - log_file.close() + exception_around_goer = log_file + log_file = None + exception_around_goer.close() class AnsiDecorator: plain_code = "\033[0m" diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index 43c4881..1632dae 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -375,8 +375,6 @@ class GnomeModule(ExtensionModule): # Hack to avoid passing some compiler options in if lib.startswith("-W"): continue - if gir_has_extra_lib_arg() and use_gir_args and lib.startswith("-l"): - lib = lib.replace('-l', '--extra-library=', 1) ldflags.update([lib]) if isinstance(dep, PkgConfigDependency): @@ -389,6 +387,14 @@ class GnomeModule(ExtensionModule): mlog.log('dependency %s not handled to build gir files' % dep) continue + if gir_has_extra_lib_arg() and use_gir_args: + fixed_ldflags = set() + for ldflag in ldflags: + if ldflag.startswith("-l"): + fixed_ldflags.add(ldflag.replace('-l', '--extra-library=', 1)) + else: + fixed_ldflags.add(ldflag) + ldflags = fixed_ldflags return cflags, ldflags, gi_includes @permittedKwargs({'sources', 'nsversion', 'namespace', 'symbol_prefix', 'identifier_prefix', @@ -660,7 +666,7 @@ class GnomeModule(ExtensionModule): if kwargs: raise MesonException('Unknown arguments passed: {}'.format(', '.join(kwargs.keys()))) - script = [sys.executable, state.environment.get_build_command()] + script = state.environment.get_build_command() args = ['--internal', 'yelphelper', 'install', @@ -676,20 +682,20 @@ class GnomeModule(ExtensionModule): args.append('--langs=' + '@@'.join(langs)) inscript = build.RunScript(script, args) - potargs = [state.environment.get_build_command(), '--internal', 'yelphelper', 'pot', + potargs = state.environment.get_build_command() + ['--internal', 'yelphelper', 'pot', '--subdir=' + state.subdir, '--id=' + project_id, '--sources=' + source_str] - pottarget = build.RunTarget('help-' + project_id + '-pot', sys.executable, - potargs, [], state.subdir) + pottarget = build.RunTarget('help-' + project_id + '-pot', potargs[0], + potargs[1:], [], state.subdir) - poargs = [state.environment.get_build_command(), '--internal', 'yelphelper', 'update-po', + poargs = state.environment.get_build_command() + ['--internal', 'yelphelper', 'update-po', '--subdir=' + state.subdir, '--id=' + project_id, '--sources=' + source_str, '--langs=' + '@@'.join(langs)] - potarget = build.RunTarget('help-' + project_id + '-update-po', sys.executable, - poargs, [], state.subdir) + potarget = build.RunTarget('help-' + project_id + '-update-po', poargs[0], + poargs[1:], [], state.subdir) rv = [inscript, pottarget, potarget] return ModuleReturnValue(None, rv) @@ -717,7 +723,7 @@ class GnomeModule(ExtensionModule): raise MesonException('You can only specify main_xml or main_sgml, not both.') main_file = main_xml targetname = modulename + '-doc' - command = [sys.executable, state.environment.get_build_command()] + command = state.environment.get_build_command() namespace = kwargs.get('namespace', '') mode = kwargs.get('mode', 'auto') diff --git a/mesonbuild/modules/i18n.py b/mesonbuild/modules/i18n.py index 00a4fbf..2af09de 100644 --- a/mesonbuild/modules/i18n.py +++ b/mesonbuild/modules/i18n.py @@ -72,7 +72,7 @@ class I18nModule(ExtensionModule): datadirs = self._get_data_dirs(state, mesonlib.stringlistify(kwargs.pop('data_dirs', []))) datadirs = '--datadirs=' + ':'.join(datadirs) if datadirs else None - command = [state.environment.get_build_command(), '--internal', 'msgfmthelper', + command = state.environment.get_build_command() + ['--internal', 'msgfmthelper', '@INPUT@', '@OUTPUT@', file_type, podir] if datadirs: command.append(datadirs) @@ -105,28 +105,28 @@ class I18nModule(ExtensionModule): datadirs = '--datadirs=' + ':'.join(datadirs) if datadirs else None extra_args = '--extra-args=' + '@@'.join(extra_args) if extra_args else None - potargs = [state.environment.get_build_command(), '--internal', 'gettext', 'pot', pkg_arg] + potargs = state.environment.get_build_command() + ['--internal', 'gettext', 'pot', pkg_arg] if datadirs: potargs.append(datadirs) if extra_args: potargs.append(extra_args) - pottarget = build.RunTarget(packagename + '-pot', sys.executable, potargs, [], state.subdir) + pottarget = build.RunTarget(packagename + '-pot', potargs[0], potargs[1:], [], state.subdir) - gmoargs = [state.environment.get_build_command(), '--internal', 'gettext', 'gen_gmo'] + gmoargs = state.environment.get_build_command() + ['--internal', 'gettext', 'gen_gmo'] if lang_arg: gmoargs.append(lang_arg) - gmotarget = build.RunTarget(packagename + '-gmo', sys.executable, gmoargs, [], state.subdir) + gmotarget = build.RunTarget(packagename + '-gmo', gmoargs[0], gmoargs[1:], [], state.subdir) - updatepoargs = [state.environment.get_build_command(), '--internal', 'gettext', 'update_po', pkg_arg] + updatepoargs = state.environment.get_build_command() + ['--internal', 'gettext', 'update_po', pkg_arg] if lang_arg: updatepoargs.append(lang_arg) if datadirs: updatepoargs.append(datadirs) if extra_args: updatepoargs.append(extra_args) - updatepotarget = build.RunTarget(packagename + '-update-po', sys.executable, updatepoargs, [], state.subdir) + updatepotarget = build.RunTarget(packagename + '-update-po', updatepoargs[0], updatepoargs[1:], [], state.subdir) - script = [sys.executable, state.environment.get_build_command()] + script = state.environment.get_build_command() args = ['--internal', 'gettext', 'install', '--subdir=' + state.subdir, '--localedir=' + state.environment.coredata.get_builtin_option('localedir'), diff --git a/mesonbuild/scripts/commandrunner.py b/mesonbuild/scripts/commandrunner.py index 87e3b8b..f99cddb 100644 --- a/mesonbuild/scripts/commandrunner.py +++ b/mesonbuild/scripts/commandrunner.py @@ -15,13 +15,14 @@ """This program is a wrapper to run external commands. It determines what to run, sets up the environment and executes the command.""" -import sys, os, subprocess, shutil +import sys, os, subprocess, shutil, shlex -def run_command(source_dir, build_dir, subdir, mesonintrospect, command, arguments): +def run_command(source_dir, build_dir, subdir, meson_command, command, arguments): env = {'MESON_SOURCE_ROOT': source_dir, 'MESON_BUILD_ROOT': build_dir, 'MESON_SUBDIR': subdir, - 'MESONINTROSPECT': mesonintrospect} + 'MESONINTROSPECT': ' '.join([shlex.quote(x) for x in meson_command + ['introspect']]), + } cwd = os.path.join(source_dir, subdir) child_env = os.environ.copy() child_env.update(env) @@ -47,10 +48,16 @@ def run(args): src_dir = args[0] build_dir = args[1] subdir = args[2] - mesonintrospect = args[3] - command = args[4] - arguments = args[5:] - pc = run_command(src_dir, build_dir, subdir, mesonintrospect, command, arguments) + meson_command = args[3] + if 'python' in meson_command: # Hack. + meson_command = [meson_command, args[4]] + command = args[5] + arguments = args[6:] + else: + meson_command = [meson_command] + command = args[4] + arguments = args[5:] + pc = run_command(src_dir, build_dir, subdir, meson_command, command, arguments) pc.wait() return pc.returncode diff --git a/mesonbuild/scripts/meson_install.py b/mesonbuild/scripts/meson_install.py index 01ea771..b05ffbc 100644 --- a/mesonbuild/scripts/meson_install.py +++ b/mesonbuild/scripts/meson_install.py @@ -13,6 +13,7 @@ # limitations under the License. import sys, pickle, os, shutil, subprocess, gzip, platform, errno +import shlex from glob import glob from . import depfixer from . import destdir_join @@ -247,7 +248,9 @@ def run_install_script(d): 'MESON_BUILD_ROOT': d.build_dir, 'MESON_INSTALL_PREFIX': d.prefix, 'MESON_INSTALL_DESTDIR_PREFIX': d.fullprefix, - 'MESONINTROSPECT': d.mesonintrospect} + 'MESONINTROSPECT': ' '.join([shlex.quote(x) for x in d.mesonintrospect]), + } + child_env = os.environ.copy() child_env.update(env) diff --git a/msi/createmsi.py b/msi/createmsi.py index 4fbc2d6..a6a29e4 100755..100644 --- a/msi/createmsi.py +++ b/msi/createmsi.py @@ -142,8 +142,11 @@ class PackageGenerator: def build_package(self): - subprocess.check_call(['c:\\Program Files\\Wix Toolset v3.11\\bin\candle', self.main_xml]) - subprocess.check_call(['c:\\Program Files\\Wix Toolset v3.11\\bin\light', + wixdir = 'c:\\Program Files\\Wix Toolset v3.11\\bin' + if not os.path.isdir(wixdir): + wixdir = 'c:\\Program Files (x86)\\Wix Toolset v3.11\\bin' + subprocess.check_call([os.path.join(wixdir, 'candle'), self.main_xml]) + subprocess.check_call([os.path.join(wixdir, 'light'), '-ext', 'WixUIExtension', '-cultures:en-us', '-dWixUILicenseRtf=msi\\License.rtf', diff --git a/run_unittests.py b/run_unittests.py index b889c3d..1fb1b4b 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -1288,6 +1288,9 @@ int main(int argc, char **argv) { targets = mesonbuild.coredata.forbidden_target_names # We don't actually define a target with this name targets.pop('build.ninja') + # Remove this to avoid multiple entries with the same name + # but different case. + targets.pop('PHONY') for i in targets: self.assertPathExists(os.path.join(testdir, i)) @@ -1907,6 +1910,19 @@ class LinuxlikeTests(BasePlatformTests): for i in compdb: self.assertIn("-fsanitize=address", i["command"]) + def test_coverage(self): + if not shutil.which('gcovr'): + raise unittest.SkipTest('gcovr not found') + if not shutil.which('genhtml'): + raise unittest.SkipTest('genhtml not found') + if 'clang' in os.environ.get('CC', '') and os.environ.get('TRAVIS_OS_NAME', '') == 'linux': + raise unittest.SkipTest('Gcovr has a bug and does not work with Clang in the CI environment.') + testdir = os.path.join(self.common_test_dir, '1 trivial') + self.init(testdir, ['-Db_coverage=true']) + self.build() + self.run_tests() + self.run_target('coverage-html') + class LinuxArmCrossCompileTests(BasePlatformTests): ''' Tests that verify cross-compilation to Linux/ARM diff --git a/test cases/common/112 has arg/meson.build b/test cases/common/112 has arg/meson.build index 15d8cc8..a89b59e 100644 --- a/test cases/common/112 has arg/meson.build +++ b/test cases/common/112 has arg/meson.build @@ -42,3 +42,10 @@ if cc.get_id() == 'gcc' assert(cc.has_multi_arguments(pre_arg), 'Arg that should have worked does not work.') assert(cc.has_multi_arguments([pre_arg, arg]), 'Arg that should have worked does not work.') endif + +if cc.get_id() == 'clang' and cc.version().version_compare('<=4.0.0') + # 4.0.0 does not support -fpeel-loops. Newer versions may. + # Please adjust above version number as new versions of clang are released. + notyet_arg = '-fpeel-loops' + assert(not cc.has_argument(notyet_arg), 'Arg that should be broken (unless clang added support recently) is not.') +endif diff --git a/test cases/common/147 mesonintrospect from scripts/check_env.py b/test cases/common/147 mesonintrospect from scripts/check_env.py index dc8ad63..9bd64d7 100644 --- a/test cases/common/147 mesonintrospect from scripts/check_env.py +++ b/test cases/common/147 mesonintrospect from scripts/check_env.py @@ -2,6 +2,7 @@ import os import sys +import shlex do_print = False @@ -13,8 +14,15 @@ if 'MESONINTROSPECT' not in os.environ: mesonintrospect = os.environ['MESONINTROSPECT'] -if not os.path.isfile(mesonintrospect): +introspect_arr = shlex.split(mesonintrospect) + +#print(mesonintrospect) +#print(introspect_arr) + +some_executable = introspect_arr[0] + +if not os.path.isfile(some_executable): raise RuntimeError('{!r} does not exist'.format(mesonintrospect)) if do_print: - print(mesonintrospect, end='') + print(some_executable, end='') diff --git a/test cases/common/159 reserved targets/PHONY/meson.build b/test cases/common/159 reserved targets/PHONY/meson.build deleted file mode 100644 index d25583c..0000000 --- a/test cases/common/159 reserved targets/PHONY/meson.build +++ /dev/null @@ -1 +0,0 @@ -executable('test-PHONY', '../test.c') diff --git a/test cases/common/159 reserved targets/meson.build b/test cases/common/159 reserved targets/meson.build index 5123600..26572c0 100644 --- a/test cases/common/159 reserved targets/meson.build +++ b/test cases/common/159 reserved targets/meson.build @@ -15,11 +15,10 @@ subdir('coverage-xml') subdir('dist') subdir('distcheck') subdir('install') -# We end up creating duplicate lowercase target names for this on -# case-insensitive HFS+, so disable it -# https://travis-ci.org/mesonbuild/meson/jobs/264468097 -#subdir('phony') -subdir('PHONY') +# We don't have a 'PHONY' directory because Windows and OSX +# choke horribly when there are two entries with the same +# name but different case. +subdir('phony') subdir('reconfigure') subdir('scan-build') subdir('test') diff --git a/test cases/csharp/2 library/meson.build b/test cases/csharp/2 library/meson.build index 2082e03..6b246a4 100644 --- a/test cases/csharp/2 library/meson.build +++ b/test cases/csharp/2 library/meson.build @@ -1,5 +1,15 @@ project('C# library', 'cs') -l = shared_library('helper', 'helper.cs', install : true) +python3 = import('python3').find_python() +generated_sources = custom_target('gen_sources', + input: 'helper.cs', + output: 'helper.cs', + command: [python3, '-c', + 'import shutil, sys; shutil.copyfile(sys.argv[1], sys.argv[2])', + '@INPUT@', '@OUTPUT@'] +) + +l = shared_library('helper', generated_sources, install : true) + e = executable('prog', 'prog.cs', link_with : l, install : true) test('libtest', e) diff --git a/test cases/csharp/4 external dep/hello.txt b/test cases/csharp/4 external dep/hello.txt new file mode 100644 index 0000000..980a0d5 --- /dev/null +++ b/test cases/csharp/4 external dep/hello.txt @@ -0,0 +1 @@ +Hello World! diff --git a/test cases/csharp/4 external dep/meson.build b/test cases/csharp/4 external dep/meson.build new file mode 100644 index 0000000..004d25f --- /dev/null +++ b/test cases/csharp/4 external dep/meson.build @@ -0,0 +1,4 @@ +project('C# external library', 'cs') +glib_sharp_2 = dependency('glib-sharp-2.0') +e = executable('prog', 'prog.cs', dependencies: glib_sharp_2, install : true) +test('libtest', e, args: [join_paths(meson.current_source_dir(), 'hello.txt')]) diff --git a/test cases/csharp/4 external dep/prog.cs b/test cases/csharp/4 external dep/prog.cs new file mode 100644 index 0000000..9393fef --- /dev/null +++ b/test cases/csharp/4 external dep/prog.cs @@ -0,0 +1,8 @@ +using System; +using GLib; + +public class Prog { + static public void Main (string[] args) { + Console.WriteLine(GLib.FileUtils.GetFileContents(args[0])); + } +} diff --git a/test cases/frameworks/1 boost/extralib.cpp b/test cases/frameworks/1 boost/extralib.cpp new file mode 100644 index 0000000..6a3e9e4 --- /dev/null +++ b/test cases/frameworks/1 boost/extralib.cpp @@ -0,0 +1,25 @@ +#include <iostream> +#include <boost/log/trivial.hpp> +#include <boost/log/expressions.hpp> +#include <boost/log/utility/setup/console.hpp> +#include <boost/log/utility/setup/common_attributes.hpp> + +using namespace std; +namespace logging = boost::log; + +void InitLogger() { + logging::add_common_attributes(); + logging::register_simple_formatter_factory<logging::trivial::severity_level, char>("Severity"); + string log_format = "%TimeStamp% [%Severity%] - %Message%"; + + logging::add_console_log( + cout, + logging::keywords::format = log_format + ); +} + +int main(int argc, char **argv) { + InitLogger(); + BOOST_LOG_TRIVIAL(trace) << "SOMETHING"; + return 0; +} diff --git a/test cases/frameworks/1 boost/meson.build b/test cases/frameworks/1 boost/meson.build index 338dd78..6f25f8b 100644 --- a/test cases/frameworks/1 boost/meson.build +++ b/test cases/frameworks/1 boost/meson.build @@ -1,6 +1,10 @@ project('boosttest', 'cpp', default_options : ['cpp_std=c++11']) +add_project_arguments(['-DBOOST_LOG_DYN_LINK'], + language : 'cpp' +) + # We want to have multiple separate configurations of Boost # within one project. The need to be independent of each other. # Use one without a library dependency and one with it. @@ -10,15 +14,18 @@ linkdep = dependency('boost', modules : ['thread', 'system']) staticdep = dependency('boost', modules : ['thread', 'system'], static : true) testdep = dependency('boost', modules : 'test') nomoddep = dependency('boost') +extralibdep = dependency('boost', modules : ['thread', 'system', 'log_setup', 'log']) nolinkexe = executable('nolinkedexe', 'nolinkexe.cc', dependencies : nolinkdep) linkexe = executable('linkedexe', 'linkexe.cc', dependencies : linkdep) staticexe = executable('staticlinkedexe', 'linkexe.cc', dependencies : staticdep) unitexe = executable('utf', 'unit_test.cpp', dependencies: testdep) nomodexe = executable('nomod', 'nomod.cpp', dependencies : nomoddep) +extralibexe = executable('extralibexe', 'extralib.cpp', dependencies : extralibdep) test('Boost nolinktest', nolinkexe) test('Boost linktest', linkexe) test('Boost statictest', staticexe) test('Boost UTF test', unitexe) test('Boost nomod', nomodexe) +test('Boost extralib test', extralibexe) diff --git a/test cases/frameworks/14 doxygen/meson.build b/test cases/frameworks/14 doxygen/meson.build index 5dad859..55df316 100644 --- a/test cases/frameworks/14 doxygen/meson.build +++ b/test cases/frameworks/14 doxygen/meson.build @@ -9,7 +9,11 @@ cdata = configuration_data() cdata.set('VERSION', meson.project_version()) if find_program('dot', required : false).found() - cdata.set('HAVE_DOT', 'YES') + # In the real world this would set the variable + # to YES. However we set it to NO so that the + # list of generated files is always the same + # so tests always pass. + cdata.set('HAVE_DOT', 'NO') else cdata.set('HAVE_DOT', 'NO') endif |