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?