Project setup#

This page covers the setup decisions that apply to every LIBRA project regardless of whether you use the clibra CLI or plain CMake. Read this once — the quickstarts reference it rather than repeat it.

Integrating LIBRA into your project#

Choose the integration method that fits your workflow:

Method

Best for

Use when

CPM (recommended)

Most projects; no pre-installation needed

You want version-pinned, zero-install dependency management in CMake

Conan

Multi-repo organisations, complex dependencies

You already use Conan, or manage 5+ related projects

CMake package

System-wide or shared team installation

Multiple developers sharing one LIBRA installation

In situ (submodule)

Quick prototyping, standalone repos, CI/CD simplicity

Single project; you want version control over LIBRA itself

CPM fetches and caches LIBRA automatically at configure time. No pre-installation required; the version is pinned in your repository.

cmake_minimum_required(VERSION 3.31)

file(DOWNLOAD
     https://github.com/cpm-cmake/CPM.cmake/releases/download/v0.40.2/CPM.cmake
     ${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake)

set(CPM_SOURCE_CACHE
    $ENV{HOME}/.cache/CPM
    CACHE PATH "CPM source cache")

# Prefer local packages when present — useful for simultaneous
# local development of multiple LIBRA-enabled projects.
set(CPM_USE_LOCAL_PACKAGES ON)
include(${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake)

CPMAddPackage(
  NAME libra
  GIT_REPOSITORY https://github.com/jharwell/libra.git
  GIT_TAG master)

list(APPEND CMAKE_MODULE_PATH ${libra_SOURCE_DIR}/cmake)
project(my_project C CXX)
include(libra/project)

Best for managing dependencies and multi-repo scaling.

conanfile.py:

def build_requirements(self):
    self.tool_requires("libra/0.8.0")

CMakeLists.txt:

cmake_minimum_required(VERSION 3.31)
find_package(libra REQUIRED)
project(my_project C CXX)
include(libra/project)

Requires LIBRA to be installed to a system prefix or the same CMAKE_INSTALL_PREFIX as the consuming project.

Install LIBRA:

git clone https://github.com/jharwell/libra.git
cmake -S libra -B libra/build -DCMAKE_INSTALL_PREFIX=/opt/libra
cmake --build libra/build --target install

CMakeLists.txt:

cmake_minimum_required(VERSION 3.31)
find_package(libra REQUIRED)
project(my_project C CXX)
include(libra/project)

Best for standalone repos where you want LIBRA under version control.

git submodule add https://github.com/jharwell/libra.git

CMakeLists.txt:

cmake_minimum_required(VERSION 3.31)
add_subdirectory(libra)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/libra/cmake)
project(my_project C CXX)
include(libra/project)

Project layout#

LIBRA auto-discovers sources, headers, and tests when you follow these conventions:

my_project/
├── CMakeLists.txt
├── CMakePresets.json
├── cmake/
│   └── project-local.cmake   ← target definitions (required)
├── src/                      ← .cpp / .c files (auto-discovered)
├── include/                  ← .hpp / .h headers (auto-discovered)
├── tests/                    ← test files (auto-discovered by suffix)
└── docs/
    ├── Doxyfile.in           ← doxygen configuration (LIBRA_DOCS=ON)
    └── conf.py               ← sphinx configuration (LIBRA_DOCS=ON)

Mandatory file extension conventions:

  • C++ source files must end in .cpp; C++ headers in .hpp

  • C source files must end in .c; C headers in .h

If your structure differs from the above, you can disable globbing and list files manually in project-local.cmake.

In addition, build outputs in the binary directory follow these conventions. The build directory can of course be wherever you like.

  • libraries -> ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR} (usually lib or lib64)

  • executables -> ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR} (usually bin)

Test file naming#

LIBRA discovers tests by matching filenames against suffix patterns. The built-in defaults are -utest (unit), -itest (integration), -rtest (regression), and _test (harness). Negative compilation tests use .neg.cpp / .neg.c.

All patterns are configurable via matcher variables in project-local.cmake. See Testing Reference for the complete naming reference including negative tests, the test harness, and interpreted test support.

project-local.cmake#

LIBRA expects your target definitions in cmake/project-local.cmake. This keeps the root CMakeLists.txt clean and portable:

# Register the main executable. CXX_SRC is auto-populated
# from src/ at configure time.
libra_add_executable(${${PROJECT_NAME}_CXX_SRC})

# For a library instead (C_SRC auto-populated):
# libra_add_library(${${PROJECT_NAME}_C_SRC})

# Optional: enable project-wide quality gates
# set(LIBRA_ANALYSIS ON)
# set(LIBRA_FORTIFY ALL)

Note

libra_add_executable() and libra_add_library() wrap CMake’s built-in equivalents and automatically apply LIBRA’s compiler flags, analysis targets, and quality gates. Targets registered with plain add_executable() or add_library() will not receive LIBRA features unless you manually apply them.

Always prefer the LIBRA variants for targets you want LIBRA to manage.

CMakePresets.json#

LIBRA and clibra are preset-driven. The following is the recommended starting-point preset hierarchy. See Feature flags for a detailed explanation of every preset and the rationale behind the structure.

{
  "version": 6,
  "configurePresets": [
    {
      "name": "base",
      "hidden": true,
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/build/${presetName}",
      "cacheVariables": {
        "LIBRA_TESTS":    "OFF",
        "LIBRA_COVERAGE": "OFF",
        "LIBRA_ANALYSIS": "OFF",
        "LIBRA_DOCS":     "OFF"
      }
    },
    {
      "name": "debug",
      "inherits": "base",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Debug",
        "LIBRA_TESTS": "ON"
      }
    },
    {
      "name": "release",
      "inherits": "base",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Release",
        "LIBRA_LTO": "ON"
      }
    },
    {
      "name": "coverage",
      "inherits": "base",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Debug",
        "LIBRA_TESTS": "ON",
        "LIBRA_COVERAGE": "ON"
      }
    },
    {
      "name": "ci",
      "inherits": "coverage"
    },
    {
      "name": "analyze",
      "inherits": "base",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Debug",
        "LIBRA_ANALYSIS": "ON"
      }
    }
  ],
  "buildPresets": [
    { "name": "debug",    "configurePreset": "debug" },
    { "name": "release",  "configurePreset": "release" },
    { "name": "coverage", "configurePreset": "coverage" },
    { "name": "ci",       "configurePreset": "ci" },
    { "name": "analyze",  "configurePreset": "analyze",
      "targets": ["analyze"] }
  ],
  "testPresets": [
    {
      "name": "debug",
      "configurePreset": "debug",
      "output": { "outputOnFailure": true }
    },
    {
      "name": "coverage",
      "configurePreset": "coverage",
      "output": { "outputOnFailure": true }
    },
    {
      "name": "ci",
      "configurePreset": "ci",
      "output": { "outputOnFailure": true }
    }
  ]
}