The Makefile builds the hello
executable if any one of main.cpp
, hello.cpp
, factorial.cpp
changed. The smallest possible Makefile to achieve that specification could have been:
hello: main.cpp hello.cpp factorial.cpp
g++ -o hello main.cpp hello.cpp factorial.cpp
- pro: very easy to read
- con: maintenance nightmare, duplication of the C++ dependencies
- con: efficiency problem, we recompile all C++ even if only one was changed
To improve on the above, we only compile those C++ files that were edited. Then, we just link the resultant object files together.
OBJECTS=main.o hello.o factorial.o
hello: $(OBJECTS)
g++ -o hello $(OBJECTS)
main.o: main.cpp
g++ -c main.cpp
hello.o: hello.cpp
g++ -c hello.cpp
factorial.o: factorial.cpp
g++ -c factorial.cpp
- pro: fixes efficiency issue
- con: new maintenance nightmare, potential typo on object files rules
To improve on this, we can replace all object file rules with a single .cpp.o
rule:
OBJECTS=main.o hello.o factorial.o
hello: $(OBJECTS)
g++ -o hello $(OBJECTS)
.cpp.o:
g++ -c $< -o $@
- pro: back to having a short makefile, somewhat easy to read
Here the .cpp.o
rule defines how to build anyfile.o
from anyfile.cpp
.
$<
matches to first dependency, in this case, anyfile.cpp
$@
matches the target, in this case, anyfile.o
.
The other changes present in the Makefile are:
- Making it easier to changes compilers from g++ to any C++ compiler.
- Making it easier to change the compiler options.
- Making it easier to change the linker options.
- Making it easier to change the C++ source files and output.
- Added a default rule 'all' which acts as a quick check to ensure all your source files are present before an attempt to build your application is made.