aboutsummaryrefslogtreecommitdiff
path: root/doc/manual.cli
diff options
context:
space:
mode:
Diffstat (limited to 'doc/manual.cli')
-rw-r--r--doc/manual.cli2828
1 files changed, 2513 insertions, 315 deletions
diff --git a/doc/manual.cli b/doc/manual.cli
index 9d79259..847691d 100644
--- a/doc/manual.cli
+++ b/doc/manual.cli
@@ -156,7 +156,7 @@ Let's now try to build and run our program (\c{b} is the build system driver):
$ cd hello/ # Change to project root.
$ b
-c++ cxx{hello}
+c++ cxx{hello} -> obje{hello}
ld exe{hello}
$ ls -1
@@ -177,7 +177,7 @@ Or, if we are on Windows and using Visual Studio:
> cd hello
> b
-c++ cxx{hello}
+c++ cxx{hello} -> obje{hello}
ld exe{hello}
> dir /b
@@ -235,7 +235,7 @@ noise, the commands being executed are by default shown abbreviated and with
the same target type notation as we used in the \c{buildfile}. For example:
\
-c++ cxx{hello}
+c++ cxx{hello} -> obje{hello}
ld exe{hello}
\
@@ -275,7 +275,8 @@ above listings. In our \c{buildfile} we refer to the executable target as
extension, if any, will be determined based on the compiler's target platform
by the rule doing the linking. In this sense, target types are a
platform-independent replacement of file extensions (though they do have other
-benefits, such as allowing non-file targets as well as being hierarchical).
+benefits, such as allowing non-file targets as well as being hierarchical;
+see \l{#targets-types Target Types} for details).
Let's revisit the dependency declaration line from our \c{buildfile}:
@@ -311,6 +312,16 @@ it searches for a target for the \c{cxx{hello\}} prerequisite. During this
search, the \c{extension} variable is looked up and its value is used to end
up with the \c{hello.cxx} file.
+\N|To resolve a rule match ambiguity or to override a default match \c{build2}
+uses \i{rule hints}. For example, if we wanted link a C executable using the
+C++ link rule:
+
+\
+[rule_hint=cxx] exe{hello}: c{hello}
+\
+
+|
+
Here is our new dependency declaration again:
\
@@ -361,7 +372,7 @@ Nothing really new here: we've specified the default extension for the
prerequisites. If you have experience with other build systems, then
explicitly listing headers might seem strange to you. As will be discussed
later, in \c{build2} we have to explicitly list all the prerequisites of a
-target that should end up in a distribution of our project.
+target that should end up in a source distribution of our project.
\N|You don't have to list \i{all} headers that you include, only the ones
belonging to your project. Like all modern C/C++ build systems, \c{build2}
@@ -411,11 +422,11 @@ exe{hello}: {hxx cxx}{**}
development more pleasant and less error prone: you don't need to update your
\c{buildfile} every time you add, remove, or rename a source file and you
won't forget to explicitly list headers, a mistake that is often only detected
-when trying to build a distribution of a project. On the other hand, there is
-the possibility of including stray source files into your build without
-noticing. And, for more complex projects, name patterns can become fairly
-complex (see \l{#name-patterns Name Patterns} for details). Note also that on
-modern hardware the performance of wildcard searches hardly warrants a
+when trying to build a source distribution of a project. On the other hand,
+there is the possibility of including stray source files into your build
+without noticing. And, for more complex projects, name patterns can become
+fairly complex (see \l{#name-patterns Name Patterns} for details). Note also
+that on modern hardware the performance of wildcard searches hardly warrants a
consideration.
In our experience, when combined with modern version control systems like
@@ -448,7 +459,7 @@ invocation. In other words, expect an experience similar to a plain
\c{Makefile}.
One notable example where simple projects are handy is a \i{glue
-\c{buildfiles}} that \"pulls\" together several other projects, usually for
+\c{buildfile}} that \"pulls\" together several other projects, usually for
convenience of development. See \l{#intro-import Target Importation} for
details.|
@@ -587,7 +598,7 @@ configuration \i{persistent}. We will see an example of this shortly.
Next up are the \c{test}, \c{install}, and \c{dist} modules. As their names
suggest, they provide support for testing, installation and preparation of
-distributions. Specifically, the \c{test} module defines the \c{test}
+source distributions. Specifically, the \c{test} module defines the \c{test}
operation, the \c{install} module defines the \c{install} and \c{uninstall}
operations, and the \c{dist} module defines the \c{dist}
(meta-)operation. Again, we will try them out in a moment.
@@ -671,7 +682,8 @@ notation for \c{dir{\}}. As we will see shortly, it fits naturally with other
uses of directories in \c{buildfiles} (for example, in scopes).
The \c{dir{\}} target type is an \i{alias} (and, in fact, is derived from more
-general \c{alias{\}}). Building it means building all its prerequisites.
+general \c{alias{\}}; see \l{#targets-types Target Types} for
+details). Building it means building all its prerequisites.
\N|If you are familiar with \c{make}, then you can probably see the similarity
with the ubiquitous \c{all} pseudo-target. In \c{build2} we instead use
@@ -746,7 +758,7 @@ Let's take a look at a slightly more realistic root \c{buildfile}:
Here we have the customary \c{README.md} and \c{LICENSE} files as well as the
package \c{manifest}. Listing them as prerequisites achieves two things: they
will be installed if/when our project is installed and, as mentioned earlier,
-they will be included into the project distribution.
+they will be included into the project source distribution.
The \c{README.md} and \c{LICENSE} files use the \c{doc{\}} target type. We
could have used the generic \c{file{\}} but using the more precise \c{doc{\}}
@@ -805,7 +817,7 @@ in this new layout:
\
$ cd hello/ # Change to project root.
$ b
-c++ hello/cxx{hello}
+c++ hello/cxx{hello} -> hello/obje{hello}
ld hello/exe{hello}
$ tree ./
@@ -882,8 +894,8 @@ libhello/
└── README.md
\
-The overall layout (\c{build/}, \c{libhello/} source directory) as well as the
-contents of the root files (\c{bootstrap.build}, \c{root.build}, root
+The overall layout (\c{build/}, \c{libhello/} source subdirectory) as well as
+the contents of the root files (\c{bootstrap.build}, \c{root.build}, root
\c{buildfile}) are exactly the same. There is, however, the new file
\c{export.build} in \c{build/}, the new subdirectory \c{tests/}, and the
contents of the project's source subdirectory \c{libhello/} look quite a bit
@@ -963,7 +975,7 @@ To start, let's build it in the \c{hello-out/} directory next to the project:
$ b hello/@hello-out/
mkdir fsdir{hello-out/}
mkdir hello-out/fsdir{hello/}
-c++ hello/hello/cxx{hello}@hello-out/hello/
+c++ hello/hello/cxx{hello} -> hello-out/hello/obje{hello}
ld hello-out/hello/exe{hello}
$ ls -1
@@ -1043,21 +1055,25 @@ We could have also specified out for an in source build, but that's redundant:
$ b hello/@hello/
\
-There is another example of this elaborate target specification in the build
-diagnostics:
+There is another example of this elaborate target specification that can be
+seen in the build diagnostics, for instance, when installing headers of a
+library (the \c{install} operation is discussed in the next section):
\
-c++ hello/hello/cxx{hello}@hello-out/hello/
+$ b install: libhello/@libhello-out/
+...
+install libhello/libhello/hxx{hello}@libhello-out/libhello/ ->
+ /usr/local/include/
\
-Notice, however, that now the target (\c{cxx{hello\}}) is on the left of
+Notice, however, that now the target (\c{hxx{hello\}}) is on the left of
\c{@}, that is, in the src directory. It does, however, make sense if you
-think about it: our \c{hello.cxx} is a \i{source file}, it is not built and it
-resides in the project's source directory. This is in contrast, for example,
-to the \c{exe{hello\}} target which is the output of the build system and goes
-to the out directory. So in \c{build2} targets can be either in src or in out
-(there can also be \i{out of any project} targets, for example, installed
-files).
+think about it: our \c{hello.hxx} is a \i{source file}, in a sense that it is
+not built and it resides in the project's source directory. This is in
+contrast, for example, to the \c{exe{hello\}} target which is the output of
+the build system and goes to the out directory. So in \c{build2} targets can
+be either in src or in out (there can also be \i{out of any project} targets,
+for example, installed files).
The elaborate target specification can also be used in \c{buildfiles}. We
haven't encountered any so far because targets mentioned without explicit
@@ -1350,7 +1366,7 @@ prerequisite-specific). These and other variable-related topics will be
covered in subsequent sections.|
One typical place to find \c{src/out_root} expansions is in the include search
-path options. For example, the source directory \c{buildfile} generated by
+path options. For example, the source subdirectory \c{buildfile} generated by
\l{bdep-new(1)} for an executable project actually looks like this
(\c{poptions} stands for \i{preprocessor options}):
@@ -1418,7 +1434,7 @@ if ($cc.class == 'gcc')
}
if ($c.target.class != 'windows')
- c.libs += -lpthread # only C
+ c.libs += -ldl # only C
\
Additionally, as we will see in \l{#intro-operations-config Configuring},
@@ -1490,7 +1506,7 @@ In the few cases that we do, we use the following syntax:
If the scope directory is relative, then it is assumed to be relative to the
current scope. As an exercise for understanding, let's reimplement our
\c{hello} project as a single \c{buildfile}. That is, we move the contents of
-the source directory \c{buildfile} into the root \c{buildfile}:
+the source subdirectory \c{buildfile} into the root \c{buildfile}:
\
$ tree hello/
@@ -1520,7 +1536,7 @@ which explicitly opens scopes to define the build over the upstream project's
subdirectory structure.|
Seeing this merged \c{buildfile} may make you wonder what exactly caused the
-loading of the source directory \c{buildfile} in our normal setup. In other
+loading of the source subdirectory \c{buildfile} in our normal setup. In other
words, when we build our \c{hello} from the project root, who loads
\c{hello/buildfile} and why?
@@ -1634,6 +1650,15 @@ $ b update: hello/exe{hello} # Update specific target
$ b update: libhello/ tests/ # Update two targets.
\
+\N|If you are running \c{build2} from PowerShell, then you will need to use
+quoting when updating specific targets, for example:
+
+\
+$ b update: 'hello/exe{hello}'
+\
+
+|
+
Let's revisit \c{build/bootstrap.build} from our \c{hello} project:
\
@@ -1705,9 +1730,18 @@ $ b
...
\
-Let's take a look at \c{config.build}:
+To remove the persistent configuration we use the \c{disfigure}
+meta-operation:
+
+\
+$ b disfigure
+\
+
+Let's again configure our project and take a look at \c{config.build}:
\
+$ b configure config.cxx=clang++ config.cxx.coptions=-g
+
$ cat build/config.build
config.cxx = clang++
@@ -1742,6 +1776,15 @@ Any variable value specified on the command line overrides those specified in
the \c{buildfiles}. As a result, \c{config.cxx} was updated while the value of
\c{config.cxx.coptions} was preserved.
+\N|To revert a configuration variable to its default value, list its name in
+the special \c{config.config.disfigure} variable. For example:
+
+\
+$ b configure config.config.disfigure=config.cxx
+\
+
+|
+
Command line variable overrides are also handy to adjust the configuration for
a single build system invocation. For example, let's say we want to quickly
check that our project builds with optimization but without permanently
@@ -1839,7 +1882,7 @@ $ b configure: hello/@hello-gcc/,forward
$ cd hello/ # Change to project root.
$ b
-c++ hello/cxx{hello}@../hello-gcc/hello/
+c++ hello/cxx{hello} -> ../hello-gcc/hello/obje{hello}
ld ../hello-gcc/hello/exe{hello}
ln ../hello-gcc/hello/exe{hello} -> hello/
\
@@ -1949,7 +1992,7 @@ actual output:
\
$ b test
-c++ hello/cxx{hello}
+c++ hello/cxx{hello} -> hello/obje{hello}
ld hello/exe{hello}
test hello/exe{hello}
--- test.out
@@ -2051,9 +2094,9 @@ expect to see when running the tests:
\
b test
-c++ hello/cxx{hello}
+c++ hello/cxx{hello} -> hello/obje{hello}
ld hello/exe{hello}
-test hello/testscript{testscript} hello/exe{hello}
+test hello/exe{hello} + hello/testscript{testscript}
hello/testscript:7:1: error: hello/hello exit code 0 == 0
info: stdout: hello/test-hello/missing-name/stdout
\
@@ -2100,7 +2143,7 @@ libhello/
\
Specifically, there is no \c{testscript} in \c{libhello/}, the project's
-source directory. Instead, we have the \c{tests/} subdirectory which itself
+source subdirectory. Instead, we have the \c{tests/} subdirectory which itself
looks like a project: it contains the \c{build/} subdirectory with all the
familiar files, etc. In fact, \c{tests} is a \i{subproject} of our
\c{libhello} project.
@@ -2275,36 +2318,40 @@ If the value of the \c{install} variable is not \c{false}, then it is normally
a relative path with the first path component being one of these names:
\
-name default override
----- ------- --------
-root config.install.root
+name default override
+---- ------- --------
+root config.install.root
-data_root root/ config.install.data_root
-exec_root root/ config.install.exec_root
+data_root root/ config.install.data_root
+exec_root root/ config.install.exec_root
-bin exec_root/bin/ config.install.bin
-sbin exec_root/sbin/ config.install.sbin
-lib exec_root/lib/ config.install.lib
-libexec exec_root/libexec/<project>/ config.install.libexec
-pkgconfig lib/pkgconfig/ config.install.pkgconfig
+bin exec_root/bin/ config.install.bin
+sbin exec_root/sbin/ config.install.sbin
+lib exec_root/lib/ config.install.lib
+libexec exec_root/libexec/<project>/ config.install.libexec
+pkgconfig lib/pkgconfig/ config.install.pkgconfig
-etc data_root/etc/ config.install.etc
-include data_root/include/ config.install.include
-share data_root/share/ config.install.share
-data share/<project>/ config.install.data
+etc data_root/etc/ config.install.etc
+include data_root/include/ config.install.include
+include_arch include/ config.install.include_arch
+share data_root/share/ config.install.share
+data share/<project>/ config.install.data
+buildfile share/build2/export/<project>/ config.install.buildfile
-doc share/doc/<project>/ config.install.doc
-legal doc/ config.install.legal
-man share/man/ config.install.man
-man<N> man/man<N>/ config.install.man<N>
+doc share/doc/<project>/ config.install.doc
+legal doc/ config.install.legal
+man share/man/ config.install.man
+man<N> man/man<N>/ config.install.man<N>
\
Let's see what's going on here: The default install directory tree is derived
from the \c{config.install.root} value but the location of each node in this
tree can be overridden by the user that installs our project using the
-corresponding \c{config.install.*} variables. In our \c{buildfiles}, in turn,
-we use the node names instead of actual directories. As an example, here is a
-\c{buildfile} fragment from the source directory of our \c{libhello} project:
+corresponding \c{config.install.*} variables (see the \l{#module-install
+\c{install}} module documentation for details on their meaning). In our
+\c{buildfiles}, in turn, we use the node names instead of actual
+directories. As an example, here is a \c{buildfile} fragment from the source
+subdirectory of our \c{libhello} project:
\
hxx{*}:
@@ -2330,20 +2377,41 @@ root/include/libhello/
In the above \c{buildfile} fragment we also see the use of the
\c{install.subdirs} variable. Setting it to \c{true} instructs the \c{install}
module to recreate subdirectories starting from this point in the project's
-directory hierarchy. For example, if our \c{libhello/} source directory had
+directory hierarchy. For example, if our \c{libhello/} source subdirectory had
the \c{details/} subdirectory with the \c{utility.hxx} header, then this
header would have been installed as
\c{.../include/libhello/details/utility.hxx}.
+\N|By default the generated \c{pkg-config} files will contain
+\c{install.include} and \c{install.lib} directories as header (\c{-I}) and
+library (\c{-L}) search paths, respectively. However, these can be customized
+with the \c{{c,cxx\}.pkgconfig.{include,lib\}} variables. For example,
+sometimes we may need to install headers into a subdirectory of the include
+directory but include them without this subdirectory:
+
+\
+# Install headers into hello/libhello/ subdirectory of, say,
+# /usr/include/ but include them as <libhello/*>.
+#
+hxx{*}:
+{
+ install = include/hello/libhello/
+ install.subdirs = true
+}
+
+lib{hello}: cxx.pkgconfig.include = include/hello/
+\
+
+|
\h2#intro-operations-dist|Distributing|
The last module that we load in our \c{bootstrap.build} is \c{dist} which
-provides support for the preparation of distributions and defines the \c{dist}
-meta-operation. Similar to \c{configure}, \c{dist} is a meta-operation rather
-than an operation because, conceptually, we are preparing a distribution for
-performing operations (like \c{update}, \c{test}) on targets rather than
-targets themselves.
+provides support for the preparation of source distributions and defines the
+\c{dist} meta-operation. Similar to \c{configure}, \c{dist} is a
+meta-operation rather than an operation because, conceptually, we are
+preparing a distribution for performing operations (like \c{update}, \c{test})
+on targets rather than targets themselves.
The preparation of a correct distribution requires that all the necessary
project files (sources, documentation, etc) be listed as prerequisites in the
@@ -2423,14 +2491,11 @@ $ b dist
Let's now take a look at an example of customizing what gets distributed.
Most of the time you will be using this mechanism to include certain targets
-from out. Here is a fragment from the \c{libhello} source directory
+from out. Here is a fragment from the \c{libhello} source subdirectory
\c{buildfile}:
\
hxx{version}: in{version} $src_root/manifest
-{
- dist = true
-}
\
Our library provides the \c{version.hxx} header that the users can include to
@@ -2441,21 +2506,32 @@ minor, patch, etc) and then preprocesses the \c{in{\}} file substituting these
values (see the \l{#module-version \c{version}} module documentation for
details). The end result is an automatically maintained version header.
-One problem with auto-generated headers is that if one does not yet exist,
-then the compiler may still find it somewhere else. For example, we may have
-an older version of a library installed somewhere where the compiler searches
-for headers by default (for example, \c{/usr/local/include/}). To overcome
-this problem it is a good idea to ship pre-generated headers in our
-distributions. But since they are output targets, we have to explicitly
-request this with \c{dist=true}.
+Usually there is no need to include this header into the distribution since it
+will be automatically generated if and when necessary. However, we can if we
+need to. For example, we could be porting an existing project and its users
+could be expecting the version header to be shipped as part of the archive.
+Here is how we can achieve this:
+
+\
+hxx{version}: in{version} $src_root/manifest
+{
+ dist = true
+ clean = ($src_root != $out_root)
+}
+\
+
+Because this header is an output target, we have to explicitly request its
+distribution with \c{dist=true}. Notice that we have also disabled its
+cleaning for the in source build so that the \c{clean} operation results in a
+state identical to distributed.
\h#intro-import|Target Importation|
Recall that if we need to depend on a target defined in another \c{buildfile}
-within our project, then we simply include said \c{buildfile} and reference
-the target. For example, if our \c{hello} included both an executable and a
-library in separate subdirectories next to each other:
+within our project, then we simply include the said \c{buildfile} and
+reference the target. For example, if our \c{hello} included both an
+executable and a library in separate subdirectories next to each other:
\
hello/
@@ -2530,9 +2606,9 @@ source directory to use its in source build (\c{out_root\ ==\ src_root}):
\
$ b hello/ config.import.libhello=libhello/
-c++ libhello/libhello/cxx{hello}
+c++ libhello/libhello/cxx{hello} -> libhello/libhello/objs{hello}
ld libhello/libhello/libs{hello}
-c++ hello/hello/cxx{hello}
+c++ hello/hello/cxx{hello} -> hello/hello/obje{hello}
ld hello/hello/exe{hello}
\
@@ -2547,9 +2623,9 @@ $ b configure: hello/@hello-clang/ config.cxx=clang++ \
config.import.libhello=libhello-clang/
$ b hello-clang/
-c++ libhello/libhello/cxx{hello}@libhello-clang/libhello/
+c++ libhello/libhello/cxx{hello} -> libhello-clang/libhello/objs{hello}
ld libhello-clang/libhello/libs{hello}
-c++ hello/hello/cxx{hello}@hello-clang/hello/
+c++ hello/hello/cxx{hello} -> hello-clang/hello/obje{hello}
ld hello-clang/hello/exe{hello}
\
@@ -2563,6 +2639,16 @@ Subprojects and Amalgamations} for details on this subject).
subproject in \c{libhello}. The test imports \c{libhello} which is
automatically found as an amalgamation containing this subproject.|
+\N|To skip searching in subprojects/amalgamations and proceed directly to the
+rule-specific search (described below), specify the \c{config.import.*}
+variable with an empty value. For example:
+
+\
+$ b configure: ... config.import.libhello=
+\
+
+|
+
If the project being imported cannot be located using any of these methods,
then \c{import} falls back to the rule-specific search. That is, a rule that
matches the target may provide support for importing certain target types
@@ -2577,7 +2663,8 @@ subproject, or from an installation directory.
\N|Importation of an installed library will work even if it is not a
\c{build2} project. Besides finding the library itself, the link rule will
also try to locate its \c{pkg-config(1)} file and, if present, extract
-additional compile/link flags from it. The link rule also automatically
+additional compile/link flags from it (see \l{#cc-import-installed Importation
+of Installed Libraries} for details). The link rule also automatically
produces \c{pkg-config(1)} files for libraries that it installs.|
\N|A common problem with importing and using third-party C/C++ libraries is
@@ -2763,15 +2850,7 @@ impl_libs = # Implementation dependencies.
lib{hello}: {hxx ixx txx cxx}{** -version} hxx{version} \
$impl_libs $intf_libs
-# Include the generated version header into the distribution (so that
-# we don't pick up an installed one) and don't remove it when cleaning
-# in src (so that clean results in a state identical to distributed).
-#
hxx{version}: in{version} $src_root/manifest
-{
- dist = true
- clean = ($src_root != $out_root)
-}
# Build options.
#
@@ -2823,7 +2902,16 @@ recursively. And when the library is installed, this information is carried
over to its \c{pkg-config(1)} file.
\N|Similar to the \c{c.*} and \c{cc.*} sets discussed earlier, there are also
-\c{c.export.*} and \c{cc.export.*} sets.|
+\c{c.export.*} and \c{cc.export.*} sets.
+
+Note, however, that there is no \c{*.export.coptions} since a library imposing
+compilation options on its consumers is bad practice (too coarse-grained, does
+not compose, etc). Instead, the recommended approach is to specify in the
+library documentation that it expects its consumers to use a certain
+compilation option. And if your library is unusable without exporting a
+compilation option and you are sure benefits outweigh the drawbacks, then you
+can specify it as part of \c{*.export.poptions} (it is still a good idea to
+prominently document this).|
Here are the parts relevant to the library metadata protocol in the above
\c{buildfile}:
@@ -2921,7 +3009,12 @@ memory.
Note also that this only applies to shared libraries. In case of static
libraries, both interface and implementation dependencies are always linked,
-recursively.|
+recursively. Specifically, when linking a shared library, only libraries
+specified in its \c{*.export.libs} are linked. While when linking a static
+library, all its library prerequisites as well as those specified in
+\c{*.libs} are linked. Note that \c{*.export.libs} is not used when linking a
+static library since it is naturally assumed that all such libraries are also
+specified as library prerequisites or in \c{*.libs}.|
The remaining lines in the library metadata fragment are:
@@ -2980,6 +3073,16 @@ a binary-ful (\i{binful}) shared variants. Note also that binless libraries
can depend on binful libraries and are fully supported where the
\c{pkg-config(1)} functionality is concerned.
+One counter-intuitive aspect of having a binless library that depends on a
+system binful library, for example, \c{-lm}, is that you still have to specify
+the system library in both \c{*.export.libs} and \c{*.libs} because the latter
+is used when linking the static variant of the binless library. For example:
+
+\
+cxx.libs = -lm
+lib{hello}: cxx.export.libs = -lm
+\
+
If you are creating a new library with \l{bdep-new(1)} and are certain that it
will always be binless and in all configurations, then you can produce a
simplified \c{buildfile} by specifying the \c{binless} option, for example:
@@ -3094,9 +3197,10 @@ hello/
└── buildfile
$ b hello/
-c++ hello/libhello/libhello/cxx{hello}
+c++ hello/libhello/libhello/cxx{hello} ->
+ hello/libhello/libhello/objs{hello}
ld hello/libhello/libhello/libs{hello}
-c++ hello/hello/cxx{hello}
+c++ hello/hello/cxx{hello} -> hello/hello/obje{hello}
ld hello/hello/exe{hello}
\
@@ -3151,7 +3255,7 @@ configuration inheritance. As an example, let's configure the above bundled
\
$ b configure: hello/ config.cxx=clang++ config.cxx.coptions=-g
-$ b tree
+$ tree
hello/
├── build/
│ ├── config.build
@@ -3380,10 +3484,10 @@ details/ # Scope.
hxx{*}: install = false
}
-hxx{version}: # Target-specific.
+lib{hello}: # Target-specific.
{
- dist = true
- clean = ($src_root != $out_root)
+ cxx.export.poptions = \"-I$src_root\"
+ cxx.export.libs = $intf_libs
}
exe{test}: file{test.roundtrip}: # Prerequisite-specific.
@@ -3400,7 +3504,7 @@ example:
h{config}: in{config}
{
in.symbol = '@'
- in.substitution = lax
+ in.mode = lax
SYSTEM_NAME = $c.target.system
SYSTEM_PROCESSOR = $c.target.cpu
@@ -3534,8 +3638,9 @@ info $path.directory($src_base) # $src_base
info $path.base($path.leaf($src_base)) # foo
\
-Note that functions in \c{build2} are \i{pure} in a sense that they do not
-alter the build state in any way.
+Note that the majority of functions in \c{build2} are \i{pure} in a sense that
+they do not alter the build state in any way (see \l{#functions Functions} for
+details).
\N|Functions in \c{build2} are currently defined either by the build system
core or build system modules and are implemented in C++. In the future it will
@@ -4054,7 +4159,7 @@ source subdirectory \c{buildfile} of an executable created with this option:
# Unit tests.
#
-exe{*.test}
+exe{*.test}:
{
test = true
install = false
@@ -4143,12 +4248,8 @@ files as belonging to unit tests. Because it is a second-level extension, we
have to indicate this fact to the pattern matching machinery with the trailing
triple dot (meaning \"there are more extensions coming\"). If we didn't do
that, \c{.test} would have been treated as a first-level extension explicitly
-specified for our source files.
-
-\N|If you need to specify a name that does not have an extension, then end it
-with a single dot. For example, for a header \c{utility} you would write
-\c{hxx{utility.\}}. If you need to specify a name with an actual trailing
-dot, then escape it with a double dot, for example, \c{hxx{utility..\}}.|
+specified for our source files (see \l{#targets-types Target Types} for
+details).
The next couple of lines set target type/pattern-specific variables to treat
all unit test executables as tests that should not be installed:
@@ -4255,10 +4356,10 @@ latter is used to update generated source code (such as headers) that is
required to complete the match.|
Debugging issues in each phase requires different techniques. Let's start with
-the load phase. As mentioned in \l{#intro-lang Build Language}, \c{buildfiles}
-are processed linearly with directives executed and variables expanded as they
-are encountered. As we have already seen, to print a variable value we can use
-the \c{info} directive. For example:
+the load phase. As mentioned in \l{#intro-lang Buildfile Language},
+\c{buildfiles} are processed linearly with directives executed and variables
+expanded as they are encountered. As we have already seen, to print a variable
+value we can use the \c{info} directive. For example:
\
x = X
@@ -4353,7 +4454,7 @@ scopes. For that we use the \c{dump} directive.
Without any arguments, \c{dump} prints (to \c{stderr}) the contents of the
scope it was encountered in and at that point of processing the \c{buildfile}.
Its output includes variables, targets and their prerequisites, as well as
-nested scopes, recursively. As an example, let's print the source directory
+nested scopes, recursively. As an example, let's print the source subdirectory
scope of our \c{hello} executable project. Here is its \c{buildfile} with
the \c{dump} directive at the end:
@@ -4388,12 +4489,12 @@ Instead of printing the entire scope, we can also print individual targets by
specifying one or more target names in \c{dump}. To make things more
interesting, let's convert our \c{hello} project to use a utility library,
similar to the unit testing setup (\l{#intro-unit-test Implementing Unit
-Testing}). We will also link to the \c{pthread} library to see an example of a
+Testing}). We will also link to the \c{dl} library to see an example of a
target-specific variable being dumped:
\
exe{hello}: libue{hello}: bin.whole = false
-exe{hello}: cxx.libs += -lpthread
+exe{hello}: cxx.libs += -ldl
libue{hello}: {hxx cxx}{**}
dump exe{hello}
@@ -4405,7 +4506,7 @@ The output will look along these lines:
buildfile:5:1: dump:
/tmp/hello/hello/exe{hello.?}:
{
- [strings] cxx.libs = -lpthread
+ [strings] cxx.libs = -ldl
}
/tmp/hello/hello/exe{hello.?}: /tmp/hello/hello/:libue{hello.?}:
{
@@ -4416,7 +4517,8 @@ buildfile:5:1: dump:
The output of \c{dump} might look familiar: in \l{#intro-dirs-scopes Output
Directories and Scopes} we've used the \c{--dump} option to print the entire
build state, which looks pretty similar. In fact, the \c{dump} directive uses
-the same mechanism but allows us to print individual scopes and targets.
+the same mechanism but allows us to print individual scopes and targets from
+within a \c{buildfile}.
There is, however, an important difference to keep in mind: \c{dump} prints
the state of a target or scope at the point in the \c{buildfile} load phase
@@ -4430,6 +4532,9 @@ a result, while the \c{dump} directive should be sufficient in most cases,
sometimes you may need to use the \c{--dump} option to examine the build state
just before rule execution.
+\N|It is possible to limit the output of \c{--dump} to specific scopes and/or
+targets with the \c{--dump-scope} and \c{--dump-target} options.|
+
Let's now move from state to behavior. As we already know, to see the
underlying commands executed by the build system we use the \c{-v} options
(which is equivalent to \c{--verbose\ 2}). Note, however, that these are
@@ -4506,6 +4611,25 @@ Higher verbosity levels result in more and more tracing statements being
printed. These include \c{buildfile} loading and parsing, prerequisite to
target resolution, as well as build system module and rule-specific logic.
+While the tracing statements can be helpful in understanding what is
+happening, they don't make it easy to see why things are happening a
+certain way. In particular, one question that is often encountered during
+build troubleshooting is which dependency chain causes matching or execution
+of a particular target. These questions can be answered with the help of
+the \c{--trace-match} and \c{--trace-execute} options. For example, if we
+want to understand what causes the update of \c{obje{hello\}} in the
+\c{hello} project above:
+
+\
+$ b -s --trace-execute 'obje{hello}'
+info: updating hello/obje{hello}
+ info: using rule cxx.compile
+ info: while updating hello/libue{hello}
+ info: while updating hello/exe{hello}
+ info: while updating dir{hello/}
+ info: while updating dir{./}
+\
+
Another useful diagnostics option is \c{--mtime-check}. When specified, the
build system performs a number of file modification time sanity checks that
can be helpful in diagnosing spurious rebuilds.
@@ -4550,15 +4674,20 @@ cross-compilation (specifically, inability to run tests).
As a result, we recommend using \i{expectation-based} configuration where your
project assumes a feature to be available if certain conditions are
-met. Examples of such conditions at the source code level include feature
-test macros, platform macros, runtime library macros, compiler macros, etc.,
-with the build system modules exposing some of the same information via
-variables to allow making similar decisions in \c{buildfiles}. Another
-alternative is to automatically adapt to missing features using more advanced
-techniques such as C++ SFINAE. And in situations where none of this is
-possible, we recommend delegating the decision to the user via a configuration
-value. Our experience with \c{build2} as well as those of other large
-cross-platform projects such as Boost show that this is a viable strategy.
+met. Examples of such conditions at the source code level include feature test
+macros, platform macros, runtime library macros, compiler macros, etc., with
+the build system modules exposing some of the same information via variables
+to allow making similar decisions in \c{buildfiles}. The standard
+pre-installed \l{https://github.com/build2/libbuild2-autoconf/ \c{autoconf}}
+build system module provides emulation of GNU \c{autoconf} using this
+approach.
+
+Another alternative is to automatically adapt to missing features using more
+advanced techniques such as C++ SFINAE. And in situations where none of this
+is possible, we recommend delegating the decision to the user via a
+configuration value. Our experience with \c{build2} as well as those of other
+large cross-platform projects such as Boost show that this is a viable
+strategy.
Having said that, \c{build2} does provide the ability to extract configuration
information from the environment (\c{$getenv()} function) or other tools
@@ -4673,6 +4802,9 @@ executable target in the \c{<project>%exe{<project>\}} form, the
\c{config.<project>} variable is treated as an alias for
\c{config.import.<project>.<project>.exe}.
+For an imported \c{buildfile}, \c{<project>} may refer to either the importing
+project or the project from which the said \c{buildfile} was imported.
+
The build system core reserves \c{build} and \c{import} as the second
component in configuration variables as well as \c{configured} as the third
and subsequent components.|
@@ -4766,13 +4898,31 @@ is user-defined, then the default value is not evaluated.
Note also that if the configuration value is not specified by the user and you
haven't provided the default, the variable will be undefined, not \c{null},
and, as a result, omitted from the persistent configuration
-(\c{build/config.build} file). However, \c{null} is a valid default value. It
-is traditionally used for \i{optional} configuration values. For example:
+(\c{build/config.build} file). In fact, unlike other variables, project
+configuration variables are by default not \i{nullable}. For example:
+
+\
+$ b configure config.libhello.fancy=[null]
+error: null value in non-nullable variable config.libhello.fancy
+\
+
+There are two ways to make \c{null} a valid value of a project configuration
+variable. Firstly, if the default value is \c{null}, then naturally the
+variable is assumed nullable. This is traditionally used for \i{optional}
+configuration values. For example:
\
config [string] config.libhello.fallback_name ?= [null]
\
+If we need a nullable configuration variable but with a non-\c{null} default
+value (or no default value at all), then we have to use the \c{null} variable
+attribute. For example:
+
+\
+config [string, null] config.libhello.fallback_name ?= \"World\"
+\
+
A common approach for representing an C/C++ enum-like value is to use
\c{string} as a type and pattern matching for validation. In fact, validation
and propagation can often be combined. For example, if our library needed to
@@ -4816,15 +4966,32 @@ if! $defined(config.libhello.database)
fail 'config.libhello.database must be specified'
\
-And if you want to also disallow \c{null} values, then the above check should
-be rewritten like this: \N{An undefined variable expands into a \c{null}
-value.}
+\N|A configuration variable without a default value is omitted from
+\c{config.build} unless the value is specified by the user. This semantics is
+useful for values that are normally derived from other configuration values
+but could also be specified by the user. If the value is derived, then we
+don't want it saved in \c{config.build} since that would prevent it from
+being re-derived if the configuration values it is based on are changed.
+For example:
\
-if ($config.libhello.database == [null])
- fail 'config.libhello.database must be specified'
+config [strings] config.hello.database
+
+assert ($size($config.hello.database) > 0) \
+ 'database must be specified with config.hello.database'
+
+config [bool, config.report.variable=multi] config.hello.multi_database
+
+multi = ($defined(config.hello.multi_database) \
+ ? $config.hello.multi_database \
+ : $size(config.hello.database) > 1)
+
+assert ($multi || $size(config.hello.database) == 1) \
+ 'one database can be specified if config.hello.multi_database=false'
\
+|
+
If computing the default value is expensive or requires elaborate logic, then
the handling of a configuration variable can be broken down into two steps
along these lines:
@@ -4925,9 +5092,96 @@ $ b -v config.libhello.woptions=-Wno-extra
g++ ... -Wall -Wextra -Wno-extra -Werror ...
\
-While we have already seen some examples of how to propagate the configuration
-values to our source code, \l{#proj-config-propag Configuration Propagation}
-discusses this topic in more detail.
+If you do not plan to package your project, then the above rules are the only
+constraints you have. However, if your project is also a package, then other
+projects that use it as a dependency may have preferences and requirements
+regarding its configuration. And it becomes the job of the package manager
+(\c{bpkg}) to negotiate a suitable configuration between all the dependents of
+your project (see \l{bpkg#dep-config-negotiation Dependency Configuration
+Negotiation} for details). This can be a difficult problem to solve optimally
+in a reasonable time and to help the package manager come up with the best
+configuration quickly you should follow the below additional rules and
+recommendations for configuration of packages (but which are also generally
+good ideas):
+
+\ol|
+
+\li|Prefer \c{bool} configuration variables. For example, if your project
+ supports a fixed number of backends, then provide a \c{bool} variable to
+ enable each rather than a single variable that lists all the backends to
+ be enabled.|
+
+\li|Avoid project configuration variable dependencies, that is, where the
+ default value of one variable depends on the value of another. But if you
+ do need such a dependency, make sure it is expressed using the original
+ \c{config.<project>.*} variables rather than any intermediate/computed
+ values. For example:
+
+ \
+ # Enable Y only if X is enabled.
+ #
+ config [bool] config.hello.x ?= false
+ config [bool] config.hello.y ?= $config.libhello.x
+ \
+
+ |
+
+\li|Do not make project configuration variables conditional. In other words,
+ the set of configuration variables and their types should be a static
+ property of the project. If you do need to make a certain configuration
+ variable \"unavailable\" or \"disabled\" if certain conditions are met
+ (for example, on a certain platform or based on the value of another
+ configuration variable), then express this with a default value and/or a
+ check. For example:
+
+ \
+ windows = ($cxx.target.class == 'windows')
+
+ # Y should only be enabled if X is enabled and we are not on
+ # Windows.
+ #
+ config [bool] config.hello.x ?= false
+ config [bool] config.hello.y ?= ($config.hello.x && !$windows)
+
+ if $config.libhello.y
+ {
+ assert $config.hello.x \"Y can only be enabled if X is enabled\"
+ assert (!$windows) \"Y cannot be enabled on Windows\"
+ }
+ \
+
+ |
+
+|
+
+Additionally, if you wish to factor some \c{config} directives into a separate
+file (for example, if you have a large number of them or you would like to
+share them with subprojects) and source it from your \c{build/root.build},
+then it is recommended that you place this file into the \c{build/config/}
+subdirectory, where the package manager expects to find such files (see
+\l{bpkg#package-skeleton Package Build System Skeleton} for background). For
+example:
+
+\
+# root.build
+#
+
+...
+
+source $src_root/build/config/common.build
+\
+
+\N|If you would prefer to keep such a file in a different location (for
+example, because it contains things other than \c{config} directives), then
+you will need to manually list it in your package's \c{manifest} file, see the
+\l{bpkg#manifest-package-build-file \c{build-file}} value for details.|
+
+Another effect of the \c{config} directive is to print the configuration
+variable in the project's configuration report. This functionality is
+discussed in the following section. While we have already seen some examples
+of how to propagate the configuration values to our source code,
+\l{#proj-config-propag Configuration Propagation} discusses this topic in more
+detail.
\h#proj-config-report|Configuration Report|
@@ -5042,6 +5296,29 @@ config libhello@/tmp/libhello/
woptions -Wall -Wextra -Wno-extra -Werror
\
+The \c{config.report.module} attribute can be used to override the reporting
+module name, that is, \c{config} in the \c{config\ libhello@/tmp/libhello/}
+line above. It is primarily useful in imported \c{buildfiles} that wish to
+report non-\c{config.*} variables under their own name. For example:
+
+\
+config [string] config.rtos.board
+
+# Load the board description and report key information such as the
+# capability revoker.
+#
+...
+revoker = ...
+
+config [config.report.module=rtos] revoker
+\
+
+\
+$ b config.rtos.board=ibex-safe-simulator -v
+rtos hello@/tmp/hello/
+ board ibex-safe-simulator
+ revoker hardware
+\
\h#proj-config-propag|Configuration Propagation|
@@ -5311,10 +5588,699 @@ configuration header into two, one public and installed while the other
private.|
+\h1#targets|Targets and Target Types|
+
+\N{This chapter is a work in progress and is incomplete.}
+
+
+\h#targets-types|Target Types|
+
+A target type is part of a target's identity. The core idea behind the concept
+of target types is to abstract away from file extensions which can vary from
+project to project (for example, C++ source files extensions) or from platform
+to platform (for example, executable file extensions). It also allows us to
+have non-file-based targets.
+
+Target types form a \i{base-derived} inheritance tree. The root of this tree
+is the abstract \c{target{\}} type. The \c{build2} core defines a number of
+standard target types, such as \c{file{\}}, \c{doc{\}}, and \c{exe{\}}. Build
+system modules can define additional target types that are based on the
+standard ones (or on types defined by other modules). For example, the \c{c}
+module that provides the C compilation support defines the \c{h{\}} and
+\c{c{\}} target types. Finally, \c{buildfiles} can derive project-local target
+types using the \c{define} directive.
+
+\N|If a target type represents a file type with a well-established extension,
+then by convention such an extension is used as the target type name. For
+example, the C language header and source files use the \c{.h} and \c{.c}
+extensions and the target types are called \c{h{\}} and \c{c{\}}.
+
+Speaking of conventions, as you may have noticed, when mentioning a target
+type we customarily add \c{{\}} after its name. We found that this helps with
+comprehension since target type names are often short (you can also search for
+\c{<type>{} to narrow it down to target types). In a way this is a similar
+approach to adding \c{()} after a function name except here we use \c{{\}},
+which mimics target type usage in target names, for example \c{c{hello\}} for
+\c{hello.c}.|
+
+The following listing shows the hierarchy of the standard target types defined
+by the \c{build2} core (the abstract target types are marked with \c{*}) while
+the following sections describe each standard target type in detail. For
+target types defined by a module refer to the respective module documentation.
+
+\
+ .-----target*------------.
+ | | |
+ mtime_target*---. alias fsdir
+ | | |
+ path_target* group dir
+ |
+ .---------file----.
+ | | |
+ .----doc-----. exe buildfile
+ | | |
+legal man manifest
+ |
+ man<N>
+\
+
+While target types replace (potentially variable) extensions, there still
+needs to be a mechanism for specifying them since in most cases targets have
+to be mapped to files. There are several ways this can be achieved.
+
+If a target type represents a file type with a well-established extension,
+then such an extension is normally used by default and we don't need to take
+any extra steps. For example the \c{h{\}} and \c{c{\}} target types for C
+header and source files default to the \c{.h} and \c{.c} extensions,
+respectively, and if our project follows this convention, then we can simply
+write:
+
+\
+exe{utility}: c{utility} h{utility}
+\
+
+And \c{c{utility\}} will be mapped to \c{utility.c} and \c{h{utility\}} \-
+to \c{utility.h}.
+
+There are two variants of this default extension case: fixed extension and
+customizable extension. A target type may choose to fix the default extension
+if it's a bad idea to deviate from the default extension. A good example of
+such a target is \c{man1{\}}, which fixes the default extension to be
+\c{.1}. More commonly, however, a target will have a default extension but
+will allow customizing it with the \c{extension} variable.
+
+A good example where extension customization is often required are the
+\c{hxx{\}} and \c{cxx{\}} target types for C++ header and source files, which
+default to the \c{.hxx} and \c{.cxx} extensions, respectively. If our project
+uses other extensions, for example, \c{.hpp} and \c{.cpp}, then we can adjust
+the defaults (typically done in \c{root.build}, after loading the \c{cxx}
+module):
+
+\
+hxx{*}: extension = hpp
+cxx{*}: extension = cpp
+\
+
+Then we can write:
+
+\
+exe{utility}: cxx{utility} hxx{utility}
+\
+
+And \c{cxx{utility\}} will be mapped to \c{utility.cpp} and \c{hxx{utility\}}
+\- to \c{utility.hpp}.
+
+What about \c{exe{utility\}}, where does its extension come from? This is an
+example of a target type with an extension that varies from platform to
+platform. In such cases the extension is expected to be assigned by the rule
+that matches the target. In the above example, the link rule from the \c{cxx}
+module that matches updating \c{exe{utility\}} will assign a suitable
+extension based on the target platform of the C++ compiler that it was
+instructed to use.
+
+Finally, it is always possible to specify the file extension explicitly as
+part of the target name. For example:
+
+\
+exe{utility}: cxx{utility.cc} hxx{utility.hh}
+\
+
+This is normally only needed if the default extension is not appropriate or if
+the target type does not have a default extension, as is the case, for
+example, for the \l{#targets-types-file \c{file{\}}} and \l{#targets-types-doc
+\c{doc{\}}} target types. This mechanism can also be used to override the
+automatically derived extension. For example:
+
+\
+exe{($cxx.target.class == 'windows' ? utility.com : utility)}: ...
+\
+
+\N|If you need to specify a name that does not have an extension, then end it
+with a single dot. For example, for a header \c{utility} you would write
+\c{hxx{utility.\}}. If you need to specify a name with an actual trailing dot,
+then escape it with a double dot, for example, \c{hxx{utility..\}}.
+
+More generally, anywhere in a name, a double dot can be used to specify a dot
+that should not be considered the extension separator while a triple dot \-
+which should. For example, in \c{obja{foo.a.o\}} the extension is \c{.o} and
+if instead we wanted \c{.a.o} to be considered the extension, then we could
+rewrite it either as \c{obja{foo.a..o\}} or as \c{obja{foo...a.o\}}.|
+
+To derive a new target type in a \c{buildfile} we use the \c{define}
+directive. Such target types are project-local, meaning they cannot be
+exported to other projects. Typically this is used to provide a more
+meaningful name to a set of files and also avoid having to specify their
+extensions explicitly. Compare:
+
+\
+./: doc{README.md PACKAGE-README.md INSTALL.md}
+\
+
+To:
+
+\
+define md: doc
+doc{*}: extension = md
+
+./: md{README PACKAGE-README INSTALL}
+\
+
+
+\h2#targets-types-target|\c{target{\}}|
+
+The \c{target{\}} target type is a root of the target type hierarchy. It is
+abstract and is not commonly used directly, except perhaps in patterns (target
+type/pattern-specific variable, pattern rules).
+
+
+\h2#targets-types-alias|\c{alias{\}} and \c{dir{\}}|
+
+The \c{alias{\}} target type is used for non-file-based targets that serve as
+aliases for their prerequisite.
+
+\N|Alias targets in \c{build2} are roughly equivalent to phony targets in
+\c{make}.|
+
+For example:
+
+\
+alias{tests}: exe{test1 test2 test3}
+\
+
+\
+$ b test: alias{tests}
+\
+
+An \c{alias{\}} target can also serve as an \"action\" if supplied with an ad
+hoc recipe (or matched by an ad hoc pattern rule). For example:
+
+\
+alias{strip}: exe{hello}
+{{
+ diag strip $<
+ strip $path($<)
+}}
+\
+
+The \c{dir{\}} target type is a special kind of alias that represents a
+directory. Building it means building everything inside the directory. See
+\l{#intro-proj-struct Project Structure} for background.
+
+A target without a type that ends with a directory separator (\c{/}) is
+automatically treated as \c{dir{\}}. For example, the following two lines are
+equivalent:
+
+\
+./: exe{test1 test2}
+dir{./}: exe{test1 test2}
+\
+
+Omitting the target type in such situations is customary.
+
+
+\h2#targets-types-fsdir|\c{fsdir{\}}|
+
+The \c{fsdir{\}} target type represents a filesystem directory. Unlike
+\c{dir{\}} above, it is not an alias and listing an \c{fsdir{\}} directory as
+a prerequisite of a target will cause that directory to be created on
+\c{update} and removed on \c{clean}.
+
+While we usually don't need to list explicit \c{fsdir{\}} prerequisites for
+our targets, one situation where this is necessary is when the target resides
+in a subdirectory that does not correspond to an existing source directory. A
+typical example of this situation is placing object files into subdirectories.
+Compare:
+
+\
+obj{foo}: c{foo}
+sub/obj{bar}: c{bar} fsdir{sub/}
+\
+
+
+\h2#targets-types-mtime-path|\c{mtime_target{\}} and \c{path_target{\}}|
+
+The \c{mtime_target{\}} target type represents a target that uses modification
+times to determine if it is out of date. The \c{path_target{\}} target type
+represents a target that has a corresponding filesystem entry. It is derived
+from \c{mtime_target{\}} and uses the modification time of that filesystem
+entry to determine if the target is out of date.
+
+Both of these target types are abstract and are not commonly used directly,
+except perhaps in patterns (target type/pattern-specific variable, pattern
+rules).
+
+
+\h2#targets-types-group|\c{group{\}}|
+
+The \c{group{\}} target type represents a user-defined explicit target group,
+that is, a target that has multiple member targets that are all built together
+with a single recipe.
+
+Normally this target type is not used to declare targets or prerequisites but
+rather as a base of a derived group. If desired, such a derived group can be
+marked with an attribute as \"see-through\", meaning that when the group is
+listed as a prerequisite of a target, the matching rule \"sees\" its members,
+rather than the group itself. For example:
+
+\
+define [see_through] thrift_cxx: group
+\
+
+
+\h2#targets-types-file|\c{file{\}}|
+
+The \c{file{\}} target type represents a generic file. This target type is
+used as a base for most of the file-based targets and can also be used to
+declare targets and prerequisites when there are no more specific target
+types.
+
+A target or prerequisite without a target type is automatically treated as
+\c{file{\}}. However, omitting a target type in such situations is not
+customary.
+
+The \c{file{\}} target type has no default extension and one cannot be
+assigned with the \c{extension} variable. As a result, if a \c{file{\}} target
+has an extension, then it must be specified explicitly as part of the target
+name. For example:
+
+\
+./: file{example.conf}
+\
+
+\h2#targets-types-doc|\c{doc{\}}, \c{legal{\}}, and \c{man{\}}|
+
+The \c{doc{\}} target type represents a generic documentation file. It has
+semantics similar to \c{file{\}} (from which it derives): it can be used as a
+base or declare targets/prerequisites and there is no default extension. One
+notable difference, however, is that \c{doc{\}} targets are by default
+installed into the \c{doc/} installation location (see \l{#module-install
+\c{install} Module}). For example:
+
+\
+./: doc{README.md ChangeLog.txt}
+\
+
+The \c{legal{\}} target type is derived from \c{doc{\}} and represents a legal
+documentation file, such as a license, copyright notice, authorship
+information, etc. The main purpose of having a separate target type like this
+is to help with installing licensing-related files into a different
+location. To this effect, \c{legal{\}} targets are installed into the
+\c{legal/} installation location, which by default is the same as \c{doc/} but
+can be customized. For example:
+
+\
+./: legal{COPYRIGHT LICENSE AUTHORS.md}
+\
+
+The \c{man{\}} target type is derived from \c{doc{\}} and represents a manual
+page. This target type requires an explicit extension specification and is
+installed into the \c{man/} installation location
+
+\N|If you are using the \c{man{\}} target type directly (instead of one of
+\c{man<N>{\}} described below), for example, to install a localized version of
+a man page, then you will likely need to adjust the installation location
+on the per target basis.|
+
+The \c{man<N>{\}} target types (where \c{<N>} is an integer between 1 and 9)
+are derived from \c{man{\}} and represent manual pages in the respective
+sections. These target types have fixed default extensions \c{.<N>} (but an
+explicit extension can still be specified, for example \c{man1{foo.1p\}}) and
+are installed into the \c{man<N>/} installation locations. For example:
+
+\
+./: man1{foo}
+\
+
+
+\h2#targets-types-exe|\c{exe{\}}|
+
+The \c{exe{\}} target type represents an executable file. Executables in
+\c{build2} appear in two distinct but sometimes overlapping contexts: We can
+build an executable target, for example from C source files. Or we can list an
+executable target as a prerequisite in order to execute it as part of a
+recipe. And sometimes this can be the same executable target. For example,
+one project may build an executable target that is a source code generator and
+another project may import this executable target and use it in its recipes in
+order to generate some source code.
+
+To support this semantics the \c{exe{\}} target type has a peculiar default
+extension logic. Specifically, if the \c{exe{\}} target is \"output\", then
+the extension is expected to be assigned by the matching rule according to the
+target platform for which this executable is built. But if it does not,
+then we fall back to no extension (for example, a script). If, however, the
+\c{exe{\}} target is \"input\" (that is, it's listed as a prerequisite and
+there is no corresponding \"output\" target), then the extension of the host
+platform is used as the default.
+
+In all these cases the extension can also be specified explicitly. This, for
+example, would be necessary if the executable were a batch file:
+
+\
+h{generate}: exe{generate.bat}
+{{
+ diag $< -> $>
+ $< -o $path($>)
+}}
+\
+
+Here, without the explicit extension, the \c{.exe} extension would have been
+used by default.
+
+
+\h1#variables|Variables|
+
+\N{This chapter is a work in progress and is incomplete.}
+
+The following variable/value types can currently be used in \c{buildfiles}:
+
+\
+bool
+
+int64
+int64s
+
+uint64
+uint64s
+
+string
+strings
+string_set
+string_map
+
+path
+paths
+dir_path
+dir_paths
+
+json
+json_array
+json_object
+json_set
+json_map
+
+name
+names
+name_pair
+
+cmdline
+project_name
+target_triplet
+\
+
+Note that while expansions in the target and prerequisite-specific assignments
+happen in the corresponding target and prerequisite contexts, respectively,
+for type/pattern-specific assignments they happen in the scope context. Plus,
+a type/pattern-specific prepend/append is applied at the time of expansion for
+the actual target. For example:
+
+\
+x = s
+
+file{foo}: # target
+{
+ x += t # s t
+ y = $x y # s t y
+}
+
+file{foo}: file{bar} # prerequisite
+{
+ x += p # x t p
+ y = $x y # x t p y
+}
+
+file{b*}: # type/pattern
+{
+ x += w # <append w>
+ y = $x w # <assign s w>
+}
+
+x = S
+
+info $(file{bar}: x) # S w
+info $(file{bar}: y) # s w
+\
+
+
+\h1#functions|Functions|
+
+\N{This chapter is a work in progress and is incomplete.}
+
+
+Functions in \c{build2} are organized into families, such as the
+\c{$string.*()} family for manipulating strings or \c{$regex.*()} for working
+with regular expressions. Most functions are pure and those that are not,
+such as \c{$builtin.getenv()}, are explicitly documented as such.
+
+Some functions, such as from the \c{$regex.*()} family, can only be called
+fully qualified with their family name. For example:
+
+\
+if $regex.match($name, '(.+)-(.+)')
+ ...
+\
+
+While other functions can be called without explicit qualification. For
+example:
+
+\
+path = $getenv('PATH')
+\
+
+There are also functions that can be called unqualified only for certain types
+of arguments (this fact will be reflected in their synopsis and/or
+documentation). Note, however, that every function can always be called
+qualified.
+"
+
+// $builtin.*()
+//
+"
+\h#functions-builtin|Builtin Functions|
+
+The \c{$builtin.*()} function family contains fundamental \c{build2}
+functions.
+"
+source <functions-builtin.cli>;
+
+// $string.*()
+//
+"
+\h#functions-string|String Functions|
+"
+source <functions-string.cli>;
+
+
+// $integer.*()
+//
+"
+\h#functions-integer|Integer Functions|
+"
+source <functions-integer.cli>;
+
+
+// $bool.*()
+//
+"
+\h#functions-bool|Bool Functions|
+"
+source <functions-bool.cli>;
+
+
+// $path.*()
+//
+"
+\h#functions-path|Path Functions|
+
+The \c{$path.*()} function family contains function that manipulating
+filesystem paths.
+"
+source <functions-path.cli>;
+
+
+// $name.*()
+//
+"
+\h#functions-name|Name Functions|
+
+The \c{$name.*()} function family contains function that operate on target and
+prerequisite names. See also the \l{#functions-target \c{$target.*()} function
+family} for functions that operate on actual targets.
+"
+source <functions-name.cli>;
+
+
+// $target.*()
+//
+"
+\h#functions-target|Target Functions|
+
+The \c{$target.*()} function family contains function that operate on
+targets. See also the \l{#functions-name \c{$name.*()} function family} for
+functions that operate on target (and prerequisite) names.
+"
+source <functions-target.cli>;
+
+
+// $regex.*()
+//
+"
+\h#functions-regex|Regex Functions|
+
+The \c{$regex.*()} function family contains function that provide
+comprehensive regular expression matching and substitution facilities. The
+supported regular expression flavor is ECMAScript (more specifically,
+ECMA-262-based C++11 regular expressions).
+
+In the \c{$regex.*()} functions the substitution escape sequences in the
+format string (the \ci{fmt} argument) are extended with a subset of the Perl
+escape sequences: \c{\\n}, \c{\\u}, \c{\\l}, \c{\\U}, \c{\\L}, \c{\\E},
+\c{\\1} ... \c{\\9}, and \c{\\\\}. Note that the standard ECMAScript escape
+sequences (\c{$1}, \c{$2}, \c{$&}, etc) are still supported.
+
+Note that functions from the \c{$regex.*()} family can only be called fully
+qualified with their family name. For example:
+
+\
+if $regex.match($name, '(.+)-(.+)')
+ ...
+\
+
+"
+source <functions-regex.cli>;
+
+// $json.*()
+//
+"
+\h#functions-json|JSON Functions|
+
+The \c{$json.*()} function family contains function that operate on the JSON
+types: \c{json}, \c{json_array}, and \c{json_object}. For example:
+
+\
+j = [json] one@1 two@abc three@([json] x@1 y@-1)
+
+for m: $j
+{
+ n = $member_name($m)
+ v = $member_value($m)
+
+ info $n $value_type($v) $v
+}
+\
+
+"
+source <functions-json.cli>;
+
+
+// $process.*()
+//
+"
+\h#functions-process|Process Functions|
+"
+source <functions-process.cli>;
+
+
+// $filesystem.*()
+//
+"
+\h#functions-filesystem|Filesystem Functions|
+"
+source <functions-filesystem.cli>;
+
+
+// $project_name.*()
+//
+"
+\h#functions-project_name|Project Name Functions|
+
+The \c{$project_name.*()} function family contains function that operate on
+the \c{project_name} type.
+"
+source <functions-project-name.cli>;
+
+
+// $process_path.*()
+//
+"
+\h#functions-process-path|Process Path Functions|
+
+The \c{$process_path.*()} function family contains function that operate on
+the \c{process_path} type and its extended \c{process_path_ex} variant. These
+types describe a path to an executable that, if necessary, has been found in
+\c{PATH}, completed with an extension, etc. The \c{process_path_ex} variant
+includes additional metadata, such as the stable process name for diagnostics
+and the executable checksum for change tracking.
+"
+source <functions-process-path.cli>;
+
+
+// $target_triplet.*()
+//
+"
+\h#functions-target-triplet|Target Triplet Functions|
+
+The \c{$target_triplet.*()} function family contains function that operate on
+the \c{target_triplet} type that represents the ubiquitous
+\c{\i{cpu}-\i{vendor}-\i{os}} target platform triplet.
+"
+source <functions-target-triplet.cli>;
+
+
+"
+\h1#directives|Directives|
+
+\N{This chapter is a work in progress and is incomplete.}
+
+\h#directives-define|\c{define}|
+
+\
+define <derived>: <base>
+\
+
+Define a new target type \c{<derived>} by inheriting from existing target type
+\c{<base>}. See \l{#targets-types Target Types} for details.
+
+
+\h#directives-include|\c{include}|
+
+\
+include <file>
+include <directory>
+\
+
+Load the specified file (the first form) or \c{buildfile} in the specified
+directory (the second form). In both cases the file is loaded in the scope
+corresponding to its directory. Subsequent inclusions of the same file are
+automatically ignored. See also \l{#directives-source \c{source}}.
+
+
+\h#directives-source|\c{source}|
+
+
+\
+source <file>
+\
+
+Load the specified file in the current scope as if its contents were copied
+and pasted in place of the \c{source} directive. Note that subsequent sourcing
+of the same file in the same scope are not automatically ignored. See also
+\l{#directives-include \c{include}}.
+
+
\h1#attributes|Attributes|
\N{This chapter is a work in progress and is incomplete.}
+The only currently recognized target attribute is \c{rule_hint} which
+specifies the rule hint. Rule hints can be used to resolve ambiguity when
+multiple rules match the same target as well as to override an unambiguous
+match. For example, the following rule hint makes sure our executable is
+linked with the C++ compiler even though it only has C sources:
+
+\
+[rule_hint=cxx] exe{hello}: c{hello}
+\
+
\h1#name-patterns|Name Patterns|
@@ -5365,7 +6331,8 @@ Note that some wildcard characters may have special meaning in certain
contexts. For instance, \c{[} at the beginning of a value will be interpreted
as the start of the attribute list while \c{?} and \c{[} in the eval context
are part of the ternary operator and value subscript, respectively. In such
-cases the wildcard character will need to be escaped, for example:
+cases the character will need to be escaped in order to be treated as a
+wildcard, for example:
\
x = \[1-9]-foo.txt
@@ -5454,7 +6421,7 @@ exe{hello}: cxx{+{f* b*} -{foo bar}}
This is particularly useful if you would like to list the names to include or
exclude in a variable. For example, this is how we can exclude certain files
from compilation but still include them as ordinary file prerequisites (so
-that they are still included into the distribution):
+that they are still included into the source distribution):
\
exc = foo.cxx bar.cxx
@@ -5479,17 +6446,25 @@ exe{hello}: cxx{+{$inc} -{$exc}}
One common situation that calls for exclusions is auto-generated source
code. Let's say we have auto-generated command line parser in \c{options.hxx}
-and \c{options.cxx}. Because of the in-tree builds, our name pattern may or
-may not find these files. Note, however, that we cannot just include them as
-non-pattern prerequisites. We also have to exclude them from the pattern match
-since otherwise we may end up with duplicate prerequisites. As a result, this
-is how we have to handle this case provided we want to continue using patterns
-to find other, non-generated source files:
+and \c{options.cxx}. Because of the in/out of source builds, our name pattern
+may or may not find these files. Note, however, that we cannot just include
+them as non-pattern prerequisites. We also have to exclude them from the
+pattern match since otherwise we may end up with duplicate prerequisites. As a
+result, this is how we have to handle this case provided we want to continue
+using patterns to find other, non-generated source files:
\
exe{hello}: {hxx cxx}{* -options} {hxx cxx}{options}
\
+If all our auto-generated source files have a common prefix or suffix, then we
+can exclude them wholesale with a pattern. For example, if all our generated
+files end with the `-options` suffix:
+
+\
+exe{hello}: {hxx cxx}{** -**-options} {hxx cxx}{foo-options bar-options}
+\
+
If the name pattern includes an absolute directory, then the pattern match is
performed in that directory and the generated names include absolute
directories as well. Otherwise, the pattern match is performed in the
@@ -5523,8 +6498,8 @@ patterns/matches that do not already contain an extension. Then the filesystem
search is performed for matching files.
For example, the \c{cxx{\}} target type obtains the default extension from the
-\c{extension} variable. Assuming we have the following line in our
-\c{root.build}:
+\c{extension} variable (see \l{#targets-types Target Types} for background).
+Assuming we have the following line in our \c{root.build}:
\
cxx{*}: extension = cxx
@@ -5548,101 +6523,6 @@ file-based, then the name pattern is returned as is (that is, as an ordinary
name). Project-qualified names are never considered to be patterns.
-\h1#variables|Variables|
-
-\N{This chapter is a work in progress and is incomplete.}
-
-The following variable/value types can currently be used in \c{buildfiles}:
-
-\
-bool
-
-int64
-int64s
-
-uint64
-uint64s
-
-string
-strings
-
-path
-paths
-dir_path
-dir_paths
-
-name
-names
-name_pair
-
-project_name
-target_triplet
-\
-
-Note that while expansions in the target and prerequisite-specific assignments
-happen in the corresponding target and prerequisite contexts, respectively,
-for type/pattern-specific assignments they happen in the scope context. Plus,
-a type/pattern-specific prepend/append is applied at the time of expansion for
-the actual target. For example:
-
-\
-x = s
-
-file{foo}: # target
-{
- x += t # s t
- y = $x y # s t y
-}
-
-file{foo}: file{bar} # prerequisite
-{
- x += p # x t p
- y = $x y # x t p y
-}
-
-file{b*}: # type/pattern
-{
- x += w # <append w>
- y = $x w # <assign s w>
-}
-
-x = S
-
-info $(file{bar}: x) # S w
-info $(file{bar}: y) # s w
-\
-
-
-\h1#directives|Directives|
-
-\N{This chapter is a work in progress and is incomplete.}
-
-\h#directives-include|\c{include}|
-
-\
-include <file>
-include <directory>
-\
-
-Load the specified file (the first form) or \c{buildfile} in the specified
-directory (the second form). In both cases the file is loaded in the scope
-corresponding to its directory. Subsequent inclusions of the same file are
-automatically ignored. See also \l{#directives-source \c{source}}.
-
-
-\h#directives-source|\c{source}|
-
-
-\
-source <file>
-\
-
-Load the specified file in the current scope as if its contents were copied
-and pasted in place of the \c{source} directive. Note that subsequent sourcing
-of the same file in the same scope are not automatically ignored. See also
-\l{#directives-include \c{include}}.
-
-
\h1#module-config|\c{config} Module|
\N{This chapter is a work in progress and is incomplete.}
@@ -5683,12 +6563,12 @@ does not break or produce incorrect results if the environment changes.
Instead, changes to the environment are detected and affected targets are
automatically rebuilt.
-The two use-cases where hermetic configurations are really useful are when we
-need to save an environment which is not generally available (for example, an
-environment of a Visual Studio development command prompt) or when our build
-results need to exactly match the specific configuration (for example, because
-parts of the overall result have already been built and installed, as is the
-case with build system modules).|
+The two use-cases where hermetic configurations are especially useful are when
+we need to save an environment which is not generally available (for example,
+an environment of a Visual Studio development command prompt) or when our
+build results need to exactly match the specific configuration (for example,
+because parts of the overall result have already been built and installed, as
+is the case with build system modules).|
If we now examine \c{config.build}, we will see something along these lines:
@@ -5919,30 +6799,54 @@ of the Introduction, the \c{install} module defines the following standard
installation locations:
\
-name default config.* override
----- ------- -----------------
-root install.root
+name default config.install.*
+ (c.i.*) override
+---- ------- ----------------
+root c.i.root
+
+data_root root/ c.i.data_root
+exec_root root/ c.i.exec_root
-data_root root/ install.data_root
-exec_root root/ install.exec_root
+bin exec_root/bin/ c.i.bin
+sbin exec_root/sbin/ c.i.sbin
+lib exec_root/lib/<private>/ c.i.lib
+libexec exec_root/libexec/<private>/<project>/ c.i.libexec
+pkgconfig lib/pkgconfig/ c.i.pkgconfig
-bin exec_root/bin/ install.bin
-sbin exec_root/sbin/ install.sbin
-lib exec_root/lib/<private>/ install.lib
-libexec exec_root/libexec/<private>/<project>/ install.libexec
-pkgconfig lib/pkgconfig/ install.pkgconfig
+etc data_root/etc/ c.i.etc
+include data_root/include/<private>/ c.i.include
+include_arch include/ c.i.include_arch
+share data_root/share/ c.i.share
+data share/<private>/<project>/ c.i.data
+buildfile share/build2/export/<project>/ c.i.buildfile
-etc data_root/etc/ install.etc
-include data_root/include/<private>/ install.include
-share data_root/share/ install.share
-data share/<private>/<project>/ install.data
+doc share/doc/<private>/<project>/ c.i.doc
+legal doc/ c.i.legal
+man share/man/ c.i.man
+man<N> man/man<N>/ c.i.man<N>
+\
+
+The \c{include_arch} location is meant for architecture-specific files, such
+as configuration headers. By default it's the same as \c{include} but can be
+configured by the user to a different value (for example,
+\c{/usr/include/x86_64-linux-gnu/}) for platforms that support multiple
+architectures from the same installation location. This is how one would
+normally use it from a \c{buildfile}:
-doc share/doc/<private>/<project>/ install.doc
-legal doc/ install.legal
-man share/man/ install.man
-man<N> man/man<N>/ install.man<N>
+\
+# The configuration header may contain target architecture-specific
+# information so install it into include_arch/ instead of include/.
+#
+h{*}: install = include/libhello/
+h{config}: install = include_arch/libhello/
\
+The \c{buildfile} location is meant for exported buildfiles that can be
+imported by other projects. If a project contains any \c{**.build} buildfiles
+in its \c{build/export/} directory (or \c{**.build2} and \c{build2/export/} in
+the alternative naming scheme), then they are automatically installed into
+this location (recreating subdirectories).
+
The \c{<project>}, \c{<version>}, and \c{<private>} substitutions in these
\c{config.install.*} values are replaced with the project name, version, and
private subdirectory, respectively. If either is empty, then the corresponding
@@ -5961,7 +6865,9 @@ The private installation subdirectory is specified with the
directory and may include multiple components. For example:
\
-$ b install config.install.root=/usr/local/ config.install.private=hello/
+$ b install \
+ config.install.root=/usr/local/ \
+ config.install.private=hello/
\
\N|If you are relying on your system's dynamic linker defaults to
@@ -5979,6 +6885,153 @@ $ b install \
|
+
+\h#install-reloc|Relocatable Installation|
+
+A relocatable installation can be moved to a directory other than its original
+installation location. Note that the installation should be moved as a whole
+preserving the directory structure under its root (\c{config.install.root}).
+To request a relocatable installation, set the \c{config.install.relocatable}
+variable to \c{true}. For example:
+
+\
+$ b install \
+ config.install.root=/tmp/install \
+ config.install.relocatable=true
+\
+
+A relocatable installation is achieved by using paths relative to one
+filesystem entry within the installation to locate another. Some examples
+include:
+
+\ul|
+
+\li|Paths specified in \c{config.bin.rpath} are made relative using the
+\c{$ORIGIN} (Linux, BSD) or \c{@loader_path} (Mac OS) mechanisms.|
+
+\li|Paths in the generated \c{pkg-config} files are made relative to the
+\c{${pcfiledir\}} built-in variable.|
+
+\li|Paths in the generated installation manifest (\c{config.install.manifest})
+are made relative to the location of the manifest file.||
+
+While these common aspects are handled automatically, if a projects relies on
+knowing its installation location, then it will most likely need to add manual
+support for relocatable installations.
+
+As an example, consider an executable that supports loading plugins and
+requires the plugin installation directory to be embedded into the executable
+during the build. The common way to support relocatable installations for such
+cases is to embed a path relative to the executable and complete it at
+runtime, normally by resolving the executable's path and using its directory
+as a base.
+
+If you would like to always use the relative path, regardless of whether the
+installation is relocatable of not, then you can obtain the library
+installation directory relative to the executable installation directory like
+this:
+
+\
+plugin_dir = $install.resolve($install.lib, $install.bin)
+\
+
+Alternatively, if you would like to continue using absolute paths for
+non-relocatable installations, then you can use something like this:
+
+\
+plugin_dir = $install.resolve( \
+ $install.lib, \
+ ($install.relocatable ? $install.bin : [dir_path] ))
+\
+
+Finally, if you are unable to support relocatable installations, the correct
+way to handle this is to assert this fact in \c{root.build} of your project,
+for example:
+
+\
+assert (!$install.relocatable) 'relocatable installation not supported'
+\
+
+
+\h#install-filter|Installation Filtering|
+
+While project authors determine what gets installed at the \c{buildfile}
+level, the users of the project can further filter the installation using the
+\c{config.install.filter} variable.
+
+The value of this variable is a list of key-value pairs that specify the
+filesystem entries to include or exclude from the installation. For example,
+the following filters will omit installing headers and static libraries
+(notice the quoting of the wildcard).
+
+\
+$ b install config.install.filter='include/@false \"*.a\"@false'
+\
+
+The key in each pair is a file or directory path or a path wildcard pattern.
+If a key is relative and contains a directory component or is a directory,
+then it is treated relative to the corresponding \c{config.install.*}
+location. Otherwise (simple path, normally a pattern), it is matched against
+the leaf of any path. Note that if an absolute path is specified, it should be
+without the \c{config.install.chroot} prefix.
+
+The value in each pair is either \c{true} (include) or \c{false} (exclude).
+The filters are evaluated in the order specified and the first match that is
+found determines the outcome. If no match is found, the default is to
+include. For a directory, while \c{false} means exclude all the sub-paths
+inside this directory, \c{true} does not mean that all the sub-paths will be
+included wholesale. Rather, the matched component of the sub-path is treated
+as included with the rest of the components matched against the following
+sub-filters. For example:
+
+\
+$ b install config.install.filter='
+ include/x86_64-linux-gnu/@true
+ include/x86_64-linux-gnu/details/@false
+ include/@false'
+\
+
+The \c{true} or \c{false} value may be followed by comma and the \c{symlink}
+modifier to only apply to symlink filesystem entries. For example:
+
+\
+$ b config.install.filter='\"*.so\"@false,symlink'
+\
+
+A filter can be negated by specifying \c{!} as the first pair. For example:
+
+\
+$ b install config.install.filter='! include/@false \"*.a\"@false'
+\
+
+Note that the filtering mechanism only affects what gets physically copied to
+the installation directory without affecting what gets built for install or
+the view of what gets installed at the \c{buildfile} level. For example, given
+the \c{include/@false *.a@false} filters, static libraries will still be built
+(unless arranged not to with \c{config.bin.lib}) and the \c{pkg-config} files
+will still end up with \c{-I} options pointing to the header installation
+directory. Note also that this mechanism applies to both \c{install} and
+\c{uninstall} operations.
+
+\N|If you are familiar with the Debian or Fedora packaging, this mechanism is
+somewhat similar to (and can be used for a similar purpose as) the Debian's
+\c{.install} files and Fedora's \c{%files} spec file sections, which are used
+to split the installation into multiple binary packages.|
+
+As another example, the following filters will omit all the
+development-related files (headers, \c{pkg-config} files, static libraries,
+and shared library symlinks; assuming the platform uses the \c{.a}/\c{.so}
+extensions for the libraries):
+
+\
+$ b install config.install.filter='
+ include/@false
+ pkgconfig/@false
+ \"lib/*.a\"@false
+ \"lib/*.so\"@false,symlink'
+\
+
+
\h1#module-version|\c{version} Module|
A project can use any version format as long as it meets the package version
@@ -6249,7 +7302,7 @@ just not ordered correctly. As a result, we feel that the risks are justified
when the only alternative is manual version management (which is always an
option, nevertheless).
-When we prepare a distribution of a snapshot, the \c{version} module
+When we prepare a source distribution of a snapshot, the \c{version} module
automatically adjusts the package name to include the snapshot information as
well as patches the manifest file in the distribution with the snapshot number
and id (that is, replacing \c{.z} in the version value with the actual
@@ -6280,12 +7333,9 @@ for our \c{libhello} library. To accomplish this we add the \c{version.hxx.in}
template as well as something along these lines to our \c{buildfile}:
\
-lib{hello}: ... hxx{version}
+lib{hello}: {hxx cxx}{** -version} hxx{version}
hxx{version}: in{version} $src_root/file{manifest}
-{
- dist = true
-}
\
The header rule is a line-based preprocessor that substitutes fragments
@@ -6444,6 +7494,116 @@ depends: libprint [3.0.0-b.2.1 3.0.0-b.3)
\N{This chapter is a work in progress and is incomplete.}
+\h#module-bin-target-types|Binary Target Types|
+
+The following listing shows the hierarchy of the target types defined by the
+\c{bin} module while the following sections describe each target type in
+detail (\c{target{\}} and \c{file{\}} are standard target types defined by the
+\c{build2} core; see \l{#targets-types Target Types} for details).
+
+\
+ target----------------.
+ | |
+ ... |
+ | |
+ .---------------file------------. lib
+ | | | | | | libul
+ | libue obje bmie hbmie def obj
+liba libua obja bmia hbmia bmi
+libs libus objs bmis hbmis hbmi
+\
+
+
+\h2#module-bin-target-types-lib|\c{lib{\}}, \c{liba{\}}, \c{libs{\}}|
+
+The \c{liba{\}} and \c{libs{\}} target types represent static (archive) and
+shared libraries, respectively.
+
+The \c{lib{\}} target type is a group with the \c{liba{\}} and/or \c{libs{\}}
+members. A rule that encounters a \c{lib{\}} prerequisite may pick a member
+appropriate for the target being built or it may build all the members
+according to the \c{bin.lib} variable. See \l{#intro-lib Library Exportation
+and Versioning} for background.
+
+The \c{lib*{\}} file extensions are normally automatically assigned by the
+matching rules based on the target platform.
+
+
+\h2#module-bin-target-types-libu|\c{libul{\}}, \c{libue{\}}, \c{libua{\}},
+\c{libus{\}}|
+
+The \c{libu*{\}} target types represent utility libraries. Utility libraries
+are static libraries with object files appropriate for linking an executable
+(\c{libue{\}}), static library (\c{libua{\}}), or shared library
+(\c{libus{\}}). Where possible, utility libraries are built in the
+\"thin archive\" mode.
+
+The \c{libul{\}} target type is a group with the \c{libua{\}} and/or
+\c{libus{\}} members. A rule that encounters a \c{libul{\}} prerequisite picks
+a member appropriate for the target being built.
+
+The \c{libu*{\}} file extensions are normally automatically assigned by the
+matching rules based on the target platform.
+
+
+\h2#module-bin-target-types-obj|\c{obj{\}}, \c{obje{\}}, \c{obja{\}},
+\c{objs{\}}|
+
+The \c{obj*{\}} target types represent object files appropriate for linking an
+executable (\c{obje{\}}), static library (\c{obja{\}}), or shared library
+(\c{objs{\}}).
+
+\N|In \c{build2} we use distinct object files for the three types of binaries
+(executable, static library, and shared library). The distinction between
+static and shared libraries is made to accommodate build differences such as
+the need for position-independent code (\c{-fPIC}) in shared libraries. While
+in most cases the same object file can be used for executables and static
+libraries, they are kept separate for consistency and generality.|
+
+The \c{obj{\}} target type is a group with the \c{obje{\}}, and/or
+\c{obja{\}}, and/or \c{objs{\}} members. A rule that encounters an \c{obj{\}}
+prerequisite picks a member appropriate for the target being built.
+
+The \c{obj*{\}} file extensions are normally automatically assigned by the
+matching rules based on the target platform.
+
+
+\h2#module-bin-target-types-bmi|\c{bmi{\}}, \c{bmie{\}}, \c{bmia{\}},
+\c{bmis{\}}|
+
+The \c{bmi*{\}} target types represent binary module interfaces (BMI) for
+C++20 named modules appropriate for linking an executable (\c{bmie{\}}),
+static library (\c{bmia{\}}), or shared library (\c{bmis{\}}).
+
+The \c{bmi{\}} target type is a group with the \c{bmie{\}}, and/or
+\c{bmia{\}}, and/or \c{bmis{\}} members. A rule that encounters an \c{bmi{\}}
+prerequisite picks a member appropriate for the target being built.
+
+The \c{bmi*{\}} file extensions are normally automatically assigned by the
+matching rules based on the target platform.
+
+
+\h2#module-bin-target-types-hbmi|\c{hbmi{\}}, \c{hbmie{\}}, \c{hbmia{\}},
+\c{hbmis{\}}|
+
+The \c{hbmi*{\}} target types represent binary module interfaces (BMI) for
+C++20 header units appropriate for linking an executable (\c{hbmie{\}}),
+static library (\c{hbmia{\}}), or shared library (\c{hbmis{\}}).
+
+The \c{hbmi{\}} target type is a group with the \c{hbmie{\}}, and/or
+\c{hbmia{\}}, and/or \c{hbmis{\}} members. A rule that encounters an
+\c{hbmi{\}} prerequisite picks a member appropriate for the target being
+built.
+
+The \c{hbmi*{\}} file extensions are normally automatically assigned by the
+matching rules based on the target platform.
+
+
+\h2#module-bin-target-types-def|\c{def{\}}|
+
+The \c{def{\}} target type represents Windows module definition files and has
+the fixed default extension \c{.def}.
+
\h1#module-cc|\c{cc} Module|
@@ -6459,12 +7619,12 @@ config.c
config.cxx
cc.id
- c.target
- c.target.cpu
- c.target.vendor
- c.target.system
- c.target.version
- c.target.class
+ cc.target
+ cc.target.cpu
+ cc.target.vendor
+ cc.target.system
+ cc.target.version
+ cc.target.class
config.cc.poptions
cc.poptions
@@ -6483,6 +7643,11 @@ config.cc.libs
config.cc.internal.scope
cc.internal.scope
+
+config.cc.reprocess
+ cc.reprocess
+
+config.cc.pkgconfig.sysroot
\
Note that the compiler mode options are \"cross-hinted\" between \c{config.c}
@@ -6498,6 +7663,41 @@ $ b config.cxx=\"g++ -m32\"
$ b config.cxx=\"clang++ -stdlib=libc++\"
\
+\h#cc-target-types|C-Common Target Types|
+
+The following listing shows the hierarchy of the target types defined by the
+\c{cc} module while the following sections describe each target type in detail
+(\c{file{\}} is a standard target type defined by the \c{build2} core; see
+\l{#targets-types Target Types} for details). Every \c{cc}-based module (such
+as \c{c} and \c{cxx}) will have these common target types defined in addition
+to the language-specific ones.
+
+\
+.--file--.
+| |
+h pc
+ |
+ pca
+ pcs
+\
+
+\N|While the \c{h{\}} target type represents a C header file, there is hardly
+a C-family compilation without a C header inclusion. As a result, this target
+types is defined by all \c{cc}-based modules.|
+
+For the description of the \c{h{\}} target type refer to \l{#c-target-types-c
+\c{c{\}}, \c{h{\}}} in the C module documentation.
+
+\h2#cc-target-types-pc|\c{pc{\}}, \c{pca{\}}, \c{pcs{\}}|
+
+The \c{pc*{\}} target types represent \c{pkg-config} files. The \c{pc{\}}
+target type represents the common file and has the fixed default extension
+\c{.pc}. The \c{pca{\}} and \c{pcs{\}} target types represent the static and
+shared files and have the fixed default extensions \c{.static.pc} and
+\c{.shared.pc}, respectively. See \l{#cc-import-installed Importation of
+Installed Libraries} for background.
+
+
\h#cc-internal-scope|Compilation Internal Scope|
\N|While this section uses the \c{cxx} module and C++ compilation as an
@@ -6651,7 +7851,7 @@ symbols for all the Windows targets/compilers using the following arrangement
\
lib{foo}: libul{foo}: {hxx cxx}{**} ...
-lib{foo}: def{foo}: include = ($cxx.target.system == 'win32-msvc')
+libs{foo}: def{foo}: include = ($cxx.target.system == 'win32-msvc')
def{foo}: libul{foo}
if ($cxx.target.system == 'mingw32')
@@ -6661,6 +7861,9 @@ if ($cxx.target.system == 'mingw32')
That is, we use the \c{.def} file approach for MSVC (including when building
with Clang) and the built-in support (\c{--export-all-symbols}) for MinGW.
+\N|You will likely also want to add the generated \c{.def} file (or the
+blanket \c{*.def}) to your \c{.gitignore} file.|
+
Note that it is also possible to use the \c{.def} file approach for MinGW. In
this case we need to explicitly load the \c{bin.def} module (which should be
done after loading \c{c} or \c{cxx}) and can use the following arrangement:
@@ -6677,7 +7880,7 @@ if ($cxx.target.class == 'windows')
\
lib{foo}: libul{foo}: {hxx cxx}{**} ...
-lib{foo}: def{foo}: include = ($cxx.target.class == 'windows')
+libs{foo}: def{foo}: include = ($cxx.target.class == 'windows')
def{foo}: libul{foo}
\
@@ -6688,6 +7891,169 @@ to the symbol auto-importing support in Windows linkers. Note, however, that
auto-importing only works for functions and not for global variables.
+\h#cc-import-installed|Importation of Installed Libraries|
+
+As discussed in \l{#intro-import Target Importation}, searching for installed
+C/C++ libraries is seamlessly integrated into the general target importation
+mechanism. This section provides more details on the installed library search
+semantics and \c{pkg-config} integration. These details can be particularly
+useful when dealing with libraries that were not built with \c{build2} and
+which often use idiosyncratic \c{pkg-config} file names.
+
+The \c{cc}-based modules use the common installed library search
+implementation with the following semantics. To illustrate the finer points,
+we assume the following import:
+
+\
+import libs = libbar%lib{Xfoo}
+\
+
+\ol|
+
+\li|First, the ordered list of library search directories is obtained by
+combining two lists: the lists of the compiler's system library search
+directories (extracted, for example, with \c{-print-search-dirs} GCC/Clang
+options) and the list of user library search directories (specified, for
+example, with the \c{-L} options in \c{*.loptions}).
+
+The key property of this combined list is that it matches the search semantics
+that would be used by the compiler to find libraries specified with the \c{-l}
+option during linking.|
+
+\li|Given the list obtained in the previous step, a library binary (shared
+and/or static library) is searched for in the correct order and using the
+target platform-appropriate library prefix and extension (for example, \c{lib}
+prefix and the \c{.so}/\c{.a} extensions if targeting Linux).
+
+For example (continuing with the above import and assuming Linux), each
+directory will be checked for the presence of \c{libXfoo.so} and \c{libXfoo.a}
+(where the \c{Xfoo} stem is the imported target name).
+
+If only a shared or static binary is found in a given directory, no further
+directories are checked for the missing variant. Instead, the missing
+variant is assumed to be unavailable.
+
+If neither a shared nor static library is found in a given directory, then
+it is also checked for the presence of the corresponding \c{pkg-config}
+file as in the following step. If such a file is found, then the library is
+assumed to be \i{binless} (header-only, etc).|
+
+\li|If a static and/or shared library is found (or if looking for a binless
+library), the corresponding \c{pkg-config} subdirectory (normally just
+\c{pkgconfig/}) is searched for the library's \c{.pc} file.
+
+More precisely, we first look for the \c{.static.pc} file for a static
+library and for the \c{.shared.pc} file for a shared library falling back
+to the common \c{.pc} if they don't exist.
+
+\N|It is often required to use different options for consuming static and
+shared libraries. While there is the \c{Libs.private} and \c{Cflags.private}
+mechanism in \c{pkg-config}, its semantics is to append options to \c{Libs}
+and \c{Cflags} rather than to provide alternative options. And often the
+required semantics is to provide different options for static and shared
+libraries, such as to provide a macro which indicates whether linking static
+or shared in order to setup symbol exporting.
+
+As a result, in \c{build2} we produce separate \c{.pc} files for static and
+shared libraries in addition to the \"best effort\" common \c{.pc} file for
+compatibility with other build systems. Similarly, when consuming a library
+we first look for the \c{.static.pc} and \c{.shared.pc} files falling back
+to the common \c{.pc} if they are not available.|
+
+To deal with idiosyncrasies in \c{pkg-config} file names, the following base
+names are tried in order, where \ci{name} is the imported target name
+(\c{Xfoo} in the above import), \ci{proj} is the imported project name
+(\c{libbar} in the above import), and \ci{ext} is one of the above-mentioned
+\c{pkg-config} extensions (\c{static.pc}, \c{shared.pc}, or \c{pc}). The
+concrete name tried for the above import is shown in parenthesis as an
+example.
+
+\ol|
+
+\li|\c{lib\i{name}.\i{ext}} (\c{libXfoo.pc})|
+
+\li|\c{\i{name}.\i{ext}} (\c{Xfoo.pc})|
+
+\li|lowercase \c{lib\i{name}.\i{ext}} (\c{libxfoo.pc})|
+
+\li|lowercase \c{\i{name}.\i{ext}} (\c{xfoo.pc})|
+
+\li|\c{\i{proj}.\i{ext}} (\c{libbar.pc}; this test is omitted if not project-qualified)||
+
+||
+
+In particular, the last try (for \c{\i{proj}.\i{ext}}) serves as an escape
+hatch for cases where the \c{.pc} file name does not have anything to do with
+the names of library binaries. The canonical example of this is \c{zlib} which
+names its library binaries \c{libz.so}/\c{libz.a} while its \c{.pc} file \-
+\c{zlib.pc}. To be able to import \c{zlib} that was not built with \c{build2},
+we have to use the following import:
+
+\
+import libs = zlib%lib{z}
+\
+
+Note also that these complex rules (which are unfortunately necessary to deal
+with the lack of any consistency in \c{.pc} file naming) can sometimes produce
+surprising interactions. For example, it may appear that a clearly incorrect
+import nevertheless appears to somehow work, as in the following example:
+
+\
+import libs = zlib%lib{znonsense}
+\
+
+What happens here is that while no library binary is found, \c{zlib.pc} is
+found and as a result the library ends up being considered binless with the
+\c{-lz} (that is found in the \c{Libs} value of \c{zlib.pc}) treated as a
+prerequisite library, resolved using the above algorithm, and linked. In other
+words, in this case we end up with a binless library \c{lib{znonsense\}} that
+depends on \c{lib{z\}} instead of a single \c{lib{z\}} library.
+
+\h2#cc-import-installed-sysroot|Rewriting Installed Libraries System Root (sysroot)|
+
+Sometimes the installed libraries are moved to a different location after the
+installation. This is especially common in embedded development where the code
+is normally cross-compiled and the libraries for the target platform are
+placed into a host directory, called system root or \i{sysroot}, that doesn't
+match where these libraries were originally installed to. For example, the
+libraries might have been installed into \c{/usr/} but on the host machine
+they may reside in \c{/opt/target/usr/}. In this example, \c{/opt/target/} is
+the sysroot.
+
+While such relocations usually do not affect the library headers or binaries,
+they do break the \c{pkg-config}'s \c{.pc} files which often contain \c{-I}
+and \c{-L} options with absolute paths. Continue with the above example, a
+\c{.pc} file as originally installed may contain \c{-I/usr/include} and
+\c{-L/usr/lib} while now, that the libraries have been relocated to
+\c{/opt/target/}, they somehow need to be adjusted to
+\c{-I/opt/target/usr/include} and \c{-L/opt/target/usr/lib}.
+
+While it is possible (and perhaps correct) to accomplish this by fixing the
+\c{.pc} files to match the new location, it is not always possible or easy.
+As a result, \c{build2} provides a mechanism for automatically adjusting the
+system root in the \c{-I} and \c{-L} options extracted from \c{.pc} files.
+
+\N|This functionality is roughly equivalent to that provided with the
+\c{PKG_CONFIG_SYSROOT_DIR} environment variable by the \c{pkg-config}
+utility.|
+
+Specifically, the \c{config.cc.pkgconfig.sysroot} variable can be used to
+specify an alternative system root. When specified, all absolute paths in the
+\c{-I} and \c{-L} options that are not already in this directory will be
+rewritten to start with this sysroot.
+
+\N|Note that this mechanism is a workaround rather than a proper solution since
+it is limited to the \c{-I} and \c{-L} options. In particular, it does not
+handle any other options that may contain absolute paths nor \c{pkg-config}
+variables that may be queried.
+
+As a result, it should only be used for dealing with issues in third-party
+\c{.pc} files that do not handle relocation (for example, using the
+\c{${pcfiledir\}} built-in \c{pkg-config} variable). In particular, for
+\c{build2}-generated \c{.pc} files a \l{#install-reloc relocatable
+installation} should be used instead.|
+
+
\h#cc-gcc|GCC Compiler Toolchain|
The GCC compiler id is \c{gcc}.
@@ -6916,6 +8282,185 @@ config.c.internal.scope
c.internal.scope
\
+\h#c-target-types|C Target Types|
+
+The following listing shows the hierarchy of the target types defined by the
+\c{c} module while the following sections describe each target type in detail
+(\c{file{\}} is a standard target type defined by the \c{build2} core; see
+\l{#targets-types Target Types} for details). See also \l{#cc-target-types
+C-Common Target Types} for target types defined by all the \c{cc}-based
+modules.
+
+\
+.--file--.
+| | |
+c m S
+h
+\
+
+The \c{m{\}} target type represents an Objective-C source file, see \l{c-objc
+Objective-C Compilation} for details.
+
+The \c{S{\}} target type represents an Assembler with C Preprocessor file, see
+\l{c-as-cpp Assembler with C Preprocessor Compilation} for details.
+
+\h2#c-target-types-c|\c{c{\}}, \c{h{\}}|
+
+The \c{c{\}} and \c{h{\}} target types represent C source and header files.
+They have the default extensions \c{.c} and \c{.h}, respectively, which can
+be customized with the \c{extension} variable.
+
+
+\h#c-objc|Objective-C Compilation|
+
+The \c{c} module provides the \c{c.objc} submodule which can be loaded in
+order to register the \c{m{\}} target type and enable Objective-C compilation
+in the \c{C} compile rule. Note that \c{c.objc} must be loaded after the \c{c}
+module and while the \c{m{\}} target type is registered unconditionally,
+compilation is only enabled if the C compiler supports Objective-C for the
+target platform. Typical usage:
+
+\
+# root.build
+#
+using c
+using c.objc
+\
+
+\
+# buildfile
+#
+lib{hello}: {h c}{*}
+lib{hello}: m{*}: include = ($c.target.class == 'macos')
+\
+
+Note also that while there is support for linking Objective-C executables and
+libraries, this is done using the C compiler driver and no attempt is made to
+automatically link any necessary Objective-C runtime library (such as
+\c{-lobjc}).
+
+
+\h#c-as-cpp|Assembler with C Preprocessor Compilation|
+
+The \c{c} module provides the \c{c.as-cpp} submodule which can be loaded in
+order to register the \c{S{\}} target type and enable Assembler with C
+Preprocessor compilation in the \c{C} compile rule. Note that \c{c.as-cpp}
+must be loaded after the \c{c} module and while the \c{S{\}} target type is
+registered unconditionally, compilation is only enabled if the C compiler
+supports Assembler with C Preprocessor compilation. Typical usage:
+
+\
+# root.build
+#
+using c
+using c.as-cpp
+\
+
+\
+# buildfile
+#
+exe{hello}: {h c}{* -hello.c}
+
+# Use C implementation as a fallback if no assembler.
+#
+assembler = ($c.class == 'gcc' && $c.target.cpu == 'x86_64')
+
+exe{hello}: S{hello}: include = $assembler
+exe{hello}: c{hello}: include = (!$assembler)
+\
+
+\
+/* hello.S
+ */
+#ifndef HELLO_RESULT
+# define HELLO_RESULT 0
+#endif
+
+text
+
+.global hello
+hello:
+ /* ... */
+ movq $HELLO_RESULT, %rax
+ ret
+
+#ifdef __ELF__
+.section .note.GNU-stack, \"\", @progbits
+#endif
+\
+
+The default file extension for the \c{S{\}} target type is \c{.S} (capital)
+but that can be customized using the standard mechanisms. For example:
+
+\
+# root.build
+#
+using c
+using c.as-cpp
+
+h{*}: extension = h
+c{*}: extension = c
+S{*}: extension = sx
+\
+
+Note that \c{*.coptions} are passed to the C compiler when compiling Assembler
+with C Preprocessor files because compile options may cause additional
+preprocessor macros to be defined. Plus, some of them (such as \c{-g}) are
+passed (potentially translated) to the underlying assembler. To pass
+additional options when compiling Assembler files use \c{c.poptions} and
+\c{c.coptions}. For example (continuing with the previous example):
+
+\
+if $assembler
+{
+ obj{hello}:
+ {
+ c.poptions += -DHELLO_RESULT=1
+ c.coptions += -Wa,--no-pad-sections
+ }
+}
+\
+
+\h#c-predefs|C Compiler Predefined Macro Extraction|
+
+The \c{c} module provides the \c{c.predefs} submodule which can be loaded in
+order to register a rule that generates a C header with predefined compiler
+macros. Note that the \c{c.predefs} module must be loaded after the \c{c}
+module and the rule will only match with an explicit rule hint. Typical usage:
+
+\
+# root.build
+#
+using c
+using c.predefs
+\
+
+\
+# buildfile
+#
+[rule_hint=c.predefs] h{predefs}:
+\
+
+Note also that the MSVC compiler only supports the predefined macro extraction
+starting from Visual Studio 2019 (16.0; \c{cl.exe} version 19.20). If support
+for earlier versions is required, then you will need to provide a fallback
+implementation appropriate for your project. For example:
+
+\
+[rule_hint=c.predefs] h{predefs}:
+% update
+if ($c.id == 'msvc' && \
+ ($c.version.major < 19 || \
+ ($c.version.major == 19 && $c.version.minor < 20)))
+{{
+ diag c-predefs $>
+
+ cat <<EOF >$path($>)
+ #define _WIN32
+ EOF
+}}
+\
+
\h1#module-cxx|\c{cxx} Module|
@@ -6984,6 +8529,45 @@ config.cxx.translate_include
\
+\h#cxx-target-types|C++ Target Types|
+
+The following listing shows the hierarchy of the target types defined by the
+\c{cxx} module while the following sections describe each target type in
+detail (\c{file{\}} is a standard target type defined by the \c{build2} core;
+see \l{#targets-types Target Types} for details). See also \l{#cc-target-types
+C-Common Target Types} for target types defined by all the \c{cc}-based
+modules.
+
+\
+ .--file--.
+ | |
+cxx mm
+hxx
+ixx
+txx
+mxx
+\
+
+The \c{mm{\}} target type represents an Objective-C++ source file, see
+\l{cxx-objcxx Objective-C++ Compilation} for details.
+
+\h2#cxx-target-types-cxx|\c{cxx{\}}, \c{hxx{\}}, \c{ixx{\}}, \c{txx{\}},
+\c{mxx{\}}|
+
+The \c{cxx{\}}, \c{hxx{\}}, \c{ixx{\}}, \c{txx{\}}, and \c{mxx{\}} target
+types represent C++ source, header, inline, template, and module interface
+files. They have the default extensions \c{.cxx}, \c{.hxx}, \c{.ixx},
+\c{.txx}, and \c{.mxx}, respectively, which can be customized with the
+\c{extension} variable. For example (normally done in \c{root.build}):
+
+\
+using cxx
+
+cxx{*}: extension = cpp
+hxx{*}: extension = hpp
+mxx{*}: extension = cppm
+\
+
\h#cxx-modules|C++ Modules Support|
This section describes the build system support for C++ modules.
@@ -7121,7 +8705,7 @@ module implementation units appears reasonable and that's what we recommend.
A module declaration (exporting or non-exporting) starts a \i{module purview}
that extends until the end of the module translation unit. Any name declared
-in a module's purview \i{belongs} to said module. For example:
+in a module's purview \i{belongs} to the said module. For example:
\
#include <string> // Not in purview.
@@ -7291,7 +8875,7 @@ say_hello (const std::string&);
\
One way to think of a re-export is \i{as if} an import of a module also
-\"injects\" all the imports said module re-exports, recursively. That's
+\"injects\" all the imports the said module re-exports, recursively. That's
essentially how most compilers implement it.
Module re-export is the mechanism for assembling bigger modules out of
@@ -7689,7 +9273,7 @@ header-like search mechanism (\c{-I} paths, etc.), an explicit list of
exported modules is provided for each library in its \c{.pc} (\c{pkg-config})
file.
-Specifically, the library's \c{.pc} file contains the \c{cxx_modules} variable
+Specifically, the library's \c{.pc} file contains the \c{cxx.modules} variable
that lists all the exported C++ modules in the \c{<name>=<path>} form with
\c{<name>} being the module's C++ name and \c{<path>} \- the module interface
file's absolute path. For example:
@@ -7700,15 +9284,15 @@ Version: 1.0.0
Cflags:
Libs: -L/usr/lib -lhello
-cxx_modules = hello.core=/usr/include/hello/core.mxx hello.extra=/usr/include/hello/extra.mxx
+cxx.modules = hello.core=/usr/include/hello/core.mxx hello.extra=/usr/include/hello/extra.mxx
\
Additional module properties are specified with variables in the
-\c{cxx_module_<property>.<name>} form, for example:
+\c{cxx.module_<property>.<name>} form, for example:
\
-cxx_module_symexport.hello.core = true
-cxx_module_preprocessed.hello.core = all
+cxx.module_symexport.hello.core = true
+cxx.module_preprocessed.hello.core = all
\
Currently, two properties are defined. The \c{symexport} property with the
@@ -8569,6 +10153,77 @@ macros may not be needed by all consumers. This way we can also keep the
header macro-only which means it can be included freely, in or out of module
purviews.
+\h#cxx-objcxx|Objective-C++ Compilation|
+
+The \c{cxx} module provides the \c{cxx.objcxx} submodule which can be loaded
+in order to register the \c{mm{\}} target type and enable Objective-C++
+compilation in the \c{C++} compile rule. Note that \c{cxx.objcxx} must be
+loaded after the \c{cxx} module and while the \c{mm{\}} target type is
+registered unconditionally, compilation is only enabled if the C++ compiler
+supports Objective-C++ for the target platform. Typical usage:
+
+\
+# root.build
+#
+using cxx
+using cxx.objcxx
+\
+
+\
+# buildfile
+#
+lib{hello}: {hxx cxx}{*}
+lib{hello}: mm{*}: include = ($cxx.target.class == 'macos')
+\
+
+Note also that while there is support for linking Objective-C++ executables
+and libraries, this is done using the C++ compiler driver and no attempt is
+made to automatically link any necessary Objective-C runtime library (such as
+\c{-lobjc}).
+
+
+\h#cxx-predefs|C++ Compiler Predefined Macro Extraction|
+
+The \c{cxx} module provides the \c{cxx.predefs} submodule which can be loaded
+in order to register a rule that generates a C++ header with predefined
+compiler macros. Note that the \c{cxx.predefs} module must be loaded after the
+\c{cxx} module and the rule will only match with an explicit rule
+hint. Typical usage:
+
+\
+# root.build
+#
+using cxx
+using cxx.predefs
+\
+
+\
+# buildfile
+#
+[rule_hint=cxx.predefs] hxx{predefs}:
+\
+
+Note also that the MSVC compiler only supports the predefined macro extraction
+starting from Visual Studio 2019 (16.0; \c{cl.exe} version 19.20). If support
+for earlier versions is required, then you will need to provide a fallback
+implementation appropriate for your project. For example:
+
+\
+[rule_hint=cxx.predefs] hxx{predefs}:
+% update
+if ($cxx.id == 'msvc' && \
+ ($cxx.version.major < 19 || \
+ ($cxx.version.major == 19 && $cxx.version.minor < 20)))
+{{
+ diag c++-predefs $>
+
+ cat <<EOF >$path($>)
+ #define _WIN32
+ #define __cplusplus 201402L
+ EOF
+}}
+\
+
\h1#module-in|\c{in} Module|
@@ -8636,13 +10291,13 @@ symbol is expected to start a substitution with unresolved (to a variable
value) names treated as errors. The double substitution symbol (for example,
\c{$$}) serves as an escape sequence.
-The substitution mode can be relaxed using the \c{in.substitution} variable.
-Its valid values are \c{strict} (default) and \c{lax}. In the lax mode a pair
-of substitution symbols is only treated as a substitution if what's between
-them looks like a build system variable name (that is, it doesn't contain
-spaces, etc). Everything else, including unterminated substitution symbols, is
-copied as is. Note also that in this mode the double substitution symbol is
-not treated as an escape sequence.
+The substitution mode can be relaxed using the \c{in.mode} variable. Its
+valid values are \c{strict} (default) and \c{lax}. In the lax mode a pair of
+substitution symbols is only treated as a substitution if what's between them
+looks like a build system variable name (that is, it doesn't contain spaces,
+etc). Everything else, including unterminated substitution symbols, is copied
+as is. Note also that in this mode the double substitution symbol is not
+treated as an escape sequence.
The lax mode is mostly useful when trying to reuse existing \c{.in} files from
other build systems, such as \c{autoconf}. Note, however, that the lax mode is
@@ -8655,7 +10310,7 @@ substitutions as is. For example:
h{config}: in{config} # config.h.in
{
in.symbol = '@'
- in.substitution = lax
+ in.mode = lax
CMAKE_SYSTEM_NAME = $c.target.system
CMAKE_SYSTEM_PROCESSOR = $c.target.cpu
@@ -8669,6 +10324,42 @@ target-specific variables. Typed variable values are converted to string
using the corresponding \c{builtin.string()} function overload before
substitution.
+While specifying substitution values as \c{buildfile} variables is usually
+natural, sometimes this may not be possible or convenient. Specifically, we
+may have substitution names that cannot be specified as \c{buildfile}
+variables, for example, because they start with an underscore (and are thus
+reserved) or because they refer to one of the predefined variables. Also, we
+may need to have different groups of substitution values for different cases,
+for example, for different platforms, and it would be convenient to pass such
+groups around as a single value.
+
+To support these requirements the substitution values can alternatively be
+specified as key-value pairs in the \c{in.substitutions} variable. Note that
+entries in this substitution map take precedence over the \c{buildfile}
+variables. For example:
+
+\
+/* config.h.in */
+
+#define _GNU_SOURCE @_GNU_SOURCE@
+#define _POSIX_SOURCE @_POSIX_SOURCE@
+\
+
+\
+# buildfile
+
+h{config}: in{config}
+{
+ in.symbol = '@'
+ in.mode = lax
+
+ in.substitutions = _GNU_SOURCE@0 _POSIX_SOURCE@1
+}
+\
+
+\N|In the above example, the \c{@} characters in \c{in.symbol} and
+\c{in.substitutions} are unrelated.|
+
Using an undefined variable in a substitution is an error. Using a \c{null}
value in a substitution is also an error unless the fallback value is
specified with the \c{in.null} variable. For example:
@@ -8682,11 +10373,21 @@ h{config}: in{config}
}
\
-A number of other build system modules, for example, \l{#module-version
-\c{version}} and \l{#module-bash \c{bash}}, are based on the \c{in} module and
-provide extended functionality. The \c{in} preprocessing rule matches any
-\c{file{\}}-based target that has the corresponding \c{in{\}} prerequisite
-provided none of the extended rules match.
+\N|To specify a \c{null} value using the \c{in.substitutions} mechanism omit
+the value, for example:
+
+\
+in.substitutions = _GNU_SOURCE
+\
+
+|
+
+A number of other build system modules, for example,
+\l{https://github.com/build2/libbuild2-autoconf/ \c{autoconf}},
+\l{#module-version \c{version}}, and \l{#module-bash \c{bash}}, are based on
+the \c{in} module and provide extended functionality. The \c{in} preprocessing
+rule matches any \c{file{\}}-based target that has the corresponding \c{in{\}}
+prerequisite provided none of the extended rules match.
\h1#module-bash|\c{bash} Module|
@@ -8739,11 +10440,12 @@ buildfiles.
The \c{say-hello.bash} module is \i{imported} by the \c{hello} script with the
\c{@import\ hello/say-hello@} substitution. The \i{import path}
-(\c{hello/say-hello} in our case) is a relative path to the module file within
-the project. Its first component (\c{hello} in our case) must be the project
-base name and the \c{.bash} module extension can be omitted. \N{The constraint
-placed on the first component of the import path is required to implement
-importation of installed modules, as discussed below.}
+(\c{hello/say-hello} in our case) is a path to the module file within the
+project. Its first component (\c{hello} in our case) must be both the project
+name and the top-level subdirectory within the project. The \c{.bash} module
+extension can be omitted. \N{The constraint placed on the first component of
+the import path is required to implement importation of installed modules, as
+discussed below.}
During preprocessing, the import substitution will be replaced with a
\c{source} builtin call and the import path resolved to one of the \c{bash{\}}
@@ -8762,11 +10464,12 @@ OS. The script, however, can provide a suitable implementation as a function.
See the \c{bash} module tests for a sample implementation of such a function.|
By default, \c{bash} modules are installed into a subdirectory of the \c{bin/}
-installation directory named as the project base name. For instance, in the
-above example, the script will be installed as \c{bin/hello} and the module as
-\c{bin/hello/say-hello.bash} with the script sourcing the module relative to
-the \c{bin/} directory. Note that currently it is assumed the script and all
-its modules are installed into the same \c{bin/} directory.
+installation directory named as the project name plus the \c{.bash} extension.
+For instance, in the above example, the script will be installed as
+\c{bin/hello} and the module as \c{bin/hello.bash/say-hello.bash} with the
+script sourcing the module relative to the \c{bin/} directory. Note that
+currently it is assumed the script and all its modules are installed into the
+same \c{bin/} directory.
Naturally, modules can import other modules and modules can be packaged into
\i{module libraries} and imported using the standard build system import
@@ -8831,10 +10534,11 @@ by searching in the \c{PATH} environment variable.
By convention, \c{bash} module libraries should use the \c{lib} name prefix,
for example, \c{libhello}. If there is also a native library (that is, one
written in C/C++) that provides the same functionality (or the \c{bash}
-library is a language binding for said library), then it is customary to add
-the \c{.bash} extension to the \c{bash} library name, for example,
-\c{libhello.bash}. Note that in this case the project base name is
-\c{libhello}.
+library is a language binding for the said library), then it is customary to
+add the \c{.bash} extension to the \c{bash} library name, for example,
+\c{libhello.bash}. Note that in this case the top-level subdirectory within
+the project is expected to be called without the \c{bash} extension, for
+example, \c{libhello}.
Modules can be \i{private} or \i{public}. Private modules are implementation
details of a specific project and are not expected to be imported from other
@@ -8881,4 +10585,498 @@ corresponding \c{in{\}} and one or more \c{bash{\}} prerequisites as well as
\c{bash{\}} targets that have the corresponding \c{in{\}} prerequisite (if you
need to preprocess a script that does not depend on any modules, you can use
the \c{in} module's rule).
+
+
+\h1#json-dump|Appendix A \- JSON Dump Format|
+
+This appendix describes the machine-readable, JSON-based build system state
+dump format that can be requested with the \c{--dump-format=json-v0.1} build
+system driver option (see \l{b(1)} for details).
+
+The format is specified in terms of the serialized representation of C++
+\c{struct} instances. See \l{b.xhtml#json-output JSON OUTPUT} for details on
+the overall properties of this format and the semantics of the \c{struct}
+serialization.
+
+\N|This format is currently unstable (thus the temporary \c{-v0.1} suffix)
+and may be changed in ways other than as described in \l{b.xhtml#json-output
+JSON OUTPUT}. In case of such changes the format version will be incremented
+to allow detecting incompatibilities but no support for older versions is
+guaranteed.|
+
+The build system state can be dumped after the load phase (\c{--dump=load}),
+once the build state has been loaded, and/or after the match phase
+(\c{--dump=match}), after rules have been matched to targets to execute the
+desired action. The JSON format differs depending on after which phase it is
+produced. After the load phase the format aims to describe the
+action-independent state, essentially as specified in the \c{buildfiles}.
+While after the match phase it aims to describe the state for executing the
+specified action, as determined by the rules that have been matched. The
+former state would be more appropriate, for example, for an IDE that tries to
+use \c{buildfiles} as project files. While the latter state could be used to
+determine the actual build graph for a certain action, for example, in order
+to infer which executable targets are considered tests by the \c{test}
+operation.
+
+While it's possible to dump the build state as a byproduct of executing an
+action (for example, performing an update), it's often desirable to only dump
+the build state and do it as quickly as possible. For such cases the
+recommended option combinations are as follows (see the \c{--load-only} and
+\c{--match-only} documentation for details):
+
+\
+$ b --load-only --dump=load --dump-format=json-v0.1 .../dir/
+
+$ b --match-only --dump=match --dump-format=json-v0.1 .../dir/
+$ b --match-only --dump=match --dump-format=json-v0.1 .../dir/type{name}
+\
+
+\N|Note that a match dump for a large project can produce a large amount of
+data, especially for the \c{update} operation (tens and even hundreds of
+megabytes is not uncommon). To reduce this size it is possible to limit the
+dump to specific scopes and/or targets with the \c{--dump-scope} and
+\c{--dump-target} options.|
+
+The complete dump (that is, not of a specific scope or target) is a tree of
+nested scope objects (see \l{#intro-dirs-scopes Output Directories and Scopes}
+for background). The scope object has the serialized representation of the
+following C++ \c{struct} \c{scope}. It is the same for both load and match
+dumps except for the type of the \c{targets} member:
+
+\
+struct scope
+{
+ string out_path;
+ optional<string> src_path;
+
+ vector<variable> variables; // Non-type/pattern scope variables.
+
+ vector<scope> scopes; // Immediate children.
+
+ vector<loaded_target|matched_target> targets;
+};
+\
+
+For example (parts of the output are omitted for brevity):
+
+\N|The actual output is produced unindented to reduce the size.|
+
+\
+$ cd /tmp
+$ bdep new hello
+$ cd hello
+$ bdep new -C @gcc cc
+$ b --load-only --dump=load --dump-format=json-v0.1
+{
+ \"out_path\": \"\",
+ \"variables\": [ ... ],
+ \"scopes\": [
+ {
+ \"out_path\": \"/tmp/hello-gcc\",
+ \"variables\": [ ... ],
+ \"scopes\": [
+ {
+ \"out_path\": \"hello\",
+ \"src_path\": \"/tmp/hello\",
+ \"variables\": [ ... ],
+ \"scopes\": [
+ {
+ \"out_path\": \"hello\",
+ \"src_path\": \"/tmp/hello/hello\",
+ \"variables\": [ ... ],
+ \"targets\": [ ... ]
+ }
+ ],
+ \"targets\": [ ... ]
+ }
+ ],
+ \"targets\": [ ... ]
+ }
+ ]
+}
+\
+
+The \c{out_path} member is relative to the parent scope. It is empty for the
+special global scope, which is the root of the tree. The \c{src_path} member
+is absent if it is the same as \c{out_path} (in source build or scope outside
+of project).
+
+\N|For the match dump, targets that have not been matched for the specified
+action are omitted.|
+
+In the load dump, the target object has the serialized representation of the
+following C++ \c{struct} \c{loaded_target}:
+
+\
+struct loaded_target
+{
+ string name; // Relative quoted/qualified name.
+ string display_name; // Relative display name.
+ string type; // Target type.
+ optional<string> group; // Absolute quoted/qualified group target.
+
+ vector<variable> variables; // Target variables.
+
+ vector<prerequisite> prerequisites;
+};
+\
+
+For example (continuing with the previous \c{hello} setup):
+
+\
+{
+ \"out_path\": \"\",
+ \"scopes\": [
+ {
+ \"out_path\": \"/tmp/hello-gcc\",
+ \"scopes\": [
+ {
+ \"out_path\": \"hello\",
+ \"src_path\": \"/tmp/hello\",
+ \"scopes\": [
+ {
+ \"out_path\": \"hello\",
+ \"src_path\": \"/tmp/hello/hello\",
+ \"targets\": [
+ {
+ \"name\": \"exe{hello}\",
+ \"display_name\": \"exe{hello}\",
+ \"type\": \"exe\",
+ \"prerequisites\": [
+ {
+ \"name\": \"cxx{hello}\",
+ \"type\": \"cxx\"
+ },
+ {
+ \"name\": \"testscript{testscript}\",
+ \"type\": \"testscript\"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
+\
+
+The target \c{name} member is the target name that is qualified with the
+extension (if applicable and known) and, if required, is quoted so that it can
+be passed back to the build system driver on the command line. The
+\c{display_name} member is unqualified and unquoted. Note that both the target
+\c{name} and \c{display_name} members are normally relative to the containing
+scope (if any).
+
+The prerequisite object has the serialized representation of the following C++
+\c{struct} \c{prerequisite}:
+
+\
+struct prerequisite
+{
+ string name; // Quoted/qualified name.
+ string type;
+ vector<variable> variables; // Prerequisite variables.
+};
+\
+
+The prerequisite \c{name} member is normally relative to the containing scope.
+
+In the match dump, the target object has the serialized representation of the
+following C++ \c{struct} \c{matched_target}:
+
+\
+struct matched_target
+{
+ string name;
+ string display_name;
+ string type;
+ optional<string> group;
+
+ optional<path> path; // Absent if not path target, not assigned.
+
+ vector<variable> variables;
+
+ optional<operation_state> outer_operation; // null if not matched.
+ operation_state inner_operation; // null if not matched.
+};
+\
+
+For example (outer scopes removed for brevity):
+
+\
+$ b --match-only --dump=match --dump-format=json-v0.1
+{
+ \"out_path\": \"hello\",
+ \"src_path\": \"/tmp/hello/hello\",
+ \"targets\": [
+ {
+ \"name\": \"/tmp/hello/hello/cxx{hello.cxx}@./\",
+ \"display_name\": \"/tmp/hello/hello/cxx{hello}@./\",
+ \"type\": \"cxx\",
+ \"path\": \"/tmp/hello/hello/hello.cxx\",
+ \"inner_operation\": {
+ \"rule\": \"build.file\",
+ \"state\": \"unchanged\"
+ }
+ },
+ {
+ \"name\": \"obje{hello.o}\",
+ \"display_name\": \"obje{hello}\",
+ \"type\": \"obje\",
+ \"group\": \"/tmp/hello-gcc/hello/hello/obj{hello}\",
+ \"path\": \"/tmp/hello-gcc/hello/hello/hello.o\",
+ \"inner_operation\": {
+ \"rule\": \"cxx.compile\",
+ \"prerequisite_targets\": [
+ {
+ \"name\": \"/tmp/hello/hello/cxx{hello.cxx}@./\",
+ \"type\": \"cxx\"
+ },
+ {
+ \"name\": \"/usr/include/c++/12/h{iostream.}\",
+ \"type\": \"h\"
+ },
+ ...
+ ]
+ }
+ },
+ {
+ \"name\": \"exe{hello.}\",
+ \"display_name\": \"exe{hello}\",
+ \"type\": \"exe\",
+ \"path\": \"/tmp/hello-gcc/hello/hello/hello\",
+ \"inner_operation\": {
+ \"rule\": \"cxx.link\",
+ \"prerequisite_targets\": [
+ {
+ \"name\": \"/tmp/hello-gcc/hello/hello/obje{hello.o}\",
+ \"type\": \"obje\"
+ }
+ ]
+ }
+ }
+ ]
+}
+\
+
+The first four members in \c{matched_target} have the same semantics as in
+\c{loaded_target}.
+
+The \c{outer_operation} member is only present if the action has an outer
+operation. For example, when performing \c{update-for-test}, \c{test} is the
+outer operation while \c{update} is the inner operation.
+
+The operation state object has the serialized representation of the following
+C++ \c{struct} \c{operation_state}:
+
+\
+struct operation_state
+{
+ string rule; // null if direct recipe match.
+
+ optional<string> state; // One of unchanged|changed|group.
+
+ vector<variable> variables; // Rule variables.
+
+ vector<prerequisite_target> prerequisite_targets;
+};
+\
+
+The \c{rule} member is the matched rule name. The \c{state} member is the
+target state, if known after match. The \c{prerequisite_targets} array is a
+subset of prerequisites resolved to targets that are in effect for this
+action. The matched rule may add additional targets, for example, dynamically
+extracted additional dependencies, like \c{/usr/include/c++/12/h{iostream.\}}
+in the above listing.
+
+The prerequisite target object has the serialized representation of the
+following C++ \c{struct} \c{prerequisite_target}:
+
+\
+struct prerequisite_target
+{
+ string name; // Absolute quoted/qualified target name.
+ string type;
+ bool adhoc;
+};
+\
+
+The \c{variables} array in the scope, target, prerequisite, and prerequisite
+target objects contains scope, target, prerequisite, and rule variables,
+respectively.
+
+The variable object has the serialized representation of the following C++
+\c{struct} \c{variable}:
+
+\
+struct variable
+{
+ string name;
+ optional<string> type;
+ json_value value; // null|boolean|number|string|object|array
+};
+\
+
+For example:
+
+\
+{
+ \"out_path\": \"\",
+ \"variables\": [
+ {
+ \"name\": \"build.show_progress\",
+ \"type\": \"bool\",
+ \"value\": true
+ },
+ {
+ \"name\": \"build.verbosity\",
+ \"type\": \"uint64\",
+ \"value\": 1
+ },
+ ...
+ ],
+ \"scopes\": [
+ {
+ \"out_path\": \"/tmp/hello-gcc\",
+ \"scopes\": [
+ {
+ \"out_path\": \"hello\",
+ \"src_path\": \"/tmp/hello\",
+ \"scopes\": [
+ {
+ \"out_path\": \"hello\",
+ \"src_path\": \"/tmp/hello/hello\",
+ \"variables\": [
+ {
+ \"name\": \"out_base\",
+ \"type\": \"dir_path\",
+ \"value\": \"/tmp/hello-gcc/hello/hello\"
+ },
+ {
+ \"name\": \"src_base\",
+ \"type\": \"dir_path\",
+ \"value\": \"/tmp/hello/hello\"
+ },
+ {
+ \"name\": \"cxx.poptions\",
+ \"type\": \"strings\",
+ \"value\": [
+ \"-I/tmp/hello-gcc/hello\",
+ \"-I/tmp/hello\"
+ ]
+ },
+ {
+ \"name\": \"libs\",
+ \"value\": \"/tmp/hello-gcc/libhello/libhello/lib{hello}\"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
+\
+
+The \c{type} member is absent if the variable value is untyped.
+
+The \c{value} member contains the variable value in a suitable JSON
+representation. Specifically:
+
+\ul|
+
+\li|\c{null} values are represented as JSON \c{null}.|
+
+\li|\c{bool} values are represented as JSON \c{boolean}.|
+
+\li|\c{int64} and \c{uint64} values are represented as JSON \c{number}.|
+
+\li|\c{string}, \c{path}, \c{dir_path} values are represented as JSON
+ \c{string}.|
+
+\li|Untyped simple name values are represented as JSON \c{string}.|
+
+\li|Pairs of above values are represented as JSON objects with the \c{first}
+ and \c{second} members corresponding to the pair elements.|
+
+\li|Untyped complex name values are serialized as target names and represented
+ as JSON \c{string}.|
+
+\li|Containers of above values are represented as JSON arrays corresponding to
+ the container elements.|
+
+\li|An empty value is represented as an empty JSON object if it's a typed
+ pair, as an empty JSON array if it's a typed container or is untyped, and
+ as an empty string otherwise.||
+
+One expected use-case for the match dump is to determine the set of targets
+for which a given action is applicable. For example, we may want to determine
+all the executables in a project that can be tested with the \c{test}
+operation in order to present this list to the user in an IDE plugin or
+some such. To further illuminate the problem, consider the following
+\c{buildfile} which declares a number of executable targets, some are
+tests and some are not:
+
+\
+exe{hello1}: ... testscript # Test because of testscript prerequisite.
+
+exe{hello2}: test = true # Test because of test=true.
+
+exe{hello3}: ... testscript # Not a test because of test=false.
+{
+ test = false
+}
+\
+
+As can be seen, trying to infer this information is not straightforward and
+doing so manually by examining prerequisites, variables, etc., while possible,
+will be complex and likely brittle. Instead, the recommended approach is to
+use the match dump and base the decision on the \c{state} target object
+member. Specifically, a rule which matched the target but determined that
+nothing needs to be done for this target, returns the special \c{noop}
+recipe. The \c{build2} core recognizes this situation and sets such target's
+state to \c{unchanged} during match. Here is what the match dump will look
+like for the above three executables:
+
+\
+$ b --match-only --dump=match --dump-format=json-v0.1 test
+{
+ \"out_path\": \"hello\",
+ \"src_path\": \"/tmp/hello/hello\",
+ \"targets\": [
+ {
+ \"name\": \"exe{hello1.}\",
+ \"display_name\": \"exe{hello1}\",
+ \"type\": \"exe\",
+ \"path\": \"/tmp/hello-gcc/hello/hello/hello1\",
+ \"inner_operation\": {
+ \"rule\": \"test\"
+ }
+ },
+ {
+ \"name\": \"exe{hello2.}\",
+ \"display_name\": \"exe{hello2}\",
+ \"type\": \"exe\",
+ \"path\": \"/tmp/hello-gcc/hello/hello/hello2\",
+ \"inner_operation\": {
+ \"rule\": \"test\"
+ }
+ },
+ {
+ \"name\": \"exe{hello3}\",
+ \"display_name\": \"exe{hello3}\",
+ \"type\": \"exe\",
+ \"inner_operation\": {
+ \"rule\": \"test\",
+ \"state\": \"unchanged\"
+ }
+ }
+ ]
+}
+\
+
"