Domanda

Ho una directory "lib" nelle mie applicazioni directory principale, che contiene un numero arbitrario di sottodirectory, ciascuna con un proprio Makefile.

Mi piacerebbe avere un unico Makefile nella directory principale, che chiama Makefile di ogni sottodirectory. So che questo è possibile se vi elenco manualmente le sottocartelle, ma vorrei averlo fatto automaticamente.

Stavo pensando a qualcosa di simile a quanto segue, ma ovviamente non funziona. Si noti che ho anche pulito, di prova, ecc obiettivi, quindi% non è probabilmente una buona idea a tutti.

LIBS=lib/*

all: $(LIBS)

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

Ogni aiuto è apprezzato!

È stato utile?

Soluzione

Di seguito lavorerà con GNU make:

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

Se ci potrebbe essere qualcosa di diverso da directory in lib, si potrebbe in alternativa utilizzare:

LIBS=$(shell find lib -type d)

Per risolvere il problema bersagli multipli, è possibile costruire gli obiettivi speciali per ogni directory, quindi togliere il prefisso per il sub-build:

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

Altri suggerimenti

V'è anche un modo di elencare sotto-directory con i comandi solo gmake, senza l'uso di comandi di shell:

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

Questo elencherà tutti i sub-directory con trailing '/'. Per rimuoverlo è possibile utilizzare il modello sostitutivo:

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

Poi per creare effettivamente le regole esecuzione makefile in ogni sotto-directory è possibile utilizzare un piccolo trucco - un obiettivo fasullo in una directory inesistente. Penso che in questo caso un esempio dirà più di ogni spiegazione:

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

In sostanza, bersaglio 'all' elenca tutti i sub-directory come prerequisiti. Per esempio, se LIB_DIRS lib/folder1 lib/folder2 conteneva allora l'espansione sarebbe simile a questa:

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

Poi 'fare', al fine di eseguire regola 'all', cerca di abbinare ogni prerequisito con un target esistente. In questo caso l'obiettivo è 'make-rule/%:', che utilizza '$*' estrarre la stringa dopo 'make-rule/' e lo utilizza come argomento nella ricetta. Ad esempio, il primo requisito sarebbe abbinato e ampliato così:

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

Che cosa succede se si desidera chiamare obiettivi diversi rispetto a tutto in un numero imprecisato di sottodirectory?

Il seguente Makefile utilizza le macro in modo da creare un inoltro manichino-bersaglio per un numero di sottodirectory di applicare la data di destinazione dalla riga di comando per ciascuno di essi:

# 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))))

Spero che questo aiuti. Davvero disponibile quando si tratta di paralelism: fare -j12 pulire tutto in un albero con makefiles avere questi obiettivi ... Come sempre: giocare con make è pericoloso, diversi meta-livelli di programmazione sono troppo vicini tra loro, -)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top