| ``dds`` has been designed from the very beginning as an extremely opinionated | ``dds`` has been designed from the very beginning as an extremely opinionated | ||||
| hybrid *build system* and *package manager*. Unlike most build systems however, | hybrid *build system* and *package manager*. Unlike most build systems however, | ||||
| ``dds`` has a hyper-specific focus on a particular aspect of software | ``dds`` has a hyper-specific focus on a particular aspect of software | ||||
| development: C++ libraries. | |||||
| development: C and C++ libraries. | |||||
| This may sound pointless, right? Libraries are useless unless we can use them | This may sound pointless, right? Libraries are useless unless we can use them | ||||
| to build applications! | to build applications! | ||||
| Indeed, applications *are* essential, but that is "not our job." | |||||
| Indeed, applications *are* essential, but that is "not our job" with ``dds``. | |||||
| Another design decision is that ``dds`` is built to be driven by automated | Another design decision is that ``dds`` is built to be driven by automated | ||||
| tools as well as humans. ``dds`` will not build your AAA console game, nor will | |||||
| it compile an OS kernel. Instead, the build system of your AAA console game or | |||||
| OS kernel can *use* ``dds``. | |||||
| tools as well as humans. ``dds`` is not designed to entirely replace existing | |||||
| build systems and package management solutions. Rather, it is designed to be | |||||
| easy to integrate *with* existing systems and tools. | |||||
| Background | Background | ||||
| ********** | ********** | ||||
| I'm going to say something somewhat controversial: C++ doesn't need "package | |||||
| management." At least, not *generalize* "package management." C++ needs | |||||
| *library* "package management." | |||||
| I'm going to say something somewhat controversial: C and C++ don't need | |||||
| "package management." At least, not *generalized* "package management." C++ | |||||
| needs *library* "package management." | |||||
| The C and C++ compilation model is inherently *more complex* than almost any | The C and C++ compilation model is inherently *more complex* than almost any | ||||
| other language in use today. This isn't to say "bad," but rather than it is | other language in use today. This isn't to say "bad," but rather than it is | ||||
| different, despite both using the same underlying "Build System." | different, despite both using the same underlying "Build System." | ||||
| ``dds`` takes a massive divergence at this point. One project using ``dds`` as | ``dds`` takes a massive divergence at this point. One project using ``dds`` as | ||||
| their build system has an identical build process to every other project using | |||||
| ``dds``. Simply running :code:`dds -F` is enough to build *any* ``dds`` | |||||
| project. | |||||
| their build system has a nearly identical build process to every other project | |||||
| using ``dds``. Simply running :code:`dds build -t <toolchain>` should be enough | |||||
| to build *any* ``dds`` project. | |||||
| In order to reach this uniformity and simplicity, ``dds`` drops almost all | In order to reach this uniformity and simplicity, ``dds`` drops almost all | ||||
| aspects of project-by-project customizability. Instead, ``dds`` affords the | aspects of project-by-project customizability. Instead, ``dds`` affords the | ||||
| on. | on. | ||||
| ``dds`` contains a minimal amount of functionality for building simple | ``dds`` contains a minimal amount of functionality for building simple | ||||
| applications, but it is certainly not its primary purpose (See the ``--apps`` | |||||
| flag). | |||||
| applications, but it is certainly not its primary purpose. | |||||
| .. _design.rules.change: | .. _design.rules.change: | ||||
| .. note:: | .. note:: | ||||
| These prescriptions are not as draconian as they may sound upon first | These prescriptions are not as draconian as they may sound upon first | ||||
| reading. Refer to the :doc:`layout` page for more information. | |||||
| reading. Refer to the :doc:`packages` page for more information. | |||||
| .. _Pitchfork: https://api.csswg.org/bikeshed/?force=1&url=https://raw.githubusercontent.com/vector-of-bool/pitchfork/develop/data/spec.bs | .. _Pitchfork: https://api.csswg.org/bikeshed/?force=1&url=https://raw.githubusercontent.com/vector-of-bool/pitchfork/develop/data/spec.bs | ||||
| Only ``src/`` and ``include/`` will ever be used as the basis for header | Only ``src/`` and ``include/`` will ever be used as the basis for header | ||||
| resolution while building a library, so all ``#include`` directives should be | resolution while building a library, so all ``#include`` directives should be | ||||
| relative to those directories. Refer to :ref:`guide.layout.include`. | |||||
| relative to those directories. Refer to :ref:`pkg.source-root`. | |||||
| .. _design.rules.uniform-compile: | .. _design.rules.uniform-compile: | ||||
| identical set of options. Additionally, when DDS compiles a dependency tree, | identical set of options. Additionally, when DDS compiles a dependency tree, | ||||
| every library in that dependency tree will be compiled with an identical set of | every library in that dependency tree will be compiled with an identical set of | ||||
| options. Refer to the :doc:`toolchains` page for more information. | options. Refer to the :doc:`toolchains` page for more information. | ||||
| Currently, the only exception to this rules is for flags that control compiler | |||||
| warnings: Dependencies will be compiled without adding any warnings flags, | |||||
| while the main project will be compiled with warnings enabled by default. |
| :maxdepth: 2 | :maxdepth: 2 | ||||
| design | design | ||||
| layout | |||||
| packages | |||||
| toolchains | toolchains |
| Project Layout | |||||
| ############## | |||||
| The layout expected by ``dds`` is based on the `Pitchfork layout`_ (PFL). | |||||
| ``dds`` does not make use of every provision of the layout document, but the | |||||
| features it does have are based on PFL. | |||||
| .. _Pitchfork layout: https://api.csswg.org/bikeshed/?force=1&url=https://raw.githubusercontent.com/vector-of-bool/pitchfork/develop/data/spec.bs | |||||
| In particular, the following directories are used: | |||||
| - ``src/`` | |||||
| - ``include/`` | |||||
| - ``libs/`` | |||||
| - ``_build/`` (the default build output directory used by ``dds``). | |||||
| Note that the ``libs/*/`` directories can contain their own ``src/`` and | |||||
| ``include/`` directories, the purposes and behaviors of which match those of | |||||
| their top-level counterparts. | |||||
| .. _guide.layout.include: | |||||
| Include Directories and Header Resolution | |||||
| ***************************************** | |||||
| A compiler's "include path" is the list of directories in which it will attempt | |||||
| to resolve ``#include`` directives. | |||||
| The layout prescriptions permit either ``src/``, ``include/``, or both. In the | |||||
| presence of both, the ``include/`` directory is used as the *public* include | |||||
| directory, and ``src/`` is used as the *private* include directory. When only | |||||
| one of either is present, that directory will be treated as the *public* | |||||
| include directory (and there will be no *private* include directory). | |||||
| .. _guide.layout.sources: | |||||
| Source Files | |||||
| ************ | |||||
| ``dds`` distinguishes between *headers* and *compilable* sources. The heuristic | |||||
| used is based on common file extensions: | |||||
| The following are considered to be *header* source files: | |||||
| - ``.h`` | |||||
| - ``.hpp`` | |||||
| - ``.hxx`` | |||||
| - ``.inl`` | |||||
| - ``.h++`` | |||||
| While the following are considered to be *compilable* source files: | |||||
| - ``.c`` | |||||
| - ``.cpp`` | |||||
| - ``.cc`` | |||||
| - ``.cxx`` | |||||
| - ``.c++`` | |||||
| ``dds`` will compile every compilable source file that appears in the ``src/`` | |||||
| directory. ``dds`` will not compile compilable source files that appear in the | |||||
| ``include/`` directory and will issue a warning on each file found. | |||||
| .. _guide.layout.apps-tests: | |||||
| Applications and Tests | |||||
| ********************** | |||||
| ``dds`` will recognize certain compilable source files as belonging to | |||||
| applications and tests. If a compilable source file stem ends with ``.main`` or | |||||
| ``.test``, that source file is assumed to correspond to an executable to | |||||
| generate. The filename stem before the ``.main`` or ``.test`` will be used as | |||||
| the name of the generated executable. For example: | |||||
| - ``foo.main.cpp`` will generate an executable named ``foo``. | |||||
| - ``bar.test.cpp`` will generate an executable named ``bar``. | |||||
| - ``cat-meow.main.cpp`` will generate an executable named ``cat-meow``. | |||||
| - ``cats.musical.test.cpp`` will generate an executable named ``cats.musical``. | |||||
| .. note:: | |||||
| ``dds`` will automatically append the appropriate filename extension to the | |||||
| generated executables based on the host and toolchain. | |||||
| If the inner extension is ``.main``, then ``dds`` will assume the corresponding | |||||
| executable to be an *application*. If the inner extension is ``.test``, ``dds`` | |||||
| will assume the executable to be a test. | |||||
| The building of tests and applications can be controlled when running | |||||
| ``dds build``. If tests are built, ``dds`` will automatically execute those | |||||
| tests in parallel once the executables have been generated. | |||||
| In any case, the executables are associated with a *library*, and, when those | |||||
| executables are linked, the associated library (and its dependencies) will be | |||||
| linked into the final executable. There is no need to manually specify this | |||||
| linking behavior. | |||||
| .. _guide.layout.libraries: | |||||
| Libraries | |||||
| ********* | |||||
| The *library* is a fundamental unit of consumable code, and ``dds`` is | |||||
| specifically built to work with them. When you are in ``dds``, the library is | |||||
| the center of everything. | |||||
| A *source root* is a directory that contains the ``src/`` and/or ``include/`` | |||||
| directories. The ``src/`` and ``include/`` directories are themselves | |||||
| *source directories*. A single *source root* will always correspond to exactly | |||||
| one library. If the library has any compilable sources then ``dds`` will use | |||||
| those sources to generate a static library file that is linked into runtime | |||||
| binaries. If a library contains only headers then ``dds`` will not generate an | |||||
| archive to be included in downstream binaries, but it will still generate link | |||||
| rules for the dependencies of a header-only library. | |||||
| In the previous section, :ref:`guide.layout.apps-tests`, it was noted that | |||||
| applications and tests are associated with a library. This association is | |||||
| purely based on being collocated within the same source root. | |||||
| When an executable is built within the context of a library, that library (and | |||||
| all of its dependencies) will be linked into that executable. |
| Package Layout | |||||
| ############## | |||||
| The units of distribution in ``dds`` are *packages*. A single package consists | |||||
| of one or more *libraries*. In the simplest case, a package will contain a | |||||
| single library. | |||||
| It may be easiest to work from the bottom-up when trying to understand how | |||||
| ``dds`` understands code. | |||||
| The layout expected by ``dds`` is based on the `Pitchfork layout`_ (PFL). | |||||
| ``dds`` does not make use of every provision of the layout document, but the | |||||
| features it does have are based on PFL. | |||||
| .. _Pitchfork layout: https://api.csswg.org/bikeshed/?force=1&url=https://raw.githubusercontent.com/vector-of-bool/pitchfork/develop/data/spec.bs | |||||
| In particular, the following directories are used: | |||||
| - ``src/`` | |||||
| - ``include/`` | |||||
| - ``libs/`` | |||||
| - ``_build/`` (the default build output directory used by ``dds``). | |||||
| Note that the ``libs/*/`` directories can contain their own ``src/`` and | |||||
| ``include/`` directories, the purposes and behaviors of which match those of | |||||
| their top-level counterparts. | |||||
| Source Files | |||||
| ************ | |||||
| The smallest subdivision of code that ``dds`` recognizes is the *source file*, | |||||
| which is exactly as it sounds: A single file containing some amount of code. | |||||
| Source files can be grouped on a few axes, the most fundamental of which is | |||||
| "Is this compiled?" | |||||
| ``dds`` uses source file extensions to determine whether a source file should | |||||
| be fed to the compiler. All of the common C and C++ file extensions are | |||||
| supported: | |||||
| .. list-table:: | |||||
| - * Compiled as C | |||||
| * ``.c`` and ``.C`` | |||||
| - * Compiled as C++ | |||||
| * ``.cpp``, ``.c++``, ``.cc``, and ``.cxx`` | |||||
| - * Not compiled | |||||
| * ``.H``, ``.H++``, ``.h``, ``.h++``, ``.hh``, ``.hpp``, ``.hxx``, and ``.inl`` | |||||
| If a file's extension is not listed in the table above, ``dds`` will ignore it. | |||||
| .. note:: | |||||
| Although headers are not compiled, this does not mean they are ignored. | |||||
| ``dds`` still understands and respects headers, and they are collected | |||||
| together as part of *source distribution*. | |||||
| Applications and Tests | |||||
| ********************** | |||||
| ``dds`` will recognize certain compilable source files as belonging to | |||||
| applications and tests. If a compilable source file stem ends with ``.main`` or | |||||
| ``.test``, that source file is assumed to correspond to an executable to | |||||
| generate. The filename stem before the ``.main`` or ``.test`` will be used as | |||||
| the name of the generated executable. For example: | |||||
| - ``foo.main.cpp`` will generate an executable named ``foo``. | |||||
| - ``bar.test.cpp`` will generate an executable named ``bar``. | |||||
| - ``cat-meow.main.cpp`` will generate an executable named ``cat-meow``. | |||||
| - ``cats.musical.test.cpp`` will generate an executable named ``cats.musical``. | |||||
| .. note:: | |||||
| ``dds`` will automatically append the appropriate filename extension to the | |||||
| generated executables based on the host and toolchain. | |||||
| An *application* source file is a source file whose file stem ends with | |||||
| ``.main``. ``dds`` will assume this source file to contain a program entry | |||||
| point function and not include it as part of the main library build. Instead, | |||||
| when ``dds`` is generating applications, the source file will be compiled, and | |||||
| the resulting object will be linked together with the enclosing library into an | |||||
| executable. | |||||
| A *test* source file is a source file whose file stem ends with ``.test``. Like | |||||
| application sources, a *test* source file is omitted from the main library, and | |||||
| it will be used to generate tests. The exact behavior of tests is determined by | |||||
| the ``Test-Driver`` setting for the package, but the default is that each test | |||||
| source file will generate a single test executable that is executed by ``dds`` | |||||
| when running unit tests. | |||||
| The building of tests and applications can be controlled when running | |||||
| ``dds build``. If tests are built, ``dds`` will automatically execute those | |||||
| tests in parallel once the executables have been generated. | |||||
| In any case, the executables are associated with a *library*, and, when those | |||||
| executables are linked, the associated library (and its dependencies) will be | |||||
| linked into the final executable. There is no need to manually specify this | |||||
| linking behavior. | |||||
| .. _pkg.source-root: | |||||
| Source Roots | |||||
| ************ | |||||
| Source files are collected as children of some *source root*. A *source | |||||
| root* is a single directory that contains some *portable* bundle of source | |||||
| files. The word "portable" is important: It is what distinguishes the | |||||
| source root from its child directories. | |||||
| Portability | |||||
| =========== | |||||
| By saying that a source root is "portable", It indicates that the directory | |||||
| itself can be moved, renamed, or copied without breaking the ``#include`` | |||||
| directives of its children or of the directory's referrers. | |||||
| As a practical example, let's examine such a directory, which we'll call | |||||
| ``src/`` for the purposes of this example. Suppose we have a directory named | |||||
| ``src`` with the following structure: | |||||
| .. code-block:: text | |||||
| <path>/src/ | |||||
| animals/ | |||||
| mammal/ | |||||
| mammal.hpp | |||||
| cat/ | |||||
| cat.hpp | |||||
| sound.hpp | |||||
| sound.cpp | |||||
| dog/ | |||||
| dog.hpp | |||||
| sound.hpp | |||||
| sound.cpp | |||||
| In this example, ``src/`` is a *source root*, but ``src/animals/``, | |||||
| ``src/animals/cat/``, and ``src/animals/dog/`` are **not** source roots. | |||||
| While they may be directories that contain source files, they are not "roots." | |||||
| Suppose now that ``dog.hpp`` contains an ``#include`` directive: | |||||
| .. code-block:: c++ | |||||
| #include <animals/mammal/mammal.hpp> | |||||
| or even a third-party user that wants to use our library: | |||||
| .. code-block:: c++ | |||||
| #include <animals/dog/dog.hpp> | |||||
| #include <animals/dog/sound.hpp> | |||||
| In order for any code to compile and resolve these ``#include`` directives, the | |||||
| ``src/`` directory must be added to their *include search path*. | |||||
| Because the ``#include`` directives are based on the *portable* source root, | |||||
| the exactly location of ``src/`` is not important to the content of the | |||||
| consuming source code, and can thus be relocated and renamed as necessary. | |||||
| Consumers only need to update the path of the *include search path* in a single | |||||
| location rather than modifying their source code. | |||||
| Source Roots in ``dds`` | |||||
| ======================= | |||||
| To avoid ambiguity and aide in portability, the following rules should be | |||||
| strictly adhered to: | |||||
| #. Source roots may not contain other source roots. | |||||
| #. Only source roots will be added to the *include-search-path*. | |||||
| #. All ``#include``-directives are relative to a source root. | |||||
| By construction, ``dds`` cannot build a project that has nested source roots, | |||||
| and it will only ever add source roots to the *include-search-path*. | |||||
| ``dds`` supports either one or two source roots in a library. | |||||
| Library Roots | |||||
| ************* | |||||
| In ``dds``, a *library root* is a directory that contains a ``src/`` directory, | |||||
| an ``include/`` directory, or both. ``dds`` will treat both directories as | |||||
| source roots, but behaves differently between the two. The ``src/`` and | |||||
| ``include/`` directories are themselves *source roots*. | |||||
| ``dds`` distinguishes between a *public* include-directory, and a *private* | |||||
| include-directory. When ``dds`` is compiling a library, both its *private* and | |||||
| its *public* include-paths will be added to the compiler's | |||||
| *include-search-path*. When a downstream user of a library is compiling against | |||||
| a library managed by ``dds``, only the *public* include-directory will be | |||||
| added to the compiler's *include-search-path*. This has the effect that only | |||||
| the files that are children of the source root that is the *public* | |||||
| include-directory will be available when compiling consumers. | |||||
| .. warning:: | |||||
| Because only the *public* include-directory is available when compiling | |||||
| consumers, it is essential that no headers within the *public* | |||||
| include-directory attempt to use headers from the *private* | |||||
| include-directory, as they **will not** be visible. | |||||
| If both ``src/`` and ``include/`` are present in a library root, then ``dds`` | |||||
| will use ``include/`` as the *public* include-directory and ``src/`` as the | |||||
| *private* include-directory. If only one of the two is present, then that | |||||
| directory will be treated as the *public* include-directory, and there will be | |||||
| no *private* include-directory. | |||||
| When ``dds`` exports a library, the header files from the *public* | |||||
| include-directory source root will be collected together and distributed as | |||||
| that library's header tree. The path to the individual header files relative to | |||||
| their source root will be retained as part of the library distribution. | |||||
| ``dds`` will compile every compilable source file that appears in the ``src/`` | |||||
| directory. ``dds`` will not compile compilable source files that appear in the | |||||
| ``include/`` directory and will issue a warning on each file found. | |||||
| Libraries | |||||
| ********* | |||||
| The *library* is a fundamental unit of consumable code, and ``dds`` is | |||||
| specifically built to work with them. When you are in ``dds``, the library is | |||||
| the center of everything. | |||||
| A single *library root* will always correspond to exactly one library. If the | |||||
| library has any compilable sources then ``dds`` will use those sources to | |||||
| generate a static library file that is linked into runtime binaries. If a | |||||
| library contains only headers then ``dds`` will not generate an archive to be | |||||
| included in downstream binaries, but it will still generate link rules for the | |||||
| dependencies of a header-only library. | |||||
| In order for ``dds`` to be able to distribute and interlink libraries, a | |||||
| ``library.dds`` file must be present at the corresponding library root. | |||||
| Package Roots | |||||
| ************* | |||||
| A *package root* is a directory that contains some number of library roots. If | |||||
| the package root contains a ``src/`` and/or ``include/`` directory then the | |||||
| package root is itself a library root, and a library is defined at the root of | |||||
| the package. This is intended to be the most common and simplest method of | |||||
| creating libraries with ``dds``. | |||||
| If the package root contains a ``libs/`` directory, then each subdirectory of | |||||
| the ``libs/`` directory is checked to be a library root. Each direct child of | |||||
| the ``libs/`` directory that is also a library root is added as a child of the | |||||
| owning package. | |||||
| Packages | |||||
| ******** | |||||
| A package is defined by some *package root*, and contains some number of | |||||
| *libraries*. In order for a package to be exported by ``dds`` it must have a | |||||
| ``package.dds`` file at its package root. |
| DDS | DDS | ||||
| ###### | ###### | ||||
| **dds** is the Drop-Dead-Simple Build and Library Management Tool. | |||||
| **dds** is the Drop-Dead-Simple build and library management tool. | |||||
| dds is a hybrid build system and package manager with a unique twist. | |||||
| There's a lot to learn, but I'm glad you're here! I hope you find ``dds`` | |||||
| useful to you and your projects. | |||||
| dds is a hybrid build system and package manager with a few distinguishing | |||||
| design decisions that set it apart from current offerings. There's a lot to | |||||
| learn, but I'm glad you're here! I hope you find ``dds`` useful to you and your | |||||
| projects. | |||||
| If you're completely new and have no idea what the project is about, check out | If you're completely new and have no idea what the project is about, check out | ||||
| the :doc:`guide/design` page to get started. | the :doc:`guide/design` page to get started. |