2011-04-13 11 views
5

Me gustaría hacer un Makefile que funciona ya sea con gnumake o makepp que los paquetes de todos los archivos bajo directiories dadas:Makefile: dependa de todos los archivos de un directorio

DIRS:=$(shell find . -mindepth 2 -maxdepth 2 -not -name mp3 -not -name ".*" -type d) 
PACKAGES = $(DIRS:%=%.npk) 

all: packages 

packages: $(PACKAGES) 

%.npk: %/* 
    npack c [email protected] @^ 

.PHONY: all packages 

el problema es que no hay tal cosa como%/* en las dependencias. Necesito los objetivos (X.npk) para depender de cada archivo en el directorio X, pero no sé cuáles son los archivos cuando escribo el archivo Makefile, porque se generan más tarde.

Un ejemplo:

./dirA/x 
./dirA/y 
./dirB/e 
./dirB/f 

Me gustaría crear ./dirA.npk (en función de x, y), ./dirB.npk (e, f) No hay nada que sé sobre el dirs o los archivos por adelantado, excepto que el hallazgo utilizado en la primera línea encuentra todos los directorios.

+0

Intenté:% .npk: $ (comodín%/*) pero eso no funciona. También pensé en un semafor pero llegué al mismo problema, que necesitaría depender de target_dir/*. – Gavriel

Respuesta

1

Esta es la solución que encontré: se basa en la idea makedepend, con algunos "meta" scripting. No muy agradable, pero funciona.

PACKAGES := 

all: packages 

-include Makefile.depend 

packages: Makefile.depend $(PACKAGES) 

depend: clean Makefile.depend 

Makefile.depend: 
    @(PACKAGES= ; \ 
    for DIR in `find . -mindepth 2 -maxdepth 2 -not -name mp3 -not -name ".*" -type d` ; \ 
    do \ 
     PACKAGE=`basename $${DIR}.npk` ; \ 
     PACKAGES="$${PACKAGES} $${PACKAGE}" ; \ 
     DEPS=`find $${DIR} -not -type d | sed -e 's#\([: ]\)#\\\\\1#' -e 's#^\./\(.*\)# \1#' | tr -d "\n"` ; \ 
     SUBDIR=`echo $${DIR} | sed -e 's#^\./\([^/]\+\)/.*#\1#'` ; \ 
     FILES=`echo \ $${DEPS} | sed -e "s# $${SUBDIR}/# #g"` ; \ 
     echo "$${PACKAGE}:$${DEPS}" ; \ 
     echo " @cd $${SUBDIR} ; \\" ; \ 
     echo " npack c ../\[email protected] $${FILES} ; \\" ; \ 
     echo ; \ 
    done ; \ 
    echo "PACKAGES = $${PACKAGES}" \ 
    )>> Makefile.depend ; \ 

cleanall: clean 
    rm -f *.npk 

clean: 
    @rm -f Makefile.depend 

.PHONY: all packages depend clean 
2

Trate de usar la directiva wildcard:

DEPS := $(foreach dir, $(DIRS), $(wildcard $(dir)/*)) 

%.npk: $(DEPS) 
    npack c [email protected] $^ 

EDIT: Lo anterior es sólo un ejemplo del uso wildcard y hace que cada archivo .npk depende de los archivos en todas las otras carpetas. Tu uso sería ligeramente diferente.

Creo que puede haber una manera más fácil de hacerlo. ¿Por qué quieres tener una dependencia en todos los archivos de la carpeta? ¿Es solo usar el operador $^? ¿O necesita reconstruir el .npk si alguno de los archivos ha cambiado?

Una alternativa (y posiblemente más limpia) solución sería utilizar la utilidad find en su receta en lugar de $^ y utilizar la directiva .FORCE para forzar siempre el archivo .npk que ser reconstruido. La desventaja es que los archivos .npk pueden reconstruirse innecesariamente.

EDIT 2: Si no hay una manera de hacerlo limpiamente con make comandos, se puede evitar mediante el uso de .FORCE para asegurar que la receta es siempre correr y mover el "debería reconstruir este archivo" cheque en el cuerpo de la receta:

%.npk: .FORCE 
    check_for_rebuild.sh [email protected] && npack c [email protected] $^ 

donde check_for_rebuild.sh es un shell script que hace algo como esto:

#!/bin/bash 
# Returns non-zero if the archive needs to be rebuilt 
if [ -e $1 ]; then 
    folder_name=$(basename $1 .npk) 
    [ -z "$(find $folder_name -newer $1 -not -type d)" ] && return 0 
fi 
return 1 

Pongo Realmente me gusta esa solución porque funciona en torno al problema en lugar de resolverlo directamente, pero puede mientras tanto hacerlo funcionar. Si va a seguir esa ruta, probablemente sea más limpio y fácil hacer todo en el script de shell y hacer que el archivo MAKE invoque simplemente el script o elimine por completo el archivo MAKE.

+0

exactamente, necesito reconstruir el archivo npk si alguno de los archivos cambió o se agregó un nuevo archivo. .FORCE no es una opción, estoy tratando de hacer el opuesto (actualmente tengo un script de shell que reempaqueta todo en X.npk.tmp, y luego, si 'cmp X.npk X.npk.tmp' muestra cambios, renombro el de lo contrario, lo borro. Pero se está volviendo lento ya que tengo más directorios y archivos. – Gavriel

0

Con makepp se puede hacer esto en 2 pasos, a través de la: modificador regla foreach:

$(foreach).txt: $(foreach)/*: foreach */ 
    &echo $(inputs) -o $(output) 

Esto proporciona una regla para cada subdirectorio, que reexecutes cada vez que hay un cambio en la lista de archivos en el mismo.

Cuestiones relacionadas