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.

+3


source to share


1 answer


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.

+5


source







All Articles