2009-12-19 10 views
14

Ho una directory "lib" nella directory principale delle mie applicazioni, che contiene un numero arbitrario di sottodirectory, ognuna con il proprio Makefile.fanno gli obiettivi delle sottodirectory dei caratteri jolly

Mi piacerebbe avere un singolo Makefile nella directory principale, che chiama il Makefile di ciascuna sottodirectory. So che questo è possibile se elencherò manualmente i sottodirectory, ma mi piacerebbe averlo fatto automaticamente.

Stavo pensando a qualcosa di simile al seguente, ma ovviamente non funziona. Nota che ho anche obiettivi puliti, test, ecc. Quindi probabilmente% non è affatto una buona idea.

LIBS=lib/* 

all: $(LIBS) 

%: 
    (cd [email protected]; $(MAKE)) 

Qualsiasi aiuto è apprezzato!

risposta

23

Di seguito lavorerà con GNU make:

LIBS=$(wildcard lib/*) 
all: $(LIBS) 
.PHONY: force 
$(LIBS): force 
    cd [email protected] && pwd 

se ci potrebbe essere qualcosa di diverso da directory in lib, si potrebbe in alternativa usare:

LIBS=$(shell find lib -type d) 

per affrontare la questione bersagli multipli, è puoi creare obiettivi speciali per ogni directory, quindi rimuovere il prefisso per la sottostruttura:

LIBS=$(wildcard lib/*) 
clean_LIBS=$(addprefix clean_,$(LIBS)) 
all: $(LIBS) 
clean: $(clean_LIBS) 
.PHONY: force 
$(LIBS): force 
    echo make -C [email protected] 
$(clean_LIBS): force 
    echo make -C $(patsubst clean_%,%,[email protected]) clean 
+0

Wow, Grazie. Funziona come un fascino! – Zed

+1

Perché non hai definito '$ (clean_LIBS)' come fasullo? Per esempio. '.PHONY: $ (LIBS) $ (clean_LIBS)', quindi penso che non sia necessario 'force'. –

+0

@dma_k: sei un punto eccellente. Non ho testato il tuo suggerimento, ma il tuo ragionamento mi sembra giusto. In effetti, suona molto simile a quello che suggerisce il manuale di GNU Make qui (vedi il bit su sottodirectory): http://www.gnu.org/software/make/manual/make.html#Phony-Targets – mrkj

2

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

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

una lista di tutte le sotto-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, l'obiettivo 'all' elenca tutti i sub-directory come prerequisiti. Per esempio, se LIB_DIRS conteneva lib/folder1 lib/folder2 quindi l'espansione sarebbe simile a questa:

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

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

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

Credo che 'tutto: DIRS_CMD' dovrebbe invece essere' tutto: $ DIRS_CMD' poiché l'iterazione corrente non espande correttamente il file. Stavo ottenendo qualcosa sulla falsariga di "make: *** Nessuna regola per rendere target" DIRS_CMD ", necessario per" tutti ". Stop. – jnt30

+0

È possibile. Penso che per me ha funzionato senza $ ma non ho le fonti e non posso verificare. – Amiramix

0

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 [email protected] 
.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)_%,%,[email protected]) $(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 utile quando si ha a che fare con il paralelismo: make -j12 pulisci tutto in un albero con makefile con questi obiettivi ... Come sempre: giocare con make è pericoloso, diversi meta-livelli di programmazione sono troppo vicini, -)