我不确定这是一个git问题还是一个make问题,或者也许都是这两个问题,但这是可行的...
假设您有一个文件foo.cpp
,它是由生成器程序gen.py
生成的。如果修改了生成器程序,则必须再次运行它以生成foo.cpp
的新版本。
编码此行为的makefile规则可以如下所示: 1 :
foo.cpp: gen.py
gen.py
对于在gen.py
上进行积极开发,我认为这是理想的选择。
但是,请考虑在github或其他类似站点上通过git远程访问项目的情况。用户将下载并制作您的项目。
处理已生成文件的传统方法是不全部检查它们:不要在git all中包括foo.cpp
(将其添加到您的.gitignore中),并且当用户构建您的项目时,该文件将生成。
但是,另一种方法 是将生成的文件foo.cpp
包含在git中。如果更改了一个gen.py
和foo.cpp
而又不更新另一个,则有可能gen.py
和gen.py
“不同步” 2 :
foo.cpp
的用户不需要具有运行gen.py
的先决条件(例如Python)。make
暗示对foo.cpp
的更改将获得直接反馈。相对于始终在本地生成文件,我对诉讼生成文件的优点不感兴趣。您可能会认为,对于某些项目,已经决定签入生成的文件,并且该决定不值得商debate。
那么在这种情况下,我的问题是:
对于刚克隆项目或同步涉及两个文件的提交的用户,我如何确保foo.cpp
不尝试生成gen.py
?默认情况下,git在同步文件时将使用当前时间,因此foo.cpp
和foo.cpp
将具有相同的时间戳,并且coplot
将被重建。
我不能要求用户更改其git配置。
1 也许points
会有其他依赖关系,这也将作为前提条件出现,但这是“基本情况”。
2 一种合理的方法是通过git hook强制它们同步。
答案 0 :(得分:2)
您可以比较输出,并仅在目标不同时更新目标。例如,假设您的gen.py
会将其输出写入stdout,因此通常情况下,您会有如下规则:
foo.cpp: gen.py
./gen.py > $@
您可以将其更改为:
foo.cpp: gen.py
./gen.py > $@.tmp
cmp -s $@ $@.tmp && rm -f $@.tmp || mv -f $@.tmp $@
这里的缺点是,直到您 DO 更新foo.cpp
,gen.py
配方将始终运行。但是,不会建立依赖于foo.cpp
的目标 ,因为其时间戳未更改。
如果这很昂贵,并且您想解决这个问题,则必须做一些更复杂的事情:如果比较结果正确(无差异),则需要重置gen.py
上的时间戳,以便与目标相同;这样可以确保以后不再将目标视为过时的目标。像这样:
foo.cpp: gen.py
./gen.py > $@.tmp
if test -e $@ && cmp -s $@ $@.tmp; then \
rm -f $@.tmp; \
touch -r $@ gen.py; \
else \
mv -f $@.tmp $@; \
fi
如果无法轻松更改gen.py
的输出文件名,那么您将不得不做一些更令人作呕的事情,例如在运行{{1}之前将$@
重命名为$@.old
}},然后改回它或适当地使用新的。
ETA 如果您只是想避免运行./gen.py
,如果它是同一版本,那么它更像是一个Git问题而不是makefile问题,因为您真正要问的是如何知道这些文件是否在同一Git提交中。这很容易,但是正如我在下面的评论中所说,我认为这实际上是不对的:
gen.py
答案 1 :(得分:0)
一个post-merge
钩子可能会解决您的问题:
向您的存储库中添加一个hooks/post-merge
脚本,其中包含例如(使用bash
版本> 4):
$ cat hooks/post-merge
#!/usr/bin/env bash
printf 'running post-merge\n'
declare -A generated=()
generated["foo.cpp"]="gen.py"
# add other (generated, generator) pairs to the generated associative array
for g in "${!generated[@]}"; do
s="${generated[$g]}"
if ! git diff ORIG_HEAD HEAD --exit-code -- "$g" "$s" &> /dev/null; then
printf 'touch %s\n' "$g"
touch "$g"
fi
done
$ chmod +x hooks/post-merge
添加一个runme.sh
脚本,并要求您的用户在克隆存储库后手动运行它(他们必须真的信任您,但是安全性超出了此答案的范围):
$ cat runme.sh
#!/usr/bin/env bash
for s in hooks/*; do
ln -sf ../../"$s" .git/hooks
done
如果每对(generated
,generator
)对都被git pull修改,则post-merge
钩子将触碰generated
,以使其最后一次修改时间戳比generator
更新。
当然,这只是一个起点,可能还有其他几件事要考虑(重新设置,...)。