Uniform C Code Layout

UCCL - Uniform C Code Layout #

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.
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 to PATH 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.

Used for storing intermediate build artifacts (object files, symbols, etc.)
Any data files required by a package.
Documentation and documentation-related files.
Sample program files.
Unit tests and other test files.

Recommendations #

The following guidelines are born from experience with this layout.

  1. 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.

  2. Place files related to the build toolchain used in a directory with a name that clearly indicates the toolchain used. Some suggested names are:

    • cmake/ for CMake files
    • clang/ for CLang compiler
    • gcc/ for GCC tools
    • msc/ for Visual Studio
  3. Use a scheme like <platform name>/<configuration> for subdirectories of lib/; keep the library name unchanged.

    Example: DEV_ROOT/lib/x64/debug/package_a.lib the library name created by package_a when compiled in debug mode for x64 platform.

    Some suggested platform names are:

    • x64
    • x86
    • arm