Makefile: depend on every file of a directory

9.6k Views Asked by At

I'd like to do a Makefile that runs either with gnumake or makepp that packs all the files under given directiories:

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

all: packages

packages: $(PACKAGES)

%.npk: %/*
    npack c $@ @^

.PHONY: all packages

the problem is that there's no such thing as %/* in the dependencies. I need the targets (X.npk) to depend on every file in directory X, but I don't know what the files are when I write the Makefile, 'cause they're generated later.

An example:

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

I'd like to create ./dirA.npk (depending on x,y), ./dirB.npk (e,f) There's nothing I know about the dirs or the files in advance except that the find used in the 1st line finds all the dirs.

3

There are 3 best solutions below

1
On BEST ANSWER

This is the solution I found: it is based on the makedepend idea, with some "meta" scripting. Not very nice, but works.

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 ../\$$@ $${FILES} ; \\" ; \
        echo ; \
    done ; \
    echo "PACKAGES = $${PACKAGES}" \
    )>> Makefile.depend ; \

cleanall: clean
    rm -f *.npk

clean:
    @rm -f Makefile.depend

.PHONY: all packages depend clean
1
On

Try using the wildcard directive:

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

%.npk: $(DEPS)
    npack c $@ $^

EDIT: The above is just an example of using wildcard and makes each .npk file dependent on the files in all of the other folders. Your usage would be slightly different.

I think there may be an easier way to go about this. Why are you wanting to have a dependency on all of the files in the folder? Is it just to use the $^ operator? Or do you need to rebuild the .npk if any of the files changed?

One alternate (and possibly cleaner) solution would be to use the find utility in your recipe instead of $^ and use the .FORCE directive to always force the .npk file to be rebuilt. The downside is that .npk files may be rebuilt unnecessarily.

EDIT 2: If there's not a way to do this cleanly with make commands, you can work around it by using .FORCE to ensure that the recipe is always run and move the "should I rebuild this file" check into the body of the recipe:

%.npk: .FORCE
    check_for_rebuild.sh $@ && npack c $@ $^

where check_for_rebuild.sh is a shell script that does something like this:

#!/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

I don't really like that solution because it works around the problem instead of solving it directly, but it may be able to get you going in the meantime. If you are going to go that route, it's probably cleaner and easier to do everything in the shell script and either have the makefile simply invoke the script or get rid of the makefile entirely.

0
On

With makepp you can do this in 2 steps, via the :foreach rule modifier:

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

This provides a rule for every subdirectory, which reexecutes whenever there is a change in the list of files therein.