Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Makefiles in multiple directories

Tags:

makefile

I want to build an app and I have multiple modules stored in multiple directories. I've decided to follow this idea, i.e. to have a makefile in each directory and then to merge it. But - as a beginner programmer - I still do not see how to do that. First of all, how would such "partial" makefiles look like. They cannot have main function as there can be only one per binary, though when I try to compile it gcc complains for the undefined reference to main. Secondly, I have no idea how would putting all those modules together look like.

I would appreciate any help, but please try to keep your answers simple. Makefiles are still a bit of black magic to me.

like image 468
yauser Avatar asked Oct 17 '12 22:10

yauser


People also ask

Can you have multiple makefiles?

If you use more than one ' -f ' or ' --file ' option, you can specify several makefiles. All the makefiles are effectively concatenated in the order specified.

Do people still use makefiles?

Makefiles are not obsolete, in the same way that text files are not obsolete. Storing all data in plain text is not always the right way of doing things, but if all you want is a Todo List then a plain text file is fine.

Where do you put makefiles?

some projects put their makefile in src/ subdirectory of the root directories of the projects, some projects put their makefiles in the root directory of the project.

What does $@ mean in makefiles?

The file name of the target of the rule. If the target is an archive member, then ' $@ ' is the name of the archive file. In a pattern rule that has multiple targets (see Introduction to Pattern Rules), ' $@ ' is the name of whichever target caused the rule's recipe to be run. $%


1 Answers

Before you can do anything with a makefile, you must know how to do it without a makefile.

Since you are using gcc, I will assume that your source code is C++.

You haven't told us what your directory structure looks like, so I'll suppose that you have three source files in two directories: primary/main.cc, other/foo.cc and other/bar.cc. (We can deal with header files like foo.h later.) And you want to build myApp.

STEP 1: Doing It By Hand

To do this in one command, you might use:

gcc -Wall primary/main.cc other/foo.cc other/bar.cc -o myApp

This will compile the three source files and link the binary objects together into the executable myApp.

STEP 2: Doing It In Pieces (Do not attempt this until you can get the previous step to work perfectly.)

Instead of building with one command, you could take an intermediate step, compiling the source files into binary object files:

gcc -Wall -c primary/main.cc -o primary/main.o
gcc -Wall -c other/foo.cc -o other/foo.o
gcc -Wall -c other/bar.cc -o other/bar.o

This will produce alpha/main.o, beta/foo.o and beta/bar.o. The compiler won't complain about foo and bar lacking a main() function, because an object file doesn't need one. Then link the objects together into an executable:

gcc -Wall primary/main.o other/foo.o other/bar.o -o myApp

STEP 3: Doing It Locally (Do not attempt this until you can get the previous step to work perfectly.)

Just like the previous step, but we act in primary/ and other/:

cd primary
gcc -Wall -c main.cc -o main.o
cd ../other
gcc -Wall -c foo.cc -o foo.o
gcc -Wall -c bar.cc -o bar.o
cd ..
gcc -Wall primary/main.o other/foo.o other/bar.o -o myApp

STEP 4: Using a Makefile (Do not attempt this until you can get the previous step to work perfectly.)

We could have a makefile perform STEP 1, but that isn't really necessary. Write a makefile in primary (i.e. primary/makefile) like this:

main.o:
    gcc -Wall -c main.cc -o main.o

(That whitespace in fromt of gcc... is a TAB.)

Now try this:

cd primary
make
cd ../other
gcc -Wall -c foo.cc -o foo.o
gcc -Wall -c bar.cc -o bar.o
cd ..
gcc -Wall primary/main.o other/foo.o other/bar.o -o myApp

STEP 5: Using Several Makefiles (Do not attempt this until you can get the previous step to work perfectly.)

Write a other/makefile:

both: foo.o bar.o

foo.o:
    gcc -Wall -c foo.cc -o foo.o

bar.o:
    gcc -Wall -c bar.cc -o bar.o

and a makefile in the top directory, where you're building myApp:

myApp:
    gcc -Wall primary/main.o other/foo.o other/bar.o -o myApp

Now try this:

cd primary
make
cd ../other
make
cd ..
make

STEP 6: Using One Makefile That Calls Others (Do not attempt this until you can get the previous step to work perfectly.)

Edit the top makefile:

myApp:
    cd primary; make
    cd other; make
    gcc -Wall primary/main.o other/foo.o other/bar.o -o myApp

Now try:

make

If all of this works, what you have is a crude but effective makefile system. There are many refinements possible, when you're ready to take the training wheels off.

EDIT:

If there are many source files in a subdirectory (e.g. other/) and you don't want to maintain a list in the top makefile by hand, there are several ways to handle it. This is one:

OTHER_SOURCES := $(wildcard other/*.cc)

OTHER_OBJECTS := $(OTHER_SOURCES:.cc=.o)

myApp:
    cd primary; make
    cd other; make
    gcc -Wall primary/main.o $(OTHER_OBJECTS) -o myApp

But you should get these makefiles working and understand them, before you try any more streamlining.

like image 150
Beta Avatar answered Nov 08 '22 21:11

Beta