Pregunta

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

Me gustaría tener una sola Makefile en el directorio principal, que llama a Makefile de cada subdirectorio. Sé que esto es posible si enumero manualmente los subdirectorios, pero me gustaría tener que hacer de forma automática.

Yo estaba pensando en algo como lo siguiente, pero, obviamente, no funciona. Tenga en cuenta que también tengo limpio, ensayo, etc. objetivos, así% no es probablemente una buena idea en absoluto.

LIBS=lib/*

all: $(LIBS)

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

Cualquier ayuda se agradece!

¿Fue útil?

Solución

A continuación se trabajará con make GNU:

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

Si puede haber algo distinto de directorios en lib, usted podría utilizar alternativamente:

LIBS=$(shell find lib -type d)

Para abordar la cuestión múltiples objetivos, se puede construir objetivos especiales para cada directorio, y luego quitarse el prefijo para la sub-estructura:

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

Otros consejos

También hay un modo de lista de subdirectorios con comandos gmake solamente, sin necesidad de utilizar ningún comando shell:

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

Esto mostrará 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, las listas de destino 'all' todos los subdirectorios como requisitos previos. Por ejemplo, si LIB_DIRS contenía lib/folder1 lib/folder2 continuación, la expansión se vería así:

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

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

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

¿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 muñeco-diana reenvío de 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 $@
.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))))

Espero que esto ayude. Muy servicial cuando se trata de paralelismo: hacer -j12 limpiar todo en un árbol con los archivos make tener estos objetivos ... Como siempre: jugar con el maquillaje es peligroso, diferentes meta-niveles de programación están demasiado juntos, -)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top