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.
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.
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.
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.
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. $%
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With