Zooming In: Separate Compilation, and Linking Statically#
Remember: All-In-One Build …#
User |
Valuable and rock-stable code |
|---|---|
#include "hello.h"
int main(void)
{
hello(); // <--- HERE
return 0;
}
|
Would be built like so,
$ gcc -o hello-first hello-first.c hello.c
Solution: Separate Compilation And Linking Steps#
Goal: only a single compilation step of
hello.cThis cannot produce an executable, obviously
Compilation only: turn
hello.cintohello.o
hello.c#$ gcc -c -o hello.o hello.c
Same for both users of
hello()hello-first.c⟶hello-first.o$ gcc -c -o hello-first.o hello-first.c
hello-second.c⟶hello-second.o$ gcc -c -o hello-second.o hello-second.c
Linking existing object files into executables
hello-firstneedshello-first.oandhello.o$ gcc -o hello-first hello-first.o hello.o
hello-secondneedshello-second.oandhello.o$ gcc -o hello-second hello-second.o hello.o
Note
This is referred to as static linking. Each of the resulting executables
hello-firstandhello-secondhas its own copy ofhello.oin it!As opposed to dynamic linking where
hello.ois wrapped into a shared library (usually named likelibhello.so). This shared library is then loaded at program startup, just likelibc.soas we saw in Toolchain: Basics
Complication: Modification Tracking#
Question: what if I modify hello.c?
Answer: re-do the following steps
Re-compile
hello.ofrom it$ gcc -c -o hello.o hello.c
Re-link both using executable to update their copy of
hello.o$ gcc -o hello-first hello-first.o hello.o
$ gcc -o hello-second hello-second.o hello.o
Note
A similar dance has to be performed if you modify one of the using
files hello-first.c or hello-second.c.
The following directed acyclic graph reflects exactly those
relationships (an arrow A “⟶” B says that “If
B is newer than A, then A has to be recreated from B):

Note
The all node is artificial in that it does not correspond to a
file, but rather means the “see if anything needs to be done” case.
Enter Makefiles#
Problem: how would I manually track all those dependencies in a rapidly growing project?
Answer: automate it!
The following Makefile describes exactly the situation above,
.PHONY: all
all: hello-first hello-second
hello.o: hello.c
gcc -c -o hello.o hello.c
hello-first.o: hello-first.c
gcc -c -o hello-first.o hello-first.c
hello-second.o: hello-second.c
gcc -c -o hello-second.o hello-second.c
hello-first: hello-first.o hello.o
gcc -o hello-first hello-first.o hello.o
hello-second: hello-second.o hello.o
gcc -o hello-second hello-second.o hello.o
To run the commands in that file, standing in the directory where the
Makefile is, simply say [1] ,
$ make
gcc -c -o hello-first.o hello-first.c
gcc -c -o hello.o hello.c
gcc -o hello-first hello-first.o hello.o
gcc -c -o hello-second.o hello-second.c
gcc -o hello-second hello-second.o hello.o
As a test, modify hello-second.c, and see how only a subset of the
commands run,
$ make
gcc -c -o hello-second.o hello-second.c
gcc -o hello-second hello-second.o hello.o
Footnotes