Unit 7.1 · about 4 h
42 / 324Compiling, linking, loading, ABI and C linkage
A native extension can compile successfully yet fail to link or import. Separating these stages lets you repair the boundary rather than change unrelated source code.
- explain
You can now
- Trace a source file through preprocessing, compilation, assembly, linking and loading, naming each artifact.
- Diagnose a missing declaration, missing definition or missing shared library at the responsible stage.
- Explain which ABI and ownership agreements a C-linkage boundary still needs.
Covers
- Preprocess, compile, assemble, link, load and symbols
- Warnings, debug symbols, optimization and ABI compatibility
- C linkage and stable foreign-function boundaries
Study, in this order
4 steps
- Compilation ProcessAlgoMaster C++
Recap of the Pipeline; Stage 1 through Stage 4; Putting It Together: A Two-File Build; Mapping Errors to Stages
Depth · Use the artifacts and error examples. Do not adopt the lesson's unmeasured optimization speedup ranges or its mention of trigraph translation: trigraphs were removed in C++17.
- Language linkagecppreference
Explanation and Notes, including the
__cplusplusconditional header exampleDepth · Skip compiler-specific function-type overload disputes.
- Cross-compiler interfacesC++ Core Guidelines
I.26: If you want a cross-compiler ABI, use a C-style subset
- Linux dynamic linker/loader`ld.so`: dynamic linker/loader
DESCRIPTION, including dependency search order and Dynamic string tokens; ENVIRONMENT entry
LD_DEBUGDepth · Stop before legacy hardware-capability directories and auditing.
Focus on
- A declaration lets a translation unit type-check a call. A definition supplies the implementation; an object file can still contain unresolved symbols.
- Use
-Wall-Wextra-Wpedanticand-gfor development. Compare-O0and-O2artifacts without treating optimization as a correctness fix or a promised speedup. - ABI covers calling conventions, representation and binary compatibility. extern C linkage does not make STL objects, exceptions or allocators portable across arbitrary binaries.
- The Linux loader searches for shared objects at runtime. A link-time
-Ldirectory is not automatically a runtime search path.
Reproduce closed-book
-std=c++20 -O0 -g on Linux x86-64, define extern "C" int inc(int x) { return x + 1; } in one translation unit and declare it in another whose main returns inc(41) == 42 ? 0 : 1. Produce preprocessed text with -E, assembly with -S and objects with -c. Inspect nm: the defining object has T inc and the caller U inc. Linking only the caller fails with undefined reference to inc; linking both objects succeeds and exits zero. Compare -O2 assembly, recording the flags rather than promising specific instructions.Traps
- Including a header is not the same as linking the implementation that its declarations require.
- An unmangled C symbol is not a complete stable ABI. Agree on widths, buffer lengths, ownership, error codes and compatible platform conventions.
- Debug symbols and optimization are independent choices. Optimized code can have debug information while some source variables are optimized out.
Practice
The section mini-project covers this: document the native component's build artifacts and ABI, and diagnose one missing-symbol or runtime-library failure.
Self-test
-
Why can
-csucceed when a called function has no definition?The declaration suffices for compilation. The object records an unresolved symbol for the linker to resolve. -
An executable links but reports a missing
.sowhen started. Which stage needs investigation?Loading. Inspect the dependency name and runtime search paths, not just the source include path. -
Does extern C make a function returning
std::vector<int>safe for an arbitrary C caller?No. It changes language linkage, not the vector representation, C type system or allocator ownership contract.
Completion criterion
Stop when
You reproduce the two-object link and correctly classify a missing header, unresolved symbol and missing runtime library, with a written C-boundary ownership contract.
Mark passed, then open 7.2 Only mark this when you can do it without notes.Leads to
- 7.9 Repeatable CMake builds and test targets Encode the pipeline as repeatable targets.
- 7.8 Python and native code: dtype, stride, ownership and GIL contracts Apply compatibility and ownership contracts at import and call time.
Resources for this unit
- AlgoMaster C++ Use the sections on compilation, pointers and references, memory, RAII and smart pointers, copy and move, STL containers, templates, errors, concurrency and paired exercises. Skip competitive-programming breadth already covered in Algorithms.
- C++ Core Guidelines Use the Philosophy, Interfaces, Resource management, Expressions, Containers and concurrency rule groups to review ownership and safety decisions in the native component.
- cppreference Consult language lifetime, object model, value categories, memory model, atomics, containers and iterator invalidation while reading or modifying code.
- `ld.so`: dynamic linker/loader Read DESCRIPTION, Dynamic string tokens and
LD_DEBUGto distinguish link-time symbols from runtime shared-library discovery on Linux.
Also in this section
- Clang AddressSanitizer and UndefinedBehaviorSanitizer Compile seeded memory defects with AddressSanitizer and UndefinedBehaviorSanitizer, preserve the reports, repair the root cause and keep regression tests.
- pybind11 documentation Follow First steps and NumPy support to expose one small native function with explicit shape, dtype, stride, ownership, GIL and exception behavior.
- CMake tutorial Use the introductory steps for targets, libraries, testing and install rules. Produce one clean debug build and one optimized build without copied one-off commands.
- Algorithmica - AoS and SoA Read the AoS and SoA experiment for a measured case where keeping each record together wins, the counterpart to a single-field scan.
- Memory Layout Transformations Read Overview and Topics through AOS Form and SOA Form for field-wise access and locality trade-offs. Skip Intel array-notation syntax and the LIBOR example.
- GDB manual: Backtraces Use section 8.2 for frame numbers,
bt,bt -fulland optimized-out arguments when inspecting a native failure.