build - gnu make : prerequisite is always called even when target has not changed

标签 build npm makefile

我是新来的,来自 npm。我正在尝试将它们一起使用,效果非常好。 only 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) @cdcd 有什么区别?在 minify 目标中,我可以 @cd 到 npm 文件夹并运行 npm install,但在stream.js.zip 目标中,我从 npm 收到错误,因为它是仍在网站目录中(没有 package.json)。在这种情况下,当我执行 @cd 时,为什么我不在 npm 目录中?

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 从未存在,因此 make 每次都会运行第二条规则的配方。

这是最终的工作 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) 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,make 在执行时会回显该命令。 @command 抑制回显。我猜这与你的问题无关。

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

cd there
pwd

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

cd there; pwd

或者:

cd there; \
pwd

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

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

关于build - gnu make : prerequisite is always called even when target has not changed,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34146272/

相关文章:

c - makefile循环依赖和覆盖命令

Android Studio Gradle 2.0.0-alpha1 构建错误

node.js - 符号链接(symbolic link) SublimeText3 构建系统问题(Mac 到 PC)

firebase - 获取类型错误 : Cannot convert object to primitive value when running firebase emulators:start

node.js - 无法在 Ubuntu 中卸载 Angular CLI - 显示 `up to date in 0.083s`

cmake 交叉编译 GNU 工具

c - "make"编译写在 "cc ex1.c -o ex1"文件中的代码,为什么我们使用 "exe1.c"命令

caching - GitLab CI 中的 ccache 没有命中

dll - 使用 MinGw 在 Windows 上构建 Mlt 时出错。 undefined reference dlsym dlclose dlopen dlerror dlclose

node.js - 无法在node.js中导入@tensorflow-models