afiori
afiori

Reputation: 639

How to compile multiple simple projects with GNU make

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

Answers (2)

John Bollinger
John Bollinger

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

Ondrej K.
Ondrej K.

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

Related Questions