3

I've got a Makefile that extracts a series of tarballs. Right now the rules are written like:

dirname:
        tar zxvf file.tar.gz

and other targets that depend on the expanded tarball reference dirname. But, it's kind of cluttery to define a rule like this for every tarball. So, I'm trying to use the eval function to auto generate these rules. My attempt looks like this:

TARFILES = $(wildcard *.tar.gz *.tgz)
define extract_tmpl =
 $(shell tar tf $(1) | head -1):
        tar zxvf $(1)
endef
$(foreach file, $(TARFILES), $(eval $(call extract_tmpl, $(file))))

But it doesn't seem to work. I'm testing with this tarball (in the same dir):

$ ls Python-2.6.6.tgz 
Python-2.6.6.tgz
$ tar tf Python-2.6.6.tgz | head -1
Python-2.6.6/
$ make Python-2.6.6/
make-3.79.1-p7: *** No rule to make target `Python-2.6.6/'.  Stop.

It seems like it should work to me, but honestly I'm not even sure how I can see what it expands to. Anything obviously wrong here?

4

1 に答える 1

6
  • You do not need an = after the define.
  • There should be a hard tab before the tar zxvf $(1)
  • Optional, define a rule called default as the first rule in the Makefile, which depends on all the directories that would be created, so that if you just run make, it would extract all the tarballs.
  • Optional, but good practice is to define default as a PHONY rule since it does not create any files called default.

This is how the Makefile would look like (and tested using 2 tarballs in the current directory):

TARFILES = $(wildcard *.tar.gz *.tgz)

define extract_tmpl
$(shell tar tf $(1) | head -1):
    tar zxvf $(1)
# ^
# HARD-TAB
#
endef

TAR_DIRS := $(foreach file, $(TARFILES), $(shell tar tf $(file) | head -1))

default: $(TAR_DIRS)

$(foreach file, $(TARFILES), $(eval $(call extract_tmpl, $(file))))

.PHONY: default

An alternate solution without using eval and just static pattern rules:

  • Used .extract_file.tar.gz or .extract_file.tgz as empty files to not re-extract the archives if already extracted
  • No eval, but just static pattern rules, which should make it compatible with older versions of make like v3.79
  • Added rules for clean

This is the Makefile:

TARFILES = $(wildcard *.tar.gz *.tgz)

EXTRACT_TARGETS := $(addprefix .extract_,$(TARFILES))
CLEAN_TARGETS := $(addprefix .clean_,$(TARFILES))

default: $(EXTRACT_TARGETS)

clean: $(CLEAN_TARGETS)

$(CLEAN_TARGETS): .clean_%: .extract_%
    rm -rf "$(shell tar tf $(patsubst .extract_%,%,$<) | head -1)"
    rm -f $<

$(EXTRACT_TARGETS): .extract_%: %
    tar zxf $<
    touch $@

.PHONY: default clean $(CLEAN_TARGETS)
于 2013-03-11T21:12:10.007 に答える