Calling subdir.mk from Makefile with multiple code directories - makefile

Below is the folder structure for my code.
This is a very small example to understand the concept of multiple makefiles based on which I have to create makefile for bigger code structure.
work
├── code
| |
| └── main.h and test.h files here
│ └── main.c and test.c files here
| └── subdir.mk
|
├── _Build/
│ └── Makefile here
I am keeping both Makefile and subdir.mk files to be very basic and simple to grasp the concept.
Below is the code for subdir.mk
#subdir.mk
#============================================
test.o : test.c test.h
#echo Building test.c ...
gcc -Werror -Wall -c test.c -o test.o
main.o : main.c main.h test.h
#echo Building main.c ...
gcc -Werror -Wall -c main.c -o main.o
#============================================
Below is the code for main file ... Makefile
#Makefile
#============================================
include ../code/subdir.mk
main : ../code/main.o ..code/test.o
#echo Building ...
make subdir.mk # <--- What is the correct way to perform this code
#echo Linking files ...
gcc -Llib ../code/main.o ../code/test.o -lm -o main
clean:
rm -rv ../code/*.o
#============================================
The error I am getting is
make: *** No rule to make target 'test.c', needed by 'test.o'. Stop.
In subdir.mk I am trying to generate object files.
In Makefile I am trying to link the object files generated in subdir.mk
The way I am trying to execute is correct way or some different steps are followed when we have multiple subdir.mk and main Makefile.
Share your valuable comments please.

You cannot both include the subdir.mk file and also invoke it recursively.
You need to decide whether you want to use non-recursive make (which means you'd use include) or recursive make (which means you'd run a sub-make command).
If you want to use non-recursive make then your subdir.mk makefile needs to be prepared to be run when the current working directory is different than the directory that the subdir.mk file appears in.
If you want to use recursive make then you need a separate rule to build the objects, and you should not include subdirs.mk. Something like this:
main : ../code/main.o ..code/test.o
#echo Linking files ...
gcc -Llib ../code/main.o ../code/test.o -lm -o main
../code/main.o ..code/test.o : subdir ;
subdir:
#echo Building ...
cd ../code && $(MAKE) -f subdir.mk
.PHONY: subdir
Be sure to include the semicolon after the subdir in the .o rule.
When invoking sub-makes you should always use the $(MAKE) variable, never use the literal string make.
You will probably be better off having your subdir.mk build a single library out of the objects rather than having to repeat all the object files in multiple places. Then replace the list of object files in this makefile with the library.
Contrary to Andreas's assertion, this will not always rebuild main. It will only be rebuilt when one of the object files was changed.

subdir.mk has to use paths relative to the main makefile. E.g.
../code/test.o : ../code/test.c ../code/test.h
...

What you need is a recipe for creating the object files. In Makefile you'll need to remove include ../code/subdir.mk and add something like this:
.PHONY: ../code/main.o ..code/test.o
../code/main.o ..code/test.o:
$(MAKE) -C ../code/ -f subdir.mk $(#F)
When you build target main, make sees you need the object files. Then make find the above recipe for creating the object files and so runs it.
Having them .PHONY is because the top Makefile can´t tell whether or not they´re up to date. Without it the object files would never be rebuilt. This has the unfortunate consequence that main will always be rebuilt, even if subdir.mk determines the object files were indeed up to date. The solution is either to have it all in a single make (can still split into files and include), or change to a build tool that can get it right.

Related

Makefile to generate a binary file for each source file

I have the following structure in my project.
/
src/
bin/
Makefile
In src directory there will be multiple src files (each has a main function). I need to write makefile such that when I run
make program1
It should search for program1.c in src folder and compile the executable as program1* in bin folder.
I have came across this question How can Makefile use separate directories for source code and binaries?
But, it seems that I need to manually enter all program names into PROG variable.
I just need to supply binary name with make and it should do the compilation for that respective src file?
Okay, after a bit of experimentation with my Makefile. I finally got the solution for my problem.
Current Build System
CC = gcc
CFLAGS = -g -Wall
SRC = ./src/
BIN = ./bin/
%: $(SRC)%.c
$(CC) $(CFLAGS) $< -o $(BIN)$#
.PHONY: clean
clean:
rm $(BIN)*

Makefile does not recognize pattern rule

I'm really struggling in understanding why the following makefile won't work:
all: buildFolders main.out
mv main.out build/
-echo "File compiled"
buildFolders:
mkdir -p build src
cp *.c src/
%.s: %.c
gcc -S $< -o $#
%.out: src/%.s
gcc $< -o $#
It is executed in a folder containing only the makefile and a main.c file. It should build the src and build folder, copy the main.c in the src folder and then start compiling the main.out. Unfortunately it throws the error "no rule to make target 'main.out'". Since I have the %.out that matches 'main.out' I don't see why it gives me that error. Instead it should look for the src/main.s file, create it and then use it to generate the main.out.
What am I doing wrong? Thanks
You have a number of problems.
First, listing prerequisites in order doesn't create a dependency relationship. If, for example, you ever wanted to enable parallel builds then this:
all: buildFolders main.out
doesn't force the buildFolders target to be built before main.out. These two targets both must be built before all but this doesn't tell make that there's any relationship between buildFolders and main.out. If buildFolders must be completed before main.out can be built then main.out must list buildFolders as a prerequisite.
Second, you haven't told make how to build a file src/main.c. It's built as a side-effect of the buildFolders target, but make can't know that. You need to explain to make that this file can exist. I recommend adding a rule:
src/%.c: %.c
mkdir -p src
cp $< $#
and removing the buildFolders target altogether.
However, I really question why you want to do this anyway. What's the point of copying the source files in the current directory to some sub-directory to build them? It's dangerous and confusing to have multiple copies of source files lying around because they can get out of sync with each other, then you're building older versions and you spend hours trying to understand why something doesn't work. It's a really bad idea.

Makefile is always not up to date even without any changes

I have a directory with two folders, src and bin with the makefile at root directory. This makefile keeps compiling (not up to date) even without changes. Am I missing something with this makefile?
all:
make a b
a: ./src/a.cpp
g++ -o ./bin/a ./src/a.cpp
b: ./src/b.cpp
g++ -o ./bin/b ./src/b.cpp
Your rules claim to create the files a and b, but they don't: They create bin/a and bin/b.
So when make checks your rules, it always finds that a and b don't exist and tries to create them by executing their associated commands.
Possible fix:
.PHONY: all
all: bin/a bin/b
bin/a: src/a.cpp
g++ -o bin/a src/a.cpp
bin/b: src/b.cpp
g++ -o bin/b src/b.cpp
On .PHONY: https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html#Phony-Targets

How to tell make to watch dependencies of a sub-make target?

I was investigating on the same question here, but I was not very clear of what I was asking, even for myself. Sorry for those who spent time answering my unclear question.
So let's try again with a more realistic example. We consider this structure:
.
├── Makefile
└── src/
├── bar
├── foo
└── Makefile
Where the main Makefile is:
all: src/foobar
src/foobar:
make -C $(dir $#)
And the sub-makefile is:
foobar: foo bar
join $^ > $#
If I run make for the first time (from ./) everything works as expected, foobar is produced.
$ make
make -C src/
make[1]: Entering directory '/project/src'
join foo bar > foobar
make[1]: Leaving directory '/project/src'
$ make
make: Nothing to be done for 'all'.
However if I touch any of the foobar dependencies. The parent Makefile will not regenerate the target. Here, I perfectly understand the behavior of Make, but I want to tell it to be aware of foobar' dependencies.
$ touch src/foo
$ make
make: Nothing to be done for 'all'.
My current solution which is not very neat is to ask for the dependencies. So the src/Makefile become:
src=foo bar
foobar: $(src)
#echo "Joining"
join $^ > $#
files: $(src)
#echo $^
And the ./Makefile:
all: src/foobar
src=$(addprefix src/,$(shell make --no-print-directory -C src files | tr '\n' ' '))
src/foobar: $(src)
make -C $(dir $#)
I must also say that this particular example could be simplified using a single Makefile only. My real example is quite more complex. The src/Makefile generate an executable while the parent Makefile do lots of other things (packing in a specific format, generate the documentation, build other sub-makefiles and so on). Thus, I want to keep these tasks well separated and I need to different Makefiles.
In the main Makefile create a dependency for the child target or directory that is always in need of building, and let the child Make then do the real work.
There is a good example here: http://owen.sj.ca.us/~rk/howto/slides/make/slides/makerecurs.html.
To translate for your case, change your main Makefile to be:
all: src/foobar
src/foobar: force
$(MAKE) $(MFLAGS) -C src
force:
true
I also added $(MFLAGS) which will pass same flags from parent to child make.

Recursive makefile for compiling my own library

I have an application directory with source code and within that same directory there is another directory with a library. I want to compile this using recursion. Here is the example:
I make a fictitious directory tree as:
> mkdir lib
> touch lib/src1.c
> touch lib/src2.c
Then in the main directory I create a main.c with the code
int main(){return 0;}
and a makefile with
all: test
main.o: lib/libsomelib.a
lib/libsomelib.a: lib
lib:
make --directory=$#
.PHONY: lib
test: main.o
cc -L./lib -lsomelib main.o -o $#
within lib I create a makefile with:
all: libsomelib.a
.PHONY: all
libsomelib.a: src1.o src2.o
ar rcs $# $^
Running make from the parent directory has the desired effect.
Now, if I remove say lib/src1.o:
rm lib/src1.o
and run make again, the makefile will run recursively into lib but since the dependency for the library is checked BEFORE the library is rebuilt, the main application is not updated.
I need to RERUN make to compile the executable.
How do I fix this?
Thank you in advance.
Simply change:
lib:
make --directory=$#
.PHONY: lib
test: main.o
cc -L./lib -lsomelib main.o -o $#
to:
lib/libsomelib.a:
make --directory=$#
test: main.o lib/libsomelib.a
cc -L./lib -lsomelib main.o -o $#
Note that, as Beta intimated, Recursive Make Considered Harmful, as it gets you thinking on a per-directory basis, rather than across the entire tree, cutting you off from the real power of make. If you get into the habit of writing heirarchical make files, you'll find that your build are not only faster, but more reliable (less need to 'make clean && make').

Resources