Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

CC Project Processor

Purpose

Builds full C/C++ projects with multiple targets (libraries and executables) defined in a cc.yaml manifest file. Unlike the CC Single File processor which compiles each source file into a standalone executable, this processor supports multi-file targets with dependency linking.

How It Works

The processor scans for cc.yaml files. Each manifest defines libraries and programs to build. All paths in the manifest (sources, include directories) are relative to the cc.yaml file’s location and are automatically resolved to project-root-relative paths before compilation. All commands run from the project root.

Output goes under out/cc/<path-to-cc.yaml-dir>/, so a manifest at src/exercises/foo/cc.yaml produces output in out/cc/src/exercises/foo/. A manifest at the project root produces output in out/cc/.

Source files are compiled to object files, then linked into the final targets:

src/exercises/foo/cc.yaml defines:
  library "mymath" (static) from math.c, utils.c
  program "main" from main.c, links mymath

Build produces:
  out/cc/src/exercises/foo/obj/mymath/math.o
  out/cc/src/exercises/foo/obj/mymath/utils.o
  out/cc/src/exercises/foo/lib/libmymath.a
  out/cc/src/exercises/foo/obj/main/main.o
  out/cc/src/exercises/foo/bin/main

cc.yaml Format

All paths in the manifest are relative to the cc.yaml file’s location.

# Global settings (all optional)
cc: gcc               # C compiler (default: gcc)
cxx: g++              # C++ compiler (default: g++)
cflags: [-Wall]       # Global C flags
cxxflags: [-Wall]     # Global C++ flags
ldflags: []           # Global linker flags
include_dirs: [include]  # Global -I paths (relative to cc.yaml location)

# Library definitions
libraries:
  - name: mymath
    lib_type: shared   # shared (.so) | static (.a) | both
    sources: [src/math.c, src/utils.c]
    include_dirs: [include]  # Additional -I for this library
    cflags: []               # Additional C flags
    cxxflags: []             # Additional C++ flags
    ldflags: [-lm]           # Linker flags for shared lib

  - name: myhelper
    lib_type: static
    sources: [src/helper.c]

# Program definitions
programs:
  - name: main
    sources: [src/main.c]
    link: [mymath, myhelper]  # Libraries defined above to link against
    ldflags: [-lpthread]      # Additional linker flags

  - name: tool
    sources: [src/tool.cc]    # .cc -> uses C++ compiler
    link: [mymath]

Library Types

TypeOutputDescription
sharedlib/lib<name>.soShared library (default). Sources compiled with -fPIC.
staticlib/lib<name>.aStatic library via ar rcs.
bothBoth .so and .aBuilds both shared and static variants.

Language Detection

The compiler is chosen per source file based on extension:

ExtensionsCompiler
.cC compiler (cc field)
.cc, .cpp, .cxx, .CC++ compiler (cxx field)

Global cflags are used for C files and cxxflags for C++ files.

Output Layout

Output is placed under out/cc/<cc.yaml-relative-dir>/:

out/cc/<cc.yaml-dir>/
  obj/<target_name>/    # Object files per target
    file.o
  lib/                  # Libraries
    lib<name>.a
    lib<name>.so
  bin/                  # Executables
    <program_name>

Build Modes

Each source is compiled to a .o file, then targets are linked from objects. This provides incremental rebuilds — only changed sources are recompiled.

Single Invocation

When single_invocation = true in rsconstruct.toml, programs are built by passing all sources directly to the compiler in one command. Libraries still use compile+link since ar requires object files.

Configuration

[processor.cc]
enabled = true            # Enable/disable (default: true)
cc = "gcc"                # Default C compiler (default: "gcc")
cxx = "g++"               # Default C++ compiler (default: "g++")
cflags = []               # Additional global C flags
cxxflags = []             # Additional global C++ flags
ldflags = []              # Additional global linker flags
include_dirs = []         # Additional global -I paths
single_invocation = false # Use single-invocation mode (default: false)
extra_inputs = []         # Extra files that trigger rebuilds
cache_output_dir = true   # Cache entire output directory (default: true)

Note: The cc.yaml manifest settings override the rsconstruct.toml defaults for compiler and flags.

Configuration Reference

KeyTypeDefaultDescription
enabledbooltrueEnable/disable the processor
ccstring"gcc"Default C compiler
cxxstring"g++"Default C++ compiler
cflagsstring[][]Global C compiler flags
cxxflagsstring[][]Global C++ compiler flags
ldflagsstring[][]Global linker flags
include_dirsstring[][]Global include directories
single_invocationboolfalseBuild programs in single compiler invocation
extra_inputsstring[][]Extra files that trigger rebuilds when changed
cache_output_dirbooltrueCache the entire output directory
scan_dirstring""Directory to scan for cc.yaml files
extensionsstring[]["cc.yaml"]File patterns to scan for

Example

Given this project layout:

myproject/
  rsconstruct.toml
  exercises/
    math/
      cc.yaml
      include/
        math.h
      math.c
      main.c

With exercises/math/cc.yaml:

include_dirs: [include]

libraries:
  - name: math
    lib_type: static
    sources: [math.c]

programs:
  - name: main
    sources: [main.c]
    link: [math]

Running rsconstruct build produces:

out/cc/exercises/math/obj/math/math.o
out/cc/exercises/math/lib/libmath.a
out/cc/exercises/math/obj/main/main.o
out/cc/exercises/math/bin/main