ccache是“compiler cache”的缩写,是一个gcc/g++的c语言编译器缓存。它加快了编译速度,特别是对于重复编译相同文件的情况,主要是通过缓存以前的编译并检测是否相同来重新编译。
ccache 是免费软件,发布于 GNU 通用公共许可证(版本3或更高版本)。
ccache的作用和优势:
ccache会将每次编译的输出结果缓存起来 ,当下次遇到相同的编译任务时,会直接使用缓存中的结果,而不需要重新编译,从而节省时间。
通过避免重复编译相同文件,ccache可以显著加快编译过程,尤其是对于大型项目或需要频繁修改和构建的代码来说,效果尤为明显。
由于避免了大量的重复编译操作,使用ccache能够减轻系统的负担,降低了CPU和磁盘等资源的占用。
ccache可以用于任何支持C、C++和类似语言的编译器。
简言之,ccache通过在单个gcc编译命令级别对本次编译产物进行压缩并存储到缓存目录中。下次发现相同编译命令且未修改源文件时,直接使用缓存中的结果,省去编译时间,从而优化了编译时长。在项目工程中,一次代码修改通常只涉及少量源文件,因此ccache只需重新编译修改的部分,而未变动的源文件可直接使用缓存,进一步优化了编译时长。
CCache加速编译的流程图原理示意图:
这个流程图描绘了CCache在编译过程中的工作原理:
ccache可以通过apt直接安装,也可以通过源码安装。
(1)通过apt直接安装:
# 先更新apt包管理器的软件包列表
sudo apt update
# 进行ccache的安装
sudo apt install ccache
(2)开源软件的迭代较快,apt源并不能实时同步最新版本,可通过源码编译安装的方式,获取最新版本。通过源码安装:
从ccache的官方网站下载最新版本的ccache源代码压缩包。比如Linux X86-64版本:wget https://github.com/ccache/ccache/releases/download/v4.9/ccache-4.9-linux-x86_64.tar.xz
。
将下载的压缩包解压缩到一个目录。比如tar -zxvf ccache-4.9-linux-x86_64.tar.xz
。
进入解压后的ccache源代码目录并使用以下命令开始编译和安装ccache:
./configure
make
sudo make install
查看ccache版本:
ccache -V
ccache具有丰富的配置选项和参数,可以通过配置文件或命令行参数进行设置。
配置文件选项:
max_size
:指定ccache缓存目录的最大尺寸,默认为 5GB。cache_dir
:指定ccache缓存的目录位置。umask
:设置以八进制表示的缓存文件的umask值。compression
:配置文件压缩级别,可以是 0(无压缩)到 9(最大压缩)。direct_mode
:启用或禁用直接模式,用于在多个机器上共享缓存。sloppiness
:用于控制ccache的宽松模式,可以包括文件时间戳宽松、编译器错误宽松等选项。命令行参数:
-c, --cleanup
:清理过期的缓存文件。-M, --max-size=SIZE
:设置ccache缓存目录的最大尺寸。-s, --show-stats
:显示ccache的统计信息。-z, --zero-stats
:将ccache的统计信息清零。-C, --clear
:清除ccache的全部缓存。其他常用参数:
--config
:手动指定ccache的配置文件。-E, --set-config=CONFIG
:设置指定的配置选项。-F, --cleanup-timeout=SECS
:设置清理过期缓存文件的超时时间。-I, --skip-includes
:忽略包括导入的文件。-S, --skip-sloppiness
:禁用宽松模式。使用ccache跑一个工程的时候,如果不注意标准输出内容,就比较难判断本次编译是否使用了ccache。ccache提供了查询缓存命中能力更好的判断当前工程有没有使用ccache:
ccache -s -v
输出:
root@hecs-274489:~/workspace/learning# ccache -s -v
Summary:
Cache directory: /root/.cache/ccache
Primary config: /root/.config/ccache/ccache.conf
Secondary config: /etc/ccache.conf
Stats updated: Thu Jan 18 17:51:21 2024
Hits: 1 / 2 (50.00 %)
Direct: 1 / 2 (50.00 %)
Preprocessed: 0 / 1 (0.00 %)
Misses: 1
Direct: 1
Preprocessed: 1
Uncacheable: 7
Primary storage:
Hits: 2 / 4 (50.00 %)
Misses: 2
Cache size (GB): 0.00 / 5.00 (0.00 %)
Files: 2
Uncacheable:
Called for linking: 5
Unsupported source language: 2
可以详细的看到:
在实际工程当中,可能是由Makefile或者CMake进行管理编译,不可能手动修改所有的编译命令,我们应该将ccache使用上呢?
这时候需要对编译工具和环境进行相应的配置。不同编译环境下使用ccache的方法:
(1)在Makefile中使用ccache。打开Makefile文件,找到编译命令的位置。将编译命令前加上ccache,例如:
CC=ccache gcc
CXX=ccache g++
(2)在CMake中使用ccache。在CMakeLists.txt中设置CMAKE_CXX_COMPILER
和CMAKE_C_COMPILER
变量为ccache,例如:
set(CMAKE_CXX_COMPILER "ccache g++")
set(CMAKE_C_COMPILER "ccache gcc")
(3)在Autotools中使用ccache。
AC_PROG_CCACHE
宏。(4)在Visual Studio中使用ccache
最为常用的方式是:无论是在Makefile还是Cmake都可以通过声明环境变量的方式来使用ccache。
# 在构建脚本中增加
export CC="ccache gcc"
export CXX="ccache g++"
# 再进行编译make/cmake
make
# cmake:
cmake -B output && cmake --build output
为了在日常编译中可以轻松使用ccache,可以将ccache伪装成编译器,比如:
# 找到ccache的安装路径
which ccache
# 安装实际路径为: /usr/bin/ccache
# 创建软连接,将ccache伪装成g++编译器
ln -s /usr/bin/ccache g++
# 使用伪装后的g++ 进行编译
./g++ -c hello.cpp -o hello.o
小试牛刀:使用ccache编译一个简单的cpp。
(1)没有使用ccache的编译:
root@hecs-274489:~/workspace/learning# time g++ -c test.cpp -o test.o
real 0m0.466s
user 0m0.385s
sys 0m0.080s
(2)首次通过ccache 进行编译:
root@hecs-274489:~/workspace/learning# time ccache g++ -c test.cpp -o test.o
real 0m0.538s
user 0m0.477s
sys 0m0.062s
(3)二次通过ccache 进行编译:
root@hecs-274489:~/workspace/learning# time ccache g++ -c test.cpp -o test.o
real 0m0.012s
user 0m0.005s
sys 0m0.005s
编译方式 | 编译时长 |
---|---|
原始构建 | 0.466s |
使用ccache首次构建 | 0.538s |
使用ccache二次构建 | 0.012s |
结论:首次使用ccache会对编译命令做缓存处理需要花费一些耗时,结果显示使用ccache首次编译时长 > 原始编译时长 >> 使用ccache二次编译时长
实验的硬件环境信息:
# lshw -short
H/W path Device Class Description
=====================================================
system OpenStack Nova
/0 bus Motherboard
/0/0 memory 96KiB BIOS
/0/400 processor Intel(R) Xeon(R) Gold 6161 CPU @ 2.20GHz
/0/1000 memory 4GiB System Memory
/0/1000/0 memory 4GiB DIMM RAM
/0/100 bridge 440FX - 82441FX PMC [Natoma]
/0/100/1 bridge 82371SB PIIX3 ISA [Natoma/Triton II]
/0/100/1/0 system PnP device PNP0b00
/0/100/1/1 input PnP device PNP0303
/0/100/1/2 input PnP device PNP0f13
/0/100/1/3 storage PnP device PNP0700
/0/100/1/4 communication PnP device PNP0501
/0/100/1.1 storage 82371SB PIIX3 IDE [Natoma/Triton II]
/0/100/1.2 bus 82371SB PIIX3 USB [Natoma/Triton II]
/0/100/1.2/1 usb1 bus UHCI Host Controller
/0/100/1.2/1/1 input5 input QEMU QEMU USB Tablet
/0/100/1.3 bridge 82371AB/EB/MB PIIX4 ACPI
/0/100/2 /dev/fb0 display GD 5446
/0/100/3 network Virtio network device
/0/100/3/0 eth0 network Ethernet interface
/0/100/4 bridge QEMU PCI-PCI bridge
/0/100/5 bridge QEMU PCI-PCI bridge
/0/100/5/1 storage Virtio block device
/0/100/5/1/0 /dev/vda disk 42GB Virtual I/O device
/0/100/5/1/0/1 /dev/vda1 volume 39GiB EXT4 volume
/0/100/6 bridge QEMU PCI-PCI bridge
/0/100/7 bridge QEMU PCI-PCI bridge
/0/100/8 bridge QEMU PCI-PCI bridge
/0/100/9 bridge QEMU PCI-PCI bridge
/0/100/a bridge QEMU PCI-PCI bridge
/0/100/b bridge QEMU PCI-PCI bridge
/0/100/c communication Virtio console
/0/100/c/0 generic Virtual I/O device
/0/100/d generic Virtio memory balloon
/0/100/d/0 generic Virtual I/O device
/1 input0 input Power Button
/2 input1 input AT Translated Set 2 keyboard
/3 input3 input VirtualPS/2 VMware VMMouse
/4 input4 input VirtualPS/2 VMware VMMouse
工程项目:stressapptest和muduo。
工程项目:stressapptest。
原始直接make:
real 0m11.902s
user 0m10.161s
sys 0m1.656s
找到src/Makefile
中的CC
和CXX
,并将它们更改为:
CC = ccache gcc
CXX = ccache g++
ac_ct_CC = ccache gcc
ac_ct_CXX = ccache g++
make clean后使用ccache首次编译:
real 0m13.912s
user 0m11.942s
sys 0m1.892s
make clean后使用ccache二次编译:
real 0m0.444s
user 0m0.317s
sys 0m0.125s
编译方式 | 编译时长 |
---|---|
原始构建 | 11.902s |
使用ccache首次构建 | 13.912s |
使用ccache二次构建 | 0.444s |
可以看到,使用ccache二次编译的速度提升了96%左右。
工程项目:muduo。
muduo的依赖项安装:
#安装cmake
sudo apt-get install cmake
#安装boost
sudo apt-get install libboost-dev libboost-test-dev
#三个非必须的依赖库:curl、c-ares DNS、Google Protobuf (安装之后cmake会自动多编译一些示例)
sudo apt-get install libcurl4-openssl-dev libc-ares-dev
sudo apt-get install protobuf-compiler libprotobuf-dev
原始直接cmake:
time ./build.sh
执行时间:
real 4m36.686s
user 4m2.975s
sys 0m33.327s
清除之前的构建,除了在CMakeLists.txt中添加ccache,也可以在构建脚本中增加如下的语句(比如在build.sh中):
export CC="ccache gcc"
export CXX="ccache g++"
使用ccache首次编译:
real 5m14.653s
user 4m33.229s
sys 0m41.105s
清除上次构建内容后后使用ccache二次编译:
real 0m34.869s
user 0m22.974s
sys 0m10.292s
编译方式 | 编译时长 |
---|---|
原始构建 | 4m36.686s |
使用ccache首次构建 | 5m14.653s |
使用ccache二次构建 | 34.869s |
可以看到,使用ccache二次编译的速度提升了87%左右。
ccache会自动清理较长时间未访问的缓存文件,使用LRU(最近最少使用)算法,以确保缓存文件总大小不超过指定的缓存大小。不要手动删除缓存目录下的文件,因为这可能会导致缓存丢失。
如果默认的缓存目录会占用过多磁盘空间,可以通过在/etc/profile中增加ccache的环境变量配置来改变缓存目录,并使其持续生效,从而解决磁盘空间不足的问题。
# 将ccache的缓存目录设置为了/home/fly/ccache
vim /etc/profile
# 追加环境变量
export CCACHE_DIR=/home/fly/ccache
# 让环境变量生效
source /etc/profile
ccache的局限性与不足:
ccache使用本地磁盘缓存编译结果,缓存大小受限于本地磁盘空间,如果缓存空间不足,会导致编译结果被清理,从而影响编译速度。
ccache的缓存命中率取决于项目中文件的变化情况,如果项目文件频繁变动,将降低缓存命中率,无法发挥其应有的性能优势。
ccache只能用于本地编译环境中,无法在分布式编译环境中发挥作用。
ccache只能缓存完整的编译结果,对于中间生成的对象文件等无法实现缓存。
ccache主要是为支持标准构建系统而设计的,对于非标准构建系统的支持有限。
新的编译加速技术对ccache的影响:
新的编译加速技术提供更有效的缓存机制,提高缓存命中率,减少重新编译的次数。这将提高ccache的效率并增强其在编译加速中的地位。
一些新的编译加速技术支持更好的多核并行编译,使得编译过程更加快速。这减少ccache在编译速度方面的优势,因为编译速度本身已经得到改善。
新的技术会涉及构建缓存,即缓存构建过程中产生的中间输出,使得编译可以更快地进行。而ccache目前主要关注源码层面的缓存。
对于重复编译,无论是单命令编译,还是实际工程编译,使用ccache构建速度都极大的提升了编译效率。
ccache通过缓存已经编译过的对象文件,可以大大减少重复的编译工作。帮助减轻大型项目的编译负担,节约开发过程中的计算资源和成本。