【发布时间】:2011-02-24 20:35:31
【问题描述】:
在使用普通旧 make 的相对较大的项目中,即使在没有任何变化的情况下构建项目也需要几十秒。尤其是对make -C 的多次执行,这会产生新的进程开销。
这个问题的明显解决方案是基于操作系统的inotify-like 功能的构建工具。它会查看某个文件何时更改,并根据该列表单独编译该文件。
那里有这样的机器吗?开源项目的奖励积分。
【问题讨论】:
在使用普通旧 make 的相对较大的项目中,即使在没有任何变化的情况下构建项目也需要几十秒。尤其是对make -C 的多次执行,这会产生新的进程开销。
这个问题的明显解决方案是基于操作系统的inotify-like 功能的构建工具。它会查看某个文件何时更改,并根据该列表单独编译该文件。
那里有这样的机器吗?开源项目的奖励积分。
【问题讨论】:
你的意思是Tup:
从主页:
“Tup 是一个基于文件的构建系统 - 它输入文件更改列表和有向无环图 (DAG),然后处理 DAG 以执行更新依赖文件所需的适当命令。DAG 存储在SQLite 数据库。默认情况下,文件更改列表是通过扫描文件系统生成的。或者,可以通过运行包含的文件监视器守护进程预先提供该列表。"
【讨论】:
Tup编译吧?
tup monitor -a - 到目前为止,看起来不错 - 相关文件已编译并且程序已准备就绪,我什至还没来得及切换到终端:-D
我只是想知道是不是 stat()ing 需要这么长时间的文件。要检查这里,我编写了一个小的 systemtap 脚本来测量 stat() 文件所需的时间:
# call-counts.stp
global calls, times
probe kernel.function(@1) {
times[probefunc()] = gettimeofday_ns()
}
probe kernel.function(@1).return {
now = gettimeofday_ns()
delta = now - times[probefunc()]
calls[probefunc()] <<< delta
}
然后像这样使用它:
$ stap -c "make -rC ~/src/prj -j8 -k" ~/tmp/count-calls.stp sys_newstat
make: Entering directory `/home/user/src/prj'
make: Nothing to be done for `all'.
make: Leaving directory `/home/user/src/prj'
calls["sys_newstat"] @count=8318 @min=684 @max=910667 @sum=26952500 @avg=3240
我运行它的项目有 4593 个源文件,make 需要大约 27 毫秒(以上为 26952500 纳秒)来统计所有文件以及相应的 .d 文件。不过我使用的是非递归make。
【讨论】:
stat() 文件需要更长的时间。
tup 的作者,用几秒钟的时间来制作一个包含 100k 个文件的未更改项目gittup.org/tup/make_vs_tup.html
noatime。
ninja 的作者同意inotify 不值得麻烦。 “inotify。我原本打算让 Ninja 驻留在内存中,并使用 inotify 来始终保持构建状态热。但是在编写代码时,我发现它足够快,每次都可以从头开始运行。也许是一台较慢的计算机仍然会从 inotify 中受益;数据结构的设置使得使用 inotify 应该不难。” martine.github.com/ninja/manual.html
如果你使用的是 OSX,你可以使用fswatch
https://github.com/alandipert/fswatch
以下是如何使用 fswatch 对文件进行更改,然后在检测到任何内容时运行 make
fswatch -o anyFile | xargs -n1 -I{} make
您可以像这样从 makefile 中运行 fswatch:
watch: $(FILE)
fswatch -o $^ | xargs -n1 -I{} make
(当然,$(FILE) 是在 makefile 中定义的。) make 现在可以像这样监视文件中的更改:
> make watch
你可以像这样观看另一个文件:
> make watch anotherFile
【讨论】:
安装inotify-tools 并写几行bash 以在某些目录更新时调用make。
附带说明一下,递归 make 的扩展性很差并且容易出错。首选non-recursive make。
【讨论】:
stating 一个文件,触摸它。而且,如果您需要在每次执行单个 make 时统计 100,000 个文件,则可能需要一段时间(其中 99.9% 的文件对您来说并不有趣,您已经将它们编译为 libsomething.so,这就是您所需要的全部)。
-noatime。请参阅thunk.org/tytso/blog/2009/03/01/… 了解更多信息。
您描述的变更依赖已经是 Make 的一部分,但是 Make 足够灵活,可以以低效的方式使用。如果缓慢确实是由递归(make -C 命令)引起的——它可能是——那么你应该减少递归。 (您可以尝试放入自己的条件逻辑来决定是否执行make -C,但这将是一个非常不雅的解决方案。)
粗略地说,如果你的 makefile 看起来像这样
# main makefile
foo:
make -C bar baz
还有这个
# makefile in bar/
baz: quartz
do something
你可以把它们改成这样:
# main makefile
foo: bar/quartz
cd bar && do something
有很多细节需要修改,但现在如果bar/quartz 没有更改,foo 规则将不会运行。
【讨论】: