Thank you for your interest in CFBox. This document covers building, testing, and contributing.
- Compiler: GCC 13+ or Clang 17+ (C++23 support required)
- CMake: 3.26+
- Git
cmake -B build
cmake --build buildDebug builds automatically enable AddressSanitizer (ASan) and UndefinedBehaviorSanitizer (UBSan) with -g3 -O0. Compiler warnings are treated as errors (-Werror) with extensive warning flags (see CompilerFlag.cmake).
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build buildRelease builds use -O2 by default and enable LTO. For size-optimized builds, add -DCFBOX_OPTIMIZE_FOR_SIZE=ON to use -Os instead.
# Unit tests (399 GTest cases)
ctest --test-dir build --output-on-failure
# Integration tests (54 shell scripts comparing against GNU coreutils)
bash tests/integration/run_all.sh# Dynamic linking
cmake -B build-aarch64 \
-DCMAKE_TOOLCHAIN_FILE=cmake/toolchain/Toolchain-aarch64.cmake \
-DCMAKE_BUILD_TYPE=Release \
-DCFBOX_OPTIMIZE_FOR_SIZE=ON
cmake --build build-aarch64
# Static linking
cmake -B build-aarch64-static \
-DCMAKE_TOOLCHAIN_FILE=cmake/toolchain/Toolchain-aarch64.cmake \
-DCMAKE_BUILD_TYPE=Release \
-DCFBOX_OPTIMIZE_FOR_SIZE=ON \
-DCFBOX_STATIC_LINK=ON
cmake --build build-aarch64-staticRequires: aarch64-linux-gnu-g++ (install via gcc-aarch64-linux-gnu g++-aarch64-linux-gnu).
# Static linking (requires Arm GNU Toolchain)
cmake -B build-armhf-static \
-DCMAKE_TOOLCHAIN_FILE=cmake/toolchain/Toolchain-armhf.cmake \
-DCMAKE_BUILD_TYPE=Release \
-DCFBOX_OPTIMIZE_FOR_SIZE=ON \
-DCFBOX_STATIC_LINK=ON
cmake --build build-armhf-staticRequires: Arm GNU Toolchain (arm-none-linux-gnueabihf-g++).
file build-aarch64/cfbox # Confirm target architecture
size build-aarch64/cfbox # Check section sizes
scripts/measure_size.sh build-aarch64/cfbox # Detailed size analysisRun cross-compiled binaries under QEMU user-mode emulation with full integration tests:
# Requires: qemu-user-static
./scripts/qemu_user_test.sh --target aarch64 --link static
./scripts/qemu_user_test.sh --target armhf --link staticBoot a minimal Linux kernel with CFBox as PID 1. Requires the Linux kernel source (as a git submodule):
# Build initramfs
./scripts/build_initramfs.sh --arch aarch64 --cfbox build-aarch64-static/cfbox
# Boot and test
./scripts/qemu_system_test.sh \
--arch aarch64 \
--kernel path/to/Image \
--initramfs build/aarch64-initramfs.cpioThe init applet auto-mounts proc/sysfs/devtmpfs, runs smoke tests, then powers off. Minimal kernel config: configs/qemu-virt-aarch64.config.
The CI pipeline (ci.yml) runs on every push/PR to main with 5 stages:
| Stage | Description |
|---|---|
| native | x86-64 Debug build with ASan/UBSan + all tests |
| release-size | Release build (-Os + LTO) + binary size report |
| cross-compile | aarch64/armhf cross-compilation (dynamic + static) |
| qemu-user-test | Integration tests under QEMU user-mode emulation |
| qemu-system-test | Full boot test with CFBox as PID 1 (main/release branches only) |
- Format code with the project .clang-format (LLVM-based, 4-space indent, 100-column limit).
- All code must compile cleanly with the flags in CompilerFlag.cmake (
-Wall -Wextra -Wpedanticplus additional warnings, all treated as errors). - Follow existing patterns:
std::expected<T, Error>withCFBOX_TRYfor error handlingcfbox::args::parse()for CLI argument parsingcfbox::iofor file I/O,cfbox::fsfor filesystem operations
- No
using namespace std.
- Create
src/applets/<name>.cppwith signatureauto <name>_main(int argc, char* argv[]) -> int.- Add a comment header listing supported flags and known differences from GNU.
- Add a
constexpr cfbox::help::HelpEntry HELPconstant in the anonymous namespace. - Handle
--help/--versionright afterargs::parse():if (parsed.has_long("help")) { cfbox::help::print_help(HELP); return 0; } if (parsed.has_long("version")) { cfbox::help::print_version(HELP); return 0; }
- Declare the function in applets.hpp, guarded by
#if CFBOX_ENABLE_<UPPER>. - Add one entry to
APPLET_REGISTRYin applets.hpp, also guarded by#if CFBOX_ENABLE_<UPPER>. - Add the applet name to the
CFBOX_APPLETSlist in cmake/Config.cmake. - Add a
#cmakedefine01 CFBOX_ENABLE_<UPPER>line to include/cfbox/applet_config.hpp.in. - Add GTest unit tests in
tests/unit/test_<name>.cpp(see test_capture.hpp for stdout capture andTempDirutilities). Guard the test file with#if CFBOX_ENABLE_<UPPER>. - Add shell integration tests in
tests/integration/test_<name>.shfollowing the pattern in existing scripts.
Note: The
initapplet is special — it runs as PID 1 in QEMU system-mode tests and uses manualargvscanning instead ofargs::parse(). Regular applets should not need special PID 1 handling.
CFBox supports per-applet configuration via CMake options:
# Disable individual applets
cmake -DCFBOX_ENABLE_GREP=OFF -DCFBOX_ENABLE_SED=OFF ..
# Use preset profiles
cmake -DCFBOX_PROFILE=minimal .. # Only core file operations
cmake -DCFBOX_PROFILE=embedded .. # Everything except optional text processing
cmake -DCFBOX_PROFILE=desktop .. # All applets enabled (default)Available profiles: minimal (echo, cat, ls, cp, mv, rm, mkdir, grep), embedded (all except sort/uniq/sed), desktop/full (all enabled).
- Fork the repository.
- Create a feature branch.
- Ensure all tests pass (
ctest+run_all.sh). - Open a pull request against
main.
Use GitHub Issues.