Build 是否有基于类似inotify机制的构建工具

Build 是否有基于类似inotify机制的构建工具,build,makefile,inotify,Build,Makefile,Inotify,在相对较大的项目中,使用纯旧的make,即使在没有任何变化的情况下构建项目也需要几十秒。尤其是执行了大量的make-C,这会带来新的进程开销 这个问题的明显解决方案是基于操作系统类似于inotify的特性的构建工具。当某个文件发生更改时,它会进行查看,并根据该列表单独编译该文件 有这样的机器吗?开源项目的额外好处。您描述的变更依赖性已经是Make的一部分,但是Make足够灵活,可以以低效的方式使用。如果速度慢确实是由递归(make-C命令)引起的,那么您应该减少递归。(您可以尝试输入自己的条件逻

在相对较大的项目中,使用纯旧的
make
,即使在没有任何变化的情况下构建项目也需要几十秒。尤其是执行了大量的
make-C
,这会带来新的进程开销

这个问题的明显解决方案是基于操作系统类似于inotify的特性的构建工具。当某个文件发生更改时,它会进行查看,并根据该列表单独编译该文件


有这样的机器吗?开源项目的额外好处。

您描述的变更依赖性已经是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
规则将不会运行。

安装并编写几行
bash
以在某些目录更新时调用
make

顺便说一句,递归使伸缩性差,并且容易出错。喜欢。

你的意思是:

从主页:


“Tup是一个基于文件的生成系统-它输入文件更改列表和有向无环图(DAG),然后处理DAG以执行更新依赖文件所需的适当命令。DAG存储在SQLite数据库中。默认情况下,文件更改列表是通过扫描文件系统生成的。或者,可以通过运行附带的文件监视器守护进程提前提供该列表。”

我只是想知道是不是
stat()
占用了这么长时间的文件。为了检查这一点,我编写了一个小脚本,用于测量创建
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
}

我运行它的项目有4593个源文件,make统计所有文件以及相应的.d文件需要大约27毫秒(上面是2695250nsec)。不过我使用的是非递归make。

如果您使用的是OSX,您可以使用
fswatch

下面介绍如何使用fswatch来查找对文件的更改,然后在检测到任何更改时运行make

fswatch -o anyFile | xargs -n1 -I{} make
您可以在makefile中运行fswatch,如下所示:

$ 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
watch: $(FILE)
  fswatch -o $^ | xargs -n1 -I{} make
> make watch
> make watch anotherFile
(当然,$(文件)是在makefile中定义的。) make现在可以监视文件中的更改,如下所示:

$ 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
watch: $(FILE)
  fswatch -o $^ | xargs -n1 -I{} make
> make watch
> make watch anotherFile
您可以观看另一个文件,如下所示:

$ 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
watch: $(FILE)
  fswatch -o $^ | xargs -n1 -I{} make
> make watch
> make watch anotherFile

嗯?调用make会触及项目中的每个文件。我不想那样做!“make”的要点是永远不要接触所有文件,即使是为了获得修改时间。@Elazar Leibovich:make不会接触任何文件。它的STAT的源文件,看看是否需要重建目标。马克西姆,我不知道你怎么样,但我考虑<代码> STAT< <代码>一个文件,触摸它。如果你每次做一个make都需要统计100000个文件,这可能需要一段时间(99.9%的文件对你来说不感兴趣,你已经把它们编译成libsomething.so了,这就是你所需要的)。哦,你指的是文件访问时间吗?此功能完全有缺陷,在装载文件系统时,每次读写都要使用
-noatime
。请参阅以了解更多信息。@Maxim,这是一个很好的技巧,但我的方法保证将开销减少到99.9%(访问一个已更改的文件,而不访问其他100000个文件,inotify make将忽略它们)。这是一个折衷方案。使用您的方法会给我一个巨大的、膨胀的makefile,它更快。我想吃我的蛋糕,也想吃它。这是可能的与inotify魔术。永远不要触摸任何未修改的文件,即使是修改日期。你可能是正确的,这可能是过早的优化。顺便问一下,缓存是热的吗?看看一个有10万人的项目很有趣,看看你的统计时间是否可以缩放。请注意,对于真正的大型项目,非递归make很多时候都不是一个选项+文件系统缓存很热(我编译的工作站有12Gb的RAM)。它位于本地ext3文件系统上。但是,在NFS上构建文件时,创建
stat()
文件需要几个数量级的时间。作为
tup
的作者,要使一个包含100k文件的未更改项目变得有趣,需要几秒钟的时间。我想知道测试中的文件系统是否安装了
noatime
ninja
的作者同意
inotify
不值得麻烦。“inotify。我原本打算让Ninja驻留在内存中,并使用inotify随时保持构建状态。但在编写代码时,我发现它足够快,每次都可以从头开始运行。也许速度较慢的计算机仍然会受益于inotify;数据结构的设置使得使用inotify应该不难。”我想知道,当你编辑一个文件并保存它的不完整版本时会发生什么。必须是每次保存都会触发
Tup
对其进行编译,对吗?Tup只在您请求时进行编译,但它总是监视文件系统的更改。
Tup monitor-a
–到目前为止,看起来不错–相关文件已经编译好,程序在我准备更改到终端之前就准备好了:-D