Question

J'ai un répertoire « lib » dans mes applications de répertoire principal, qui contient un nombre arbitraire de sous-répertoires, chacun ayant sa propre Makefile.

Je voudrais avoir un Makefile dans le répertoire principal, qui appelle Makefile de chaque sous-répertoire. Je sais que cela est possible si je liste manuellement les subdirs, mais je voudrais l'avoir fait automatiquement.

Je pensais à quelque chose comme ce qui suit, mais il ne fonctionne évidemment pas. Notez que j'ai aussi propre, test, etc. cibles, donc% est probablement pas une bonne idée du tout.

LIBS=lib/*

all: $(LIBS)

%:
  (cd $@; $(MAKE))

Toute aide est appréciée!

Était-ce utile?

La solution

Ce qui suit travaillera avec GNU make:

LIBS=$(wildcard lib/*)
all: $(LIBS)
.PHONY: force
$(LIBS): force
  cd $@ && pwd

S'il pourrait y avoir autre chose que des répertoires dans lib, vous pourriez également utiliser:

LIBS=$(shell find lib -type d)

Pour répondre à la question des multiples objectifs, vous pouvez construire des cibles spécifiques pour chaque répertoire, puis dénuder le préfixe de la sous-construction:

LIBS=$(wildcard lib/*)
clean_LIBS=$(addprefix clean_,$(LIBS))
all: $(LIBS)
clean: $(clean_LIBS)
.PHONY: force
$(LIBS): force
  echo make -C $@
$(clean_LIBS): force
  echo make -C $(patsubst clean_%,%,$@) clean

Autres conseils

Il y a aussi une manière de lister les sous-répertoires avec gmake uniquement les commandes, sans utiliser de commandes shell:

test:
  @echo $(filter %/, $(wildcard lib/*/))

Cette liste tous les sous-répertoires avec '/' arrière. Pour le supprimer, vous pouvez utiliser le modèle de substitution:

subdirs = $(filter %/, $(wildcard lib/*/))
test:
  @echo $(subdirs:%/=%)

Ensuite, pour créer effectivement des règles d'exécution makefiles dans chaque sous-répertoire, vous pouvez utiliser une petite astuce - une cible dans un répertoire phony inexistant. Je pense que dans ce cas un exemple racontera plus que toute explication:

FULL_DIRS =$(filter %/, $(wildcard lib/*/))
LIB_DIRS  =$(FULL_DIRS:%/=%)
DIRS_CMD  =$(foreach subdir, $(LIB_DIRS), make-rule/$(subdir))

make-rule/%:
  cd $* && $(MAKE)

all: DIRS_CMD

En fait, les listes de cibles 'all' tous les sous-répertoires comme conditions préalables. Par exemple, si LIB_DIRS contenait lib/folder1 lib/folder2 alors l'expansion ressemblerait à ceci:

all: make-rule/lib/folder1 make-rule/lib/folder2

Alors « faire », afin d'exécuter la règle 'all', tente de faire correspondre chaque condition sine qua non à une cible existante. Dans ce cas, la cible est 'make-rule/%:', qui utilise '$*' pour extraire la chaîne après 'make-rule/' et l'utilise comme argument dans la recette. Par exemple, serait adapté la première condition sine qua non et développé comme ceci:

make-rule/lib/folder1:
  cd lib/folder1 && $(MAKE)

Que faire si vous voulez appeler différentes cibles que tous dans un nombre inconnu de sous-répertoires?

Le Makefile suivant utilise des macros créent donc une cible fictive pour transmettre un certain nombre de sous-répertoires pour appliquer la cible donnée à partir de la ligne de commande pour chacun d'eux:

# all direct directories of this dir. uses "-printf" to get rid of the "./"
DIRS=$(shell find . -maxdepth 1 -mindepth 1 -type d -not -name ".*" -printf '%P\n')
# "all" target is there by default, same logic as via the macro
all: $(DIRS)

$(DIRS):
    $(MAKE) -C $@
.PHONY: $(DIRS)

# if explcit targets where given: use them in the macro down below. each target will be delivered to each subdirectory contained in $(DIRS).
EXTRA_TARGETS=$(MAKECMDGOALS)

define RECURSIVE_MAKE_WITH_TARGET
# create new variable, with the name of the target as prefix. it holds all
# subdirectories with the target as suffix
$(1)_DIRS=$$(addprefix $(1)_,$$(DIRS))

# create new target with the variable holding all the subdirectories+suffix as
# prerequisite
$(1): $$($1_DIRS)

# use list to create target to fullfill prerequisite. the rule is to call
# recursive make into the subdir with the target
$$($(1)_DIRS):
      $$(MAKE) -C $$(patsubst $(1)_%,%,$$@) $(1)

# and make all targets .PHONY
.PHONY: $$($(1)_DIRS)
endef

# evaluate the macro for all given list of targets
$(foreach t,$(EXTRA_TARGETS),$(eval $(call RECURSIVE_MAKE_WITH_TARGET,$(t))))

Espérons que cela aide. Vraiment serviable quand traiter paralelism: faire -j12 nettoyer le tout dans un arbre avec makefiles ayant ces objectifs ... Comme toujours: jouer avec make est dangereux, différentes méta-niveaux de programmation sont trop rapprochées, -)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top