Reputation: 639
I am trying to implement various project from a programming book. My intention was to have each project exercise in its own folder and then have a makefile that compiles all of them with something like a make all
. The folder structure is like this:
.
├── Makefile
├── bin
│ ├── prog1
│ ├── prog2
│ └── prog3
└── src
├── prog1
│ ├── Makefile
│ └── main.c
├── prog2
│ ├── Makefile
│ └── main.c
└── prog3
├── Makefile
└── main.c
I would like to learn how to set up such a structure. In particular the part where the top makefile visit all folders in src
calls make
there, and then copies and renames the executable into the bin
folders.
Upvotes: 0
Views: 959
Reputation: 181714
Your layout schematic shows a makefile for each exercise, plus the top-level makefile that you seem actually to be asking about. It would be best for the top-level makefile to avoid duplicating the behavior of the per-exercise makefiles, as such duplication would create an additional maintenance burden for you. Additionally, it is likely that you will eventually progress to exercises involving multiple source files, and perhaps to some that have multiple artifacts to be built. This is all the more reason for each per-exercise makefile to contain everything necessary to build the exercise with which it is associated (into the exercise-specific directory), and for the top-level makefile to depend on those.
Following that scheme would leave a well-defined role for the top-level makefile: to perform the per-exercise builds (by recursively running make
), and to copy the resulting binaries to bin/
. This is not the only way to set up a system of cooperating makefiles, but it is fairly easy, and that will allow you to focus on the exercises instead of on the build system.
Let us suppose, then, that each individual exercise can be built by changing to its directory and running make
, with the result being an executable in the same directory, with the same name as the directory. That is, from the top-level directory, executing cd src/prog2; make
would produce the wanted executable as src/prog2/prog2
. In that case, the top-level makefile needs little more than the names of all the exercises, and a couple of rules:
EXERCISES = prog1 prog2 prog3
BINARIES = $(EXERCISES:%=bin/%)
all: $(BINARIES)
$(BINARIES):
make -C src/$$(basename $@)
cp src/$$(basename $@)/$$(basename $@) $@
Note: that uses a feature specific to GNU's implementation of make
to compute the names of the wanted binaries from the exercise names. I take that to be acceptable, since you tagged [gnu-make], but in any case, it is a convenience feature, not a necessity.
Upvotes: 1
Reputation: 9679
There are different ways to tackle this, but something like this should work for your example:
PROGS := bin/prog1 bin/prog2 bin/prog3
all: $(PROGS)
$(PROGS):
$(MAKE) -C src/$(@F)
mkdir -p $(@D)
cp src/$(@F)/main $@
.PHONY: clean
clean:
rm -f $(PROGS)
for t in $(PROGS); do make -C src/`basename $$t` clean; done
We define a list of targets (PROGS
) we are to build. We say these targets are prerequisites of all
and then we go ahead and define how they should be built, that is: we recursively descent into src/
plus filename part of the target to run make there. We create directory of the target to be sure it's there and copy main
from the directory we've descended to the path of the target.
For a good measure, there is a clean
target as well that removes all the PROGS
and runs make clean
recursively in src/
.
Upvotes: 0