Makefile目标变量无法正常工作

时间:2018-10-22 20:08:49

标签: variables makefile target

如果尚未提取文件包含的文件,我想解压缩文件。如果我指定的目标没有变量%,那么它将起作用。但是,我不确定如何使用%进行此操作。对文件及其以.tgz结尾的tar压缩文件也有依赖性。这是我到目前为止所拥有的。我可以做make T2,但不能做make T1make T3。有人可以帮我了解我在做什么错。谢谢。

TAR_FILE1 := ../a_files.tgz 
EXTRACT_DIR1 := ../ 
EXTRACT_LIST1 :=        \

TAR_FILE2 := ../b_files.tgz 
EXTRACT_DIR2 := ../ 
EXTRACT_LIST2 :=        \

F := ../b_files/b.v
TF := ../b_files.tgz 
DIR := ../ 
ET := 

IP_EXTRACT: $(RTL_FILES%) 

$(RTL_FILES%): $(IP_TAR_FILE%)   
    @echo -e "\nTarget $@ with $*:"
    gtar zxvfmC $(IP_TAR_FILE%) $(IP_EXTRACT_DIR%) $(IP_EXTRACT_LIST%)

$(F): $(TF)   
    @echo -e "\nTarget $@ with $*:"
    gtar zxvfmC $(TF) $(DIR) $(ET)

$(FILES%): $(TAR_FILE%)   
    @echo -e "\nTarget $@ with $*:"
    gtar zxvfmC $(TAR_FILE%) $(EXTRACT_DIR%) $(EXTRACT_LIST%)

FILES1 := \
../a_files/a.v  \
../a_files/a1.v \
../a_files/a2.v

FILES2 := ../b_files/b.v ../b_files/b1.v ../b_files/b2.v

print-%  : ; @echo $* = $($*)


T1: $(FILES%)
T2: $(F)
T3: $(FILES1)

clean:
    rm -rf ../a_files ../b_files

1 个答案:

答案 0 :(得分:0)

%制造通配符显然不是您想的。在您的Makefile中,几乎到处都是常规字符,是make变量名称的一部分。例如,当您编写:

$(RTL_FILES%): $(IP_TAR_FILE%)

()之间的字符串是变量名。而且,由于您可能未定义此类变量,因此它们会扩展为空字符串。

唯一的例外是print-%规则,该规则正确地用于形成模式规则。出于同样的原因,您对$*自动变量的所有使用都可能是错误的:它总是作为空字符串扩展。此外,您的问题是不完整的,因为您没有说明变量RTL_FILESIP_TAR_FILEFILESTAR_FILE ...是什么。

无论如何,如果您要“ 如果文件中包含的文件尚未解压缩,则将其解压缩”,则有多种可能。以下内容假设您使用GNU make,并且您的../a_files.tgz压缩包扩展为:

a_files
├── a
└── b
    └── b

它还假定您没有带有空格,制表符,特殊字符...的文件或目录名称。

一个简单的解决方案

让我们从一个简单的解决方案开始,您要在../a_files.tgz目录不存在的情况下解压缩../a_files。否则,您认为压缩包已被提取。

.PHONY: all

all: | ../a_files

../a_files:
    tar -C .. -xvf ../a_files.tgz

请注意all引入的|目标的order-only prerequisite。它告诉我们只有先决条件的存在,而不是其最后修改时间。在大多数情况下,当先决条件是目录时,是必需的。

演示:

$ make
tar -C .. -xvf ../a_files.tgz
a_files/
a_files/b/
a_files/b/b
a_files/a
$ make
make: Nothing to be done for 'all'.

更复杂(但功能更强大)的解决方案

但是,如果您不想将a_files的存在等同于“ 已提取所有文件”怎么办?例如,如果您希望Makefile能够防止意外删除某些文件,那么该怎么办?

只要存在../a_files目录,即使已删除其完整内容,上述“ 简单解决方案”也不会再次解压缩:

$ rm -rf ../a_files/*
$ make
make: Nothing to be done for 'all'.

一个不错的解决方案是考虑提取文件的完整列表,而不仅仅是它们的父目录。如果缺少任何人,您将再次解压缩,否则不会。但是事情有点困难,因为我们需要:

  1. 获取文件列表。您可以将列表硬连接到Makefile中,但这不是很方便。借助GNU make tar -tf <tarball>函数,也可以通过查看压缩包(shell)自动计算该列表:

    LIST    := $(shell tar -tf ../a_files.tgz)
    
  2. 告诉我们,所有这些文件都是通过一次执行tar配方来创建的。这并不是那么容易,因为自然的制作风格是一次执行配方将创建一个文件。而且,如果我们只声明压缩包是所有提取文件的先决条件:

    FILES   := $(addprefix ../,$(LIST))
    
    $(FILES): ../a_files.tgz
        tar -C .. -xvf $<
    

    make可以决定运行多少个tar配方,只要有要提取的文件即可。这不是我们想要的。幸运的是,具有多个目标的模式规则是一个例外,我们可以利用它。棘手的是,我们必须在%的所有单词中至少用$(FILES)替换一个公共字符。让我们替换s中的../a_files/XXX

    LIST    := $(patsubst a_files/%,%,$(shell tar -tf ../a_files.tgz))
    FILES   := $(addprefix ../a_files/,$(LIST))
    PATTERN := $(addprefix ../a_file%/,$(LIST))
    

    现在,我们的make变量将使用值:

    LIST    :=  b/ b/b a
    FILES   := ../a_files/b/ ../a_files/b/b ../a_files/a
    PATTERN := ../a_file%/b/ ../a_file%/b/b ../a_file%/a
    

    并且如果我们使用$(PATTERN)作为规则的目标,make将考虑所有相同的目标,对于任何给定的相同%替换,都是由相关配方的一次执行创建的。 / p>

  3. 告诉我们,文件的最后修改时间不应用于决定它们是否与tarball有关。我们在第一个解决方案中已经看到的仅订购先决条件是实现此目的的一种方法。

所有方面,以下应该做我们想要的:

.PHONY: all

LIST    := $(patsubst a_files/%,%,$(shell tar -tf ../a_files.tgz))
FILES   := $(addprefix ../a_files/,$(LIST))
PATTERN := $(addprefix ../a_file%/,$(LIST))

all: $(FILES)

$(PATTERN): | ../a_files.tgz
    tar -C .. -xvf ../a_files.tgz

演示:

$ make
tar -C .. -xvf ../a_files.tgz
a_files/
a_files/b/
a_files/b/b
a_files/a
$ make
make: Nothing to be done for 'all'.
$ rm ../a_files/a
$ make
tar -C .. -xvf ../a_files.tgz
a_files/
a_files/b/
a_files/b/b
a_files/a