#cmake #vcpkg #build-system #cpp #cross-compiling

build cforge

A TOML-based build system for C/C++ with CMake and vcpkg integration

3 releases

new 1.4.3-beta Mar 26, 2025
1.4.2-beta Mar 25, 2025

#31 in Build Utils

Download history 336/week @ 2025-03-12 489/week @ 2025-03-19

825 downloads per month

MIT license

505KB
9K SLoC

⚠️ WARNING: BETA VERSION ⚠️

🚨 This software is currently in BETA. Features may be incomplete, contain bugs, or change without notice, and being frequently updated. Use at your own risk.

  • Not recommended for production environments
  • Data loss or corruption may occur
  • APIs are subject to change without warning
  • Limited support available

Please report any bugs or issues in the Issues section.

CForge

Version License

A TOML-based build system for C/C++ projects with seamless CMake and vcpkg integration.

CForge is a modern build system designed to simplify C/C++ project management. It provides a clean TOML-based configuration approach while leveraging the power of CMake and vcpkg under the hood.


📖 Table of Contents

  1. Features
  2. Installation
  3. Quick Start
  4. Command Reference
  5. Project Configuration
  6. Working with Dependencies
  7. Workspaces
  8. Build Variants
  9. Cross-Compilation
  10. IDE Integration
  11. Scripts & Hooks
  12. Testing
  13. Advanced Topics
  14. Examples
  15. Troubleshooting
  16. Goals & Roadmap
  17. Contributing
  18. License

🚀 Features

  • Simple TOML Configuration: Easy project setup without complex CMake syntax
  • Multi-platform: Supports Windows, macOS, Linux
  • Dependency Management: Integrated support for vcpkg, Conan, Git, and custom dependencies
  • Workspaces: Manage multiple projects together with dependency resolution
  • Cross-compilation: Support for Android, iOS, Raspberry Pi, WebAssembly
  • IDE Integration: VS Code, CLion, Xcode, Visual Studio
  • Testing: Integrated with CTest
  • Custom Scripts & Hooks: Run project-specific tasks at various stages
  • Automatic Tool Setup: Installs missing tools automatically
  • Enhanced Diagnostics: Clear, informative compiler errors
  • Build Variants: Easily switch between different build configurations
  • Package Management: Create distributable packages for your software

📥 Installation

From Cargo

cargo install cforge@version-beta
# For example cforge@1.4.2-beta

From Source

git clone https://github.com/ChaseSunstrom/cforge.git
cd cforge
cargo build --release
cargo install --path .

Prerequisites

  • Rust
  • CMake (≥3.15)
  • C/C++ Compiler (GCC, Clang, MSVC)
  • Optional: Ninja, Make, or Visual Studio Build Tools

⚡ Quick Start

Creating a New Project

# Create a new project in the current directory
cforge init

# Create a specific project type
cforge init --template lib     # Create a library project
cforge init --template header-only  # Create a header-only library

# Build the project
cforge build

# Run the executable (for application projects)
cforge run

Example Project Structure

After initializing a project with cforge init, you'll have a structure like this:

myproject/
├── cforge.toml         # Project configuration
├── src/
│   └── main.cpp        # Main source file
├── include/            # Header files
├── scripts/            # Custom scripts
└── build/              # Build artifacts (generated)

Example C++ Code

src/main.cpp (generated automatically):

#include <iostream>

int main(int argc, char* argv[]) {
    std::cout << "Hello, cforge!" << std::endl;
    return 0;
}

Build and Run

$ cforge build
┌──────────────────────────────────────────────────┐
           cforge - C/C++ Build System            │
                    v1.2.0                        │
└──────────────────────────────────────────────────┘

Building: myproject
[1/4] Checking build tools
Checking for required build tools...
CMake:
Compiler 'clang': ✓
Build generator 'Ninja': ✓
vcpkg: ✓ (will be configured during build)
All required build tools are available.

[2/4] Configuring project
Project configured with generator: Ninja (Debug)

[3/4] Running pre-build hooks
Running pre-build hooks
Running hook: echo Starting build process...
Starting build process...

