Now you run the pipeline. Recall the mnemonic COAL: Compile → Objects →
Archive → Link.
Recall Solution 2.1
gcc -c add.c -o add.ogcc -c sub.c -o sub.o
Why -c? It stops the pipelinebefore the link stage, emitting relocatable code — machine code where addresses are
still placeholders. Libraries have no main(), so there is nothing to link into an
executable yet.
Recall Solution 2.2
ar rcs libmath.a add.o sub.o
r = insert/replace members, c = create quietly, s = write the symbol index.
The s builds the table add → add.o, sub → sub.o so the linker resolves symbols
without scanning every member.
Here you predict outcomes and explain the mechanism. The link-order rule lives here.
Recall Solution 3.1
(A) fails. The linker walks left → right, keeping a running set of currently
undefined symbols (see the figure above).
In (A), when it reaches -lmath the undefined set is empty (nothing has asked
for add yet), so it pulls zero members from the archive. Then main.o references
add → still undefined at the end → error.
In (B), main.o is processed first, putting add on the "wanted" list. When
-lmath is reached, add is undefined, so the member defining it is pulled in and
resolved.
Rule: users left, libraries right — a library must appear after whatever uses it.
Why this works:--start-group ... --end-group tells the linker to re-scan the
enclosed archives repeatedly until no new undefined symbols appear — breaking the
single-pass limitation for that group only.
Recall Solution 3.3
Yes, it still runs. Static linking copiedadd's machine code into the
executable at build time. The archive was only a build-time source; the runtime
executable is self-contained. (Contrast with Shared libraries — .so / .dll, where
the library must be present at run time.)
Same three COAL stages — compile (cl /c), archive (lib), link (cl ... math.lib) —
just different tool names. MSVC passes the .libdirectly on the command line rather
than via -l.
Edge cases and reasoning the parent note only gestured at. These separate "can run the
commands" from "understands the machine."
Recall Solution 5.1
Only add.o is copied in. sub.o and mul.o are left out.
Mechanism: the linker pulls a member from the archive only if that member resolves a
currently-undefined symbol. Nothing references sub or mul, so those members never
enter the "wanted" set. This is the selectivity goal — you get reuse without bloating
the executable with unused code.
Recall Solution 5.2
Yes — giant is copied in too. The unit of extraction is the whole object file,
not the individual function. Because add and giant live in the sameutil.o,
pulling in add drags giant along.
Fix (build time): put each function in its own .c → own .o so the archive has
fine-grained members. (Alternatively compile with -ffunction-sections and link with
-Wl,--gc-sections so the linker garbage-collects unreferenced sections.)
Recall Solution 5.3
The archive is created successfully but contains no members and no defined symbols.
At link time it contributes nothing, so add stays undefined → the linker fails with
undefined reference to 'add'. Lesson: an empty (or wrong) library is not an error by
itself — the error surfaces only when a needed symbol goes unresolved.
Recall Solution 5.4
The first archive that resolves add wins — here libA.a, because it is scanned
before libB.a in left-to-right order. Once add is satisfied, libB.a's member
defining add is never pulled in (nothing undefined needs it), so there is no
multiple-definition error. (This differs from linking two object files that both
define add directly, which would be a duplicate-symbol error — the archive's
"pull only if needed" rule quietly hides the collision.)