So far we have mostly worked with programs that have consisted of a single file. Most programs, however, are split into multiple files. In order to compile multiple files together, we could pass them all to clang++ like so:
$ clang++ a.cpp b.cpp c.cpp -o program
However, if we want to change one of the files, then recompiling with this method is not efficient because it will compile all three files every time. For small programs, this is not a problem, but large programs can take minutes or even hours to compile. To get around this, we could compile the .cpp files into object files and link them at the end:
$ clang++ -c a.cpp $ clang++ -c b.cpp $ clang++ -c c.cpp $ clang++ a.o b.o c.o -o program
Then if we change one of the files, we will only need to recompile that one file, and relink the executable. The problem with this is that it's tough to remember which files we changed and need to recompile - especially difficult if we change a header file. This is the problem makefiles are designed to solve.
A makefile is a file that describes the dependencies between the source files of your program. It also contains the commands that are needed to compile your code into an executable. The make command reads the makefile and your programs source code to build your program.make looks at the timestamp of your program in order to determine which files are out of date. Using the dependency information in the makefile, it only recompiles the files that need to be recompiled.
A makefile must be named either "makefile" or "Makefile". It consists of a number of rules that look like this:
The space to the left of the command must be a tab character, not spaces.
filename: dependency1 dependency2 dependency3 command to produce filename
# make the main program circle: circle.o main.o clang++ circle.o main.o -o circle @echo "All done" # make the circle object file circle.o: circle.cpp circle.h clang++ -c circle.cpp # make the main object file main.o: main.cpp circle.h clang++ -c main.cpp
We can use this makefile to compile this program by typing "make" on the command line. By default, make will try to build the first target in this case "circle". If we wanted to build another one, we could specify it for example "make main.o".
# macros FLAGS = -W -Wall # make the main program circle: circle.o main.o clang++ $(FLAGS) circle.o main.o -o circle @echo "All done" # make the circle object file circle.o: circle.cpp circle.h clang++ $(FLAGS) -c circle.cpp # make the main object file main.o: main.cpp circle.h clang++ $(FLAGS) -c main.cpp
clean: rm -f circle *.o
Then on the command line, we can run:
To clean up the binary files.
$ tar -cvf filename.tar file1 file2 ...
The "c" option stands for create, the "v" option stands for verbose (which provides extra output) and the "f" option stands for filename.
In order to extract a tarball, use the "x" option instead of "c":
$ tar -xvf filename.tar
Tar can be used to package multiple files in a project together (to email or create backups for example).
Sometimes, people put in a rule to create a tar ball under a "dist" target:
dist: tar -cvf circle.tar.gz main.cpp circle.cpp circle.h
Copyright © 2018 Ian Finlayson | Licensed under a Creative Commons Attribution 4.0 International License.