[4/4] Building project
Building myproject in Debug configuration
 Compiling 1 source files (completed in 1.2s)

 Build completed successfully

$ cforge run
┌──────────────────────────────────────────────────┐
           cforge - C/C++ Build System            │
                    v1.2.0                        │
└──────────────────────────────────────────────────┘

Running: myproject
Found executable: build/bin/myproject
Running: build/bin/myproject

Program Output
────────────
Hello, cforge!

 Program executed successfully

🛠️ Command Reference

Command Description Example
init Create new project/workspace cforge init --template lib
build Build the project cforge build --config Release
clean Clean build artifacts cforge clean
run Run built executable cforge run -- arg1 arg2
test Execute tests (CTest integration) cforge test --filter MyTest
install Install project binaries cforge install --prefix /usr/local
deps Manage dependencies cforge deps --update
script Execute custom scripts cforge script format
startup Manage workspace startup project cforge startup my_app
ide Generate IDE project files cforge ide vscode
package Package project binaries cforge package --type zip
list List variants, configs, or targets cforge list variants

Command Options

All commands accept the following global options:

  • --verbosity: Set verbosity level (quiet, normal, verbose)

Many commands support these options:

  • --config: Build/run with specific configuration (e.g., Debug, Release)
  • --variant: Use a specific build variant
  • --target: Specify a cross-compilation target

📋 Project Configuration

Basic Configuration

The cforge.toml file is the heart of your project configuration:

[project]
name = "my_project"
version = "0.1.0"
description = "My C/C++ project"
type = "executable"  # executable, library, static-library, header-only
language = "c++"
standard = "c++17"   # c++11, c++14, c++17, c++20, c++23

[build]
build_dir = "build"
default_config = "Debug"
generator = "Ninja"  # Ninja, "Visual Studio 17 2022", NMake Makefiles, etc.

[build.configs.Debug]
defines = ["DEBUG", "_DEBUG"]
flags = ["NO_OPT", "DEBUG_INFO"]

[build.configs.Release]
defines = ["NDEBUG"]
flags = ["OPTIMIZE", "OB2", "DNDEBUG"]

[targets.default]
sources = ["src/**/*.cpp", "src/**/*.c"]
include_dirs = ["include"]
links = []

Target Configuration

A project can have multiple targets (executables or libraries):

[targets.main_app]
sources = ["src/app/**/*.cpp"]
include_dirs = ["include"]
links = ["fmt", "boost_system"]

[targets.utils_lib]
sources = ["src/utils/**/*.cpp"]
include_dirs = ["include/utils"]
links = []

Platform-specific Configuration

[platforms.windows]
defines = ["WINDOWS", "WIN32"]
flags = ["UNICODE"]

[platforms.darwin]
defines = ["OSX"]
flags = []

[platforms.linux]
defines = ["LINUX"]
flags = []

📦 Working with Dependencies

CForge supports multiple dependency management systems:

vcpkg Integration

[dependencies.vcpkg]
enabled = true
path = "~/.vcpkg"  # Optional, defaults to ~/.vcpkg
packages = ["fmt", "boost", "nlohmann-json"]

Example C++ code using vcpkg dependencies:

#include <fmt/core.h>
#include <nlohmann/json.hpp>

int main() {
    // Using fmt library from vcpkg
    fmt::print("Hello, {}!\n", "world");
    
    // Using nlohmann/json library from vcpkg
    nlohmann::json j = {
        {"name", "CForge"},
        {"version", "1.2.0"}
    };
    
    fmt::print("JSON: {}\n", j.dump(2));
    return 0;
}

Conan Integration

[dependencies.conan]
enabled = true
packages = ["fmt/9.1.0", "spdlog/1.10.0"]
options = { "fmt:shared": "False", "spdlog:shared": "False" }
generators = ["cmake", "cmake_find_package"]

Git Dependencies

[[dependencies.git]]
name = "nlohmann_json"
url = "https://github.com/nlohmann/json.git"
tag = "v3.11.3"
# Optional settings
shallow = true  # Faster clone with reduced history
update = false  # Whether to update the repo on builds

