Appearance
Manual Builds That Expose Every Layer
Manual commands are valuable because they reveal inputs and artifacts. They are not a recommendation to maintain a hundred-file application with shell history. Build tools automate the same graph introduced here.
Compile translation units separately
For a project with src/main.cpp, src/report.cpp, and include/report/report.hpp:
sh
c++ -std=c++20 -Iinclude -Wall -Wextra -Wpedantic -g -c src/report.cpp -o report.o
c++ -std=c++20 -Iinclude -Wall -Wextra -Wpedantic -g -c src/main.cpp -o main.o
c++ main.o report.o -o report-cli-Iinclude changes header search during compilation. It does not link a library. -Ldirectory changes library search during linking; -lname requests a platform-named library such as libname.a or libname.so.
Quote includes normally search relative/project paths according to driver rules; angle includes normally represent configured/system include paths. Do not encode machine-specific absolute include directories in source.
Let the compiler driver link
Use c++ for a C++ final link so it supplies the correct C++ runtime and standard library. The order of archive libraries matters on common one-pass Unix-style linkers:
sh
c++ main.o -Lvendor/lib -lreport -o report-cliThe object that references a symbol appears before the archive expected to satisfy it. Build systems abstract this while preserving dependency order.
MSVC expresses analogous inputs differently:
powershell
cl /std:c++20 /W4 /EHsc /I include /c src\report.cpp
cl /std:c++20 /W4 /EHsc /I include /c src\main.cpp
link main.obj report.obj /OUT:report-cli.exeOrdinarily cl can coordinate the final link as well.
Archives collect objects
sh
ar rcs libreport.a report.o
c++ main.o -L. -lreport -o report-cliAn archive index lets the linker select members satisfying unresolved references. ar packages objects; it does not compile them. MSVC uses lib.exe for static libraries.
Shared libraries are platform-specific products
On a typical ELF platform:
sh
c++ -std=c++20 -fPIC -Iinclude -c src/report.cpp -o report.o
c++ -shared report.o -o libreport.somacOS uses dynamic-library flags and install names; Windows DLLs require exported symbols and commonly produce an import library. Copying this ELF recipe across platforms is not portability.
The consumer needs compile-time headers, link-time library metadata, and runtime access to the shared binary. RPATH/install-name policies, application bundles, or installers should make discovery intentional.
Macros configure translation
sh
c++ -DREPORT_TRACE=1 -DREPORT_LIMIT=100 ...Every translation unit that depends on an ABI-affecting macro must agree. Conditional fields or calling annotations in public headers can silently make objects incompatible. Prefer generated configuration headers and target-level build definitions over ad hoc command differences.
Dependency files enable correct incremental builds
An object depends on its source and every included header. GCC-compatible drivers can emit Make-compatible dependency data:
sh
c++ -MMD -MP -c src/report.cpp -o report.oThis commonly writes report.d. A handwritten Makefile that tracks only .cpp timestamps will fail to rebuild after header changes.
Flags belong to purposes
- Language contract:
-std=c++20 - Diagnostics:
-Wall -Wextra -Wpedantic - Debug information:
-g - Optimization:
-O0,-O2,-O3, or size-oriented choices - Instrumentation: sanitizer and coverage flags
- Code generation: architecture, visibility, PIC, runtime options
- Preprocessor:
-D,-I - Linker inputs/options: libraries and driver-forwarded linker flags
Do not copy an internet “ultimate flags” list. Flags differ by compiler and target; some change ABI or floating semantics.
Inspect artifacts
Use file to identify formats, nm to inspect symbols, objdump/readelf for ELF details, otool for Mach-O dependencies, and dumpbin for Windows objects. Ask focused questions: which architecture, is a symbol defined, which shared library is required, is debug information present?
Optional prompts
Debug: Adding -Ivendor/include does not fix an undefined reference. Why?
Answer: Include paths affect compilation and declarations. An undefined reference is a link problem requiring a matching object or library with a compatible symbol.
Explain: Why should a C++ final link normally use c++/g++/clang++?
Answer: The C++ driver supplies the standard library and runtime link defaults required by C++ objects.