如何在makefile中正确使用gzip?

时间:2014-10-24 17:13:36

标签: makefile gzip

我是make新手,所以请随意更正我对此问题的语法。

我想创建一个下载一堆压缩文件的makefile,解压缩它们并对它们做一些事情。这是我的玩具示例:

my_dir/*.txt.gz:
    echo "# obtaining data"
    mkdir -p my_dir
    echo 1 > my_dir/file1.txt
    gzip my_dir/file1.txt
    echo 2 > my_dir/file2.txt
    gzip my_dir/file2.txt

my_dir/*.txt: my_dir/*.txt.gz
    echo "# unzipping data"
    parallel gzip -d ::: my_dir/*.txt.gz

final.txt: my_dir/*.txt
    echo "# doing something with data"
    cat my_dir/*.txt > $@

clean_my_dir:
    rm -rf my_dir
    rm -f final.txt

当我运行make final.txt时,我得到了我期望的结果(final.txt包含1\n2),但如果我再次运行make final.txt(不运行make clean_my_dir)我得到一个错误:

make final.txt
echo "# obtaining data"
# obtaining data
mkdir -p my_dir
echo 1 > my_dir/file1.txt
gzip my_dir/file1.txt
echo 2 > my_dir/file2.txt
gzip my_dir/file2.txt
echo "# unzipping data"
# unzipping data
parallel gzip -d ::: my_dir/*.txt.gz
echo "# unzipping data"
# unzipping data
parallel gzip -d ::: my_dir/*.txt.gz
gzip: can't stat: my_dir/*.txt.gz (my_dir/*.txt.gz.gz): No such file or directory
make: *** [my_dir/file2.txt] Error 1

我确信我在设置目标和先决条件方面犯了错误:我希望final.txt包含file1.txtfile2.txt的内容,但是这些文件最初是压缩的。如果有压缩文件,我如何告诉make调用gzip,如果未压缩文件可用,我怎么告诉他们什么都不做?

2 个答案:

答案 0 :(得分:2)

经过一些实验后,我创建了以下makefile:

COMPRESSED_DIR = my_dir
UNCOMPRESSED_DIR = temp_dir

DEPS = \
    $(UNCOMPRESSED_DIR)/file1.txt \
    $(UNCOMPRESSED_DIR)/file2.txt

##
##  Recipes how to obtain compressed files
##  (may propably not so trivial in your intended application)
##
$(COMPRESSED_DIR)/file1.txt.gz: 
    @echo ""
    @echo "# obtaining $@"
    mkdir -p $(COMPRESSED_DIR)
    echo 1 > $(COMPRESSED_DIR)/file1.txt
    gzip $(COMPRESSED_DIR)/file1.txt

$(COMPRESSED_DIR)/file2.txt.gz: 
    @echo ""
    @echo "# obtaining $@"
    mkdir -p $(COMPRESSED_DIR)
    echo 2 > $(COMPRESSED_DIR)/file2.txt
    gzip $(COMPRESSED_DIR)/file2.txt

## or alternatively:
#$(COMPRESSED_DIR)/%.txt.gz: 
#   @echo ""
#   @echo "# obtaining $@"
#   mkdir -p $(COMPRESSED_DIR)
#   echo $* > $(COMPRESSED_DIR)/$*.txt
#   gzip $(COMPRESSED_DIR)/$*.txt

##
##  Recipe to unpack compressed files
##
$(UNCOMPRESSED_DIR)/%.txt: $(COMPRESSED_DIR)/%.txt.gz
    @echo ""
    @echo "# unpacking $<..."
    mkdir -p $(UNCOMPRESSED_DIR)
    gzip -c -d $< > $@

##
##  Recipe to make final.txt
##
final.txt: $(DEPS)
    @echo ""
    @echo "# doing something with data"
    cat $(UNCOMPRESSED_DIR)/*.txt > final.txt

##
##  Recipe to clean
##
clean:
    rm -rf $(COMPRESSED_DIR)
    rm -rf $(UNCOMPRESSED_DIR)
    rm -f final.txt

如前所述,gzip会删除txt.gz文件,因此如果再次制作final.txt,则会重新执行创建txt.gz文件的方法。

我所做的是将解压缩的txt.gz文件放在一个单独的目录中,并强制gzip在解压缩时保留原始文件。这会导致以下行为:

如果第一次调用,将创建并解压缩txt.gz文件并创建final.txt:

# obtaining my_dir/file1.txt.gz
mkdir -p my_dir
echo 1 > my_dir/file1.txt
gzip my_dir/file1.txt

# unpacking my_dir/file1.txt.gz...
mkdir -p temp_dir
gzip -c -d my_dir/file1.txt.gz > temp_dir/file1.txt

# obtaining my_dir/file2.txt.gz
mkdir -p my_dir
echo 2 > my_dir/file2.txt
gzip my_dir/file2.txt

# unpacking my_dir/file2.txt.gz...
mkdir -p temp_dir
gzip -c -d my_dir/file2.txt.gz > temp_dir/file2.txt

# doing something with data
cat temp_dir/*.txt > final.txt

如果再次调用(没有make clean),输出将是make: final.txt'是最新的。如果删除$(DEPS)文件,将重新解压缩相应的txt.gz文件。如果删除了.txt.gz文件,将重新创建.txt.gz文件并重新解压缩(因为它比现有的.txt文件更新)。

另外,如果您已经获得了要处理的所有* .txt.gz文件(如果缺少makefile,则不必创建它们),您可以使用以下makefile:

COMPRESSED_DIR = my_dir
UNCOMPRESSED_DIR = temp_dir

# get a list of all *.txt.gz files within $(COMPRESSED_DIR)
ARCHIVES = $(wildcard $(COMPRESSED_DIR)/*.txt.gz)

# do some magic to modify $(ARCHIVES) into a list of *.txt files to produce
DEPS = $(subst $(COMPRESSED_DIR),$(UNCOMPRESSED_DIR),$(subst .txt.gz,.txt,$(ARCHIVES)))

##
##  Recipe to unpack compressed files
##
$(UNCOMPRESSED_DIR)/%.txt: $(COMPRESSED_DIR)/%.txt.gz
    @echo ""
    @echo "# unpacking $<..."
    mkdir -p $(UNCOMPRESSED_DIR)
    gzip -c -d $< > $@

##
##  Recipe to make final.txt
##
final.txt: $(DEPS)
    @echo "Archives:"
    @echo $(ARCHIVES)
    @echo ""
    @echo "Deps:"
    @echo $(DEPS)
    @echo ""
    @echo "# doing something with data"
    cat $(UNCOMPRESSED_DIR)/*.txt > final.txt

##
##  Recipe to clean
##
clean:
    rm -rf $(UNCOMPRESSED_DIR)
    rm -f final.txt

此makefile将COMPRESSED_DIR中的所有* .txt.gz文件解压缩到UNCOMPRESSED_DIR,并将所有* .txt文件解压缩到final.txt。

答案 1 :(得分:1)

你可以一步完成枪械冲刺:

my_dir:
    [ -d $@ ] || mkdir -p $@

my_dir/%.txt.gz: my_dir
    @echo "# obtaining data for $@"
    echo $* | gzip -c > $@

final.txt: my_dir/*.txt.gz
    @echo "# doing something with data for $@"
    gunzip -c $+ > $@

clean:
    rm -rf my_dir final.txt

依赖关系my_dir/*.txt.gz意味着final.txt将来自当时恰好存在的任何匹配文件(当没有匹配文件时它将失败)。为确保文件在不存在时生成,您需要明确列出它们,例如(if GNU Make is used

final.txt: $(foreach x,1 2 3 4 5 6 7 8,my_dir/$x.txt.gz)