Consider writing a "hello world!" program in c. Lets say our source code is in a file called source.c, now in order to run our program we need to compile it, typically on Linux (using gcc) we would need to type $> gcc source.c -o output
where output is the name of the executable to be generated. For a basic program this works well but as programs become more complex our compilation command can also become more complex. This is where a Makefile comes in, makefiles allow us to write out a fairly complex set of rules for how to compile a program and then simply compile it by typing make on the command line. For instance here is a possible example Makefile for the hello wold example above.
Basic Makefile
Lets make a basic Makefile and save it to our system in the same directory as our source code named Makefile. Note that this file needs to be named Makefile, however the capitol M is optional. That said it is relatively standard to use a capitol M.
output: source.c
gcc source.c -o output
Note that there is exactly one tab before the gcc command on the second line (this is important in makefiles). Once this Makefile is written every time the user types make (in the same directory as the Makefile) make will check to see if source.c has been modified (checks the time stamp) if it has been modified more recently than output it will run the compilation rule on the following line.
Variables in Makefiles
Depending on the project you may want to introduce some variables to your make file. Here is an example Makefile with variables present.
CFLAGS = -g -Wall
output: source.c
gcc $< $(CFLAGS) -o $@
Now lets explore what happened here. In the first line we declared a variable named CFLAGS that holds several common flags you may wish to pass to the compiler, note that you can store as many flags as you like in this variable. Then we have the same line as before telling make to check source.c to see if it has been changed more recently than output, if so it runs the compilation rule. Our compilation rule is mostly the same as before but it has been shortened by using variables, the $<
variable is built into make (referred to as an automatic variable see https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html) and it always stands for the source so in this case source.c. $(CFLAGS)
is our variable that we defined before, but note that we had to put the variable in parenthesis with a $ in front like this$(someVariable)
. This is the syntax for telling Make to expand the variable out to what you typed before. Finally we have the $@ symbol, once again this is a variable built into make, and it simply stands for the target of the compilation step, so in this case it stands for output.
Clean
Make clean is another useful concept to learn about make files. Lets modify the Makefile from above
CFLAGS = -g -Wall
TARGETS = output
output: source.c
gcc $< $(CFLAGS) -o $@
clean:
rm $(TARGETS)
As you can see we simply added one more rule to our Makefile, and one additional variable that contains all of our targets. This is a somewhat common rule to have in makefiles as it allows you to quickly remove all of the binaries you produced simply by typing $> make clean
. By typing make clean you tell the make program to run the clean rule and then make will run the rm command to delete all of your targets.
I hope this brief overview of using make helps you speed up your workflow, Makefiles can become very complex, but with these ideas you should be able to get started using make and have a better understanding of what is going on in other programmers Makefiles. For more information about using make an excellent resource is https://www.gnu.org/software/make/manual/.