2009-12-19 15 views
14

Tengo un directorio "lib" en mi directorio principal de aplicaciones, que contiene un número arbitrario de subdirectorios, cada uno con su propio Makefile.make wildcard subdirectory targets

Me gustaría tener un único Makefile en el directorio principal, que llame al Makefile de cada subdirectorio. Sé que esto es posible si lista manualmente los subdires, pero me gustaría que se haga automáticamente.

Estaba pensando en algo como lo siguiente, pero obviamente no funciona. Tenga en cuenta que también tengo objetivos limpios, de prueba, etc., por lo que% probablemente no sea una buena idea.

LIBS=lib/* 

all: $(LIBS) 

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

¡Se agradece cualquier ayuda!

Respuesta

23

El siguiente trabajo con GNU make:

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

si podría haber algo distinto de directorios en lib, se puede utilizar como alternativa:

LIBS=$(shell find lib -type d) 

Para abordar la cuestión múltiples objetivos, se puede crear objetivos especiales para cada directorio, luego quitar el prefijo para la subconstrucción:

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, Gracias. ¡Funciona de maravilla! – Zed

+1

¿Por qué no ha definido '$ (clean_LIBS)' como falso? P.ej. '.PHONY: $ (LIBS) $ (clean_LIBS)', entonces creo que no necesitas 'force'. –

+0

@dma_k: Usted hace un excelente punto. No he probado tu sugerencia, pero tu razonamiento suena bien para mí. De hecho, suena muy parecido a lo que sugiere el manual de GNU Make aquí (vea el bit en subdirectorios): http://www.gnu.org/software/make/manual/make.html#Phony-Targets – mrkj

2

También hay un modo de lista subdirectorios con gmake comandos solo, sin el uso de comandos de la shell:

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

Esto listará todos los subdirectorios con arrastrarse '/'. Para quitarlo puede utilizar el patrón sustituto:

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

A continuación, para realmente crear reglas de ejecución makefiles en cada subdirectorio puede utilizar un pequeño truco - un objetivo falso en un directorio que no existe. Creo que en este caso un ejemplo le dirá más que cualquier explicación:

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 

Básicamente, el objetivo 'all' listas de todos los subdirectorios como requisitos previos. Por ejemplo, si LIB_DIRS contenían lib/folder1 lib/folder2 continuación, la expansión se vería así:

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

Entonces 'make', con el fin de ejecutar la regla 'all', intenta hacer coincidir cada requisito con un objetivo existente. En este caso, el objetivo es 'make-rule/%:', que usa '$*' para extraer la cadena después de 'make-rule/' y la usa como argumento en la receta. Por ejemplo, el primer requisito se igualó y se expandió como esto:

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

Creo que el 'all: DIRS_CMD' debería ser' all: $ DIRS_CMD' ya que la iteración actual no expande correctamente el. Estaba obteniendo algo parecido a 'make: *** No rule to make target 'DIRS_CMD', necesario para 'all'. Detener. – jnt30

+0

Es posible. Creo que funcionó sin $ pero no tengo las fuentes y no puedo verificar. – Amiramix

0

¿Qué pasa si desea llamar a diferentes objetivos que todos en un número desconocido de subdirectorios?

La siguiente Makefile utiliza macros para crear un desvío de maniquí-objetivo para un número de subdirectorios para aplicar el objetivo dado desde la línea de comandos para cada uno de ellos:

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

Espero que esto ayude.Realmente útil cuando se trata de paralelismo: make -j12 limpia todo en un árbol con makefiles que tienen estos objetivos ... Como siempre: jugar con make es peligroso, los diferentes meta-niveles de programación están muy juntos, -)