首页 > 解决方案 > 尽管存在目标,但始终执行 Makefile 规则

问题描述

我正在尝试调整我MakefileGoLang 项目。我有几条规则应该:

  1. 设置一个 git pre-commit 钩子(不想提交二进制文件并意外违反版权法)
  2. 通过以下方式下载 mp3 文件youtube-dl
  3. 通过以下方式提取该视频的一部分ffmpeg

以前我是通过 shellscript 执行此操作并手动检查每个文件,但在将我的脚本转换为 Makefile 的过程中,我似乎遗漏了一些东西。

唯一不会重新运行的规则是 pre-hook,但我认为这是因为我没有为我的目标/规则名称使用变量?

.default: install
.phony: install generate clean

export bin_directory = bin
export asset_directory = data/assets
export song_url = https://www.youtube.com/watch?v=z8cgNLGnnK4
export song_file = ${bin_directory}/nsp-you-spin-me-cover.mp3
export loop_file = ${asset_directory}/spin-loop.mp3

install:
    go install .

generate: $(loop_file)
    go generate ./data

$(loop_file): $(song_file)
    mkdir -p "${asset_directory}"
    ffmpeg -i "${song_file}" -ss 00:01:13.30 -to 00:01:30.38 -c copy "${loop_file}"

$(song_file): .git/hooks/pre-commit
    mkdir -p "${bin_directory}"
    youtube-dl "${song_url}" --extract-audio --audio-format mp3 --exec "mv {} ${song_file}"

.git/hooks/pre-commit:
    cp ./pre-commit .git/hooks/pre-commit
    chmod +x .git/hooks/pre-commit

clean:
    git clean -xdf

更新:如果我generate像这样将所有依赖项集中到规则中,我发现这可以正常工作(这似乎是错误的做法)

.default: install
.phony: install generate clean

bin_directory:=bin
asset_directory:=data/assets
song_url:=https://www.youtube.com/watch?v=z8cgNLGnnK4
song_file:=$(bin_directory)/nsp-you-spin-me-cover.mp3
loop_file:=$(asset_directory)/spin-loop.mp3

install:
    go install .

.git/hooks/pre-commit:
    cp ./pre-commit .git/hooks/pre-commit
    chmod +x .git/hooks/pre-commit

$(song_file):
    mkdir -p "${bin_directory}"
    youtube-dl "${song_url}" --extract-audio --audio-format mp3 --exec "mv {} ${song_file}"

$(loop_file):
    mkdir -p "${asset_directory}"
    ffmpeg -i "${song_file}" -ss 00:01:13.30 -to 00:01:30.38 -c copy "${loop_file}"

generate: .git/hooks/pre-commit $(song_file) $(loop_file)
    go generate ./data

clean:
    git clean -xdf

标签: gomakefile

解决方案


您没有指定,但我假设您在make generate看到此行为时正在运行。如果您显示您键入的命令、您获得的输出(剪切和粘贴并正确格式化)或至少足以看到问题,并准确指出输出的哪一部分是意外的以及什么,那么在提问时总是最好的你预计会发生。

假设上面准确描述了您的环境和 makefile,那么您所看到的行为的最明显原因是此命令:

youtube-dl "${song_url}" --extract-audio --audio-format mp3 --exec "mv {} ${song_file}"

没有更新输出文件上的时间戳$(song_file),所以它看起来总是比依赖它的目标更老,所以 make 总是重建它。

运行 makefile 后,ls -l对所有预期的输出文件使用并查看它们的修改时间是否已更新。如果不是,您可能需要touch $@在命令之后添加到您的规则youtube-dl,以确保它已更新:

$(song_file): .git/hooks/pre-commit
        mkdir -p "${@D}"
        youtube-dl "${song_url}" --extract-audio --audio-format mp3 --exec "mv {} $@"
        touch $@

同样如上述评论中所述,以及 GNU make 文档中所述,特殊目标是.DEFAULT(大写) 和.PHONY(大写),而不是.defaultand .phony。后者只是您定义的目标,就像foo或其他一样;它们对 GNU make 没有特殊意义。像所有 UNIX/POSIX 工具和语言一样,makefile 是区分大小写的,因此请小心为 GNU make 手册中描述的关键字使用正确的大小写(以及您在 makefile 中定义的目标)

删除export不会改变任何东西:GNU make 允许在同一行上分配和导出变量。


推荐阅读