gnu make:即使目标没有改变,也始终会调用先决条件

时间:2015-12-08 01:07:36

标签: build npm makefile

我是新来的,来自npm。我正在尝试将它们结合使用,效果非常好。只有make似乎认为它每次都需要运行某个npm命令,但目标文件在那里并保持不变。

我在git中有一个项目的网站。该网站有一个这个项目的git子模块,名为npm。唯一重要的是,我需要在该目录中构建一些文件并将其压缩到网站的根目录。该网站没有package.json,因此npm将无法在该目录中使用。

下面是MakeFile,最后是我的问题。

REPO_FOLDER = npm
MINI_FILES = stream.min.js stream.min.js.map
#STREAM_MINI_FILES := $(REPO_FOLDER)/stream.min.js $(REPO_FOLDER)/stream.min.js.map
STREAM_MINI_FILES := $(MINI_FILES:%=REPO_FOLDER/%) #6.3.1 Substitution References

stream.js.zip: $(STREAM_MINI_FILES)
    cd $(REPO_FOLDER); \
    npm run zip ../stream.js.zip $(MINI_FILES)

$(STREAM_MINI_FILES): minify

minify:
    @cd $(REPO_FOLDER); \
    test -d "node_modules" || npm install; \
    npm run minify;

update:
    @git submodule update --remote

all: update stream.js.zip

.PHONY: minify, update, all

1)即使npm / stream.min.js npm / stream.min.js.map存在,minify目标也始终运行。为什么这样,我如何才能识别这两个文件?

2)@cdcd之间有什么区别?在minify目标中我可以@cd到npm文件夹并运行npm install,但是在stream.js.zip目标中,我从npm收到错误,因为它仍然在网站目录中(没有的package.json)。为什么我不在npm目录中,当我在那种情况下执行@cd?

3)我使用npm来压缩两个编译的文件。我已经看到make中有一个ar命令,但是它可以创建一个zip文件吗?如果是,那该怎么办?

更新 事实证明,我的变量替换是错误的,因此第二个目标也是错误的。 $(STREAM_MINI_FILES)将解析为REPO_FOLDER/stream.min.js REPO_FOLDER/stream.min.js.map而不是stream/stream.min.js stream/stream.min.js.map。由于第一条规则中的先决条件是 REPO_FOLDER 从不存在,因此每次都会生成第二条规则的食谱。

这是最终的MakeFile:

REPO_FOLDER = stream
MINI_FILES = stream.min.js stream.min.js.map
ZIP_FILE = stream.js.zip 
#STREAM_MINI_FILES := $(REPO_FOLDER)/stream.min.js $(REPO_FOLDER)/stream.min.js.map
STREAM_MINI_FILES := $(MINI_FILES:%=$(REPO_FOLDER)/%) #6.3.1 Substitution References


$(ZIP_FILE): $(STREAM_MINI_FILES)
    @cd $(REPO_FOLDER); \
    npm run zip ../$@ $(MINI_FILES)

$(STREAM_MINI_FILES):
    @cd $(REPO_FOLDER); \
    test -d "node_modules" || npm install; \
    npm run minify;


update:
    @git submodule update --remote

clean:
    @rm --verbose $(ZIP_FILE) $(STREAM_MINI_FILES)

all: update $(ZIP_FILE)

.PHONY: update, clean, all

1 个答案:

答案 0 :(得分:3)

1)minify被声明为.PHONY特殊目标的先决条件。每次必须构建另一个依赖于它的目标时,make会重建它,或者使用此目标调用make。如果你使用make调用make(也就是说,没有指定目标),它将尝试在你的情况下在makefile stream.js.zip中构建第一个目标。由于它取决于$(STREAM_MINI_FILES),因此make会首先检查这些是否是最新的,如果不是,则重建它们。 $(STREAM_MINI_FILES)本身依赖于minify,这是.PHONY的先决条件,因此必须在每种情况下重新制作,即使名为minify的文件存在并且最多 - 日期。

此外,我怀疑minify是一个符号目标,并且没有这个名称的真实文件(我错了吗?)。这是make重建它的另一个原因:它不存在但是$(STREAM_MINI_FILES)需要它。

一种选择是完全删除minify(包括.PHONY先决条件)并合并规则:

$(STREAM_MINI_FILES):
    @cd $(REPO_FOLDER); \
    test -d "node_modules" || npm install; \
    npm run minify

仅当$(STREAM_MINI_FILES)中列出的某个文件丢失时,才应运行该配方。一个缺点是配方将运行多次,因为丢失文件,这是一种浪费。为避免这种情况,您可以保留minify目标,但要将其设为真实的空文件,以便跟踪已经完成的操作:

$(STREAM_MINI_FILES): minify

minify:
    @cd $(REPO_FOLDER); \
    test -d "node_modules" || npm install; \
    npm run minify
    touch $@

这是一个非常常见的技巧,每次你的构建过程都不像“获取一个源文件并构建一个结果文件”时证明非常有用。

2)在配方中使用command,在执行命令时回显命令。 @command抑制回声。我想这与你的问题无关。

make配方中的命令列表由make执行,每行有一个单独的进程。所以,如果你:

cd there
pwd

这两行在两个不同的进程中执行,第一行对第二行没有影响。将命令放在同一个bash列表中,即用;强制分隔命令使得在一个进程中执行它们(\作为一行的最后一个字符逃脱行尾字符):

cd there; pwd

或:

cd there; \
pwd

是等效的,将在pwd目录中执行there命令。在stream.js.zip食谱中,您只有一个bash列表。因此,它应该按预期工作,列表的第二个成员应该从$(REPO_FOLDER)目录执行。你的问题来自别的东西。您是否尝试手动运行该命令?您是否检查过\是否真的是该行的最后一个字符(否则它不会逃脱行尾)。

3)ar不是make命令。它是一个GNU归档实用程序。不,它不能制作不同格式的zip存档。请注意,make可以在ar档案的内部操作,就像它们被解压缩一样,这可能很有用。输入man ar以了解有关ar的更多信息。