Libraries

A CRS library is the smallest consumable unit in a package. A package can have one or more libraries, but a library can only belong to one package. Each library within a single package must have a unique name. A library can have some number of dependencies, and can “use” other libraries within the same package.

Terms

library name

The name of the library. The name must be unique within the containing CRS package, and must be a valid name.

library path

The “path” of a library is a POSIX-style relative filepath (relative to the root of the containing package). The path must name a CRS library root within the package.

library internal usages

Each library in a package can declare that it “uses” other libraries in that same package.

See also

Internal Usages

library external dependencies

Each library in a package can declare a unique set of dependencies and library usages on libraries from other packages.

library usage

Library usage is a one-way relationship between a user library and a used library. The user library is able to reference and make use all entities publicly exposed by the used library, including headers, classes, functions, modules, and macros. Library usage also transitive.

If \(A\) uses \(B\), and \(B\) uses \(C\), then \(A\) has a transitive usage of \(C\).

A library usage may identify a library within the same package as the library user, or may specify a library in a dependency package.

When library \(A\) uses library \(B\), \(B\)‘s public header root is added as a header search path for \(A\), and any programs in \(A\) will be linked with the public translation units for \(B\).

Library usage must never form a cycle where a library can (transitively) “use itself”.

library user

The users of a library \(L\) are the libraries that declare a library usage on \(L\).

Library usage is a one-way relationship between a user library and a used library. The user library is able to reference and make use all entities publicly exposed by the used library, including headers, classes, functions, modules, and macros. Library usage also transitive.

used-library

The libraries used-by \(L\) are the libraries upon which \(L\) declares a library usage. \(L\) becomes a “library user” of the libraries that it uses.

Library usage is a one-way relationship between a user library and a used library. The user library is able to reference and make use all entities publicly exposed by the used library, including headers, classes, functions, modules, and macros. Library usage also transitive.

CRS library root

The directory in which the source files of a single library reside. Contains the src/ and include/ directories for a library.

CRS source root

A subdirectories of the CRS library root that contain the source files for a the library (including headers).

See also

Source Roots

source code

The code for a program written in some programming language.

source file

Source files are regular (non-directory) files that contain code of some programming language.

header
header file

A header file (or just “header”) is kind of source file that contains source code that is not directly fed to a compiler. It is intended to be used within other source files via the #include preprocessor directive.

Header files usually use a special file extension that indicates their being header files. Examples of header file extensions include .h and .hpp

public header root

The subdirectory of the CRS library root that contains the header files that should be exposed to library users.

See also

Source Roots

private header root

The subdirectory of the CRS library root that contains the header files that are required to compile the respective library, but should not be exposed to the library users.

It is possible that library does not have a private header root.

See also

Source Roots

compiled source root

The subdirectory of the CRS library root that contains the source files of the library that must be given to the compiler to generate the library’s translation units.

It is possible that a library does not have a compiled source root.

public translation units

The set of translation units generated for a library that are included when linking downstream library users.

recognized compiled source file extension

A file extension that is defined to be a source file that generates a translation unit containing the definition of entities for a library. Comparing the file extension against the set of recognized extensions must be a case-insensitive comparison. Only the lowercase extensions are listed in this documentation.

The source file extensions recognized by a tool will depend on the programming language under scrutiny.

Only the .c file extension is supported for the C programming language.

The following file extensions are available for the C++ programming language:

  • .cpp

  • .cc

  • .cxx

  • .c++

header search path

A filepath from which a compiler will resolve references to header files.

While the behavior of the #include directive is implementation-defined, CRS (and bpt) assumes the following behavior:

  1. When compiling a source file, the compiler has a list of header search paths \(L\) that it will use to resolve #include directives.

  2. An #include or __has_include directive specifies a filepath \(H\) of the form <\(H\)>

  3. For each directory \(L_s\) in \(L\):

    1. Create a filepath \(H_s\) by joining \(L_s\) and \(H\) with a directory separator.

    2. If \(H_s\) names a regular file, the directive will resolve to that file.

  4. If no directory in \(L\) was able to resolve \(H\), the header is considered to be not-found.

Properties

The following are the salient attributes of a library within a package:

Roots

The CRS library root is the directory in which the source files of a single library reside. CRS recognizes two top-level subdirectories within a library root: src/ and include/. A library root must contain one or both of these directories. Each directory is a CRS source root. CRS does not impose any semantics on any other files in the library root.

The following semantics apply, based on the presence of src/ and/or include/:

One should note that a library can only have two distinct source root paths. It is not possible that the public header root, private header root, and compiled source root are all pointing to distinct locations.

Source Roots

A source root is a directory that contains library source files, including header files. If the source root is a compiled source root, then that directory may contain source files that will be used to generate the consumable translation units for the library. If a source root is not compiled, then it is a header-only source root.

Both compiled and header-only source roots may contain headers, but whether those headers can be resolved and used by downstream consumers depends on whether the source root is the public header root or the private header root.

Philosophy

A source root should have the following properties:

Being relocatable in this context means that the location of the directory on the filesystem is irrelevant to the code contained within. As long as the files within a source root are compiled with their used-libraries available, moving or renaming the source root directory should never result in any #include directives failing to resolve.

Code that explicitly assumes the location of its own source root, including in relation to other source roots, is expressly unsupported by CRS.

Example

Suppose we have a library with the following source files (note the file paths):

include/mylib/foo.hpp
// I am a public header
src/mylib/bar.hpp
// I am a private header
src/mylib/foo.cpp
// [1] Okay:
#include <mylib/foo.hpp>

// [2] Not okay
#include <foo.hpp>

// [3] Not okay
#include "../include/foo.hpp"

// [4] Okay and recommended
#include <mylib/bar.hpp>

// [5] Okay and recommended
#include "./bar.hpp"

// [6] Okay, but suspicious
#include "bar.hpp"
#include <bar.hpp>

This library has two CRS source root directories: include/ and src/. src/ is the private header root and compiled source root, while include/ is the public header root. The following applies to each example:

  1. Okay: <mylib/foo.hpp> is a fully-qualified path from the public header root directory, which will be set as a header search path while compiling the file.

  2. Not okay: The <foo.hpp> directive will not resolve because that path will not name an existing file when joined with the any header search path.

  3. Not okay: This will only work so long as the include/ and src/ directories are siblings of the same parent directory, but this violates the restriction that these directories be relocatable.

  4. Okay and recommended: Like [1], specifies a fully-qualified path from the private header root directory, which will be added as a header search path while compiling the file.

  5. Okay: Relative #include directives that specify a leading . or .. are unambiguous to the reader, although it is possible that they will still resolve within a different header search path than the containing file’s own directory.

  6. Okay, but suspicious: While most compilers will insert the containing directory of the file being compiled as a header search path, it is not clear that the author is relying on this fact without the reader knowing that bar.hpp names a file within the same directory.

Public Header Root

The public header root is the CRS source root directory that contains headers that will be visible to the library’s users. When compiling the containing library and all of its users, the public header root of the library should be added as a header search path.

Transitive usage also applies: If library \(A\) uses library \(B\), and library \(B\) uses library \(C\), the public header root of \(C\) should be included as a header search path while compiling \(A\), even if \(A\) does not have an explicit library usage on \(C\).

Private Header Root

The private header root is the CRS source root directory that contains headers that should not be visible to the library’s users, but will be visible while compiling the library’s public translation units.

When compiling the public translation units, the private header root will be added as a header search path.

None of the header files in the library’s public header root should refer to the private headers. A verification step by compiling/checking the public headers should not add the private header root as a header search path.

Compiled Source Root

The compiled source root is the source root directory that contains the files that will be used to generate the library’s public translation units.

Collecting the Public Translation Units

The public translation units of a library are given by finding the public compiled sources of the library.

For each file \(S\) in the compiled source root directory and all descendent directories, with a filepath \(F_s\) as a relative filepath from its containing source root:

  1. If the file extension of the file stem of \(F_s\) is “.test” or “.main”, then \(S\) is not a public compiled source.

  2. Otherwise, if the file extension of \(F_s\) is a recognized compiled source file extension, then \(S\) is a public compile source.

  3. Otherwise, \(S\) is not a public compiled source.

When linking a program \(P\) that uses a library \(L\), every public translation unit of \(L\) should be included in the link operation. The linker may discard translation units which would be unnecessary to generate \(P\).

Internal Usages

Libraries within a single CRS package

External Dependencies

Dependencies