Ship real C++: describe a build with CMake, pull in dependencies with vcpkg or Conan, write unit tests with GoogleTest, and debug with gdb and sanitizers.
Real projects have many files and platforms, so nobody types g++ by hand. CMake describes the build declaratively in CMakeLists.txt and generates the actual build files (Make, Ninja, MSVC). This is the de-facto standard for C++ projects.
# CMakeLists.txt
cmake_minimum_required(VERSION 3.20)
project(myapp LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(myapp src/main.cpp src/shape.cpp)
# configure + build from the shell:
# cmake -S . -B build
# cmake --build build
# ./build/myappC++ has no single built-in package manager, so projects use vcpkg (Microsoft) or Conan. They fetch, build, and expose libraries so CMake can find_package them — replacing the old pain of vendoring source by hand. Pick one per project and commit its manifest.
# vcpkg: install a library, then let CMake find it
vcpkg install fmt
# In CMakeLists.txt:
# find_package(fmt CONFIG REQUIRED)
# target_link_libraries(myapp PRIVATE fmt::fmt)
# Conan alternative — declare deps in conanfile.txt:
# [requires]
# fmt/10.2.1
# [generators]
# CMakeDeps
# CMakeToolchain
conan install . --output-folder=build --build=missingTests are how you change C++ without fear. GoogleTest (gtest) is the most common framework: TEST() defines a case and EXPECT_* macros assert results. Wire it in through CMake and run the whole suite with ctest.
#include <gtest/gtest.h>
int add(int a, int b) { return a + b; }
TEST(AddTest, HandlesPositive) {
EXPECT_EQ(add(2, 3), 5);
EXPECT_NE(add(2, 3), 6);
}
TEST(AddTest, HandlesNegative) {
EXPECT_EQ(add(-2, -3), -5);
}
// build links against gtest_main, then:
// ctest --test-dir buildCompile with -g to embed debugging symbols, then step through with gdb (or lldb) to inspect state at a crash. Even better, build with sanitizers: -fsanitize=address catches leaks and use-after-free, -fsanitize=undefined catches undefined behavior — turning silent corruption into a clear report.
# build with debug symbols and run under the debugger
g++ -std=c++20 -g app.cpp -o app
gdb ./app # then: run / break main / next / print x / backtrace
# catch memory bugs automatically (invaluable in C++)
g++ -std=c++20 -g -fsanitize=address,undefined app.cpp -o app
./app # prints exact file:line of leaks / UB when they happen