Peer Gynt
Peer Gynt

Reputation: 55

recursive make Q.: generic target *after* other targets?

I know that recursive make is deemed evil, etc. Please bear with me anyway.

We manage a relatively large project with GNU make, which heavily uses make includes to keep the individual make files simple. I'd like to add a target which gets executed after other targeted. More precisely, the problem is the following:

I have a Makefile like this:

 PROJ_SRC = a.cpp b.cpp
 PROJ_LIB = ab

 PROJ_SUBDIRS  = x/ y/ z/
 PROJ_EXAMPLES = example/

I would like to first call make in the subdirs x,y,z, then build the lib in PWD itself, and only then go into the 'example' subdir to build the examples using that lib.

Everything but the example bit is working fine, but I cannot wrap my head around a clean solution for that last bit. Here are the things I tried:

 # works ok for the target 'all', but nothing else
 all: subdirs ... $(PROJ_OBJ) $(PROJ_LIB_FULL) ... $(PROJ_EXAMPLES)

 # ugly, needs to be adde on all targets, and runs into examples 
 # repeatedly if multiple targets get invoked.
 full_lib:: $(PROJ_LIB_FULL)
 $(PROJ_LIB_FULL):: subdirs
   $(CXX) ...
 ifdef PROJ_EXAMPLES
   $(MAKE) -C $(PROJ_EXAMPLES)
 endif

 # this does not make sense, as it builds the lib even on 'make clean' etc
 $(PROJ_EXAMPLES):: full_lib

Any idea on how to generalize that?

PS.: sorry if the above snippets are not 100% clean syntax - they are just supposed to illustrate the problem...

Upvotes: 0

Views: 755

Answers (1)

Beta
Beta

Reputation: 99094

There is an advanced trick for "making" a directory, so that, for instance, you won't have to run Make unnecessarily in the subdirectories. But even without that you can get a pretty clean solution:

$(PROJ_LIB): $(PROJ_SUBDIRS)
  $(CXX) ...

$(PROJ_EXAMPLES): $(PROJ_LIB)
  $(MAKE) -C $@

.PHONY: clean
clean: TARG=clean
clean: $(PROJ_SUBDIRS)
  $(MAKE) -C $(PROJ_EXAMPLES) $@

.PHONY: $(PROJ_SUBDIRS)
$(PROJ_SUBDIRS):
  $(MAKE) -C $@ $(TARG)

And if you don't like that trick for avoiding building the library when cleaning, you could always have the example/ makedir be the one that calls for the building of the library. After all, that dependency really belongs to example.

EDIT:

If you're willing to let example/Makefile handle the lib dependency, that simplifies things. You can wrap up the recursive targets pretty neatly:

$(PROJ_LIB): $(PROJ_SUBDIRS)
  $(CXX) ...

RECURSIVES = clean distclean veryclean squeakyclean
.PHONY: $(RECURSIVES)

$(RECURSIVES): TARG=$@

ALL_SUBDIRS = $(PROJ_SUBDIRS) $(PROJ_EXAMPLES)

# Maybe you want them all to recurse into the same directories:
$(RECURSIVES): $(ALL_SUBDIRS)

#...or maybe not:
clean veryclean squeakyclean: $(ALL_SUBDIRS)
distclean: $(PROJ_EXAMPLES)

# This part does the recursion:
.PHONY: $(ALL_SUBDIRS)
$(ALL_SUBDIRS)
  $(MAKE) -C $@ $(TARG)

# And you still have to define the top-level rules:

clean:
  rm ...

# Maybe nothing to do at this level for distclean

veryclean:
  rm ... and ...

squeakyclean:
  rm *

Upvotes: 3

Related Questions