[[dependencies.git]]
name = "fmt"
url = "https://github.com/fmtlib/fmt.git"
tag = "9.1.0"
cmake_options = ["-DFMT_TEST=OFF", "-DFMT_DOC=OFF"]  # Pass CMake options when building

[[dependencies.git]]
name = "imgui"
url = "https://github.com/ocornut/imgui.git"
branch = "master"  # Use a specific branch instead of tag
shallow = true

[[dependencies.git]]
name = "custom_repo"
url = "https://example.com/repo.git"
commit = "abc123def456"  # Use a specific commit hash

Git dependencies are automatically cloned into a deps directory. The libraries can be included in your project by adding their include paths to your target configuration:

[targets.default]
include_dirs = ["include", "deps/nlohmann_json/single_include", "deps/fmt/include"]
defines = ["FMT_HEADER_ONLY"]  # Optionally add defines for your dependencies

You can also use the libraries in your code immediately:

#include <nlohmann/json.hpp>
#include <fmt/core.h>

int main() {
    // Using nlohmann/json
    nlohmann::json obj = {{"name", "cforge"}, {"version", "1.4.0"}};
    
    // Using fmt
    fmt::print("Project: {}\n", obj["name"].get<std::string>());
    return 0;
}

Custom Dependencies

[[dependencies.custom]]
name = "my_library"
url = "https://example.com/my_library-1.0.0.zip"
include_path = "include"
library_path = "lib"

System Dependencies

[dependencies]
system = ["X11", "pthread", "dl"]

🗂️ Workspaces

Workspaces allow you to manage multiple related projects together:

# Initialize a workspace
cforge init --workspace

# Initialize a project within the workspace
cd projects
cforge init --template lib

# Build all projects
cd ..
cforge build

# Build a specific project
cforge build my_lib

# Run a specific project
cforge run my_app

Workspace Configuration

# cforge-workspace.toml
[workspace]
name = "my_workspace"
projects = ["projects/app", "projects/lib"]
default_startup_project = "projects/app"

Project Dependencies within Workspace

# projects/app/cforge.toml
[dependencies.workspace]
name = "lib"
link_type = "static"  # static, shared, interface

🚩 Build Variants

Build variants allow for different build configurations beyond just Debug/Release:

[variants]
default = "standard"

[variants.variants.standard]
description = "Standard build"

[variants.variants.performance]
description = "Optimized build"
defines = ["HIGH_PERF=1"]
flags = ["OPTIMIZE_MAX", "LTO"]

[variants.variants.memory_safety]
description = "Build with memory safety checks"
defines = ["ENABLE_MEMORY_SAFETY=1"]
flags = ["MEMSAFE"]

Building with variants:

cforge build --variant performance

🌐 Cross-Compilation

CForge supports cross-compilation for various platforms:

[cross_compile]
enabled = true
target = "android-arm64"
sysroot = "$ANDROID_NDK/platforms/android-24/arch-arm64"
cmake_toolchain_file = "$ANDROID_NDK/build/cmake/android.toolchain.cmake"
flags = ["-DANDROID_ABI=arm64-v8a", "-DANDROID_PLATFORM=android-24"]

Cross-compilation targets:

  • android-arm64: Android ARM64 platform
  • android-arm: Android ARM platform
  • ios: iOS ARM64 platform
  • raspberry-pi: Raspberry Pi ARM platform
  • wasm: WebAssembly via Emscripten

Example:

cforge build --target android-arm64

🖥️ IDE Integration

Generate IDE-specific project files:

# VS Code
cforge ide vscode

# CLion
cforge ide clion

# Xcode (macOS only)
cforge ide xcode

# Visual Studio (Windows only)
cforge ide vs2022
cforge ide vs:x64  # With architecture specification

Example VS Code launch configuration (generated automatically):

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Debug",
      "type": "cppdbg",
      "request": "launch",
      "program": "${workspaceFolder}/build/bin/${workspaceFolderBasename}",
      "args": [],
      "stopAtEntry": false,
      "cwd": "${workspaceFolder}",
      "environment": [],
      "externalConsole": false,
      "MIMode": "gdb",
      "setupCommands": [
        {
          "description": "Enable pretty-printing for gdb",
          "text": "-enable-pretty-printing",
          "ignoreFailures": true
        }
      ],
      "preLaunchTask": "build"
    }
  ]
}

