GNU make: Generate rules for extracting tarballs

gnu-make, makefile

Solution

- 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)

Problem

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?

Original source