How to put .o and .exe files in / build / directory using makefile
I am struggling to find information on makefiles that are really entry-level. Even the question here , as asked, is presented using a load of symbols that I don't understand, for example $(CC) $(INC) $< $(CFLAGS) -o $(BIN)$@ $(LIBS)
. It throws me off.
My makefile looks like this:
cpptest: main.o
g++ -o cpptest main.o
main.o: main.cpp
g++ -c main.cpp
clean:
rm cpptest main.o
This is a complete limit to what I know how to do with makefiles. It works, but puts the main.o and cpptest.exe files in the root of the project.
I want to put the main.o file and the cpptest.exe file in the / build / directory. However, if I put ./build/
before every main.o and every cpptest, the object file appears in the root of the project, and the exe file does not appear at all.
I am building this thing using Sublime Text 3 on Windows, for what it's worth.
source to share
A slightly better solution would be this: Please note: I do 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/*
Okay, let's take a look at the first and second goals:
all: build/cpptest
.PHONY: all
I created a default target all
. This is a bogus target (it doesn't actually create a file named all
), so I marked it all
as bogus by making it dependent on .PHONY
. (this basically says not to ignore the rule all
if a new file with the name all
already exists). all
has no recipes, so it does nothing other than cause its dependencies to be created. This may sound a little confusing, 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 goal:
build:
@echo "building directory $@"
mkdir -p $@
For the first target, build, this is the name of the directory you are creating. build
is a goal, it has no dependencies and has two lines of recipes. The first line of the recipe starts with @
. This means that you do not print the recipe before running it. If you don't have that, your result will look like this:
echo "building directory build"
building directory build
Which is ugly. @
does this only at the beginning of a line. You will notice that later on the line you have $@
. This is different. It is a variable that expands to the target name ( build
in this case). It's a good habit to use this variable when needed, as it will simplify more complex makefiles later. The second target recipe build
creates a directory.
The fourth goal:
build/cpptest: build/main.o | build
@echo building $@
g++ -o $@ $^
That says it build/cpptest
depends on build/main.o
and build
(i.e. don't start building them until the other two are done). One big cavitator: pay attention to the character |
before build
. This makes it dependent on the order. This means that if the directory build
already exists and its timestamp is newer than build/cpptest
, then do not consider it build/cpptest
obsolete (do not rebuild it). On the other hand, another dependency build/main.o
is to the left of the symbol |
. This suggests that if build/main.o
does not exist, OR if it is NEWER than build/cpptest
, make make should rebuild build/cpptest
.
The reason we need |
(order dependency only) for build
is because the catalog date is updated every time you add a new file. Thus, build
it will always have a newer timestamp than build/cpptest
. This type falls under the extended makefile, but this is the correct way to do it, so I decided to show it here.
As @Felix pointed out, ordering is not available in all versions of make (GNU make does support it).
In the recipe, I used a variable $@
and a variable $^
. $^
represents all order dependent relationships (i.e., main.cpp
in this case). They are expanded before the rule is launched.
You can take a few more steps to make it really right (like defining a variable $(objs)
, etc.), which will make the makefile easier to handle in the future, but hopefully this will give you a good start.
source to share