280 likes | 395 Views
make: the good, the bad, and the ugly. Dan Berger dberger@cs.ucr.edu Titus Winters titus@cs.ucr.edu. Outline. What is make, and why do you care? Key concepts makefiles, targets, directives & variables. A simple makefile Implicit variables A better makefile Words of caution.
E N D
make: the good, the bad, and the ugly Dan Berger dberger@cs.ucr.edu Titus Winters titus@cs.ucr.edu
Outline • What is make, and why do you care? • Key concepts • makefiles, targets, directives & variables. • A simple makefile • Implicit variables • A better makefile • Words of caution
What is Make? • “The ‘make’ utility automatically determines which pieces of a large program need to be recompiled, and issues commands to recompile them.” -- The GNU Make Manual
Why Do I Care? • Let’s say I have a program with only one source file – simple.cc. • Creating the program is easy: • g++ <flags> simple.cc –o simple • What if I have 10 source files? • g++ <flags> s1.cc … s10.cc –o simple • If I change two of them?
Incremental Compilation • If I know which two I’ve changed, I can recompile them (into objects) and re-link the executable. • Figuring out the minimum number of steps that must be performed is what make is good at.
How Does Make Work? • You tell make what files your program depends on – some that you provide (the source) and some that the compiler provides (objects). • You tell make how to run the compiler, and finally how to assemble all those files into the program. • When things change, make decides what commands need to be run to bring your program up to date.
For the Technically Minded • Make constructs a dependency graph: • what targets depend on what other targets • how do I construct a given target • When you invoke Make for a specific target, it visits the graph, performing the needed commands to produce the thing you asked for.
It’s not Just for Programs Anymore • Make isn’t just good for compiling programs – it’s good for figuring out what commands to run to perform some task. • Time permitting, we’ll give non-programming examples of make later.
Key Concepts: Makefile • Make needs instructions on how to decide what to do – by convention, these instructions are stored in a file called “Makefile”. • It’s just a convention – the –f flag to make will tell it to look at a specific file for it’s instructions. • Makefiles (regardless of their filename) have a specific format…
Basic Makefile Format # comment line variable-name = value target: dependencies <TAB>directive • The <TAB> is critical – it can’t be spaces, it must be a tab. Emacs has a makefile mode and will warn you if it finds an obvious error.
Make Targets • The first part of a rule – the thing make is trying to make. • Generally (but not always) a file – a .o, for example. • Targets have a (possibly empty) list of dependencies – other targets that this target depends on.
Directives • The final part of a rule – tells make what command(s) to run to create this target. • Generally the compiler for whatever language you’re working in.
Variables • If you don’t know what a variable is, time to review CS5/10. • Make variables look a lot like variables in SH. • Assignment: VARNAME=Value • Reference: ${VARNAME}, or $(VARNAME)
Makefile.ex1 # three rules to build simple all: simple simple: simple.o <TAB>g++ -W –w –Wall –Werror –pedantic \ -o simple simple.o simple.o: simple.cc <TAB>g++ -W –w –Wall –Werror –pedantic \ -c -o simple.o simple.cc
Makefile.ex2 CPPFLAGS=-W –w –Wall –Werror –pedantic CXX=g++ all: simple simple: simple.o <TAB>${CXX} –o simple simple.o simple.o: simple.cc <TAB>${CXX} ${CPPFLAGS} –o simple.o –c \ simple.cc
Implicit Rules & Their Variables • Make has a slew of implicit rules – for example, it “knows” how to turn a .cc file into a .o file without you telling it. • To make these implicit rules flexible, make uses a range of built-in variable names in them. • If you assign to these variables, make will insert those values into the rules.
Some Built In Variables • CC – the C compiler • CFLAGS – flags for the C compiler • CXX – the C++ compiler • CPPFLAGS – any guesses? • LD – the linker • LDFLAGS – let’s not see the same hands…
Makefile.ex3 CPPFLAGS=-W –w –Wall –Werror –pedantic all: simple
Having Make Figure Out Dependencies • Makefile.ex3 only works for single file projects. • Real projects have more than one file, and those files have to be built in a specific order. • Make (with some help from the compiler) can figure out that order for you.
Makefile.ex4 CC=${CXX} SOURCE = simple.cc .depend:${SOURCE} <TAB>@set –e; $(CC) –MM ${CPPFLAGS} \ ${SOURCE} | \ sed ‘s/\($*\)\.o[ :]*/\1.o : /g’ \ > .depend; [ -s $@ ] || rm –f $@ -include .depend
Say What? • If you really want to know how/why it works – I encourage you to go figure it out. • Read the make manual • Read the sed man page • See if you can figure out what’s going on.
Having Make Find The Source • Thanks to some nifty tricks built into (gnu) make – you often don’t even need to tell make what the source files are. • You might think you could do: • SOURCE = *.cc • But that’s not what you want. What you want: • SOURCE := $(wildcard *.cc)
Why Not SOURCE=*.cc? • The trouble with saying • SOURCE = *.cc • Is that make doesn’t evaluate that wildcard during variable assignment, it will expand it when the variable is used in a target or command. • SOURCE := $(wildcard *.cc)
Two Forms of = ?? • There are two different assignment operators in Make: • = is a “deferred” assignment – it’s evaluated when make is actually running commands. • := is an “immediate” assignment – it’s evaluated when make is reading makefiles and deciding what to do. • the distinction is subtle, and can be confusing.
Next Step: Figuring out the Objects • Wouldn’t it be nice if we could tell make – “the list of objects is the list of source files, but replace .cc with .o” ? • We can, like this: OBJS := $(patsubst %.cc,%.o,$(wildcard *.cc)) • Or this: OBJS = $(SOURCE:.cc=.o)
So What Do We End Up With? CC=${CXX} CPPFLAGS=-w –W –Wall –Werror –pedantic CPPFLAGS += -g LDFLAGS = SOURCE := $(wildcard *.cc) OBJS := $(patsubst %.cc,%.o,$(wildcard *.cc)) TARGET = simple all : ${TARGET} ${TARGET}: ${OBJS} .depend…
So What’s Not To Love? • Makefile syntax is ugly – especially the fact that TABs have to be TABs. • While make has been ported to many operating systems, it’s easy to write Makefiles that aren’t portable. • That sed trick, for example, won’t work on Windows. • Many have tried to “fix” make – few of those efforts have survived.
Learning More • % info make • google for “make tutorial”