aboutsummaryrefslogtreecommitdiff
path: root/doc/intro.cli
diff options
context:
space:
mode:
Diffstat (limited to 'doc/intro.cli')
-rw-r--r--doc/intro.cli844
1 files changed, 699 insertions, 145 deletions
diff --git a/doc/intro.cli b/doc/intro.cli
index 417ecc0..6671cbd 100644
--- a/doc/intro.cli
+++ b/doc/intro.cli
@@ -25,17 +25,13 @@
// - Maximum <pre> line is 70 characters.
//
-"
-\h0#preface|Preface|
-
-This document is an overall introduction to the \c{build2} toolchain that
-shows how the main components, namely the build system, the package dependency
-manager, and the project dependency manager are used together to handle the
-entire C/C++ project development lifecycle: creation, development, testing,
-and delivery. For additional information, including documentation for
-individual toolchain components, man pages, etc., refer to the \c{build2}
-project \l{https://build2.org/doc.xhtml Documentation} page.
-
+// Some people say they find the TLDR "abhorrent" (because it doesn't look
+// like something they can understand without reading the rest of the doc
+// first).
+//
+// Note: command output is most likely outdated.
+//
+/*
\h1#tldr|TL;DR|
@@ -66,8 +62,8 @@ Hello, World!
$ edit repositories.manifest # add https://example.org/libhello.git
$ edit manifest # add 'depends: libhello ^1.0.0'
-$ edit hello/buildfile # import libhello
-$ edit hello/hello.cxx # use libhello
+$ edit hello/buildfile # import libhello library
+$ edit hello/hello.cxx # include libhello header
$ b
fetching from https://example.org/libhello.git
@@ -100,6 +96,20 @@ synchronizing:
reconfigure hello/0.1.0
\
+*/
+
+"
+\h0#preface|Preface|
+
+This document is an overall introduction to the \c{build2} toolchain that
+shows how the main components, namely the build system, the package dependency
+manager, and the project dependency manager are used together to handle the
+entire C/C++ project development lifecycle: creation, development, testing,
+and delivery. For additional information, including documentation for
+individual toolchain components, man pages, HOWTOs, etc., refer to the
+\c{build2} project \l{https://build2.org/doc.xhtml Documentation} page.
+
+
\h1#guide|Getting Started Guide|
The aim of this guide is to get you started developing C/C++ projects with the
@@ -140,8 +150,8 @@ $ bdep new -l c++ -t exe hello
created new executable project hello in /tmp/hello/
\
-The \l{bdep-new(1)} command creates a \i{canonical} \c{build2} project. In
-our case it is an executable implemented in C++.
+The \l{bdep-new(1)} command creates a \c{build2} project. In this case it is
+an executable implemented in C++.
\N|To create a library, pass \c{-t\ lib}. By default \c{new} also initializes
a \c{git} repository and generates suitable \c{.gitignore} files (pass \c{-s\
@@ -173,9 +183,10 @@ hello/
and rationale behind this layout. While it is recommended, especially for new
projects, \c{build2} is flexible enough to support various arrangements used
in today's C and C++ projects. Furthermore, the \l{bdep-new(1)} command
-provides a number of customization options and chances are you will be able to
-create your preferred layout automatically. See \l{bdep-new.xhtml#src-layout
-SOURCE LAYOUT} for more information and examples.|
+provides a number of customization options and chances are good you will be
+able to create your preferred layout automatically. See
+\l{bdep-new.xhtml#src-layout SOURCE LAYOUT} for more information and
+examples.|
Similar to version control tools, we normally run all \c{build2} tools from
the project's source directory or one of its subdirectories, so:
@@ -271,6 +282,7 @@ $ cat manifest
: 1
name: hello
version: 0.1.0-a.0.z
+language: c++
summary: hello C++ executable
license: other: proprietary
description-file: README.md
@@ -311,8 +323,12 @@ designated as the default with additional conveniences.
The \l{bdep-init(1)} command is used to initialize a project in a build
configuration. As a shortcut, it can also create a new build configuration in
-the process, which is just what we need here. Let's start with GCC (remember
-we are in the project's root directory):
+the process, which is just what we need here.
+
+\N|To create build configurations separately from initialization and to manage
+them after that, use the \l{bdep-config(1)} subcommands.|
+
+Let's start with GCC (remember we are in the project's root directory):
\
$ bdep init -C ../hello-gcc @gcc cc config.cxx=g++
@@ -376,7 +392,7 @@ with Visual Studio, start a command prompt and then run:
> bdep init -C ..\hello-debug @debug cc ^
\"config.cxx=cl /MDd\" ^
\"config.cc.coptions=/Od /Zi\" ^
- config.cc.loptions=/DEBUG
+ config.cc.loptions=/DEBUG:FULL
> bdep init -C ..\hello-release @release cc ^
config.cxx=cl ^
@@ -420,7 +436,7 @@ complete list with their rough \c{make} equivalents:
We can also use their \c{config.c.*} (C compilation) and \c{config.cxx.*} (C++
compilation) variants if we only want them applied during the respective
-language compilation. For example:
+language compilation/linking. For example:
\
$ bdep init ... cc \
@@ -467,12 +483,12 @@ $ bdep status
hello configured 0.1.0-a.0.19700101000000
$ b
-c++ hello/cxx{hello}@../hello-gcc/hello/hello/
+c++ hello/cxx{hello} -> ../hello-gcc/hello/hello/obje{hello}
ld ../hello-gcc/hello/hello/exe{hello}
ln ../hello-gcc/hello/hello/exe{hello} -> hello/
$ b test
-test hello/testscript{testscript} ../hello-gcc/hello/hello/exe{hello}
+test ../hello-gcc/hello/hello/exe{hello} + hello/testscript{testscript}
$ hello/hello World
Hello, World!
@@ -489,11 +505,12 @@ $ bdep status @clang
hello configured 0.1.0-a.0.19700101000000
$ b ../hello-clang/hello/
-c++ hello/cxx{hello}@../hello-clang/hello/hello/
+c++ hello/cxx{hello} -> ../hello-clang/hello/hello/obje{hello}
ld ../hello-clang/hello/hello/exe{hello}
$ b test: ../hello-clang/hello/
-test hello/testscript{testscript} ../hello-clang/hello/hello/exe{hello}
+test ../hello-clang/hello/hello/exe{hello} +
+ hello/testscript{testscript}
$ ../hello-clang/hello/hello/hello World
Hello, World!
@@ -506,9 +523,10 @@ more convenient if we could refer to them by names. The \l{bdep-update(1)} and
\
$ bdep test @clang
-c++ hello/cxx{hello}@../hello-clang/hello/hello/
+c++ hello/cxx{hello} -> ../hello-clang/hello/hello/obje{hello}
ld ../hello-clang/hello/hello/exe{hello}
-test hello/testscript{testscript} ../hello-clang/hello/hello/exe{hello}
+test ../hello-clang/hello/hello/exe{hello} +
+ hello/testscript{testscript}
\
And we can also perform the desired build system operation on several (or
@@ -517,10 +535,11 @@ And we can also perform the desired build system operation on several (or
\
$ bdep test @gcc @clang
in configuration @gcc:
-test hello/testscript{testscript} ../hello-gcc/hello/hello/exe{hello}
+test ../hello-gcc/hello/hello/exe{hello} + hello/testscript{testscript}
in configuration @clang:
-test hello/testscript{testscript} ../hello-clang/hello/hello/exe{hello}
+test ../hello-clang/hello/hello/exe{hello} +
+ hello/testscript{testscript}
\
\N|As we will see later, the \l{bdep-test(1)} command also allows us to test
@@ -530,14 +549,14 @@ project. We call it \i{deep testing}.|
While we are here, let's also check how hard it would be to cross-compile:
\
-$ bdep init -C ../hello-mingw @mingw cc config.cxx=x86_64-w64-mingw32-g++
+$ bdep init -C @mingw cc config.cxx=x86_64-w64-mingw32-g++
initializing in project /tmp/hello/
created configuration @mingw /tmp/hello-mingw/ auto-synchronized
synchronizing:
new hello/0.1.0-a.0.19700101000000
$ bdep update @mingw
-c++ hello/cxx{hello}@../hello-mingw/hello/hello/
+c++ hello/cxx{hello} -> ../hello-mingw/hello/hello/obje{hello}
ld ../hello-mingw/hello/hello/exe{hello}
\
@@ -548,7 +567,8 @@ on a properly setup GNU/Linux machine (that automatically uses \c{wine} as an
\
$ bdep test @mingw
-test hello/testscript{testscript} ../hello-mingw/hello/hello/exe{hello}
+test ../hello-mingw/hello/hello/exe{hello} +
+ hello/testscript{testscript}
$ ../hello-mingw/hello/hello/hello.exe Windows
Hello, Windows!
@@ -595,6 +615,24 @@ synchronizing:
drop hello
\
+\N|By default \c{bdep} initializes a project for development by automatically
+passing \c{config.<project>.develop=true} unless a custom value is specified.
+For example:
+
+\
+$ bdep init ... @gcc cc config.cxx=g++ config.hello.develop=false
+\
+
+To change the development mode of an already initialized project, use
+\l{bdep-sync(1)}:
+
+\
+$ bdep sync @gcc config.hello.develop=false
+\
+
+See \l{b#proj-config Project Configuration} for background on the development
+mode.|
+
As mentioned earlier, by default \l{bdep-new(1)} initializes a \c{git}
repository for us. Now that we have successfully built and tested our project,
it might be a good idea to make a first commit and publish it to a remote
@@ -653,17 +691,17 @@ CI request is queued:
Let's see what's going on here. By default \c{ci} submits a test request to
\l{https://ci.cppget.org ci.cppget.org}, a public CI service run by the
\c{build2} project (see available \l{https://ci.cppget.org?build-configs Build
-Configurations} and \l{https://ci.cppget.org?ci Use Policies}). It is testing
-the current working tree state (branch and commit) of our package which should
-be available from our remote repository (on GitHub in this example) since
-that's where the CI service expects to find it. In response we get a URL where
-we can see the build and test results, logs, etc.
+Configurations} and \l{https://ci.cppget.org?ci Use Policies}). In our case it
+will be testing the current working tree state (branch and commit) of our
+package which should be available from our remote repository (on GitHub in
+this example) since that's where the CI service expects to get it from. In
+response we get a URL where we can see the build and test results, logs, etc.
\N|This \i{push} CI model works particularly well with the \"feature branch\"
development workflow. Specifically, you would develop a new feature in a
separate branch, publishing and remote-testing it as necessary. When the
feature is ready, you would merge any changes from \c{master}, test the result
-one more time, and then merge the feature into master.|
+one more time, and then merge (fast-forward) the feature into master.|
Now is a good time to get an overview of the \c{build2} toolchain. After all,
we have already used two of its tools (\c{bdep} and \c{b}) without a clear
@@ -679,12 +717,12 @@ management toolset.
\N|While \c{build2} can work without a VCS, this will result in reduced
functionality.|
-At the bottom of the hierarchy is the build system, \l{b(1)}. Next comes the
-package dependency manager, \l{bpkg(1)}. It is primarily used for \i{package
-consumption} and depends on the build system. The top of the hierarchy is the
-project dependency manager, \l{bdep(1)}. It is used for \i{project
-development} and relies on \c{bpkg} for building project packages and their
-dependencies.
+At the bottom of the hierarchy is the \c{build2} build system, which we invoke
+using the \l{b(1)} driver. Next comes the package dependency manager,
+\l{bpkg(1)}. It is primarily used for \i{package consumption} and depends on
+the build system. The top of the hierarchy is the project dependency manager,
+\l{bdep(1)}. It is used for \i{project development} and relies on \c{bpkg} for
+building project packages and their dependencies.
\N|The main reason for this separation is modularity and the resulting
flexibility: there are situations where we only need the build system (for
@@ -702,13 +740,19 @@ order to automate project versioning. Note that currently only \c{git(1)} is
supported.|
Now that we understand the tooling, let's also revisit the notion of \i{build
-configuration} (those \c{hello-gcc} and \c{hello-clang} directories). A
-\c{bdep} build configuration is actually a \c{bpkg} build configuration which,
-in the build system terms, is an \i{amalgamation} \- a project that contains
-\i{subprojects}. In our case, the subprojects in these amalgamations will be
-the projects we have initialized with \c{init} and, as we will see later,
-packages that they depend on. For example, here is what our \c{hello-gcc}
-contains:
+configuration} (those \c{hello-gcc} and \c{hello-clang} directories). While we
+often talk of build configurations in the abstract, as a set of common options
+used to build our code, in \c{build2} this term also has a very concrete
+meaning \- a directory where our projects and their dependencies are built
+with such a set of common options.
+
+The concept of a build configuration appears prominently throughout the
+toolchain: a \c{bdep} build configuration is actually a \c{bpkg} build
+configuration which, in the build system terms, is a special kind of an
+\i{amalgamation} \- a project that contains \i{subprojects}. In our case, the
+subprojects in these amalgamations will be the projects we have initialized
+with \c{init} and, as we will see in a moment, packages that they depend
+on. For example, here is what our \c{hello-gcc} contains:
\
$ tree hello-gcc
@@ -730,9 +774,9 @@ meta-operation (see \l{b(1)} for details).
The important point here is that the \c{bdep} build configuration is not a
black box that you should never look inside of. On the contrary, it is a
-normal and predictable concept of the package manager and the build system and
-as long as you understand what you are doing, you should feel free to interact
-with it directly.|
+well-defined concept of the package manager and the build system and as long
+as you understand what you are doing, you should feel free to interact with it
+directly.|
Let's now move on to the reason why there is \i{dep} in the \c{bdep} name:
dependency management.
@@ -746,8 +790,8 @@ let's see if we can find something suitable to use in our project.
Where should we look? That's a good question. But before we can try to answer
it, we need to understand where \c{build2} can source dependencies. In
-\c{build2} packages come from \i{package repositories}. Two commonly used
-repository types are \i{version control} and \i{archive}-based (see
+\c{build2} packages usually come from \i{package repositories}. Two commonly
+used repository types are \i{version control} and \i{archive}-based (see
\l{bpkg-repository-types(1)} for details).
As the name suggests, a version control-based repository uses a VCS as its
@@ -756,15 +800,16 @@ repository normally contains multiple versions of a single package or,
perhaps, of a few related packages.
An archive-based repository contains multiple, potentially unrelated
-packages/versions as archives along with some meta information (package list,
+packages/versions as archives along with some metadate (package list,
prerequisite/complement repositories, signatures, etc) that are all accessible
via HTTP(S).
Version control and archive-based repositories have different
trade-offs. Version control-based repositories are great for package
-developers: With services like GitHub they are trivial to setup. In fact, your
-project's (already existing) VCS repository will normally be the \c{build2}
-package repository \- you might need to add a few files, but that's about it.
+developers since with services like GitHub they are trivial to setup. In fact,
+your project's (already existing) VCS repository will normally be the
+\c{build2} package repository \- you might need to add a few files, but that's
+about it.
However, version control-based repositories are not without drawbacks: It will
be hard for your users to discover your packages (try searching for \"hello
@@ -821,7 +866,7 @@ along with a list of available versions. Pick a version that you like and you
will see the package version description page with quite a bit of information,
including the list of platform/compiler combinations that this version has
been successfully (or unsuccessfully) tested with. If you like what you see,
-copy the \c{location} value \- this is the repository location where this
+copy the \c{repository} value \- this is the repository location where this
package version can be sourced from.
\N|The \l{https://cppget.org cppget.org} repository is split into several
@@ -940,6 +985,11 @@ semantic versioning), we suggest that you use the \c{^} constraint which
provides a good balance between compatibility and upgradability with \c{~}
being a more conservative option.
+Besides the version constraint, the dependency declaration supports a number
+of more advanced features, including conditional dependencies, dependency
+alternatives, and dependency configuration. For details, see the
+\l{bpkg#manifest-package-depends \c{depends}} value documentation.
+
Ok, we've specified where our package comes from (\c{repositories.manifest})
and which versions we find acceptable (\c{manifest}). The next step is to edit
\c{hello/buildfile} and import the \c{libhello} library into our build:
@@ -990,10 +1040,20 @@ to our project:
\
repositories.manifest # add https://pkg.cppget.org/1/stable
manifest # add 'depends: libhello ^1.0.0'
-buildfile # import libhello
-hello.cxx # use libhello
+buildfile # import libhello library
+hello.cxx # include libhello header (or import module)
\
+\N|While the repository URL and package name are easy to find on the
+\l{https://cppget.org cppget.org}'s package description page, the C/C++
+library ecosystem unfortunately does not follow any predictable library or
+header naming scheme. If the library documentation does not provide any clues,
+then another place to check are the library tests and examples that can often
+be found in the package source directory (or source repository). In
+particular, every library in the \c{stable} section of the
+\l{https://cppget.org cppget.org} repository should provide at least a basic
+test.|
+
With a new dependency added, let's check the status of our project:
\
@@ -1003,7 +1063,7 @@ warning: authenticity of the certificate for pkg:cppget.org/stable
cannot be established
certificate is for cppget.org, \"Code Synthesis\" <admin@cppget.org>
certificate SHA256 fingerprint:
-86:BA:D4:DE:2C:87:1A:EE:38:<...>:5A:EA:F4:F7:8C:1D:63:30:C6
+70:64:FE:E4:E0:F3:60:F1:B4:<...>:E5:C2:68:63:4C:A6:47:39:43
trust this certificate? [y/n] y
hello configured 0.1.0-a.0.19700101000000
@@ -1024,7 +1084,7 @@ the repository's about page):
\
role: prerequisite
location: https://pkg.cppget.org/1/stable
-trust: 86:BA:D4:DE:2C:87:1A:EE:38:<...>:5A:EA:F4:F7:8C:1D:63:30:C6
+trust: 70:64:FE:E4:E0:F3:60:F1:B4:<...>:E5:C2:68:63:4C:A6:47:39:43
\
To synchronize a project with one or more build configurations we use the
@@ -1045,9 +1105,10 @@ $ b
synchronizing:
new libhello/1.0.0 (required by hello)
upgrade hello/0.1.0-a.0.19700101000000#1
-c++ ../hello-gcc/libhello-1.0.0/libhello/cxx{hello}
+c++ ../hello-gcc/libhello-1.0.0/libhello/cxx{hello} ->
+ ../hello-gcc/libhello-1.0.0/libhello/objs{hello}
ld ../hello-gcc/libhello-1.0.0/libhello/libs{hello}
-c++ hello/cxx{hello}@../hello-gcc/hello/hello/
+c++ hello/cxx{hello} -> ../hello-gcc/hello/hello/obje{hello}
ld ../hello-gcc/hello/hello/exe{hello}
ln ../hello-gcc/hello/hello/exe{hello} -> hello/
\
@@ -1098,12 +1159,13 @@ For example:
\
$ bdep test -ai
in configuration @gcc:
-test hello/testscript{testscript} ../hello-gcc/hello/hello/exe{hello}
test ../hello-gcc/libhello-1.0.0/tests/basics/exe{driver}
+test ../hello-gcc/hello/hello/exe{hello} + hello/testscript{testscript}
in configuration @clang:
-test hello/testscript{testscript} ../hello-clang/hello/hello/exe{hello}
test ../hello-clang/libhello-1.0.0/tests/basics/exe{driver}
+test ../hello-clang/hello/hello/exe{hello} +
+ hello/testscript{testscript}
\
To get rid of a dependency, we simply remove it from the \c{manifest} file
@@ -1244,6 +1306,319 @@ immediate (\c{sync\ -ui}), or even upgrade immediate and patch the rest
(\c{sync\ -ui} followed by \c{sync\ -pr}).
+\h#guide-build-time-linked|Build-Time Dependencies and Linked Configurations|
+
+The \c{libhello} dependency we've been playing with in the previous two
+sections is a \i{runtime dependency}, that is, our \c{hello} executable needs
+it at run-time. This is typical of libraries and most of our dependencies will
+be of this kind. However, sometimes we may only wish to use a dependency
+during the build, typically a tool, such as a source code generator. This kind
+of dependency is called a \i{build-time dependency}.
+
+\N|Build-time dependencies are an advanced topic and if you don't have an
+immediate need for this functionality, you may skip this section without any
+loss of continuity.|
+
+Why do we need to distinguish between the two kinds of dependencies? The
+primary reason is cross-compilation: if we build a tool in the same
+(cross-compiling) build configuration as our project, then we will not be able
+to execute it during the build (since it's built for a different target than
+what we are running). But even if you are not planning to cross-compile, there
+are other good reasons: if you have multiple build configurations for your
+project, you may want to share a single build of your tool between them (why
+waste time building the same thing multiple times). And even if you only have
+a single build of your project, you may want to build the tool with different
+options (for example, optimized instead of debug).
+
+You can probably see where this is going: in order to properly support
+build-time dependencies, we need to distinguish them from runtime and we need
+an ability to build them in a separate build configuration.
+
+Let's see how all this works using the \l{https://cppget.org/xxd \c{xxd}} tool
+as an example. If you are not familiar, \c{xxd} is a hexdump utility which can
+be used to embed external binary data into C/C++ code in a portable manner.
+Specifically, it can read a binary file and produce a C array definition of
+its contents. For example:
+
+\
+$ xxd -i names.txt
+
+unsigned char names_txt[] = {
+ 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x0a, 0x55, 0x6e, 0x69, 0x76, 0x65,
+ 0x72, 0x73, 0x65, 0x0a, 0x50, 0x65, 0x6f, 0x70, 0x6c, 0x65, 0x0a,
+ 0x4d, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6e, 0x73, 0x0a
+};
+unsigned int names_txt_len = 31;
+\
+
+\N|While the above output is a bit old school (using \c{unsigned int} instead
+of \c{size_t}) and the array/length names are derived from the input file name
+(including directories), \c{xxd} can also produce just the array values
+allowing us to wrap it into an array of our choice. See the
+\l{https://cppget.org/xxd \c{xxd}} package description for examples of
+\c{build2} recipes that do that.|
+
+So here is an idea: instead of failing if the user did not specify the name to
+greet, let's improve our \c{hello} program to greet a random generic name from
+a pre-defined list. To make this list easier to maintain, let's keep it in a
+separate file called \c{names.txt} and use \c{xxd} to embed it into our
+\c{hello} executable. We can use the one name per line format, for example:
+
+\
+$ cat names.txt
+World
+Universe
+People
+Martians
+\
+
+The first step in our plan is to add a build-time dependency on \c{xxd} to our
+project's \c{manifest}, similar to how we did for \c{libhello}:
+
+\
+...
+depends: libhello ^1.0.0
+depends: * xxd >= 8.2.0
+\
+
+The \c{*} mark in front of the \c{xxd} name indicates that it's a build-time
+dependency.
+
+Next we import \c{xxd} in our \c{buildfile}:
+
+\
+...
+
+import libs += libhello%lib{hello}
+
+import! [metadata] xxd = xxd%exe{xxd}
+
+...
+\
+
+There are two main differences compared to the way we import the \c{libhello}
+library: we request metadata (\c{[metadata]}) and we do immediate importation
+(\c{import!}). Let's briefly discuss what this means (for details, refer to
+\l{b#intro-import Target Importation} in the build system manual). Metadata
+for an executable contains information that helps the build system do a better
+job when an executable is used as part of the build. For example, it includes
+the uniform program name to be used for low-verbosity diagnostics as well as
+the version, checksum, and environment that are used to detect changes. And
+immediate importation instructs the build system to skip rule-specific
+importation (for example, search for libraries in compiler-specific search
+paths) and import the target here and now, failing if that's not possible. It
+is usually appropriate for importing executables. Note also that the metadata
+can only be requested in immediate importation.
+
+\N|While requesting the metadata means that you will have a simpler
+\c{buildfile} and a more reliable build, it also likely means that you won't
+be able to use the system-installed version of the executable since it needs
+to be patched to provide the metadata.|
+
+Now that we have the \c{xxd} tool, let's use it from an ad hoc recipe to
+convert \c{names.txt} to \c{names.cxx}. Here is the complete \c{buildfile} for
+our \c{hello} executable:
+
+\
+libs =
+import libs += libhello%lib{hello}
+
+import! [metadata] xxd = xxd%exe{xxd}
+
+exe{hello}: {hxx ixx txx cxx}{** -names} cxx{names} $libs testscript
+
+cxx{names}: file{names.txt} $xxd
+{{
+ i = $path($<[0])
+ env --cwd $directory($i) -- $xxd -i $leaf($i) >$path($>)
+}}
+\
+
+The last bit that we need to do is to modify \c{hello.cxx} to use the list of
+fallback names (the actual implementation is left as an exercise for the
+reader):
+
+\
+#include <iostream>
+
+extern unsigned char names_txt[];
+extern unsigned int names_txt_len;
+
+int main (int argc, char* argv[])
+{
+ using namespace std;
+
+ if (argc < 2)
+ {
+ // TODO: pick a random name from names_txt using newline as
+ // a name separator.
+ }
+
+ ...
+}
+\
+
+Let's recap what we've achieved so far: we've added a build-time dependency on
+\c{xxd}, we've imported it in our \c{buildfile} and used it in an ad hoc
+recipe to generate \c{names.cxx}, and we've modified \c{hello.cxx} to use the
+generated list of names. The only step left is to actually try to build it.
+But before doing that, let's also print the list of build configurations we
+currently have associated with our project (see the \c{list} subcommand
+in \l{bdep-config(1)}):
+
+\
+$ bdep config list
+@gcc /tmp/hello-gcc/ 1 target default,forwarded,auto-synchronized
+@clang /tmp/hello-clang/ 2 target auto-synchronized
+\
+
+\
+$ b
+creating configuration of host type in /tmp/hello-host/ and
+associating it with project(s):
+ /tmp/hello/
+as if by executing command(s):
+ bdep config create @host --type host --no-default /tmp/hello-host \
+ cc config.config.load=~host
+while searching for configuration for build-time dependency xxd of
+package hello/0.1.0-a.0.19700101000000#4
+while synchronizing configuration /tmp/hello-gcc/
+continue? [Y/n] y
+
+synchronizing /tmp/hello-gcc/:
+ new xxd/8.2.3075 [/tmp/hello-host/] (required by hello)
+ upgrade hello/0.1.0-a.0.19700101000000#4
+
+c ../hello-host/xxd-8.2.3075+1/c{xxd} ->
+ ../hello-host/xxd-8.2.3075+1/obje{xxd}
+ld ../hello-host/xxd-8.2.3075/exe{xxd}
+xxd hello/file{names.txt} -> ../hello-gcc/hello/hello/cxx{names}
+c++ ../hello-gcc/hello/hello/cxx{names} ->
+ ../hello-gcc/hello/hello/obje{names}
+c++ hello/cxx{hello} -> ../hello-gcc/hello/hello/obje{hello}
+ld ../hello-gcc/hello/hello/exe{hello}
+\
+
+While the diagnostics is hopefully fairly self-explanatory, let's go over the
+key points. The first part goes exactly as in the previous section: because
+we've added a new dependency, the build configuration needs to be synchronized
+with the project state. However, this is a build-time dependency and
+build-time dependencies are built in configurations of type \c{host}. So
+\c{bdep} first looks for such a configuration among the configurations already
+associated with the project. In our case there isn't one (from the listing
+above we can see that all our configurations are of type \c{target}). In this
+case, \c{bdep} offers to create one automatically. We accept this offer by
+answering \c{y} at the prompt and the rest should again look familiar: the new
+dependency is configured and built (but now in the host configuration) and our
+project is updated (which involves running the new dependency). If we now
+again print the list of build configurations associated with our project, we
+will see the new configuration among them:
+
+\
+$ bdep config list
+@gcc /tmp/hello-gcc/ 1 target default,forwarded,auto-synchronized
+@clang /tmp/hello-clang/ 2 target auto-synchronized
+@host /tmp/hello-host/ 3 host forwarded,auto-synchronized
+\
+
+Let's also try to update our project in the \c{clang} configuration:
+
+\
+$ bdep update @clang
+synchronizing:
+ upgrade hello/0.1.0-a.0.19700101000000#4
+
+xxd hello/file{names.txt} -> ../hello-clang/hello/hello/cxx{names}
+c++ ../hello-clang/hello/hello/cxx{names} ->
+ ../hello-clang/hello/hello/obje{names}
+c++ hello/cxx{hello} -> ../hello-clang/hello/hello/obje{hello}
+ld ../hello-clang/hello/hello/exe{hello}
+\
+
+This time we are neither prompted to create another configuration nor is a new
+instance of \c{xxd} built \- as we would have expected, the existing host
+configuration with the already built \c{xxd} is reused.
+
+From the above output we can see that \c{bdep} creates the host configuration
+using the default host compiler and build options (\c{~host}) which means the
+result will most likely be optimized. But if we don't like something about the
+host configuration that \c{bdep} offers us to create, we can answer \c{n} at
+the prompt, create one ourselves (by perhaps copying and tweaking the command
+line \c{bdep} was going to use), and then restart the build.
+
+Besides the \c{target} and \c{host} types, the third pre-defined configuration
+type is \c{build2}, which is used for build system modules. If you would like
+to try a build-time dependency on a build system module, there is a dummy
+\c{libbuild2-hello} module that you can use. Simply add the following line
+to your \c{manifest}:
+
+\
+depends: * libbuild2-hello
+\
+
+And the following line somewhere in your \c{buildfile}:
+
+\
+using hello
+\
+
+Then build the project and see what happens.
+
+\N|The \c{target} type signifies a configuration for the end-result of our
+build. If no type is specified during the configuration creation with the
+\c{--type} option (or \c{--config-type} if using \c{bdep-new}), then
+\c{target} is assumed.
+
+The \c{host} type signifies a configuration corresponding to the host machine,
+that is, the machine on which the build is performed. It is expected that an
+executable built in the host configuration can be executed. Oftentimes, target
+and host are the same. In this case, if you would prefer not to have separate
+configurations, then you can make your target configuration \i{self-hosted} by
+using the \c{host} type rather than \c{target}. For example:
+
+\
+$ bdep init -C ../hello-gcc @gcc --type host cc config.cxx=g++
+\
+
+The \c{build2} type is a special kind of host configuration that is used to
+build build system modules. It cannot be self-hosted.|
+
+Building build-time dependencies in separate configurations is just one
+application of the more general configuration linking mechanism which allows
+us to build a package in one configuration while its dependencies \- in one or
+more linked configurations. This, for example, can be used to create a
+\"base\" configuration with common dependencies that are shared between
+multiple configurations (sometimes also referred to as build configuration
+overlaying).
+
+Let's see how this works on our \c{hello} project. Imagine \c{libhello} that
+we depend on is very big and takes a while to compile. We also aren't really
+interested in building it in both \c{gcc} and \c{clang} configurations (it's
+our project that we are interested in building with different compilers).
+Since these two compilers are ABI-compatible (at least on Linux), we could
+build \c{libhello} with just one of them and reuse the result with the
+other. Let's see how we can achieve this with linked configurations (refer to
+\l{bdep-config(1)} for details on subcommands involved):
+
+\
+$ bdep config create ../hello-base @base --no-default cc config.cxx=g++
+$ bdep config create ../hello-gcc @gcc --default cc config.cxx=g++
+$ bdep config create ../hello-clang @clang cc config.cxx=clang++
+
+$ bdep config link @gcc @base
+$ bdep config link @clang @base
+
+$ bdep init @gcc { @base }+ ?libhello
+$ bdep init @clang
+\
+
+Most of the commands are hopefully self-explanatory except for the \c{{ @base
+\}+ ?libhello} part. Here \c{?} is a package flag that instructs \c{bdep}
+to treat \c{libhello} as a dependency. And \c{{ @base \}+} tells it to build
+this dependency in the \c{base} configuration (we don't have to do the same
+for \c{clang} since the dependency is already built). See \l{bdep-sync(1)} for
+details on this syntax.
+
\h#guide-versioning-releasing|Versioning and Release Management|
@@ -1730,23 +2105,43 @@ And that's it, now we can build and test our new arrangement:
\
$ cd ../hello # back to hello project root
$ bdep test -i
-c++ ../libhello/libhello/cxx{hello}
-c++ ../libhello/tests/basics/cxx{driver}
-c++ hello/cxx{hello}
+c++ ../libhello/libhello/cxx{hello} ->
+ ../hello-gcc/libhello/libhello/objs{hello}
+c++ ../libhello/tests/basics/cxx{driver} ->
+ ../hello-gcc/libhello/tests/basics/obje{driver}
+c++ hello/cxx{hello} -> ../hello-gcc/hello/hello/obje{hello}
ld ../hello-gcc/libhello/libhello/libs{hello}
ld ../hello-gcc/libhello/tests/basics/exe{driver}
ld ../hello-gcc/hello/hello/exe{hello}
test ../hello-gcc/libhello/tests/basics/exe{driver}
-test hello/testscript{testscript} ../hello-gcc/hello/hello/exe{hello}
+test ../hello-gcc/hello/hello/exe{hello} + hello/testscript{testscript}
\
This is also the approach we would use if we wanted to fix a bug in someone
-else's library. That is, we would clone their project repository and
+else's library. That is, we would clone their library repository and
initialize it in the build configurations of our project which will
\"upgrade\" the dependency to use the local version. Then we make the fix,
submit it upstream, and continue using the local version until our fix is
-merged/published, at which point we deinitialize the project and switch
-back to using the upstream version.
+merged/published, at which point we deinitialize their library repository and
+our project will be automatically switched back to using the new upstream
+version of the library. Here is the summary of the steps in this workflow:
+
+\
+$ cd hello/ # Our project.
+$ bdep init -C @gcc ... # Configures libhello as a dependency.
+
+$ git clone .../libhello.git # Need to fix a bug in libhello.
+$ cd libhello
+$ bdep init -A ../hello-gcc @gcc # Upgrades libhello to local version.
+
+# Fix the bug in libhello, test, and submit upstream.
+# Continue using local libhello until the bugfix is published.
+
+$ cd libhello # Bugfix has been published.
+$ bdep deinit @gcc # Switches libhello back to dependency.
+
+$ rm -r libhello # If no longer needed.
+\
Let's now examine the second option: making \c{libhello} a package inside
\c{hello}. Here is the original structure of our \c{hello} project:
@@ -1879,14 +2274,17 @@ however, that in this case we don't need to add anything to
\
$ cd .. # back to hello project root
$ bdep test
-c++ libhello/libhello/cxx{hello}
-c++ libhello/tests/basics/cxx{driver}
-c++ hello/hello/cxx{hello}
+c++ libhello/libhello/cxx{hello} ->
+ ../hello-gcc/libhello/libhello/objs{hello}
+c++ libhello/tests/basics/cxx{driver} ->
+ ../hello-gcc/libhello/tests/basics/obje{driver}
+c++ hello/hello/cxx{hello} -> ../hello-gcc/hello/hello/obje{hello}
ld ../hello-gcc/libhello/libhello/libs{hello}
ld ../hello-gcc/libhello/tests/basics/exe{driver}
ld ../hello-gcc/hello/hello/exe{hello}
test ../hello-gcc/libhello/tests/basics/exe{driver}
-test hello/hello/testscript{testscript} ../hello-gcc/hello/hello/exe{hello}
+test ../hello-gcc/hello/hello/exe{hello} +
+ hello/hello/testscript{testscript}
\
\N|A multi-package project could have several files, such as \c{README.md} and
@@ -1970,10 +2368,13 @@ configured libformat/1.0.0
configured libprint/1.0.0
configured libhello/1.1.0
configured hello/1.0.0
-c++ libprint-1.0.0/libprint/cxx{print}
-c++ hello-1.0.0/hello/cxx{hello}
-c++ libhello-1.1.0/libhello/cxx{hello}
-c++ libformat-1.0.0/libformat/cxx{format}
+c++ libprint-1.0.0/libprint/cxx{print} ->
+ libprint-1.0.0/libprint/objs{print}
+c++ hello-1.0.0/hello/cxx{hello} -> hello-1.0.0/hello/obje{hello}
+c++ libhello-1.1.0/libhello/cxx{hello} ->
+ libhello-1.1.0/libhello/objs{hello}
+c++ libformat-1.0.0/libformat/cxx{format} ->
+ libformat-1.0.0/libformat/objs{format}
ld libprint-1.0.0/libprint/libs{print}
ld libformat-1.0.0/libformat/libs{format}
ld libhello-1.1.0/libhello/libs{hello}
@@ -1992,16 +2393,24 @@ $ bpkg build hello # build package by name
|
+\N|If building a package involves building a build-time dependency and no
+configuration of type \c{host} (or \c{build2}, if the dependency is a build
+system module) is linked with the target configuration, then a private
+configuration of a suitable type is automatically created and linked. See
+\l{#guide-build-time-linked Build-Time Dependencies and Linked Configurations}
+for background on build-time dependencies and \l{bpkg-cfg-create(1)} for more
+information on \c{bpkg} configuration linking.|
+
Once built, we can install the package to the location that we have specified
with \c{config.install.root} using the \l{bpkg-pkg-install(1)} command:
\
$ bpkg install hello
...
-install libformat-1.0.0/libformat/libs{format}
-install libprint-1.0.0/libprint/libs{print}
-install libhello-1.1.0/libhello/libs{hello}
-install hello-1.0.0/hello/exe{hello}
+install libformat-1.0.0/libformat/libs{format} -> /usr/local/lib/
+install libprint-1.0.0/libprint/libs{print} -> /usr/local/lib/
+install libhello-1.1.0/libhello/libs{hello} -> /usr/local/lib/
+install hello-1.0.0/hello/exe{hello} -> /usr/local/bin/
$ hello World
Hello, World!
@@ -2087,11 +2496,58 @@ If we need to uninstall a previously installed package, there is the
\
$ bpkg uninstall hello
-uninstall hello-1.0.0/hello/exe{hello}
-uninstall libhello-1.1.0/libhello/libs{hello}
-uninstall libprint-1.0.0/libprint/libs{print}
-uninstall libformat-1.0.0/libformat/libs{format}
+uninstall hello-1.0.0/hello/exe{hello} <- /usr/local/bin/
+uninstall libhello-1.1.0/libhello/libs{hello} <- /usr/local/lib/
+uninstall libprint-1.0.0/libprint/libs{print} <- /usr/local/lib/
+uninstall libformat-1.0.0/libformat/libs{format} <- /usr/local/lib/
+...
+\
+
+Rather than installing the package locally we could instead generate a
+\i{binary distribution package} for it using the \l{bpkg-pkg-bindist(1)}
+command. Such a binary package can then be installed on a different
+machine. Currently, the \c{bindist} command supports producing Debian (and
+alike, such as Ubuntu) and Fedora (and alike, such as RHEL) packages as well
+as installation archives for all operating systems. For example, to generate a
+Debian package for our \c{hello} (running on Debian or alike):
+
+\
+$ bpkg bindist --recursive=auto --private -o /tmp/hello-deb/ hello
+...
+generated debian package for hello/1.0.0:
+ /tmp/hello-deb/hello_1.0.0-0~debian12_amd64.deb
+ /tmp/hello-deb/hello-dbgsym_1.0.0-0~debian12_amd64.deb
+ /tmp/hello-deb/hello_1.0.0-0~debian12_amd64.buildinfo
+ /tmp/hello-deb/hello_1.0.0-0~debian12_amd64.changes
+
+$ sudo apt-get install /tmp/hello-deb/hello_1.0.0-0~debian12_amd64.deb
+\
+
+And to generate a Fedora package (running on Fedora or alike):
+
+\
+$ bpkg bindist --recursive=auto --private hello
...
+generated fedora package for hello/1.0.0:
+ ~/rpmbuild/RPMS/x86_64/hello-1.0.0-1.fc38.x86_64.rpm
+ ~/rpmbuild/RPMS/x86_64/hello-debuginfo-1.0.0-1.fc38.x86_64.rpm
+
+$ sudo dnf install ~/rpmbuild/RPMS/x86_64/hello-1.0.0-1.fc38.x86_64.rpm
+\
+
+And to generate an installation archive (running on Windows in this
+example):
+
+\
+$ bpkg bindist --recursive=auto ^
+ --private ^
+ --distribution=archive ^
+ -o C:\tmp\hello-zip\ ^
+ config.install.relocatable=true ^
+ hello
+...
+generated archive package for hello/1.0.0:
+ C:\tmp\hello-zip\hello-1.0.0-x86_64-windows10.zip
\
To upgrade or downgrade packages we again use the \c{build} command. Here
@@ -2140,6 +2596,7 @@ purged libformat
purged libprint
\
+
\h#guide-system-deps|Using System-Installed Dependencies|
Our operating system might already have a package manager (which we will refer
@@ -2154,16 +2611,25 @@ and/or test with multiple versions (which is not something that many system
package managers support).
We can also have some build configurations using a system-installed version of
-a dependency while others building it from source, for example, for testing.|
+a dependency while in others building it from source, for example, for
+testing.|
We can instruct \c{build2} to configure a dependency package as available from
-the system rather than building it from source. Let's see how this works in an
-example. Say, we want to use \l{https://cppget.org/libsqlite3 \c{libsqlite3}}
-in our \c{hello} project.
-
-The first step is to add it as a dependency, just like we did for \c{libhello}.
-That is, add another \c{depends} entry to \c{manifest}, then import it in
-\c{buildfile}, and so on.
+the system rather than building it from source. Specifically, we can install a
+suitable version manually (for example, using the system package manager) and
+then communicate this fact as well as the version installed to \c{build2} so
+that it can use this information when resolving version constraints.
+Furthermore, for Debian (and alike, such as Ubuntu) and Fedora (and alike,
+such as RHEL) \c{build2} can automatically query the system package manager
+for the installed version and, if requested, automatically install a suitable
+version from the system repository if none is already installed.
+
+Let's see how all this works in an example. Say, we want to use
+\l{https://cppget.org/libsqlite3 \c{libsqlite3}} in our \c{hello} project.
+
+The first step is to add it as a dependency, just like we did for
+\c{libhello}. That is, add another \c{depends} entry to \c{manifest}, then
+import it in \c{buildfile}, and so on.
Now, if we just run \c{sync} or try to build our project, \c{build2} will
download and build the new dependency from source, just like it did for
@@ -2172,39 +2638,126 @@ configures the \c{libsqlite3} package as coming from the system:
\
$ bdep sync ?sys:libsqlite3
+\
+
+Here \c{?} is a package flag that instructs \c{build2} to treat it as a
+dependency and \c{sys} is a package scheme that tells \c{build2} it comes from
+the system. See \l{bpkg-pkg-build(1)} for details.
+
+Now what exactly happens in this case depends on which operating system we are
+running as well as whether \c{libsqlite3} is already installed. Let's examine
+each combination in turn.
+
+If we are running on an operating system for which there is \c{build2} support
+for the system package manager interactions (currently Debian, Fedora, or
+alike) and \c{libsqlite3} is already installed, then \c{build2} will get its
+version from the system package manager and use that when resolving version
+constraints. For example, running the above command on Debian with
+\c{libsqlite3-dev} version \c{3.42.0} already installed:
+
+\
+$ bdep sync ?sys:libsqlite3
synchronizing:
- configure sys:libsqlite3/*
+ configure sys:libsqlite3/3.42.0 (required by hello)
upgrade hello/0.1.0-a.0.19700101000000#3
\
-Here \cb{?} is a package \i{flag} that instructs \c{build2} to treat it as a
-dependency and \cb{sys} is a package \i{scheme} that tells \c{build2} it comes
-from the system. See \l{bpkg-pkg-build(1)} for details.
+If, on the other hand, we are running on an operating system for which there
+is \c{build2} support for the system package manager interactions but
+\c{libsqlite3} is not installed, then \c{build2} will fail:
+
+\
+$ bdep sync ?sys:libsqlite3
+error: no installed system package for libsqlite3
+ info: specify --sys-install to try to install it
+ info: specify libsqlite3/* if package is not installed with system
+ package manager
+ info: specify --sys-no-query to disable system package manager
+ interactions
+\
+
+As you can see, \c{build2} will not attempt to automatically install system
+packages unless explicitly requested with the \c{--sys-install} option. Let's
+try to add that (again, running on Debian):
+
+\
+$ bdep sync --sys-install ?sys:libsqlite3
+updating debian package index...
+synchronizing:
+ sys-install libsqlite3-0/3.42.0-1 (required by sys:libsqlite3)
+ configure sys:libsqlite3/3.42.0 (required by hello)
+ upgrade hello/0.1.0-a.0.19700101000000#3
+installing debian packages...
+The following NEW packages will be installed:
+ libsqlite3-dev
+The following packages will be upgraded:
+ libsqlite3-0 sqlite3
+Do you want to continue? [Y/n] y
+...
+Setting up libsqlite3-0:amd64 (3.42.0-1) ...
+Setting up libsqlite3-dev:amd64 (3.42.0-1) ...
+Setting up sqlite3 (3.42.0-1) ...
+\
+
+\N|You can suppress the system package manager confirmation prompt with the
+\c{--sys-yes} option. By default \c{build2} uses \c{sudo} for system package
+manager interactions that normally require administrative privileges (fetch
+package metadata, install packages, etc). This can be customized with the
+\c{--sys-sudo} option.|
+
+Finally, if we are running on an operating system for which there is no
+\c{build2} support for the system package manager interactions, then, as
+mentioned earlier, it is the user's responsibility to make sure a suitable
+package is installed and, optionally, communicate its version. In this case,
+unless we specify the installed version explicitly, a system-installed package
+is assumed to satisfy any dependency constraint (indicated with the \c{*}
+wildcard instead of the version):
+
+\
+$ bdep sync ?sys:libsqlite3
+synchronizing:
+ configure sys:libsqlite3/* (required by hello)
+ upgrade hello/0.1.0-a.0.19700101000000#3
+\
+
+\N|You can reduce the supported system package manager case to this case by
+disabling the system package manager interactions with the \c{--sys-no-query}
+option.|
\N|The system-installed dependency doesn't really have to come from the system
package manager. It can also be manually installed and, as discussed in
\l{#guide-unpackaged-deps Using Unpackaged Dependencies}, not necessarily into
the system-default location like \c{/usr/local}.|
-In the above example our dependency still has to be packaged and available
-from one of the project's prerequisite repositories. But it can be a \i{stub}
-\- a package that does not contain any source code and that can only be
-\"obtained\" from the system (see \l{bpkg#package-version Package Version} for
-details). However, if we would like to use a completely unpackaged dependency,
-then we will have to specify its version explicitly either as the actual
-version or as the \c{*} wildcard, for example:
+In the above examples our dependency (\c{libsqlite3}) still has to be packaged
+and available from one of the project's prerequisite repositories. But it can
+be a \i{stub} \- a package that does not contain any source code and that can
+only be \"obtained\" from the system.
+
+\N|The purpose of a stub is to provide the \c{build2} package to system
+package name and version mapping, in case it cannot be deduced automatically.
+See \l{bpkg#package-version Package Version} and
+\l{bpkg#manifest-package-distribution \c{*-{name, version,
+to-downstream-version\}}} package manifest values for details.|
+
+If we would like to use a completely unpackaged dependency, then, for the
+supported system package manager case, we will need to pass the
+\c{--sys-no-stub} option:
+
+\
+$ bdep sync --sys-install --sys-no-stub ?sys:libsqlite3
+\
+
+And for the unsupported system package manager case we will have to specify
+the system version explicitly either as the actual version or as the \c{*}
+wildcard, for example:
\
$ bdep sync ?sys:libsqlite3/* ?sys:libcurl/7.47.0
\
-\N|Currently, unless we specify the installed version explicitly, a
-system-installed package is assumed to satisfy any dependency constraint. In
-the future, \c{build2} will automatically query commonly used system package
-managers for the installed version and maybe even request installation of the
-absent packages. To support this functionality, the package manifest may need
-to specify package name mappings for various system package managers (which is
-the rationale behind stub packages).|
+\N|The reason at least a stub is required by default is due to the automatic
+mapping between \c{build2} and system packages often being unreliable.|
\h#guide-unpackaged-deps|Using Unpackaged Dependencies|
@@ -2354,7 +2907,7 @@ applies equally to C projects.
\N|We often find ourselves factoring common functionality out of such
end-products and into separate packages, for example, in order to be reused in
-another end-product). In this light, it can be helpful to organize a new
+another end-product. In this light, it can be helpful to organize a new
end-product project as a composition of individual packages or source
subdirectories that follow the canonical structure. The \l{bdep-new(1)}
\c{--package} and \c{--source} modes can be used to automate this process.|
@@ -2401,8 +2954,8 @@ below.
\li|\n\n\i{Header and source files (or module interface and implementation
files) are next to each other (no \c{include/} and \c{src/} split).}|
-\li|\n\i{Headers are included with \c{<>} and contain the project directory
-prefix, for example, \c{<libhello/hello.hxx>}.}|
+\li|\n\i{Headers are included with \c{<>} and contain the project name as
+a subdirectory prefix, for example, \c{<libhello/hello.hxx>}.}|
\li|\n\i{Header and source file extensions are either \c{.hpp/.cpp} or
\c{.hxx/.cxx} (\c{.mpp} or \c{.mxx} for module interfaces).}|
@@ -2452,7 +3005,7 @@ subdirectories (\c{build/}) as well as the available alternative naming
scheme.
-\h#proj-struct-src-dir|Source Directory|
+\h#proj-struct-src-dir|Source Subdirectory|
The project's source code is placed into a subdirectory of the root directory
named the same as the project, for example, \c{hello/hello/} or
@@ -2460,11 +3013,11 @@ named the same as the project, for example, \c{hello/hello/} or
There are several reasons for this layout: It implements the canonical
inclusion scheme (discussed below) where each header is prefixed with its
-project name. It also has a predictable name where users (and tools) can
-expect to find our project's source code. Finally, this layout prevents
-clutter in the project's root directory which usually contains various other
-files (like \c{README}, \c{LICENSE}) and directories (like \c{doc/},
-\c{tests/}, \c{examples/}).
+project name as a subdirectory. It also has a predictable name where users
+(and tools) can expect to find our project's source code. Finally, this layout
+prevents clutter in the project's root directory which usually contains
+various other files (like \c{README}, \c{LICENSE}) and directories (like
+\c{doc/}, \c{tests/}, \c{examples/}).
\N|Another popular approach is to place public headers into the \c{include/}
subdirectory and source files as well as private headers into \c{src/}. The
@@ -2527,8 +3080,8 @@ suffix, a mechanism that is readily available in the combined directory
layout.|
All headers within a project should be included using the \c{<>} style
-inclusion and contain the project name as a directory prefix. And all headers
-means \i{all headers} \- public, private, or implementation detail, in
+inclusion and contain the project name as a subdirectory prefix. And all
+headers means \i{all headers} \- public, private, or implementation detail, in
executables or in libraries.
As an example, let's say we've added \c{utility.hxx} to our \c{hello} project.
@@ -2557,10 +3110,11 @@ listed as to be installed), chances are that a completely unrelated header
with the same name will be found and included. Needless to say, debugging
situations like these is unpleasant.
-Prefixing all inclusions with the project name also makes sure that headers
-with common names (for example, \c{utility.hxx}) can coexist (for example,
-when installed into a system-wide directory, such as \c{/usr/include}). The
-prefix also plays an important role in supporting auto-generated headers.
+Prefixing all inclusions with the project name as subdirectory also makes sure
+that headers with common names (for example, \c{utility.hxx}) can coexist (for
+example, when installed into a system-wide directory, such as
+\c{/usr/include}). The subdirectory prefix also plays an important role in
+supporting auto-generated headers.
Note also that this header inclusion scheme is consistent with the module
importation, for example:
@@ -2569,7 +3123,7 @@ importation, for example:
import hello.utility;
\
-Finally, note that while adding the project prefix to the \c{\"\"} style
+Finally, note that while adding the subdirectory prefix to the \c{\"\"} style
inclusion (for example, \c{\"libhello/hello.hxx\"}) will make finding an
unrelated header unlikely, there is still a possibility. And it is not clear
why take the chance when there are no benefits. So let's imagine the \c{\"\"}
@@ -2578,7 +3132,7 @@ style inclusion does not exist and we will all have a much better time.|
If you have to disregard every rule and recommendation in this section but
one, for example, because you are working on an existing library, then at
minimum insist on this: \b{public header inclusions must use the library name
-as a directory prefix}.
+as a subdirectory prefix}.
The project's source subdirectory can have subdirectories of its own, for
example, to organize the code into components. Naturally, header inclusions
@@ -2615,10 +3169,10 @@ details/hxx{*}: install = false
\
\N|If you are creating a \i{family of libraries} with a common name prefix,
-then it may make sense to use a nested source directory layout with a common
-top-level directory. As an example, let's say we have the \c{libstud-path} and
-\c{libstud-url} libraries that belong to the same \c{libstud} family. Their
-source subdirectory layouts could look like this:
+then it may make sense to use a nested source subdirectory layout with a
+common top-level directory. As an example, let's say we have the
+\c{libstud-path} and \c{libstud-url} libraries that belong to the same
+\c{libstud} family. Their source subdirectory layouts could look like this:
\
libstud-path/
@@ -2850,8 +3404,8 @@ automatically excluded from the library/executable sources.|
A library's functional/integration tests should go into the \c{tests/}
subdirectory. Each such test should reside in a separate subdirectory,
potentially organized into nested subdirectories (for instance, to correspond
-to the source directory components). For example, if we were creating an XML
-parsing and serialization library, then our \c{tests/} could have the
+to the source subdirectory components). For example, if we were creating an
+XML parsing and serialization library, then our \c{tests/} could have the
following layout:
\
@@ -2914,9 +3468,9 @@ of an out of source build) or next to the sources (in case of an in source
build). See \l{b#intro-dirs-scopes Output Directories and Scopes} for details
on in and out of source builds.
-Projects managed with \l{bdep(1)} are always built out-of-source. However, by
+Projects managed with \l{bdep(1)} are always built out of source. However, by
default, the source directory is configured as \i{forwarded} to one of the
-out-of-source builds. This has two effects: we can run the build system driver
+out of source builds. This has two effects: we can run the build system driver
\l{b(1)} directly in the source directory and certain \"interesting\" targets
(such as executables, documentation, test results, etc) will be automatically
\i{backlinked} to the source directory (see \l{b#intro-operations-config
@@ -2933,7 +3487,7 @@ hello/ ~~> └── hello/
└── hello --> └── *hello
\
-The result is an \i{as-if} in-source build with all the benefits (such as
+The result is an \i{as-if} in source build with all the benefits (such as
having both source and relevant output in the same directory) but without any
of the drawbacks (such as the inability to have multiple builds or source
directory cluttered with object files).