Make multiple targets for all subdirectories - makefile

My directory structure is the following (of course the src/ subdirectories also contain files, but these are not important right now):
examples/
├───testprog1/
│ ├───bin/
│ ├───obj/
│ ├───src/
│ └───Makefile
├───testprog2/
│ ├───bin/
│ ├───obj/
│ ├───src/
│ └───Makefile
└───Makefile
The Makefile's in testprog1/ and testprog2/ look similar to this one:
OBJECTS_FILES=$(subst .cpp,.o,$(subst src/,obj/,$(wildcard src/*.cpp)))
bin/testprog1.exe: $(OBJECTS_FILES)
g++ -o $# $^
obj/%.o: src/%.cpp
g++ -c -o $# $^
clean:
rm -f obj/*.o
rm -f bin/meanTest.exe
They work perfectly fine alone, but if I want to build all examples at once, it would be better to use the Makefile in examples/ for that. What should it look like? Of course, it has to have the targets all and clean it will execute for all subdirectories. I also would like to avoid for-loops because I heard that they prevent make from using parallel processing.

You can make a recipe run in the background by appending an & to the end, which would allow you to build in parallel, but that's messy as your target could complete before the background tasks have finished running, which could cause dependency issues, so we'll steer clear of that.
A better solution would be to create a new rule for each subdir:
.PHONY: testprog1 testprog2
testprog1 testprog2:
$(MAKE) -C $# $(MAKECMDGOALS)
all clean: testprog1 testprog2
If you do a make clean, then $(MAKECMDGOALS) will be clean. It will build both testprog1 and testprog2 with this target. Notice that because testprog1 and testprog2 are directory names, you have to declare them as phonies, as their timestamp will change when you build them.
You could also specify the target as %: testprog1 testprog2 if you wanted any command (save testprog1 or testprog2) to be passed down to the submakes.

Related

Make targets using % are not working as in "Nothing to be done"

I'm trying to compile all my apps from the cmd folder but somehow this makefile is not working.
GO_BUILD_FLAGS =
APPS = my-app another-app stuff
define BUILD_BINARY =
#echo go build $(GO_BUILD_FLAGS) -o $# ./$<
go build $(GO_BUILD_FLAGS) -o $# ./$<
endef
FORCE: ;
bin/%: cmd/% FORCE
$(BUILD_BINARY)
build: $(addprefix bin/,$(APPS))
I'm continously facing following output, no matter I try.
$ make build
make: Nothing to be done for `build'.
$ make bin/my-app
make: Nothing to be done for `bin/my-app'.
$ make bin/another-app
make: Nothing to be done for `bin/another-app'.
$ make bin/stuff
make: Nothing to be done for `bin/stuff'.
Despite FORCE the bin/ targets are not executed. What am I missing?
Running this on MacOS using GNU Make 3.81.
This is how my folder looks like:
$ tree cmd
cmd
├── another-app
│ └── main.go
├── my-app
│ └── main.go
└── stuff
└── main.go
3 directories, 3 files
when running make with -d I get following:
https://pastebin.com/wh6TWxj9 (didn't fit in body as it has a 30000 char limit)
Eventually I found the issue. However I do not understand yet why the define doesn't work.
In the end I just removed:
define BUILD_BINARY =
#echo go build $(GO_BUILD_FLAGS) -o $# ./$<
go build $(GO_BUILD_FLAGS) -o $# ./$<
endef
and replaced the original bin target
bin/%: cmd/% FORCE
$(BUILD_BINARY)
with
bin/%: cmd/% FORCE
go build $(GO_BUILD_FLAGS) -o $# ./$<
Then it starts working.

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.

Calling subdir.mk from Makefile with multiple code directories

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.

How to use make's --jobs with subdirs?

Build time of my C++ project is very big. It consists of a bunch of subprojects (libraries), structured in file system folders. I want to speed up it with parallel build with --jobs (-j) parameter of make. What is the correct way of doing it? Documentation says that there are some tricks of doing parallel build with subdirs.
Makefile in root directory looks like:
...
all:
$(MAKE) -C DirA
$(MAKE) -C DirB
...
Makefile in DirA:
all:
$(MAKE) -C SubDirA
$(MAKE) -C SubDirB
$(MAKE) -C SubDirC
In DirB:
all:
$(MAKE) -C SubDirD
$(MAKE) -C SubDirE
$(MAKE) -C SubDirF
And so on. Makefiles in leaf folders are quite simple, contain only build instruction without any tricks.
You can just add -j to make using these makefiles as-is and you'll get some parallelism, but you won't get maximum parallelism. The problem is that make only parallelizes targets: clearly it won't work (in general) to run multiple commands in the same target in parallel!
So, in the top level make will run $(MAKE) -C DirA then $(MAKE) -C DirB, serially. When make builds DirA, it will first run $(MAKE) -C SubDirA, then $(MAKE) -C SubDirB, etc. serially. Then finally when make gets into SubDirA, it will build the targets there in parallel. This is fine, and maybe what you need to do if the order of building directories is important, except that there will be times when make could start working on SubDirB targets but won't, until all targets in SubDirA are complete.
A better way to handle subdirectories is to use make rules:
SUBDIRS := DirA DirB
all: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $#
.PHONY: $(SUBDIRS)
and ditto for the subdirectories. Note you must include the .PHONY.
Since each directory is a separate target, now make can invoke them in parallel if you use -j.
Oh, and if some of the contents of some subdirectories depends on others, you can declare that dependency explicitly in the makefile so make know about it:
SUBDIRS := SubDirA SubDirB SubDirC SubDirD
all: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $#
.PHONY: $(SUBDIRS)
SubDirA: SubDirD
etc.

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.

Resources