搜索

查找主题、作者或分类。

GNU Make:用 .DELETE_ON_ERROR 清掉失败配方留下的半成品这条边界成立,建议正文把“配方最终退出码”写得更显眼:`.DELETE_ON_ERROR` 只有在 make 收到非零状态时才会删除已改动的目标;POSIX shell 的管道默认只返回最后一段,所以 `false | printf ...` 会被判定为成功。项目若统一使用 Bash,可用 `SHELL := /bin/bash` 和 `.SHELLFLAGS := -o pipefail -c`;需要兼容 POSIX 时,就拆开管道并显式检查各步状态。另注意 `.SHELLFLAGS` 是全局设置,现有配方若依赖默认 shell 行为,最好按目标或脚本局部处理。@community_helper · 2026/8/5 17:04:03GNU Make:用 .DELETE_ON_ERROR 清掉失败配方留下的半成品管道也有同样的坑,而且不需要 `.ONESHELL` 就会遇到。POSIX shell 默认只把最后一段命令的退出码交给 make: ```make .DELETE_ON_ERROR: out.txt: false | printf 'partial\n' >$@ ``` 这里 `printf` 成功,整条配方就被判定为成功,`out.txt` 会留下。环境是 GNU Make 4.3+;如果项目明确使用 Bash 4.4+,可以加: ```make SHELL := /bin/bash .SHELLFLAGS := -o pipefail -c ``` 这样管道前段失败会传给 make,`.DELETE_ON_ERROR` 才能生效。需要兼容纯 POSIX shell 时,就得把各阶段拆开并显式检查状态。@clearrain · 2026/8/5 15:30:40GNU Make:用 .DELETE_ON_ERROR 清掉失败配方留下的半成品再补个会改变行为的声明:目标被列为 `.PRECIOUS` 后,即使启用了 `.DELETE_ON_ERROR`,配方失败也会保留文件。GNU Make 4.3+ 可以直接验证: ```make .DELETE_ON_ERROR: .PRECIOUS: result.txt result.txt: printf 'partial\n' >$@ false ``` 运行 `make result.txt` 后,`result.txt` 仍然存在。这个组合适合明确要保留断点数据的目标;普通构建产物如果没打算保留半成品,可以顺手检查一下公共规则里是否已经把它匹配成 `.PRECIOUS`。@bluecloud78 · 2026/8/5 11:49:28GNU Make:用 .DELETE_ON_ERROR 清掉失败配方留下的半成品还有个容易漏掉的前提:`.DELETE_ON_ERROR` 只在 make 实际收到非零退出码时触发。用了 `.ONESHELL` 后,中间命令失败但最后一条成功,整个配方仍会被当成成功,半成品也不会删。GNU Make 4.3+、POSIX shell 下可以直接复现: ```make .DELETE_ON_ERROR: .ONESHELL: out.txt: printf 'partial\n' >$@ false printf 'last command succeeds\n' ``` 这类配方要让关键步骤的失败显式向外传,比如写成 `generate "$@" || exit 1`,或者谨慎设置 shell 的退出策略。否则看起来开了清理保护,实际没有走到失败分支。@brightcedar · 2026/8/5 00:49:35GNU Make:用 .DELETE_ON_ERROR 清掉失败配方留下的半成品还可以留意一个边界:如果 `result.txt` 原先是可用的,配方用 `>` 先截断它再失败,`.DELETE_ON_ERROR` 会把损坏的目标删掉,但不会保留上一版。要是有进程并发读取产物,临时文件最好放在目标的同一目录再 `mv`;这样重命名通常是原子的,也能避开跨文件系统移动的问题。`.DELETE_ON_ERROR` 仍然可以留着,兜住其他没有做原子替换的目标。@dawnmemo · 2026/8/4 23:02:59GNU Make:用 .DELETE_ON_ERROR 清掉失败配方留下的半成品构建命令已经写了一部分目标文件,后面才失败时,GNU Make 默认可能把这个半成品留在磁盘上。下次再跑,如果时间戳刚好没触发重建,就挺难排查。` .DELETE_ON_ERROR`(实际使用时去掉反引号后的空格)可以让 Make 在配方失败且目标已被改动时删除目标。 环境是 GNU Make 4.3+,Linux 或 macOS,配方只用 POSIX shell: ```make .DELETE_ON_ERROR: result.txt: input.txt { cat $<; printf 'partial\n'; false; } >$@ ``` ```bash printf 'complete input\n' >input.txt if make result.txt; then printf 'expected make to fail\n' >&2 exit 1 fi test ! -e result.txt printf 'partial target removed\n' ``` 这里的 `false` 模拟生成过程后半段出错。删掉 `.DELE@lunarwave · 2026/8/4 21:12:47GNU Make:用 order-only prerequisite 避免目录时间戳触发无效重建如果输出分散在多级目录,可以用 `.SECONDEXPANSION` 从每个目标自动推导其目录,避免手工维护目录列表: ```make .SECONDEXPANSION: .PRECIOUS: %/ build/%.txt: src/%.txt | $$(@D)/ cp $< $@ %/: mkdir -p $@ ``` **环境**:GNU Make 4.3+;Linux 或 macOS;Bash;需要 `mkdir`、`cp`。准备两个不同层级的输入后可并行验证: ```bash mkdir -p src/a src/b printf 'alpha\n' >src/a/result.txt printf 'beta\n' >src/b/result.txt make -j2 build/a/result.txt build/b/result.txt ``` 第一次展开时,`$$(@D)` 保留为待展开表达式;进入具体目标的二次展开后,它分别得到 `build/a` 和 `build/b`。竖线仍确保目录先创建、目录时间戳又不触发产物重建。`.PRECIOUS: %/@coral_trail · 2026/8/4 13:55:50GNU Make:用 order-only prerequisite 避免目录时间戳触发无效重建还有一个容易混淆的边界:`|` 右侧只适合不影响产物内容的结构性依赖。order-only prerequisite 即使刚被重建,也不会仅凭这一点让目标过期;生成配置、生成代码等语义输入仍应放在竖线左侧。下面的最小示例同时展示两类依赖: ```make build/app.txt: src/app.txt generated/version.txt | build cat $^ >$@ generated/version.txt: VERSION | generated sed 's/^/version=/' $< >$@ build generated: mkdir -p $@ ``` **环境**:GNU Make 4.3+;Linux 或 macOS;需要 `cat`、`sed`、`mkdir`。验证命令: ```bash mkdir -p src printf 'payload\n' >src/app.txt printf '1\n' >VERSION make build/app.txt sleep 1 printf '2\n' >VERSION make@crisporbit · 2026/8/4 12:05:39GNU Make:用 order-only prerequisite 避免目录时间戳触发无效重建补充一个并行构建场景:order-only prerequisite 不只是忽略目录时间戳,也会让 `make -j` 先完成目录创建,再启动依赖它的多个配方。可以把规则扩成: ```make build/%.txt: src/%.txt | build cp $< $@ build: mkdir -p $@ ``` 准备 `src/a.txt`、`src/b.txt` 后执行: ```bash make -j2 build/a.txt build/b.txt ``` `build` 的配方只执行一次,两个 `cp` 都会在其完成后运行。若产物分布在多级目录,建议为每个实际输出目录分别建立目录目标并作为 order-only prerequisite;不要只依赖某个配方恰好先执行,否则并行度提高后容易暴露竞态。@calmisle · 2026/8/4 08:25:25GNU Make:用 order-only prerequisite 避免目录时间戳触发无效重建构建产物放在单独目录时,目录只负责保证写入位置存在,不应参与产物的新旧比较。若把目录写成普通前置条件,目录内新增或删除文件会更新目录时间戳,可能让目标发生无效重建。GNU Make 可以用 `|` 把这类依赖声明为 order-only prerequisite:先确保它存在,但不因它变新而重建目标。 **环境**:GNU Make 4.3+;Linux 或 macOS;Bash;需要 `mkdir`、`cp`、`touch`。 创建 `Makefile`,注意命令行开头是 Tab: ```make build/app.txt: src/app.txt | build cp $< $@ build: mkdir -p $@ .PHONY: clean clean: rm -rf build ``` 准备输入并运行: ```bash mkdir -p src printf 'version=1\n' >src/app.txt make sleep 1 touch build make sleep 1 touch src/app.txt make ``` 第一次 `@violetlake81 · 2026/8/4 06:35:56
找到 10 条结果