Project Story: Dev Tools

VS Code, CMake, MSBuild, Clang, dotnet CLI, Python

1.0  Development Tools

Every project in Project Story uses a consistent toolchain. This chapter surveys the six tools that appear most often - from editor to build system to runtime - so each subsequent chapter can reference them without re-explaining the setup. The tools split into three roles:
  • Editor - VS Code, the single editor used across all languages.
  • Build systems - CMake (C/C++), MSBuild (.NET and C++), Clang (compiler + tooling).
  • Runtimes / package managers - dotnet CLI (.NET), Python (interpreter + pip).

1.1  VS Code

Figure 1. VS Code with integrated terminal VS Code is a lightweight, extensible editor from Microsoft that runs on Windows, macOS, and Linux. It provides language-aware editing through the Language Server Protocol, so every language extension (rust-analyzer, clangd, C# Dev Kit, Pylance) shares the same UI for completions, diagnostics, and go-to-definition. Extensions used across Project Story projects:
  • rust-analyzer - Rust: type inference, borrow checker feedback, inlay hints.
  • clangd or C/C++ Extension Pack - C++ with CMake integration.
  • C# Dev Kit - C# with .NET SDK project navigation and test runner.
  • Pylance - Python: static type checking via Pyright, import resolution.
  • Error Lens - Inline diagnostic messages on the offending line.
  • GitLens - Blame annotations, branch history, commit diff in the editor.
The integrated terminal eliminates context-switching: build, test, and run commands all run in the same window. The built-in debugger connects to each language's debug adapter without requiring a separate IDE.
There are a number of VSCode settings that determine how panes are displayed. Those are covered in Help/VSCode

1.2  CMake

CMake is a cross-platform build-system generator. It reads a CMakeLists.txt description and generates native build files for Make, Ninja, MSBuild, or Xcode. All C and C++ projects in Project Story use CMake so the same source tree builds on Windows, Linux, and macOS without modification. Typical workflow: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release cmake --build build ./build/my_app
  • -S . - source directory (where CMakeLists.txt lives).
  • -B build - out-of-source build directory; keeps the source tree clean.
  • --build build - invokes the underlying generator (Make or Ninja or MSBuild).
  • -DCMAKE_BUILD_TYPE=Release - enables optimizations; use Debug for debug symbols.
CMake 3.15+ supports presets (cmake-presets.json) that record compiler selection, build flags, and test configuration in version-controlled JSON rather than per-developer shell scripts.
Common CMake options and CMakeLists.txt commands
Configure-time variables (pass with -D)
  • CMAKE_BUILD_TYPE=Release|Debug|RelWithDebInfo|MinSizeRel
    Controls optimization and debug-symbol flags. RelWithDebInfo gives optimized code with debug symbols attached.
  • CMAKE_CXX_STANDARD=17|20|23 and CMAKE_CXX_STANDARD_REQUIRED=ON
    Set the language standard project-wide. REQUIRED=ON makes CMake error if the compiler cannot satisfy the version.
  • CMAKE_EXPORT_COMPILE_COMMANDS=ON
    Writes compile_commands.json to the build directory. Copy or symlink it to the project root so clangd picks it up automatically.
  • CMAKE_CXX_COMPILER=/path/to/clang++
    Selects a specific compiler. Must be set at first configure; cannot be changed without deleting the build directory.
  • CMAKE_INSTALL_PREFIX=/usr/local
    Root for cmake --install. On Windows the default is C:/Program Files/<project>.
  • BUILD_SHARED_LIBS=ON
    Makes add_library produce a shared library (.dll / .so) instead of static unless the call explicitly says STATIC.
Generator selection (-G) cmake -S . -B build -G Ninja # fast parallel builds cmake -S . -B build -G "Unix Makefiles" # default on Linux/macOS cmake -S . -B build -G "Visual Studio 17 2022" # generates .sln / .vcxproj Key CMakeLists.txt commands
  • cmake_minimum_required(VERSION 3.20)
    Must be the first line. Locks policy behavior to that version.
  • project(MyApp VERSION 1.0 LANGUAGES CXX)
    Names the project and declares which languages are in use. CMake only finds compilers for declared languages.
  • add_executable(target src1.cpp src2.cpp)
    Defines a binary target from the listed sources.
  • add_library(lib STATIC|SHARED|INTERFACE src.cpp)
    STATIC produces a .lib/.a; SHARED produces a .dll/.so; INTERFACE carries usage requirements only (no compiled output - useful for header-only libraries).
  • target_link_libraries(target PRIVATE|PUBLIC|INTERFACE dep)
    Links dep to target. PRIVATE keeps the dependency internal; PUBLIC propagates it to anything that links against target.
  • target_include_directories(target PUBLIC include/)
    Adds include paths. PUBLIC propagates the path to dependents; PRIVATE is target-only.
  • target_compile_options(target PRIVATE -Wall -Wextra -Wpedantic)
    Appends compiler flags to a single target without polluting others.
  • target_compile_features(target PUBLIC cxx_std_20)
    Per-target alternative to CMAKE_CXX_STANDARD; preferred in library CMakeLists.txt to avoid overriding the caller's setting.
  • option(ENABLE_TESTS "Build unit tests" ON)
    Declares a user-visible boolean. Toggle with -DENABLE_TESTS=OFF at configure time.
  • add_subdirectory(part1)
    Pulls in a subdirectory that has its own CMakeLists.txt. Targets defined there become visible to the parent.
  • find_package(nlohmann_json 3.11 REQUIRED)
    Locates an installed library by its CMake package name. On success, imports a target (e.g. nlohmann_json::nlohmann_json) for use in target_link_libraries.
  • enable_testing() / add_test(NAME t COMMAND ./tests)
    Registers tests with CTest. Run all tests with ctest --test-dir build.
  • message(STATUS|WARNING|FATAL_ERROR "text")
    Prints a message during configure. FATAL_ERROR stops configuration immediately.

1.3  MSBuild

MSBuild is the build engine for Visual Studio and the .NET SDK. It reads .csproj, .vcxproj, and .sln files. You rarely write MSBuild XML directly - the .NET SDK and VS generate it - but knowing the key flags matters when scripting builds or debugging build failures. msbuild MyApp.sln /p:Configuration=Release /p:Platform=x64 msbuild MyApp.csproj /t:Rebuild /p:Configuration=Debug
  • /p:Configuration=Release - selects the Release configuration (optimized).
  • /p:Platform=x64 - targets 64-bit; omit for SDK-style projects that default to AnyCPU.
  • /t:Rebuild - clean then build; /t:Build is incremental.
  • /m - parallel build using all CPU cores.
For .NET 5+ projects, the dotnet CLI (section 1.5) wraps MSBuild and is the preferred command-line interface. Use MSBuild directly for legacy .vcxproj C++ projects or when you need fine-grained control over the target graph.
Common MSBuild options and .csproj / .vcxproj attributes
Command-line flags
  • /p:Property=Value
    Sets any MSBuild property from the command line. Takes precedence over values in the project file.
  • /t:Target1;Target2
    Runs the named targets in order. Default target is Build if omitted.
  • /m[:N]
    Builds in parallel using N worker processes; /m alone uses all logical CPU cores.
  • /v:quiet|minimal|normal|detailed|diagnostic
    Controls console verbosity. minimal shows only warnings and errors; diagnostic dumps every property and task.
  • /bl
    Writes a binary log (msbuild.binlog). Open with the MSBuild Structured Log Viewer to diagnose property evaluation and target execution order.
  • /nologo
    Suppresses the version banner. Useful in CI output.
Common /p: properties msbuild /p:Configuration=Release /p:Platform=x64 /p:TreatWarningsAsErrors=true
  • /p:Configuration=Debug|Release
    Selects which PropertyGroup conditions in the project file are active.
  • /p:Platform=x86|x64|AnyCPU|ARM64
    Sets the target platform. SDK-style C# projects default to AnyCPU; C++ projects require an explicit match.
  • /p:OutDir=path\
    Overrides the final output directory for binaries. Path must end with a backslash.
  • /p:TreatWarningsAsErrors=true
    Promotes all warnings to errors. Good for CI gates.
  • /p:Optimize=true|false
    Enables or disables compiler optimizations independent of the Configuration selection.
  • /p:DefineConstants=TRACE;MYFEATURE
    Adds preprocessor / conditional-compilation symbols (C# projects).
Common /t: targets
  • /t:Build - incremental build; skips up-to-date inputs (default).
  • /t:Rebuild - deletes all outputs then builds from scratch.
  • /t:Clean - removes all build outputs without rebuilding.
  • /t:Restore - restores NuGet packages; runs before the first build on a fresh clone.
  • /t:Publish - produces deployment-ready output; respects PublishProfile.
Key SDK-style .csproj elements
  • <OutputType>Exe|Library|WinExe</OutputType>
    Exe builds a console app; Library a .dll; WinExe a Windows GUI app with no console window.
  • <TargetFramework>net10.0</TargetFramework>
    Pins the .NET version. Use <TargetFrameworks> (plural) to multi-target: net8.0;net10.0.
  • <Nullable>enable</Nullable>
    Turns on C# nullable reference type analysis. Strongly recommended for new projects.
  • <ImplicitUsings>enable</ImplicitUsings>
    Auto-adds common using directives (System, LINQ, etc.) so they don't appear in every source file.
  • <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
    Required to compile any unsafe { } block.
  • <PackageReference Include="Pkg" Version="1.2.3" />
    Declares a NuGet dependency. Run dotnet restore or msbuild /t:Restore to download it.
  • <ProjectReference Include="../Lib/Lib.csproj" />
    Links another project in the same solution. MSBuild builds it first and wires up the output assembly automatically.

1.4  Clang

Clang is both a C/C++ compiler and a tooling platform. The compiler produces code comparable to GCC and MSVC. The tooling layer - clang-tidy, clang-format, clangd, and the sanitizers - makes it the most diagnostic-rich C++ toolchain available. Key tools:
  • clang / clang++ - compile with -Wall -Wextra -std=c++20 -O2 as a baseline.
  • clang-tidy - static analysis; catches common bugs, enforces coding guidelines. Run via CMake with CMAKE_CXX_CLANG_TIDY.
  • clang-format - deterministic formatting driven by .clang-format in the project root. Integrates with VS Code's "Format on Save."
  • AddressSanitizer / UBSan - compile with -fsanitize=address,undefined to catch memory errors and undefined behavior at runtime.
  • clangd - language server; powers the VS Code C++ extension with completion, diagnostics, and cross-reference based on compile_commands.json.
Generate compile_commands.json from CMake with -DCMAKE_EXPORT_COMPILE_COMMANDS=ON. Copy or symlink it to the project root so clangd finds it automatically.
Common Clang compiler flags and tool options
clang / clang++ compiler flags clang++ -std=c++20 -Wall -Wextra -Wpedantic -O2 -o app main.cpp
  • -std=c++17|c++20|c++23
    Sets the language standard. Use -std=c++20 as the baseline for new projects.
  • -Wall -Wextra -Wpedantic
    -Wall enables the most common warnings; -Wextra adds a second tier; -Wpedantic enforces strict ISO conformance. Use all three together.
  • -Werror
    Turns all warnings into errors. Use in CI; omit locally to avoid blocking exploratory builds.
  • -O0|-O1|-O2|-O3|-Os|-Og
    Optimization level. -O2 is the standard release setting. -Og enables optimizations that do not impair debugger output.
  • -g / -g3
    Emits debug symbols. -g3 includes macro definitions. Combine with -O0 or -Og for debugging.
  • -fsanitize=address,undefined
    Instruments the binary to detect heap overflows, use-after-free, and undefined behavior at runtime. Cannot combine with -fsanitize=thread.
  • -fsanitize=thread
    ThreadSanitizer: detects data races in multithreaded code. Significant runtime overhead; use for dedicated race-condition testing.
  • -I include/
    Adds a directory to the include search path.
  • -DNDEBUG / -DMY_MACRO=1
    Defines a preprocessor macro. -DNDEBUG disables assert() checks.
  • -c
    Compiles to object file only; skips linking. Used when building multi-file projects manually.
clang-tidy clang-tidy src/main.cpp -- -std=c++20 -I include/ clang-tidy --fix src/main.cpp -- -std=c++20
  • --checks=bugprone-*,modernize-*,readability-*
    Selects check categories. Prefix a category with - to disable it: -modernize-use-trailing-return-type.
  • --fix
    Applies machine-fixable suggestions in place. Review with git diff before committing.
  • --warnings-as-errors=*
    Fails the invocation on any enabled check finding. Useful as a CI gate.
  • CMake integration: set(CMAKE_CXX_CLANG_TIDY "clang-tidy;--checks=bugprone-*")
    Runs clang-tidy on every source file during the build.
clang-format clang-format --style=file -i src/*.cpp include/*.h clang-format --style=Microsoft --dump-config > .clang-format
  • --style=file
    Reads formatting rules from the nearest .clang-format file walking up the directory tree. Use this in projects.
  • --style=LLVM|Google|Chromium|Microsoft|Mozilla
    Built-in style presets. Pass to --dump-config to generate a starting .clang-format to customize.
  • -i
    Edits files in place. Without -i, formatted output goes to stdout for preview.
  • --dry-run --Werror
    Reports files that need reformatting without changing them. Exit code 1 if any file differs; use as a CI formatting check.
clangd (language server)
  • Requires compile_commands.json at the project root (or pointed to via --compile-commands-dir). Generate it from CMake with -DCMAKE_EXPORT_COMPILE_COMMANDS=ON.
  • Per-project config: place a .clangd file at the root. Common uses: suppress specific diagnostics, add extra compile flags, or exclude generated files from indexing.
  • CompileFlags: { Add: [-std=c++20, -DMY_FLAG] } in .clangd - appends flags to every translation unit without modifying CMakeLists.txt.
  • Diagnostics: { Suppress: [unused-includes] } in .clangd - silences noisy checks project-wide.

1.5  dotnet CLI

The dotnet CLI is the primary interface for .NET SDK projects. It creates, builds, tests, and runs C# projects without requiring Visual Studio. dotnet new console -n MyApp # create console project dotnet build -c Release # build dotnet run # build and run dotnet test # run xUnit / NUnit tests dotnet publish -c Release -r win-x64 --self-contained
  • dotnet new - scaffolds projects; dotnet new list shows all templates.
  • dotnet add package <name> - adds a NuGet dependency and updates the .csproj.
  • dotnet publish --self-contained - bundles the runtime into the output; no .NET install needed on the target.
  • dotnet watch run - hot-reload loop; rebuilds and restarts on file save.
SDK-style .csproj files are concise enough to edit by hand. The CLI and MSBuild share the same project model, so a project built with dotnet build opens without modification in Visual Studio.
Common dotnet CLI commands and options
Project creation dotnet new console -n MyApp -o MyApp/ # console app dotnet new classlib -n MyLib # class library dotnet new xunit -n MyApp.Tests # xUnit test project dotnet new sln -n MySolution # solution file dotnet sln add MyApp/MyApp.csproj # add project to solution dotnet new list # show all available templates Build and run dotnet build # incremental build, Debug dotnet build -c Release # optimized build dotnet build -c Release --no-restore # skip package restore dotnet run # build and run entry project dotnet run --project MyApp/MyApp.csproj # specify project explicitly dotnet run -- arg1 arg2 # pass arguments to the app dotnet watch run # hot-reload on file save Test dotnet test # run all tests dotnet test -c Release # test against Release build dotnet test --filter "FullyQualifiedName~MyTest" # run matching tests dotnet test --logger "console;verbosity=detailed" dotnet test --collect:"XPlat Code Coverage" # emit coverage data Publish dotnet publish -c Release -r win-x64 --self-contained # standalone .exe dotnet publish -c Release -r linux-x64 --self-contained dotnet publish -c Release /p:PublishSingleFile=true # single file output
  • -r <rid>
    Runtime identifier: win-x64, linux-x64, osx-arm64, etc. Required for self-contained publish.
  • --self-contained
    Bundles the .NET runtime into the output. Target machine needs no .NET install. Increases output size significantly.
  • /p:PublishSingleFile=true
    Packs the app and all dependencies into one executable.
  • /p:PublishTrimmed=true
    Removes unused framework code to reduce output size. Requires testing; trim-incompatible reflection patterns fail silently at runtime.
Package management dotnet add package Newtonsoft.Json # add latest dotnet add package Newtonsoft.Json --version 13.0.3 dotnet remove package Newtonsoft.Json dotnet list package # show all dependencies dotnet list package --outdated # show available upgrades dotnet restore # restore without building Solution and project references dotnet add reference ../Lib/Lib.csproj # project reference dotnet sln list # list projects in solution dotnet sln remove MyApp/MyApp.csproj # remove from solution Useful global options
  • -c|--configuration Debug|Release - build configuration; defaults to Debug.
  • -o|--output <path> - override the output directory.
  • --no-build - skip the build step (test, run, publish).
  • --no-restore - skip NuGet restore; useful when packages are already cached.
  • -v|--verbosity quiet|minimal|normal|detailed|diagnostic - controls log level.
  • dotnet --info - shows installed SDK versions, runtime paths, and OS details.
  • dotnet --list-sdks / dotnet --list-runtimes - enumerate installed versions.

1.6  Python

Python 3.10+ is the runtime for all Python implementations in Project Story. The interpreter is also used for scripting build steps, running analysis tools (radon, pylint, cProfile), and driving the AI agent tools in the Code/AI/ directory. Project setup with a virtual environment: python -m venv .venv # create isolated environment .venv\Scripts\activate # Windows - activate source .venv/bin/activate # Linux / macOS - activate pip install -r requirements.txt python src/main.py
  • venv - isolates dependencies per project; avoids version conflicts between projects and the system Python.
  • pip - installs packages from PyPI; pip freeze > requirements.txt records the exact versions for reproducible installs.
  • pyproject.toml - the modern project metadata file, replacing setup.py. Build tools (flit, hatchling, setuptools) read it.
  • pylint / mypy - static analysis and type checking; integrate with VS Code via the Pylance extension and the Problems panel.
Python is the only interpreted language in Project Story. That matters for performance comparisons: CPU-bound tasks run 10-100x slower than compiled languages, but I/O-bound tasks (TextFinder, file search) close much of the gap because the hot path runs in compiled C extensions inside the standard library.
Common Python commands and tool options
Interpreter and virtual environment python --version # confirm active version python -m venv .venv # create isolated environment .venv\Scripts\activate # Windows - activate source .venv/bin/activate # Linux / macOS - activate deactivate # exit the virtual environment python -m venv .venv --clear # recreate from scratch
  • python -m module
    Runs a module as a script using the active interpreter. Preferred over bare python script.py for tools like venv, pip, and pytest because it guarantees the correct environment is used.
  • python -c "code"
    Executes a one-liner directly. Useful for quick checks: python -c "import sys; print(sys.path)".
pip package management pip install requests # install latest pip install requests==2.31.0 # pin a version pip install -r requirements.txt # install from lock file pip install -e . # editable install (dev mode) pip uninstall requests pip list # show installed packages pip list --outdated # show available upgrades pip show requests # metadata for one package pip freeze > requirements.txt # snapshot current environment pip install --upgrade pip # upgrade pip itself Running and profiling python src/main.py arg1 arg2 # run a script python -m cProfile -s cumtime src/main.py # profile, sort by cumulative time python -m cProfile -o prof.out src/main.py python -m pstats prof.out # interactive stats browser python -m timeit -n 1000 "'-'.join(str(i) for i in range(100))" Testing with pytest pip install pytest pytest-cov pytest # discover and run all tests pytest tests/test_parser.py # run one file pytest -k "test_parse" # run tests matching name pattern pytest -v # verbose: show each test name pytest -x # stop on first failure pytest --tb=short # compact tracebacks pytest --cov=src --cov-report=term-missing # coverage report Static analysis and type checking pip install pylint mypy ruff pylint src/ # lint with scoring mypy src/ --strict # type check; --strict enables all checks ruff check src/ # fast linter (replaces flake8 + isort) ruff format src/ # opinionated formatter (like black)
  • mypy --strict
    Enables all optional checks including --disallow-untyped-defs and --warn-return-any. Start without --strict on existing code and tighten incrementally.
  • ruff
    Replaces flake8, isort, and parts of pylint. Configured via pyproject.toml under [tool.ruff]. Significantly faster than pylint on large codebases.
pyproject.toml key sections [build-system] requires = ["hatchling"] build-backend = "hatchling.build" [project] name = "myapp" version = "1.0.0" requires-python = ">=3.10" dependencies = ["requests>=2.31", "anthropic"] [project.scripts] myapp = "myapp.main:main" # creates a CLI entry point [tool.mypy] strict = true [tool.ruff] line-length = 100 select = ["E", "F", "I"] # pycodestyle, pyflakes, isort