``dds`` Design and Rationale ############################ ``dds`` has been designed from the very beginning as an extremely opinionated hybrid *build system* and *package manager*. Unlike most build systems however, ``dds`` has a strong focus on a particular aspect of software development: C and C++ libraries. This may sound pointless, right? Libraries are useless unless we can use them to build applications! Indeed, applications *are* essential, and ``dds`` is able to build those as well. Another design decision is that ``dds`` is built to be driven by automated 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 ********** 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 other language in use today. This isn't to say "bad," but rather than it is built to meet extremely high and strange demands. It also comes with a large burden of *legacy*. Meeting both of these requirements simultaneously presents incredible implementation challenges. Despite the vast amount of work put into build systems and tooling, virtually all developers are using them *incorrectly* and/or *dangerously* without realizing it, and we seem to be still a great distance from a unified library package distribution and consumption mechanism. Tabula Rasa *********** ``dds`` attempts to break from the pattern of legacy demands and strange usage demands in a few ways. The major differences between ``dds`` and other build systems like CMake, Meson, build2, SCons, MSBuild, etc. is that of *tradeoffs*. If you opt-in to have your library built by ``dds``, you forgoe *customizability* in favor of *simplicity* and *ease*. ``dds`` takes a look at what is needed to build and develop *libraries* and optimizes for that use case. It is also built with a very strong, very opinionated idea of *how* libraries should be constructed and used. These prescriptions are not at all arbitrary, though. They are built upon the observations of the strengths and weaknesses of build systems in use throughout industry and community. There is some ambiguity on the term "build system." It can mean one of two things: 1. A *proper noun* "Build System," such as CMake, Meson, Autotools, or even Gulp, WebPack, and Mix. These are specific tools that have been developed for the implementation of the second definition: 2. A general noun "build system" refers to the particular start-to-finish process through which a specific piece of software is mapped from its raw *inputs* (source code, resource libraries, toolchains) to the outputs (applications, appliances, libraries, or web sites). For example, LLVM and Blender both use the CMake "Build System," but their "build system" is not the same. The "build system" for each is wildly different, despite both using the same underlying "Build System." ``dds`` takes a massive divergence at this point. One project using ``dds`` as their build system has a nearly identical build process to every other project using ``dds``. Simply running ``dds build`` should be enough to build *any* ``dds`` project. In order to reach this uniformity and simplicity, ``dds`` drops almost all aspects of project-by-project customizability. Instead, ``dds`` affords the developer a contract: If you play by the rules, you get to play in this space. .. _design.rules: The Rules ********* We've talked an awful lot about the "rules" and "restrictions" that ``dds`` imposes, but what are they? .. _design.rules.not-apps: ``dds`` Is not Made for Complex Applications ============================================ Alright, this one isn't a "rule" as much as a recommendation: If you are building an application that *needs* some build process functionality that ``dds`` does not provide, ``dds`` is only open to changes that do not violate any of the other existing rules. .. note:: **However:** If you are a *library* author and you find that ``dds`` cannot correctly build your library without violating other rules, we may have to take a look. This is certainly not to say it will allow arbitrary customization features to permit the rules to be bent arbitrarily: Read on. ``dds`` *does* contain functionality for building applications, but they must also play by the rules. If you want to build a complex application with ``dds`` that uses lots of platform-specific sources, code generation, and conditional components, a good option is to use an external build script that prepares the project tree before invoking ``dds``. .. _design.rules.change: *Your Code* Should Be Changed Before ``dds`` Should Be Changed ============================================================== The wording of this rule means that the onus is on the developer to meet the expectations that ``dds`` prescribes in order to make the build work. If your project meets all the requirements outlined in this document but you still find trouble in making your build work, or if you *cannot* see *any* possible way for your project to be built by ``dds`` regardless of what changes you make, then it this is grounds for change in ``dds``, either in clarifying the rules or tweaking ``dds`` functionality .. _design.rules.layout: Library Projects Must Meet the Layout Requirements ================================================== This is a very concrete requirement. ``dds`` prescribes a particular project structure layout with minimal differing options. ``dds`` prescribes the `Pitchfork`_ layout requirements. .. note:: These prescriptions are not as draconian as they may sound upon first reading. Refer to the :doc:`guide/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 .. _design.rules.no-cond-compile: A Library Build Must Successfully Compile All Source Files ========================================================== Almost all Build Systems have a concept of *conditionally* adding a source file to a build. ``dds`` elides this feature in place of relying on in-source conditional compilation. .. _design.rules.no-lazy-code-gen: All Code Must Be in Place Before Building ========================================= ``dds`` does not provide code-generation functionality. Instead, any generated code should be generated by separate build steps before ``dds`` is executed. .. _design.rules.one-binary-per-src: All Compilable Files in a ``src/`` Directory Must Link Together =============================================================== As part of the prescribed project layout, the ``src/`` project directory contains source files. ``dds`` requires that *all* source files in a given ``src/`` directory should link together cleanly. Practically, this means that every ``src/`` directory must correspond to *exactly* one library. .. _design.rules.include: No Arbitrary ``#include`` Directories ===================================== Only ``src/`` and ``include/`` will ever be used as the basis for header resolution while building a project, so all ``#include`` directives should be relative to those directories. Refer to :ref:`pkg.source-root`. .. _design.rules.uniform-compile: All Files Compile with the Same Options ======================================= When DDS compiles a project, every source file will be compiled with an 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 options. Refer to the :doc:`guide/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.