Thomas Mailund
Thomas Mailund

Reputation: 1826

Makefile with dynamic-ish list of targets

I wrote some code for a class I'm teaching that checks if a number of tools all have the correct (and the same) behaviour on some test data and scripts that compare their relative performance. The idea is that if my students can just put their source code in a specific directory and then all the scripts will be applied to it--and I can combine all their solutions by putting them in my copy of that directory.

I have set it up such that if you put a directory with a name that ends in _src into a specific directory, and this directory has a Makefile in it, then the source will be included in builds. The way I have implemented it, though, is basically just a shell-script inside my Makefile.

mappers=$(wildcard *_src)

all:
    echo $(mappers)
    for m in $(mappers); do                               \
        mapper_name=`basename $$m _src`                  ;\
        echo $$mapper_name                               ;\
        (cd $$m && make)                                 ;\
        if [ ! -e $$mapper_name ]; then                   \
            cp $$m/$$mapper_name $$mapper_name           ;\
        fi                                               ;\
        if [ $$m/$$mapper_name -nt $$mapper_name ]; then  \
            cp $$m/$$mapper_name $$mapper_name           ;\
        fi                                               ;\
    done                                                 ;\
    for m in $(mappers); do                               \
        mapper_name=`basename $$m _src`                  ;\
        if [ ! -x $$mapper_name ]; then                   \
          echo "Hey! where did $${mapper_name} go?"      ;\
            exit 1                                       ;\
        fi                                               ;\
    done

I am sure that there must be a smarter way to include subdirectories in a Makefile and in a way so they can automatically be detected, but I am not that familiar with Make when it goes beyond simple setups.

I was thinking of making a script that would update my Makefile, similar to how makedepends work, but I am not sure that is the best solution.

Upvotes: 1

Views: 267

Answers (1)

HardcoreHenry
HardcoreHenry

Reputation: 6377

Something like this would likely work -- for each _src directory, it creates a _build directory, copies the files, and then builds from the _build directory. When done it touches the _build/.built file to mark it's done:

src_Makefiles=$(wildcard *_src/Makefile)     # Makefiles in source
src_dirs=$(src_Makefiles:/Makefile=)         # source directories
build_dirs=$(src_dirs:_src=_build)           # build directories
built_files=$(build_dirs:=/.built)           # build done files

#default target, which builds everything:    
all: $(built_files)

#for debugging only -- lets you know if you've made a mistake:
$(info built_files=$(built_files))

# the following creates a _build directory for every _src directory.

$(build_dirs) : %_build : %_src
        @echo updating $@
        @rm -rf $@     # remove any artifacts from previous builds...
        @mkdir -p $@   # make the directory
        @cp -r $@ $^   # copy the entire contents of _src to build.


# The following is the rule to build each directory.
# Each built file depends on the _src directory (which
# has a timestamp of the latest modified file -- so it
# will rebuild only if the student has modified something
# since the last build)
$(built_files): %_build/.built : %_build
        @echo building $(dir $@)
        @echo "run make -C $(dir $@)"
        touch $@

clean:
        rm -rf *_build

Upvotes: 1

Related Questions