My Systems Development Environment
A structured development setup for building, testing, debugging, and documenting C, C++, command-line tools, reusable libraries, and increasingly deeper systems software. The environment is designed to behave consistently across Windows, WSL, and Linux while keeping the Unix toolchain central.
$ gcc --version
gcc 15.2.0
$ make clean && make
Build completed successfully.
$ make test
PASS: all tests
$ valgrind --leak-check=full ./build/app
0 bytes definitely lost
$ git status
working tree clean
Environment Architecture
The setup separates the host operating system, Unix development environment, compiler toolchain, and project workflow while keeping source files accessible across platforms.
Windows Host
Provides the primary desktop environment, file management, browser, visual development tools, native applications, and access to Windows-based compilers when required.
Primary workstation hostWSL Integration
Provides a Linux command-line environment directly within Windows, allowing Unix tools, GCC, Make, CMake, GDB, Valgrind, Git, and shell automation to remain central.
Daily systems workspaceLinux Toolchain
Supplies the Unix process model, shell utilities, compiler ecosystem, debugging tools, system interfaces, permissions, file semantics, and POSIX-oriented development behavior.
Target systems environmentReproducible Workflow
Standard commands, project structures, warnings, tests, sanitizers, documentation, and Git history make each project rebuildable and inspectable.
Applied across repositoriesCore Toolchain
Tools are grouped by their role in compilation, correctness, debugging, automation, and project maintenance.
Compilation & Build
Debugging & Correctness
Workflow & Automation
Environment Setup
A practical sequence for establishing the Unix-oriented development environment and validating the core toolchain.
Setup Sequence
Each layer is installed and verified before project development begins.
Enable WSL
Install a Linux distribution and confirm that the shell, filesystem, package manager, and Windows integration work.
Install the Build Toolchain
Install GCC, G++, Make, CMake, GDB, Git, and essential development packages.
Add Diagnostic Tools
Install Valgrind and validate compiler sanitizer support.
Configure Git
Set identity, authentication, branch conventions, and repository remotes.
Verify the Environment
Compile a warning-clean program, run tests, use GDB, and check the executable with Valgrind.
Installation & Verification Commands
Representative commands for a Debian or Ubuntu-based WSL distribution.
# Update package information
sudo apt update
# Install compilers and build tools
sudo apt install build-essential gcc g++ make cmake
# Install debugging and source-control tools
sudo apt install gdb valgrind git
# Verify installed tools
gcc --version
g++ --version
make --version
cmake --version
gdb --version
valgrind --version
git --version
git config --global user.name "Bruno Fonkeng"
git config --global user.email "[email protected]"
git config --global init.defaultBranch main
git config --global core.autocrlf input
Standard Project Structure
Systems projects use a consistent directory layout so source code, headers, tests, documentation, examples, and generated files remain clearly separated.
Repository Layout
A representative structure used across modular C and C++ projects.
project/
├── README.md
├── LICENSE
├── Makefile
├── CMakeLists.txt
├── include/
│ └── project.h
├── src/
│ ├── main.c
│ └── project.c
├── tests/
│ └── test_project.c
├── examples/
├── docs/
├── build/
└── bin/
# build/ and bin/ contain generated outputs
Why This Structure Matters
The layout reinforces separation of concerns and makes each repository easier to build, test, review, and extend.
Public Interfaces
Header files define reusable contracts without exposing unnecessary implementation details.
Implementation Separation
Source files organize behavior into focused modules rather than one large program.
Dedicated Testing
Tests are independent from demonstration programs and can validate functions directly.
Generated Output Isolation
Object files, executables, and temporary artifacts remain outside source directories.
Learning Documentation
Notes, mistakes, design decisions, examples, and verified commands remain part of the repository.
Build & Validation Commands
Standard commands keep compilation strict, testing repeatable, and diagnostic behavior visible.
C Compilation
Warning-driven compilation is used as a first line of defense against incorrect or non-portable code.
gcc \
-Wall \
-Wextra \
-Wpedantic \
-std=c11 \
-g \
src/main.c \
src/project.c \
-Iinclude \
-o build/app
gcc \
-Wall \
-Wextra \
-Wpedantic \
-std=c11 \
-g \
-fsanitize=address,undefined \
-fno-omit-frame-pointer \
src/main.c \
-o build/app_san
Make & CMake Workflow
Small C projects use Make, while larger C++ libraries use out-of-source CMake builds.
make clean
make
make test
make run
rm -rf build
cmake -S . -B build
cmake --build build
ctest --test-dir build --output-on-failure
Daily Engineering Workflow
Every project follows a repeatable progression from implementation to verification and documentation.
Implement
Add one focused behavior through a clear interface and keep the change small enough to reason about.
Compile
Build with strict warnings enabled and treat unexpected warnings as defects requiring investigation.
Test
Verify normal behavior, boundary values, invalid input, failure paths, and reusable library functions.
Diagnose
Use GDB, sanitizers, and Valgrind to inspect crashes, ownership, leaks, undefined behavior, and incorrect state.
Document & Commit
Record commands, architecture, decisions, tests, lessons, and a meaningful Git milestone.
Debugging & Memory Diagnostics
Correctness is investigated with complementary tools rather than relying on print statements alone.
GDB
Used to pause execution, inspect stack frames, examine variables, trace control flow, and identify the exact point at which state becomes incorrect.
gdb ./build/app
break main
run
next
print variable
backtrace
Valgrind
Used to identify leaked allocations, invalid reads and writes, use of uninitialized values, and incorrect memory-management behavior.
valgrind \
--leak-check=full \
--show-leak-kinds=all \
--track-origins=yes \
./build/app
Compiler Sanitizers
Used during development to detect out-of-bounds access, use-after-free errors, undefined behavior, and other runtime violations with source-level reports.
ASAN_OPTIONS=detect_leaks=1 \
./build/app_san
Reproducibility Principles
The environment is designed so that another developer—or future me—can understand how a project was built, tested, and verified.
Commands Are Preserved
Compilation, test, debugging, and execution commands are stored in Makefiles, scripts, and documentation.
Generated Files Are Separate
Build outputs do not mix with source files, making clean rebuilds predictable.
Tests Define Expected Behavior
Verified behavior is captured in test cases rather than remaining only in memory or manual observations.
Milestones Are Versioned
Meaningful Git commits preserve working stages, design changes, and technical progress.
An Environment Designed for Deeper Systems Work
This setup supports the current C and C++ foundation while providing a path toward concurrency, operating systems, performance engineering, virtual machines, compilers, and runtime infrastructure.