This action might not be possible to undo. Are you sure you want to continue?
Chris Serson University of Victoria June 26, 2007
Chapter Introduction 1 – The most basic of Makefiles 2 – Syntax so far 3 – Making Makefiles Modular 4 – Multi-file projects 5 – Some more tidbits Conclusion Page 2 3 5 7 11 13 16
Even in 4th year. I didn't have a clue what was going on. When I was first introduced to these things.2 Introduction: The purpose of this tutorial is to introduce new students to the wonders and terrors of Makefiles. . I'd have to look over my friend's shoulder and copy his Makefile or copy and paste an old Makefile and hope I could just tweak it to run with my latest project. I had trouble with these things and I was always embarrassed to ask for help seeing as it is something I should have learned early on in my career as a student. Rather than typing some crazy long string of flags and files. My hope is that this tutorial will keep other students from suffering my fate. The idea behind having a Makefile is that you can save yourself a lot of typing of compiler commands. just type 'make' or 'make projectName' and away it goes.
in the file .c which would run off and compile myfile.o project1 project2 <--. But if you type: > make project2 it will run the compile command under the 'project2:' heading.. you could put that line in a Makefile (the name of the file is exactly that.c to an executable called myprog.The most basic of Makefiles: The most basic of Makefiles is basically just a file that runs the same command you would normally type into the command line. As a note. you may type: > gcc -o myprog myfile.3 Chapter 1 .c <--. '. if you type: > make it will run the first compile command. in case you didn't already know.o' files are 'object' files which contain compiled code which has yet to be linked together. We'll see this again in Chapter 4.in the file project1: myfile1. Even better. lets add another target to our Makefile: <--.c gcc -o project1 myfile1.c gcc -o project2 myfile2. Lets add another useful target: . Instead of this.end of file With this file.. More useful still is the fact that you can create a Makefile with multiple targets: <--. giving you a clean workspace to recompile your source code from scratch.c project2: myfile2.end of file Now if you type: > make clean it will delete all compiled files. clean: rm -f *. For instance. 'Makefile' no extension) and then run: > make for the exact same effect.
. <--.end of file If you add this line to the very top of your Makefile. now when you type: > make it will run your 'all:' target. ..in the file all: project1 project2 . which points to both of your 'project_' targets...end of file In this case: > make would do nothing. you could add the 'all:' target anywhere in the file and you could compile all of your targets by typing: > make all but having it as the first target makes a certain amount of sense. Another option is to create a 'default:' target at the top of the file which you could leave empty if you wanted the default action to do nothing. <--.4 <--. <--. Of course.in the file default: .
so let's try to fix that by defining some basic syntax of a Makefile. As we've seen. so adding those files to the list is a good thing. This is a good rule of thumb to use because the very next line MUST be indented with a 'tab' character.c <--.c' includes another file.Syntax so far: Up to now.c' to compile. In the case of 'project1'.h myfile2.c myfile1.5 Chapter 2 . we need the file 'myfile1. that file will be compiled automatically using the above statement. you can use the list of dependencies as a guide to help you remember what files are needed for what. you can call a target using: > make target which will run the compile command the target specifies.end of file This is the list of files the target needs .end of file Something to remember here is that if 'myfile1. <--. we've done some things which may not yet be clear. <--. <--.c extra.c gcc -o project1 myfile1.h <--. In a number of cases.c gcc -o project1 myfile1. there will be a list of files to the right of the target declaration.in the file project1: myfile1. I think it is a good idea to put a 'tab' character in for that space.its dependencies. For instance. Note the space between the target and the dependencies.in the file project1: myfile1. This next line is the actual command that gets run. However.in the file project1: myfile1.c <--. the statement 'project1:' is defining a target called 'project1'. A 'target' is the word listed before the colon.h myfile2.end of file .
in the file # this is a comment <--.h' and 'myfile2.c'. the above lines will do the same thing as the previous incarnation but gives you more information about the structure of the project.6 Assuming 'myfile1. Comments can be added to a Makefile by using the '#' character.c' includes both 'extra. For example: <--.end of file .
Once a macro has been declared. project1: myfile1.Making Makefiles Modular: Here's where things start to get more complicated. The first of these short-cuts is the macro. you've probably run across constants before.c <--.7 Chapter 3 . For example: <--. Macros in a Makefile are basically the same thing as constants but with slightly different syntax.in the file # the constant CC=gcc # this defines a macro CC which stands for the # compiler we will be using for our code.end of file . If you can program enough code that you would even consider needing a Makefile. I'm going to introduce a bunch of short-cuts to let you make more modular Makefiles. By this I mean that you should be able to create Makefiles that can be copied and pasted into different projects and be able to modify them quickly and easily without having to dig through the actual guts of the Makefile.c $(CC) -o project1 myfile1. you can use if whereever you could normally use the value it contains.
c . Most people seem to leave out white space.in the file CC=gcc # use the macro to name a target EXE=project1 # then use that macro to add the target to a list of # targets TARGETS=$(EXE) project2 # let's use the macro to declare the target now $(EXE): myfile1. but it will be just as correct to leave spaces in (ie. Here's another example: <--. 'macroname = value').. simple write 'macroname=value'.8 Notice how the macro is declared and then called. To declare a macro.o $(TARGETS) <--.. # this will delete 'project1' and 'project2' clean: rm -f *.c $(CC) -o myfile1.end of file . # let's use our TARGETS macro to list all of the possible # executable files we may have created.
There are also other built-in macros. There are a number of built in macros which can simplify the copy-and-paste method of making a Makefile: $@ -> this will copy the current target name.in the file CC=gcc CFLAGS=-Wall project1: myfile1. your executables may always need the '-Wall' flag (this just changes setting relating to warning messages): <--.c $(CC) $(CFLAGS) project1 myfile1. Here's an example: <--.9 Another example of a macro would be to create one called 'CFLAGS'.c extra. or some such.in the file CC=gcc # example 1: project1: myfile1.h $(CC) -o $@ $< . $^ -> this will copy ALL of the file names in the dependency list.c extra.h $(CC) -o project1 myfile1. $< -> this will copy the FIRST file name in the dependency list.c # same as project1: myfile1.h $(CC) -o $@ $^ # or project1: myfile1. For instance.c extra. but these are the three I actually find useful at this level.c <--.end of file On to the next thing. and use it to define compiler flags you call quite often.
It will give a whole bunch of errors # since it tries to compile both files and myfile1.c $(CC) -o $@ $< <--. linking in the other file automatically as appropriate. Note: it is possible to write # your code so this error won't actually happen and this # line will work. project1: myfile1.c myfile2.c. project1: myfile1.c.c $(CC) -o $@ $^ # this will work. It only takes the first file and compiles # it.c myfile2.10 # example 2: # this will not work.c already # includes myfile2.end of file . We effectively get a redefinition of # everything in myfile2.
in the file CC=gcc project: main.h $(CC) -c $^ list. You can see that the list code and queue code are strictly separate from the main . to continue on the thought of making these Makefiles more modular.c queue.h queue.o queue.h list.c list.c list.o list. we need to go that extra step and talk about multi-file projects. I mean projects that include a number of different '.c $(CC) -c $^ <--.o: main.in the file CC=gcc project: main.c' and '.11 Chapter 4 .h' files. however.o: list.end of file This will work just fine.h queue.o $(CC) -o $@ $^ main. Let's look at a more complex project: ->main.h // includes list.c // includes queue.c // includes queue.c // includes list.h The simple approach to compiling this: <--.Multi-file projects: Now that we have a grasp of all kinds of different crazy things to help make our Makefile more useful and reusable. By this.h ->queue.h ->list.c queue.h ->queue. Let's try something different: <--. we're going to look at a more stuctured method.o: queue. but what an evil list of file dependencies.h ->list.c $(CC) -o $@ $^ <--. We've already seen a couple of examples in the previous chapters that included multiple files and worked just fine.end of file This style of Makefile shows the structure of the code much better than the previous way.h list.h $(CC) -c $^ queue.
o' files? Basically.h' from 'main.12 program. So now what we have to do is link them together. They depend on the other files to work. If you wanted. That's what happens when we make the 'project' target. you could remove the 'queue. but you can also see where one section of code is dependant on another.o' and it would make no difference.o' and 'list.o' files don't exist or are not up-to-date. So what exactly is going on? How does this work? What are those '.o' files). These files make up the entirety of the program but they don't actually do anything on their own because they are not complete programs.h' from 'queue. however it would not be as clear the link between each code set. they are recompiled and then linked together as a final step. . If those '. When you make the 'project' it runs make on each of the '.o' file targets. we've split the program up into a bunch of pieces called object files (the '.
c $(HDIR)/queue. every day project.o \ fileio.in the file HDIR=headers SDIR=source ODIR=obj project: $(ODIR)/main. <--. use the backslash character to split the line. and maybe your object files (the '. bigproject: main.o: $(SDIR)/main.o $(CC) -o $@ $^ $(ODIR)/main. This tells the make program that the line is continued on the next line. No problem.in the file . This chapter is dedicated to stuff that you may or may not find useful.o ..o's) should be in their own folder as well (/obj).o database.Some more tid-bits: You should now have enough knowledge to pump out Makefiles for your standard. Example: <--. Just make sure your includes are correct in your code and add another macro: <--.o $(ODIR)/list.c $(HDIR)/list.o queue..end of file Multi-folder projects Let's say you have a big project and you want to keep your headers in one folder (/headers) and your source (/source) in another.h $(CC) -c $^ $(ODIR)/queue.h $(SDIR)/queue..o $(ODIR)/queue.13 Chapter 5 . These are things that I thought are pretty nifty. Splitting long lines up If you happen to have a line of text in your Makefile that is way to long to fit the average line width without scrolling.o network.o: $(HDIR)/queue.o list.h $(CC) -c $^ \ .o stack.o recursive..
o list.c file of the same name. We can get rid of them.o: %.end of file Condensing your targets You may find all those '.o: $(HDIR)/list. it does still move all of the things you're likely to change to the top of the file. This is a good technique since you don't want to go digging through the file every time you make a change. You can do this using the '%' character as below: <--.o: %. You can make a COMPILEEXE macro in the same manner: <--.end of file . this isn't really as useful if you're using the previous tid-bit.o list.o $(CREATEEXE) %.o file is compiled from a . The COMPILEOBJ macro I thought this little macro would be handy for replacing all of those nasty strings of characters you get with every object target.o $(CC) -o $@ $^ %.o queue. however.c $(CREATEOBJ) <--.h $(SDIR)/list.in the file project: main. Mind you.o queue.in the file CC=gcc COMPILEOBJ=$(CC) -c $^ CREATEEXE=$(CC) -o $@ $^ project: main.end of file What this does is say that every .c $(CC) -c $^ <--. but we'll lose a lot of readability.c $(CC) -c $^ <--.o' targets really annoying.14 $(ODIR)/list.
c $(CREATEOBJ) <--.o project: $(OBJS) $(CREATEEXE) %.o list. You may also want to consider a DEBUG macro that contains flags relating to any debugging you are doing: <--. Rather than writing all of the object files directly in the main project's dependency list.o project: $(OBJS) $(CREATEEXE) %.in the file CC=gcc DEBUG=-g # as an example. You can look up what this does CFLAGS=-Wall -c $(DEBUG) LFLAGS=-Wall $(DEBUG) -o # the -o doesn't actually do # anything # other than rename the executable # and could be left out of LFLAGS but # I've added it in to illustrate my # point.end of file LFLAGS vs CFLAGS We've seen the CFLAGS macro used before to define the flags used in relation to the compiler. but I'll mention it anyway.o: %.c $(CREATEOBJ) <--.o queue. build another macro at the top of the file: <--.o queue. COMPILEOBJ=$(CC) $(CFLAGS) $^ CREATEEXE=$(CC) $(LFLAGS) $@ $^ OBJS=main. But if you've noticed.o list.15 The OBJS macro This one is probably pretty obvious.end of file .in the file CC=gcc COMPILEOBJ=$(CC) -c $^ CREATEEXE=$(CC) -o $@ $^ OBJS=main. we use different flags to compile the object files than we do to link them together.o: %.
but if I haven't then below are a few websites which I used as references. 1.cs.edu/ug/make_help.html 3.16 Conclusion: So by now you should have a fair understanding of how a Makefile works.edu/class/spring2002/cmsc214/Tutorial/makefile.umd. http://www.hsrl. a websearch for "Makefile Tutorial" will turn up lots of helpful information. http://www.html . Also.rutgers.edu/maxwell/classes/tutorials/maketutor/ 2.swarthmore. http://palantir. I've tried to simplify things and give lots of examples while still giving you a lot to work with. I hope I've succeeded.
This action might not be possible to undo. Are you sure you want to continue?
We've moved you to where you read on your other device.
Get the full title to continue listening from where you left off, or restart the preview.