A slightly better solution would be as follows: Notice, I'm doing a couple of funky things, but I'll explain along the way
all: build/cpptest
.PHONY: all
build:
@echo "building directory $@"
mkdir -p $@
build/cpptest: build/main.o | build
@echo building $@
g++ -o $@ $^
build/main.o: main.cpp | build
@echo building $@
g++ -o $@ -c $^
clean:
@echo cleaning...
rm -f build/*
Ok, lets look at the first and second targets:
all: build/cpptest
.PHONY: all
I created a default target called all
. This is a dummy target (it doesn't actually build a file called all
), so I marked all
as phony by making it a dependency on .PHONY
. (this basically tells make not to ignore the all
rule, if a new file called all
already exists). all
has no recipes, therefore it doesn't do anything except cause its dependencies to be created. This might seem a bit convoluted, but it is standard practice in makefiles, as it gives you the freedom to organize the rules below in any order you find useful.
Third target:
build:
@echo "building directory $@"
mkdir -p $@
For the first target, build, this is the name of the directory you are creating. build
is the target, it has no dependencies, and has two recipe lines. The first recipe line starts with a @
. This just means don't print the recipe before you run it. If you didn't have this your output would look like:
echo "building directory build"
building directory build
Which is ugly. The @
only does that if it's at the start of the line. You'll notice that later on the line you have $@
. This is different. It is a variable that expands to the name of the target (build
in this case). It's a good habit to get into using this variable when appropriate, as it will simplify more complicated makefiles later on. The second recipe of the build
target creates the directory.
Fourth target:
build/cpptest: build/main.o | build
@echo building $@
g++ -o $@ $^
This says build/cpptest
is dependent on build/main.o
and build
(i.e., don't start building these until the other two are done). One big caviate: notice the |
symbol before build
. This makes it an order-only dependency. This means that if build
directory already exists, and its timestamp is newer than build/cpptest
, then don't consider build/cpptest
to be out-of-date (don't rebuild it). On the other hand, the other dependency, build/main.o
is to the left of the |
symbol. This tells make that if build/main.o
doesn't exist, OR if it is NEWER than build/cpptest
, then make should rebuild build/cpptest
.
The reason that we need the |
(order only dependency) for build
is that the directory's date is updated each time you add a new file. Thus, build
will always have a newer timestamp than build/cpptest
. This sort of falls under advanced makefile stuff, but it is the proper way to do it, so I thought I'd show it here.
As @Felix pointed out, order-only is not available in all versions of make (GNU make does support it though).
For the recipe, I used the $@
variable and the $^
variable. $^
represents all the non-order-only dependencies (i.e. main.cpp
in this case). These are expanded before the rule is run.
You can go a few steps further to make this truly proper (define an $(objs)
variable for example, etc), which makes the makefile easier to maintain in the future, but this hopefully will give you a good start.