全部博文(132)
分类: C/C++
2008-12-19 14:46:26
The idea came from Erik Thiele wrote the original program as a bourne shell script. ccache is a re-implementation of Erik's idea in C with more features and better performance.
You can get this release from the
NOTE! This release changes the hash input slighly, so you will probably find that you will not get any hits against your existing cache when you upgrade.
By using ccache you can get exactly the same effect as "make clean; make" but much faster. It also helps a lot when doing RPM builds, as RPM can make doing incremental builds tricky.
I put the effort into writing ccache for 2 reasons. The first is the Samba build farm () which constantly does clean builds of Samba on about 30 machines after each CVS commit. On some of those machines the build took over an hour. By using ccache we get the same effect as clean builds but about 6 times faster.
The second reason is the autobuild system I used to run for Quantum. That system builds our whole Linux based OS from scratch after every CVS commit to catch compilation problems quickly. Using ccache those builds are much faster.
I have coded ccache very carefully to try to provide these guarantees.
| ccache | compilercache |
---|---|---|
normal | 13m 4s | 13m 4s |
uncached | 13m 15s | 15m 41s |
cached | 2m 45s | 4m 26s |
Alternatively, you can create symbolic links from your compilers name to ccache. This allows you to use ccache without any changes to your build system.
For the bleeding edge, you can fetch ccache via CVS or rsync. To fetch via cvs use the following command:
cvs -d :pserver:cvs@pserver.samba.org:/cvsroot co ccacheTo fetch via rsync use this command:
rsync -Pavz samba.org::ftp/unpacked/ccache .
A is available for discussion of ccache.
什么是ccahe?
ccache
是一个快速的编译器缓存。当您编译一个程序的时候,它会缓存中间的结果。这样,不论什么时候您重新编译同一个程序,编译所需要得时间将被大大缩短。对于普通的编译来说,这可以提高编译速度5到10倍。
这个想法,来自 Erik Thiele 用bash写的
。只不过,ccache用C再实现了一遍。但比前者性能高许多,也有更多的特性。
安装 ccache
emerge ccache
使用 ccache
1, 设置启用ccache
在 /etc/make.conf 中设置
FEATURES="ccache"
2, 指定ccache的主目录
比如,/var/tmp/ccache
是Portage的默认ccache主目录;为了修改这个设置,您可以设定/etc/make.conf
中的CCACHE_DIR
参数。
CCACHE_DIR= /var/tmp/ccache
针对不同的系统环境,可能如上的配置会不生效,保险起见,我们再加一个环境变量配置。
比如,我在 /etc/env.d/99ken.wug(ken.wug是我的机器的名字,可以自定义) 这个文件中,加入
CCACHE_DIR="/var/tmp/ccache"
3, 设置 ccache 的主缓存大小
设定/etc/make.conf中CCACHE_SIZE, 并设置它为"2G"
CCACHE_SIZE="2G"
4, ccache 常用指令使用说明
-s 获得关于高速缓存性能的统计数据
-M 设置高速缓存的最大大小
这里默认设置的是
${HOME}/.ccache 这个目录的缓存大小。
-F
设置高速缓存目录的最大文件数目,按 16 进制舍入
-c 清空缓存
-C 完全清空缓存
3.a. DistCC
什么是DistCC?
distcc是一个分布式编译的工具,可以在同一网络上几个不一定完全相同的机器来进行工作。distcc客户端向DistCC服务器(运行distccd)发送所有必须的信息,这样他们可以给客户端编译源代码的部分。网络编译的结果就是编译时间更短。
你可以在我们的找到更多有关distcc的详细信息(以及怎样在Gentoo中使用的资料)。
安装DistCC
Distcc使用一个图形化监视器来监视你的机器用于编译的工作。如果你使用GNOME,那么将“gnome”放入你的USE设置中。但是,如果你不使用GNOME而仍让希望使用这个监视器,那么就把“gtk”放进你的USE设置。
因为distcc就像其他很多软件一样都在Gentoo的Portage中存在,安装非容容易:
注释: 从现在开始,因为你知道在你愿意的时候安装二进制包,我们在Gentoo安装手册的后面就都去掉选项--usepkg。 |
代码 1: 安装Distcc |
# emerge distcc |
激活Portage的支持
如果安装很简单,余下的部分也应该很容易了:-) 所以,让我们尽快激活Portage对distcc的支持。
首先,打开/etc/make.conf,编辑变量FEATURES使其包含distcc关键词。然后,编辑变量MAKEOPTS为-jX,其中X为运行distccd(包含当前主机)的CPU数目加上一:
代码 2: /etc/make.conf中MAKEOPTS的可能设置 |
# 假设除开这台主机,你还有两个单CPU distccd主机 |
现在,去掉/etc/make.conf里的PORTAGE_TMPDIR行,并在文件的最后添加下面一行:
代码 3: 添加额外的与distcc相关的变量到/etc/make.conf |
# 不要忘了反注释掉变量PORTAGE_TMPDIR |
现在运行distcc-config,并输入已有的DistCC服务器。作为一个简单例子,我们假设已有的DistCC服务器是192.168.1.102(当前主机)、192.168.1.103和192.168.1.104(两个远端服务器):
代码 4: 配置Distcc,使用已有的三个DistCC服务器 |
# distcc-config --set-hosts "192.168.1.102 192.168.1.103 192.168.1.104" |
当然,也不要忘了运行distccd伺服器:
代码 5: 开始Distcc伺服器 |
# /etc/init.d/distccd start |
恭喜恭喜,你的系统将可以使用分布式编译了!有关DistCC和Gentoo更多更深的信息,请阅读我们的.
3.b. ccache
什么是ccache?
ccache是一种快速编译缓冲。当你编译一个软件时,它会缓冲即时的结果,因此当你重新编译相同的程序时,编译的时间将会大大减少。对于普通的编译来说,这个可以提高编译速度5到10倍。
如果你对ccache的内幕有兴趣,请访问。
安装ccache
在Gentoo中安装ccache很轻松,只需要emerge一下就搞定了:-)
代码 6: 安装ccache |
# emerge ccache |
激活Portage的支持
首先编辑/etc/make.conf,并修改变量FEATURES使其包含ccache关键词:
代码 7: 在/etc/make.conf中编辑变量FEATURES |
FEATURES="ccache" |
然后,编辑(或者创建)变量CCACHE_SIZE(也在/etc/make.conf中),使其包含你要给ccache的磁盘空间的大小:
代码 8: 在/etc/make.conf中编辑变量CCACHE_SIZE |
CCACHE_SIZE="2G" |
现在,Portage将会在可以使用ccache的地方使用它来加快编译。如果你不确定ccache是否工作,你可以运行ccache -s来查看ccache统计数据:
代码 9: 查看ccache统计数据 |
# ccache -s |
3.c. 二进制包
创建二进制软件包
我们已经讨论了怎样使用预编译软件包,那么我们怎样创建自己的预编译软件包呢?
如果一个软件已经安装,你可以使用quickpkg命令,它会将已安装的文件打成一个包。这对于备份来说是很有意思的!
代码 10: 使用quickpkg |
# quickpkg gnumeric |
如果这个软件包还没有安装,你也可以使用emerge要求创建一个二进制包。emerge使用选项--buildpkg(简称-b)来做这个:
代码 11: 安装gnumeric并且创建二进制包 |
# emerge --buildpkg gnumeric |
如果你要Portage默认做这个,你应该在/etc/make.conf中将buildpkg关键词包含在变量FEATURES中。
代码 12: 自动创建二进制包 |
FEATURES="buildpkg" |
如果你不要安装软件,只是创建二进制软件包,你可以使用选项--buildpkgonly(简称-B):
代码 13: 给gnumeric创建二进制包 |
# emerge --buildpkgonly gnumeric |
3.d. 安全相关的特性
沙箱
编译和安装软件时,Portage使用沙箱(sandbox)来保护你目前的系统。这意味着,只要软件还没有安装到你的系统上,这个软件包不会接触到任何沙箱以外的文件。这可以确保让Portage知道一个软件包修改和创建了什么文件。
当软件编译完成时,Portage会将软件在沙箱里进行“预安装”,以说明要放置什么文件,文件要放到哪。然后它将会将这些文件从沙箱复制到你的当前系统里。
用户权限
Portage也支持非超级用户(准确来说,是以组“portage”和用户“portage”编译软件包)。这在编译过程中提高了安全性。你也可以在使用用户权限时使用或者不使用沙箱。当然,并不是说用户权限和沙箱是最常见的方法。
激活沙箱(sandbox)和/或用户权限(userpriv)
Portage默认情况下会使用sandbox。如果你要使用usepriv,你应该将其添加到变量FEATURES中。注意到激活userpriv会失去sandbox支持,除非你也激活usersandbox:
代码 14: 激活userpriv和usersandbox |
FEATURES="userpriv usersandbox" |
警告: 千万不要将sandbox从变量FEATURES中去掉! |
严格检查
Portage可以对危险的情况作出强烈的反应(如遗失或错误的Manifest文件)。添加关键词strict到变量FEATURES可以激活这个严格检查:
代码 15: 激活严格检查 |
FEATURES="strict" |
智能文件系统许可
Portage可以去自动处理可能产生安全威胁的潜在的危险文件许可。它通过在前面的安装过程中去掉setuid文件的“group”和“other”对文件的可读以及去掉setgid文件的“other”对文件的可读。添加sfperms关键词到变量FEATURES可以激活这个智能文件许可:
代码 16: 激活智能文件许可 |
FEATURES="sfperms" |
3.e. 其他的特性
Portage的帮助文件
还有几个关键词你可以放入变量FEATURES中。它们中的大部分是面对开发者而对普通用户没什么多大作用。如果你想学习更多有关这些特性(一般说来就是Portage),不要忘了你还可以阅读我们提供的make.conf的手册。
代码 17: 更多Portage相关信息 |
# man make.conf |
用ccache加快make world的编译速度 | |
|
CCACHE改善协同构建时间加快编译 | |
作者:不详 来源:中国自学编程网整理发布 发布日期:2008-07-12 | |
借助 CVS,可以很好地使用 cc 或者 gcc 将 C/C++ 项目协同构建为共享源代码文件和其他组件,但是,当应用程序融入了任何其他人的改变时,构建所需要的时间可能是相当可观的。即便您不是作为小组成员来编译 项目,重新编译一个应用程序也会需要很长时间。ccache 工具通过将头文件高速缓存到源文件之中而改进了构建性能,因而通过减少每一步编译时添加头文件所需要的时间而提高了构建速度。通过本文学习如何构建和安装 ccache、如何在您现有的环境中使用它以及如何在小组开发项目中改善编译时间。您还将了解到如何同时使用 ccache 和 distcc 来使开发环境达到最佳性能。 在标准的编译过程中,在 UNIX 下使用 C/C++ 开发应用程序通常需要用到一个编译器(如 gcc)以及一个编译工具,比如 make。make 和所有的 C 编译器的问题在于 C 预处理程序(preprocessor)和头文件的工作方式。观察一个典型的 C 源文件,您会发现其中有很多由 #include 所引用的各种头文件。 每一次编译一个文件时,C 预处理程序(cpp)都会解析并引入每个头文件以及这些头文件引用到的任何文件。通过对内容进行解析,ccp 可以将一个相当基本的 1-KB 大小的源文件转化为一个 8-KB 大小的源文件,在这个过程中,会合并入几十个甚至几百个头文件。在典型的开发项目中,有很多与项目相关的头文件可能会在不同的源文件中多次被引入,而且每 个头文件本身也可能引用很多其他头文件。 在典型的编译过程中,make 工具只编译自上次编译后发生修改的文件,这样就在很大程度上简化了编译过程。例如,清单 1 中的目录表明,foo.o 对象比相应的 foo.c 源文件的最后修改日期更新。同时,bar.o 比 bar.c 更新。使用一个经过适当配置的 Makefile,将只会从源文件编译 foo.o。 make 将必须被编译的文件限制在经过修改的那些源文件范围之内,但是即使是使用 make,仍然有相当可观的浪费。每一次编译项目时,源文件在编译为汇编语言和最终的机器代码之前,都要通过 cpp 进行解析。对每一个文件来说,每一次可能都要重新解析头文件。从编译的全过程来看,您最后可能多次解析了相同的头文件,浪费了处理器周期,更重要的是浪费 了开发者的时间,因为他们要等待这一过程的完成。在一个团队中,这一影响可能会更为明显,因为多名开发者可能都会反复多次重复这一过程,在某一天甚至可能 会同时进行。 清单 1. 一个示例源文件环境 total 808 -rw------- 1 mc mc 5123 24 Jul 14:17 bar.c -rw------- 1 mc mc 39474 24 Jul 14:19 bar.o -rw------- 1 mc mc 7856 24 Jul 14:17 foo.c -rw------- 1 mc mc 28443 24 Jul 14:19 foo.o -rwx--x--x 1 mc mc 319742 24 Jul 14:19 foobar* -rw------- 1 mc mc 1045 24 Jul 14:21 foobar.h 使用 ccache ccache(“compiler cache”的缩写)工具会高速缓存编译生成的信息,并在编译的特定部分使用高速缓存的信息,比如头文件,这样就节省了通常使用 cpp 解析这些信息所需要的时间。如果您编译清单 2 中的文件,假定 foobar.h 中包含对其他头文件的引用,ccache 会用那个文件的 cpp-parsed 版本来取代 include 声明。就那么简单。不是真正去读取、理解并解释其内容,ccache 只是将最终的文本拷贝到文件中,使得它可以立即被编译。 清单 2. 源文件内容 #include "foobar.h" void main(void) { } 安装 安装和使用 ccache 并不像您可能想像的那样复杂。它不会取代或者以任何方式影响您原来的使用编译器的方式,而是担当了您与您的编译器之间的一个接口,所以您可以根据需要选择 是否使用它。要安装 ccache,需要从 Samba 小组或者一个本地镜像(参阅本文最后的 参考资料)直接源文件。解压出文件的内容: $ bunzip2 -c ccache-2.3.tar.bz2|tar xf - 切换到那个目录: $ cd ccache-2.3 配置: $ ./configure 编译: $ make 最后,安装 ccache: $ make install 您就准备好开始使用了! 部署 如上所述,ccache 在您与您的普通编译器之间进行工作。以 gcc 为第一个参数调用 ccache,而不是调用 gcc。例如,要在命令行中编译一个文件,您通常会使用: $ gcc foo.c 要使用 ccache,您应该输入: $ ccache gcc foo.c 像这样对一个文件进行单独的编译,尤其是第一次使用 ccache 编译那个文件时,您将不会看到有任何的帮助,因为编译信息还没有被高速缓存。所以,配置 ccache 永久地取代主要编译器通常来说更为有效。设置 CC 环境变量的值来完成这一任务: $ export set CC='ccache gcc' 如果您只是想为一个项目启用 ccache,比如说编译 Perl 等第三方工具时,那么您或者可以使用环境变量,或者可以告知配置脚本或 make 命令使用哪个 C 编译器。 控制高速缓存 默认情况下,ccache 使用当前用户主目录中的一个目录($HOME/.ccache)来保持高速缓存信息。在团队环境中,您应该使用一个集中的位置来进行高速缓存,这样在编译 过程中每个人都可以使用高速缓存的信息。另一个环境变量 CCACHE_DIR 指定了高速缓存目录的位置。在单机环境中,将这个环境变量设置为一个每一个需要它的人都可以访问的目录。使用通过 tmpfs 挂载的目录可以获得更高的速度,前提是您得有支持这一功能的器。您的速度可能会再提高 10% 到 25%。 如果您是在网络中多台机器上使用 ccache,那么要确保您共享的目录要通过 NFS 导出(export)并挂载到每一个客户机上。如果您希望获得额外的加速,同样可以使用 tmpfs 文件系统。 另外的一些选项让您可以更深入地控制高速缓存设置: CCACHE_LOGFILE 环境变量定义了使用高速缓存时生成的日志文件所处的位置。 在 ccache 中使用 -s 命令行选项来获得关于高速缓存性能的统计数据(见清单 3)。 使用 -M 命令行选项来设置高速缓存的最大大小。默认是 1GB。高速缓存的设置会写入到高速缓存目录,所以您可以让不同的用户和组在不同的位置拥有不同大小的高速缓存。 -F 选项设置高速缓存目录的最大文件数目,按 16 进制舍入。和 -M 相同,只是当您希望改变配置的时候才需要使用它。 -c 选项清空缓存。您通常不需要使用这个选项,因为 ccache 在执行过程中会更新信息,但是,如果您要重用一个没有为某个文件所使用的高速缓存目录,那么就应该尝试使用这个选项。 -C 选项完全清空高速缓存。 清单 3. ccache 高速缓存统计数据 cache hit 44 cache miss 152 called for link 107 compile failed 11 no input file 2 files in cache 304 cache size 8.8 MB max cache size 976.6 MB 一旦设置了初始化选项并配置了期望的目录和高速缓存大小,就不需要再做任何改动。没有必要执行任何日常的维护。 组合 ccache 和 distcc 您可能已经想到了 distcc 这一来自 Samba 小组的另一个工具,它让您可以将编译过程分布到多台机器上。只需要为 make 添加多任务选项(使用 -j 命令行选项),它就可以有效地提高同步编译的数目。distcc 系统的工作方式是,每台主机上有一个后台进程,接收最终预解析格式的源文件,然后在本地进行编译,返回生成的对象文件。 如果使用得当,在每加入一个新的同样节点时,编译时间通常应该会以稍微低于线性的比率下降,不过您将只会在那些远不只一个源文件的项目上看到这样的影响,因为 distcc 只是分布全部源文件。 由于 distcc 所分布的是解析过的文件,所以您可以组合 ccache,它可以加速 C 预处理过程部分,同时 distcc 可以完成到对象代码的实际编译。要以这种方式来使用 distcc 和 ccache,需要在主机上配置 distcc,在主要的开发机器上配置 distcc 和 ccache。 现在在希望要编译项目的机器上设置环境变量,如清单 4 所示。 清单 4. 使用 ccache 和 distcc 所需要的环境变量 export set DISTCC_HOSTS='localhost atuin nautilus pteppic kernel' export set CCACHE_DIR=/Data/Cache/CCache export set CCACHE_PREFIX=distcc export set CCACHE_LOGFILE=/Data/Cache/CCache.log export set CC='ccache gcc' 环境变量定义如下: DISTCC_HOSTS 指定了将工作分布到哪些主机。 CCACHE_DIR 指定了高速缓存目录的位置。 CCACHE_PREFIX 定义了当 ccache 调用真实的编译器来编译源文件(预处理之后)时所使用的前缀。 CC 设置首先使用的 C 编译器的名称(ccache)。 现在,当运行 make 时,如果使用了 -j 选项来指定要执行的同步编译的数目,则首先使用 ccache 解析文件(如果需要,使用高速缓存),然后将其分布到某个 distcc 主机。 尽管 distcc 加速了编译过程,但是它没有改变环境的基本限制。例如,您不应该将 make 执行的同步作业的数目设置得大于可用 CPU 数目的两倍。例如,如果您有四台两路机器,那么将作业值设置为超过 16 的值时将不再会观察到有多大改善。 统计数据 既然一切都已就绪,现在可以观察它带来了多大的差别。在这里,我已经运行了一系列编译 Perl 的测试。我们需要编译一个足够大的项目,因为 ccache 在高速缓存了解析过的头时运转效果最好。这正是在完成了标准配置(使用 configure.gnu)以后的 make 阶段,它包括所有的步骤,甚至那些与编译代码无关的步骤。这些与编译器无关的操作不会影响整体上的统计数据。 如前所述,在第一次 编译时,ccache 的影响不会为人所察觉。不同之处在于重新编译时,在这个过程中您会重用先前的预处理程序。通过简单地接触(touch)主要 Perl 源目录中的 C 源,得到了表 1 中的重新编译时间。其中包括使用普通 gcc、ccache+gcc、ccache+distcc+gcc 所需的编译时间,编译在一个四节点中进行并选用了不同的并发 distcc 作业数目值。 表 1. 重新编译时间 环境 时间 gcc(第一次运行) 8m02.273s gcc(重新编译) 3m30.051s ccache+gcc(第一次运行) 8m54.714s ccache+gcc(重新编译) 0m45.455s ccache+distcc+gcc -j4 4m14.546s ccache+distcc+gcc -j4(重新编译) 0m38.985s ccache+distcc+gcc -j8 3m13.020s ccache+distcc+gcc -j8(重新编译) 0m34.380s 只是使用了 ccache,编译 Perl 就节省几乎 3 分钟(2 分 45 秒)的时间,所有的原因只是,ccache 已经保持了头的预编译版本,因而不需要再为每个源不断重复运行 cpp。将 distcc 引入这一过程所得的结果是,整体上速度提高,重新编译的时间快了一点点。 |