📝 Scripts & Hooks

Define custom scripts and build hooks:

[scripts]
scripts = {
  "format" = "clang-format -i src/*.cpp include/*.h",
  "count_lines" = "find src include -name '*.cpp' -o -name '*.h' | xargs wc -l",
  "clean_all" = "rm -rf build bin"
}

[hooks]
pre_build = ["echo Building...", "python scripts/version_gen.py"]
post_build = ["echo Done!", "cp build/bin/myapp /tmp/"]
pre_run = ["echo Starting application..."]
post_run = ["echo Application closed."]

Running scripts:

cforge script format

🧪 Testing

CForge integrates with CTest for testing:

[tests]
directory = "tests"
enabled = true
timeout = 30  # seconds

[[tests.executables]]
name = "math_tests"
sources = ["tests/math_test.cpp"]
includes = ["include", "tests/common"]
links = ["my_project"]
labels = ["unit", "math"]

Example test file (tests/math_test.cpp):

#include <iostream>
#include <cassert>
#include "my_project.h"

void test_addition() {
    assert(my_project::add(2, 3) == 5);
    std::cout << "Addition test passed!" << std::endl;
}

void test_multiplication() {
    assert(my_project::multiply(2, 3) == 6);
    std::cout << "Multiplication test passed!" << std::endl;
}

int main() {
    test_addition();
    test_multiplication();
    std::cout << "All tests passed!" << std::endl;
    return 0;
}

Running tests:

# Run all tests
cforge test

# Run tests with a specific label
cforge test --label unit

# Run tests matching a pattern
cforge test --filter math

# Initialize test directory with sample test
cforge test --init

# Discover tests and update config
cforge test --discover

# Generate test reports
cforge test --report xml

🧩 Advanced Topics

Precompiled Headers

[pch]
enabled = true
header = "include/pch.h"
source = "src/pch.cpp"  # Optional
exclude_sources = ["src/no_pch.cpp"]

Package Generation

# Create a package (defaults to zip/tar.gz)
cforge package

# Specify package type
cforge package --type deb  # Linux Debian package
cforge package --type rpm  # Linux RPM package
cforge package --type zip  # Zip archive

Installing Projects

# Install to default location
cforge install

# Install to specific directory
cforge install --prefix /usr/local

📚 Examples

Simple Application

# cforge.toml
[project]
name = "hello_app"
version = "1.0.0"
description = "Hello World Application"
type = "executable"
language = "c++"
standard = "c++17"

[build]
default_config = "Debug"

[targets.default]
sources = ["src/**/*.cpp"]
include_dirs = ["include"]
// src/main.cpp
#include <iostream>

int main() {
    std::cout << "Hello, CForge!" << std::endl;
    return 0;
}

Library with vcpkg Dependencies

# cforge.toml
[project]
name = "math_lib"
version = "0.1.0"
description = "Mathematics Library"
type = "library"
language = "c++"
standard = "c++17"

[dependencies.vcpkg]
enabled = true
packages = ["fmt", "doctest"]

[targets.default]
sources = ["src/**/*.cpp"]
include_dirs = ["include"]
// include/math_lib.h
#pragma once

namespace math_lib {
    int add(int a, int b);
    int subtract(int a, int b);
    int multiply(int a, int b);
    int divide(int a, int b);
}
// src/math_lib.cpp
#include "math_lib.h"
#include <fmt/core.h>

namespace math_lib {
    int add(int a, int b) {
        fmt::print("Adding {} and {}\n", a, b);
        return a + b;
    }
    
    int subtract(int a, int b) {
        fmt::print("Subtracting {} from {}\n", b, a);
        return a - b;
    }
    
    int multiply(int a, int b) {
        fmt::print("Multiplying {} by {}\n", a, b);
        return a * b;
    }
    
    int divide(int a, int b) {
        fmt::print("Dividing {} by {}\n", a, b);
        return a / b;
    }
}

