Makefile for input / output pairs

I have pairs of input / output files. I generates an output file name of the script: output=$(generate input). For example, pairs can be:

in1.c      out1.o
in2.txt    data.txt
in3        config.sh
sub/in1.c  sub/out1.o

All these pairs obey the same set of rules in the makefile:

$(out): $(in) $(common) 
    $(run) $< > $@

What is a concise and efficient way to create such a Makefile?

I would rather avoid creating a Makefile from another script.

+3
source share
3 answers

I would not generate Makefile fragments from the script, but you could use include:

INS := in1.c in2.txt in3 sub/in1.c

include rules.mk

rules.mk: Makefile
        rm -f $@
        for f in $(INS); do \
                out=`generate "$$f"`; \
                echo -e "$$out: $$f\n\t\$$(run) \$$<> > \$$@\n\n" >> $@; \
        done
+3
source

If you are include, the gmake file will try to generate and include it before any other purposes. Combining this with the default rule should bring you closer to what you want.

# makefile
gen=./generate.sh
source=a b c
run=echo

# Phony so the default rule doesn't match all
.PHONY:all
all:

# Update targets when makefile changes
targets.mk:makefile
    rm -f $@
    # Generate rules like $(target):$(source)
    for s in $(source); do echo "$$($(gen) $$s):$$s" >> $@; done
    # Generate rules like all:$(target)
    for s in $(source); do echo "all:$$($(gen) $$s)" >> $@; done

-include targets.mk

# Default pattern match rule
%:
    $(run) $< > $@

generate.sh

#!/bin/bash
echo $1 | md5sum | awk '{print $1}'

$ make
rm -f targets.mk
for s in a b c; do echo "$(./generate.sh $s):$s" >> targets.mk; done
for s in a b c; do echo "all:$(./generate.sh $s)" >> targets.mk; done
echo a > 60b725f10c9c85c70d97880dfe8191b3
echo b > 3b5d5c3712955042212316173ccf37be
echo c > 2cd6ee2c70b0bde53fbe6cac3c8b8bb1
+3

Makefile?

You can get a list of inputs and a shell script that generates the name of the output file to generate goals, dependencies, and rules using the GNU make functions:

all :

inputs := in1.c in2.txt in3 sub/in1.c
outputs :=

define make_dependency
  ${1} : ${2}
  outputs += ${1}
endef

# replace $(shell echo ${in}.out) with your $(shell generate ${in})
$(foreach in,${inputs},$(eval $(call make_dependency,$(shell echo ${in}.out),${in})))

# generic rule for all outputs, and the common dependency
# replace "echo ..." with a real rule
${outputs} : % : ${common}
    @echo "making $@ from $<"

all : ${outputs}

.PHONY : all 

Conclusion:

$ make
making in1.c.out from in1.c
making in2.txt.out from in2.txt
making in3.out from in3
making sub/in1.c.out from sub/in1.c

The above makefile uses little use of the powerful GNU make: construct $(eval $(call ...)). He asks make to expand the macro to create a piece of text, and then evaluate that piece of text as part of the makefile, i.e. Make generates a makefile of flies.

+1
source

All Articles