Build gnu make:即使目标未更改,也始终调用前提条件

Build gnu make:即使目标未更改,也始终调用前提条件,build,npm,makefile,Build,Npm,Makefile,我是新来的,来自npm。我试着把它们一起使用,效果很好。只有make似乎认为它每次都需要运行某个npm命令,但目标文件仍然存在并且没有改变 我有一个git项目的网站。该网站有一个git子模块,名为npm。唯一重要的是,我需要在该目录中构建一些文件,并将它们压缩到网站的根目录。该网站没有package.json,因此npm将无法在该目录中工作 下面是MakeFile,最后是我的问题 REPO_FOLDER = npm MINI_FILES = stream.min.js stream.min.js

我是新来的,来自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目标也始终运行。为什么会这样?我怎样才能让make识别这两个文件

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

3) 我使用npm压缩这两个编译过的文件。我已经看到make中有一个
ar
命令,但是它可以生成zip文件吗?如果可以,如何生成

更新 事实证明,我的变量替换是错误的,因此第二个目标也是错误的$(STREAM\u MINI\u文件)将解析为
REPO\u文件夹/STREAM.min.js
REPO\u文件夹/STREAM.min.js.map
而不是
STREAM/STREAM.min.js
STREAM/STREAM.min.js.map
。由于第一条规则中的先决条件(带有REPO_FOLDER的先决条件不存在),make每次都会运行第二条规则的配方

以下是最终的工作生成文件:

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)
minify
被声明为
.PHONY
特殊目标的先决条件。make每次必须构建另一个依赖于它的目标或为此目标调用make时都会重建它。如果您使用
make
调用make(也就是说,不指定目标),它将尝试在您的示例中构建makefile中的第一个目标
stream.js.zip
。由于这取决于
$(STREAM\u MINI\u FILES)
,make将首先检查这些文件是否是最新的,如果不是,则重新生成它们
$(STREAM\u MINI\u FILES)
本身依赖于
minify
,这是
.PHONY
的先决条件,因此在任何情况下都必须重新制作,即使名为
minify
的文件存在并且是最新的

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

一个选项是完全删除
缩小
(包括从
.PHONY
先决条件中删除),并合并规则:

$(STREAM_MINI_FILES):
    @cd $(REPO_FOLDER); \
    test -d "node_modules" || npm install; \
    npm run minify
只有当
$(STREAM\u MINI\u files)
中列出的一个文件丢失时,才应运行配方。一个缺点是,当缺少文件时,配方将运行多次,这是一种浪费。为了避免这种情况,您可以将
目标缩小,但将其设置为一个真正的空文件,以跟踪已完成的操作:

$(STREAM_MINI_FILES): minify

minify:
    @cd $(REPO_FOLDER); \
    test -d "node_modules" || npm install; \
    npm run minify
    touch $@
这是一个非常常见的技巧,每当您的构建过程不完全像“获取一个源文件并构建一个结果文件”时,它都会非常有用

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

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

cd there
pwd
这两行在两个不同的进程中执行,第一行对第二行没有影响。将命令放在同一个bash列表上,即通过
分隔命令
强制make在单个进程中执行它们(行尾字符转义为行上的最后一个字符时,
\
):

或:

等效,将在
那里
目录中执行
pwd
命令。在
stream.js.zip
配方中,您有一个bash列表。因此,它应该按预期工作,列表的第二个成员应该从
$(REPO_文件夹)
目录执行。你的问题来自其他方面。您是否尝试手动运行该命令?您是否检查了
\
是否确实是行中的最后一个字符(否则它不会转义到行尾)


3)
ar
不是make命令。它是一个GNU归档实用程序。不,它不能制作不同格式的zip存档。请注意,make可以在
ar
归档文件的内部操作,就好像它们是未打包的一样,这很有用。键入
man-ar
了解更多关于
ar

1)是的,你是对的<代码>缩小
不存在。如果$(STREAM\u MINI\u FILES)丢失,我只想运行minify。如果它们真的存在,那么我不想让它们缩小。显然我做错了,我明白了。为什么不合并这两个规则,抑制
minify
目标并将其配方用于
$(STREAM\u MINI\u FILES)
?使用包含两个文件的变量
$(STREAM\u MINI\u FILES)
,将配方运行两次。而且每次打电话都是这样。2)你又对了。我不知道什么时候出错并得到修复,但这与删除回声抑制符号(@)是一致的。1)我编辑了我的答案,向您展示了如何避免
$(STREAM\u MINI\u FILES)
的双重构建。但是无论如何,我建议合并这两个规则,make不应该在每次调用时运行配方,除非
$(STREAM\u MINI\u files)
中列出的一个或两个文件丢失。如果是这样的话,那就有问题了
cd there; pwd
cd there; \
pwd