UCCL - Uniform C Code Layout #
(aka “The Dogfood Layout” 1)
Motivation #
A Uniform code layout facilitates a developer’s access to an unfamiliar code base, saving valuable time and effort. At the same time it makes easier to integrate and reuse different projects.
This layout proposal uses symbolic links, called symlinks for short, to provide a uniform method for access between projects. Symbolic links are used only at directory level, not at file level.
Definitions #
- Package ≡ Repository ≈ Library
- A unit of software that resides in a unique source control repository. In general a package generates a binary library, unless it is a header-only package. All files in a package are located in one directory (that can have any number of sub-directories).
- Development tree
- A directory that contains all packages. It’s location is arbitrary but we will assume it is indicated by the
$DEV_ROOT
environment variable. - Artifacts
- Files, other than libraries produced by a package. These can include programs, data files, etc.
Layout Description #
Following is a semi-formal description of the proposed layout.
1. Basic rules #
1.1 Location of header files #
All header files of a package are placed in a subdirectory of the package directory. The name of the subdirectory is include/
.
1.2 Location of API header files #
All header files that compose the public API of a package are located in a subdirectory of the include/
directory. The name of the subdirectory must be the same as the package name.
1.3 Location of library files #
All library files are placed in the lib/
subdirectory of $DEV_ROOT
directory. Each package directory contains a symbolic link, named also lib/
to this subdirectory. Library variants for different platforms or configurations may be placed in different subdirectories. The naming scheme <platform>/<configuration>
is recommended.
With these basic rules, the layout of a package is like this:
2. References to other packages #
2.1 Location of external header files #
A package can reference another package by placing a symlink to its public API in the include
folder. The symlink has the same name as the referenced package.
Example: The package package_a
references package_b
Libraries created by other packages are implicitly visible in the lib/
directory
3. Other artifacts #
3.1 Location of executable artifacts #
Programs and related components are located in the bin/
subdirectory of the $DEV_ROOT
directory. Packages that produce these artifacts as well as packages that need them, should have a symbolic link, also named bin/
pointing to this location.
$DEV_ROOT/bin
can be added toPATH
to make these programs accessible from anywhere.
4. Source #
4.1 Location of source files #
Source files are located in the src/
folder of the package directory.
4.2 Referencing header files #
The include/
directory of a package should be added to the compiler search path. If the layout rules have been respected, there should be no ambiguity or name clashing between the different header files.
Example: Consider a filesource.cpp
in package_a
// Reference to a package_a API file
#include <package_a/api.h>
// Reference to a package_b API file
#include <package_b/api.h>
//Reference to a package_a internal header file
#include <internal.h>
5. Other directories #
The following directories can appear at the top level in any package, in addition to the ones discussed before. None of them are required.
- build/
- Used for storing intermediate build artifacts (object files, symbols, etc.)
- data/
- Any data files required by a package.
- docs/
- Documentation and documentation-related files.
- fab/
- build scripts and other build-related files.
- examples/
- Sample program files.
- tests/
- Unit tests and other test files.
Recommendations #
The following guidelines are born from experience with this layout.
Minimize the number of files at top level of a package. In general only well-known files (README, LICENSE, AUTHORS, etc.) should be kept at top level. This is not always possible as some toolchains require specific files to be also placed at top level.
Place files related to the used toolchain in a subdirectory of the
fab/
directory, with a name that clearly indicates the toolchain used. Some suggested toolset names are:clang/
for CLang compilergcc/
for GCC toolsmsc/
for Visual Studio C/C++ compiler
Use a scheme like
<platform name>/<toolset>/<configuration>
for subdirectories oflib/
; keep the library name unchanged.Example:
$DEV_ROOT/lib/x64/msc/debug/package_a.lib
the library name created bypackage_a
when compiled in debug mode for x64 platform using Visual Studio C/C++ compiler.Some suggested platform names are:
x64
x86
arm
Layout Summary #
Folder | Content |
---|---|
$DEV_ROOT/ | Root of development tree |
lib/ | Directory of static link libraries |
package/ | Package root directory |
build/ | Build artifacts |
data/ | Data files |
docs/ | Documentation files |
examples/ | Example files |
fab/ | Build scripts and related files |
include/ | Header files |
package/ | Public package header files |
lib/ | Symlink to $DEV_ROOT/lib directory |
src/ | Source files |
tests/ | Test files |
Initially I gave this proposal a nice buttoned-down name: Uniform C/C++ Code Layout. It seems however that every self-respecting open source project must have a more or less funky name. Bob Pike named his layout proposal Pitchfork Layout, so I figured this one could be named Dogfood Layout based on the title of the first CodeProject article Eat your Own Dogfood where I describe it. ↩︎