c3pg 0.3.0

A Cargo-inspired build tool for C++ projects, powered by CMake and Conan
Documentation

c3pg (C++ Playground)

c3pg (C Plus Plus PlayGround) is a command-line tool designed to simplify the process of creating, managing, and running C++ projects. Inspired by Rust's cargo, it aims to make setting up C++ projects as easy and efficient as possible, even when working with external dependencies.

While C++ development often involves managing complex build systems like CMake and dependency managers like Conan, c3pg abstracts these details, allowing you to focus on writing and testing code. The complexity still exists, but it stays under the hood.

Features

  • Quick Project Setup: Initialize a new C++ project with a single command.
  • Convention over Configuration: Simple projects need only a project name -- no build targets to declare.
  • Unified Configuration: Use c3pg.toml for all project configuration, similar to Cargo.toml in Rust.
  • Dependency Management: Easily add and remove Conan dependencies with a Cargo-like [dependencies] table.
  • Build and Run: Compile and execute your projects with minimal effort.
  • Testing: Scaffold and run GTest-based tests with auto-detection.
  • Multi-target Support: Declare [[lib]] and [[bin]] targets explicitly when needed.
  • Code Quality: Format and lint C++ sources with clang-format and clang-tidy.
  • Sanitizers: Enable AddressSanitizer, ThreadSanitizer, or UndefinedBehaviorSanitizer with a single flag.
  • Customizable C++ Standards: Specify the C++ standard for your projects (default: C++20).
  • Git Integration: Optionally initialize a Git repository for version control.

Installation

c3pg requires the following tools to be installed on your system:

Install these tools via your package manager or their respective websites.

To build and install c3pg, use the Rust toolchain:

cargo install --path .

This will install the c3pg binary locally (by default in $HOME/.cargo/bin).


Quick Start

# Create a new project
c3pg new hello

# Add a dependency, build, and run
cd hello
c3pg add fmt
# edit src/main.cpp to use fmt ...
c3pg run

# Add and run tests
c3pg test add math
# edit tests/test_math.cpp ...
c3pg test

Usage

Commands

new

Create a new C++ project.

c3pg new <name> [OPTIONS]

Options:

  • --no-git: Do not initialize a Git repository.
  • --standard: Set the C++ standard (default: C++20).

Example:

c3pg new my_project --standard 17

init

Initialize a c3pg project in the current directory.

c3pg init [OPTIONS]

Options:

  • --no-git: Do not initialize a Git repository.
  • --standard: Set the C++ standard (default: C++20).

If src/ already contains source files, they are left untouched. Otherwise a starter main.cpp is created.

add

Add a dependency to the current project.

c3pg add <dependency>

Example:

c3pg add fmt

c3pg looks for the latest version in the default Conan remote. Optionally, you can specify a version and/or a user/channel:

c3pg add fmt/10.0.1
c3pg add mylib/1.0.0@myuser/stable

remove

Remove a dependency from the current project.

c3pg remove <dependency>

build

Build the current project.

c3pg build [OPTIONS]

Options:

  • --release, -r: Build in release mode (default: debug).
  • --asan: Enable AddressSanitizer.
  • --tsan: Enable ThreadSanitizer.
  • --ubsan: Enable UndefinedBehaviorSanitizer.

run

Run the current project (builds first if necessary).

c3pg run [OPTIONS]

Options:

  • --release, -r: Build in release mode (default: debug).
  • --target <name>: Which executable to run (required when multiple exist).
  • --asan, --tsan, --ubsan: Enable sanitizers.

test

Manage and run the project's test suite. GTest is added automatically the first time a test is created.

c3pg test [OPTIONS]
c3pg test add <name>

Subcommands:

  • add <name>: Scaffold a new GTest source file (tests/test_<name>.cpp). On first use, this also adds gtest as a dependency.

Options (when running tests):

  • --filter, -f: Expression to match test cases to run.
  • --jobs, -j: Number of parallel test jobs.
  • --asan, --tsan, --ubsan: Enable sanitizers.

Examples:

# Create a test (lazily adds gtest on first use)
c3pg test add math

# Run all tests
c3pg test

# Run only tests matching "math" with 4 jobs
c3pg test --filter math --jobs 4

fmt

Format C/C++ source files with clang-format.

c3pg fmt [OPTIONS]

Options:

  • --check: Check formatting without modifying files (exit with error if unformatted).

lint

Lint C/C++ source files with clang-tidy (requires a prior c3pg build for compile_commands.json).

c3pg lint [OPTIONS]

Options:

  • --fix: Apply suggested fixes in-place.

clean

Remove all build artifacts.

c3pg clean

How It Works

Project Structure

When you create a new project, c3pg generates the following:

my_project/
  c3pg.toml          # Project configuration
  src/
    main.cpp         # "Hello World" starter
  build/
    CMakeLists.txt   # Generated CMake configuration
    conanfile.py     # Generated Conan recipe
  .gitignore         # (if Git is initialized)

Tests are added on demand via c3pg test add:

my_project/
  tests/
    test_math.cpp    # Scaffolded GTest file

Configuration

c3pg.toml

The configuration follows a convention-over-configuration approach. A fresh project needs only a project name:

[project]
name = "my_project"
standard = "Cpp20"

All sources in src/ are compiled into a single executable named after the project. This is the default when no [[lib]]/[[bin]] sections are present.

Dependencies

Dependencies are declared in a [dependencies] table, similar to Cargo.toml. A simple dependency only needs a version string. For packages from a private Conan remote you can specify user and channel using inline-table syntax:

[project]
name = "my_project"
standard = "Cpp20"

[dependencies]
fmt = "11.0.0"
boost = "1.88"
mylib = { version = "2.1.0", user = "team", channel = "stable" }

Multi-target project (library + executables)

When you need library targets or multiple executables, add [[lib]] and [[bin]] sections (similar to Cargo's [[bin]] / [lib]):

[project]
name = "my_project"

[dependencies]
fmt = "11.0.0"

[[lib]]
name = "mylib"
sources = ["src/lib"]
public-include = ["include"]

[[bin]]
name = "my_project"
sources = ["src/main.cpp"]
link = ["mylib"]

Optional sections

These sections can be added to override defaults:

[cmake]
export_compile_commands = false   # default: true

[conan]
bin = "/usr/local/bin/conan"      # default: "conan"
remote = "my_remote"              # default: first configured remote

[testing]
dir = "test"                      # default: "tests"

Sections

  • [project]: Project name, C++ standard, and build cache directory.
  • [dependencies] (optional): Conan packages with version strings or detailed inline tables ({ version, user, channel }).
  • [[lib]] (optional): Library targets with sources, public include dirs, and inter-library linking.
  • [[bin]] (optional): Executable targets with sources and library linking. Omit both [[lib]] and [[bin]] for convention-based single-executable projects.
  • [cmake] (optional): CMake-specific settings.
  • [conan] (optional): Conan binary path and remote override.
  • [testing] (optional): Test source directory.

Development

Running tests

# Unit + integration tests (no external tools needed)
cargo test

# End-to-end tests (requires cmake, conan, and a C++ compiler)
C3PG_E2E=1 cargo test --test e2e

Linting

cargo clippy --all-targets