Multi-project Workspace

# cforge-workspace.toml
[workspace]
name = "calculator"
projects = ["projects/core", "projects/gui", "projects/cli"]
default_startup_project = "projects/gui"
# projects/core/cforge.toml
[project]
name = "calc_core"
version = "0.1.0"
description = "Calculator Core Library"
type = "library"
language = "c++"
standard = "c++17"

[targets.default]
sources = ["src/**/*.cpp"]
include_dirs = ["include"]
# projects/gui/cforge.toml
[project]
name = "calc_gui"
version = "0.1.0"
description = "Calculator GUI Application"
type = "executable"
language = "c++"
standard = "c++17"

[dependencies.workspace]
name = "calc_core"
link_type = "static"

[dependencies.vcpkg]
enabled = true
packages = ["imgui", "glfw3", "opengl"]

[targets.default]
sources = ["src/**/*.cpp"]
include_dirs = ["include"]

🔧 Troubleshooting

Common Issues

  • CMake not found: Ensure it's installed and in PATH.
  • Dependency failures: Run cforge deps --update.
  • Cross-compilation: Check environment variables (e.g., $ANDROID_NDK).
  • Compiler errors: Use cforge build --verbosity verbose.

CForge provides enhanced error diagnostics:

Build error details:
ERROR[E0001]: undefined reference to 'math_lib::divide(int, int)'
 --> src/main.cpp:12:5
  12| math_lib::divide(10, 0);
     ^~~~~~~~~~~~~~~~

help: The function 'divide' is used but not defined. Check if the library is properly linked.

Useful Commands

# List available configurations
cforge list configs

# List available build variants
cforge list variants

# List cross-compilation targets
cforge list targets

# List custom scripts
cforge list scripts

🚀 Goals & Roadmap

CForge is continuously evolving to simplify C/C++ project management while providing powerful features. Here's what we've accomplished and where we're headed next:

✅ Completed Features

  • Simple TOML Configuration: Easy project setup without complex CMake syntax
  • Multi-platform Support: Windows, macOS, Linux compatibility
  • Core Dependency Management: Integrated vcpkg and git dependencies
  • Workspace Support: Basic multi-project management
  • Cross-compilation: Support for Android, iOS, Raspberry Pi, WebAssembly
  • IDE Integration: VS Code, CLion support
  • Testing: CTest integration
  • Custom Scripts & Hooks: Run tasks at various build stages
  • Build Variants: Multiple configuration support
  • Package Generation: Create distributable packages

🚧 In Progress

  • Enhanced Workspace Dependencies: Improving library detection and linking
  • Precompiled Header Optimization: Better build performance
  • Diagnostic Improvements: Clearer error messages and suggestions
  • Documentation Expansion: More examples and quick-start guides

📝 Planned Features

  • Enhanced IDE Support

    • Better Visual Studio project generation
    • QtCreator integration
    • Eclipse CDT support
    • Xcode project improvements
  • Plugin System

    • Custom build steps via plugins
    • Language server integration
    • Code generation tools
  • Documentation Features

    • Automatic API documentation generation
    • Doxygen integration
  • Advanced Testing

    • Code coverage reports
    • Benchmark framework integration
    • Sanitizer integrations
  • CI/CD Pipeline Integration

    • GitHub Actions templates
    • GitLab CI templates
    • Azure DevOps integration
  • Mobile Development

    • Improved Android/iOS workflows
    • Mobile-specific templates
  • Cloud Development

    • Remote build capabilities
    • Container-based builds
    • Package registry integration
  • Package Manager Enhancements

    • Complete Conan 2.0 support
    • Lock file management
    • Recipe generation

We welcome contributions to help achieve these goals! If you're interested in working on a specific feature or have suggestions, please open an issue or submit a pull request.

🤝 Contributing

Contributions welcome!

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/new-feature)
  3. Commit your changes (git commit -m 'Add new feature')
  4. Push to your branch (git push origin feature/new-feature)
  5. Open a Pull Request

📄 License

MIT License — see LICENSE.

Dependencies

~5–18MB
~177K SLoC