
1. 写在前面为什么要在 Ubuntu 下亲自编译 Cairo 库直接说结论如果你的项目只是需要调用 Cairo 的 API 画点图、做个简单标注运行sudo apt install libcairo2-dev就够了没必要往下看。但如果你遇到的是下面这几种情况那从源码编译 Cairo 就是绕不开的路需要静态链接 Cairo让最终的可执行文件不依赖目标机器上的动态库需要裁剪编译参数关闭用不到的 surface 后端减少依赖面需要固定一个特定版本避免系统升级导致渲染行为变化需要把 Cairo 移植到嵌入式平台或写进交叉编译工具链。我自己这次的实际场景是希望得到一个纯静态、可独立分发的 Cairo 库方便后续在另一个环境里直接链接使用。所以我选择了官方 tarball 自编译路线也建议有同样需求的人按这个思路走。这篇文章把我从零开始编译 Cairo 的全过程、踩过的坑、以及每个关键参数为什么这么选都写清楚。不管是第一次在 Ubuntu 下编译 Cairo 的新手还是被各种依赖报错折磨过、想系统搞明白编译原理的朋友都能从这里找到可操作的步骤。需要补充一点我不是在讲“如何做一个大项目”而是在讲“如何把 Cairo 这个库老老实实编出来”。它本身不复杂但涉及的工具链、依赖探测、pkg-config 机制、静态链接参数这些点理解透了才能避开后面一堆奇怪问题。2. 编译前的环境准备与依赖分析2.1 工具链的确认gcc、make、pkg-config 一个都不能少Ubuntu 下编译 C 库第一件事不是下载源码而是确认工具链已经就绪。Cairo 虽然不要求最新的编译器但某些版本对 GCC 的最低版本有要求。我建议直接安装完整的构建工具包sudo apt update sudo apt install -y build-essentialbuild-essential会带上 gcc、g、make 以及一些基础的头文件。如果你在容器环境下编译这个包尤其重要因为最小化容器往往连 gcc 都没有。另外别忽略了pkg-config。这个词在后文会反复出现它是整个依赖探测系统的核心。Cairo 的 configure 脚本靠它去查询 FreeType、Fontconfig、libpng、pixman 等依赖库是否存在、版本是否够新。没有 pkg-config或者它不工作configure 会以为你的系统里什么都没装。注意pkg-config本身是一个工具不是某个库。它通过读取.pc文件来获取库的头文件路径和链接参数。如果你发现某个库明明装了但 configure 就是探测不到第一反应不要怀疑库先怀疑 pkg-config 的搜索路径。确认工具链是否就绪gcc --version g --version make --version pkg-config --version这四个命令都正常输出版本号说明基础环境没问题。接下来就是处理 Cairo 的依赖关系。2.2 依赖项解析pixman、FreeType、Fontconfig、libpng 各自是干什么的Cairo 是一个 2D 图形库但它不是孤岛它需要依赖一票底层库。很多人在 Ubuntu 下编译 Cairo 失败不是 Cairo 本身的编译问题而是依赖库没装对。搞清楚每个依赖的作用装起来才有方向。pixman 是最核心的底层依赖负责像素级的图像合成、渐变填充、抗锯齿光栅化等操作。可以把它理解为 Cairo 的“渲染引擎”之一。Cairo 编译时如果找不到 pixmanconfigure 会直接拒绝继续。FreeType 和 Fontconfig 是文字渲染的两件套。FreeType 负责读取字体文件、解析字形轮廓、生成位图Fontconfig 负责字体发现、字体匹配、以及读系统字体配置。Cairo 绘制文字时先让 Fontconfig 找到最匹配的字体再由 FreeType 把字形转成可渲染的轮廓。如果你只在 Cairo 里画矩形、画线条这两个库可以不开但只要涉及文字标注、文本展示它们就是必须的。libpng 则是 Cairo 把渲染结果输出为 PNG 图片时要用到的编码库。Cairo 的 image surface 本身只处理像素缓冲区要保存成图片文件需要 libpng 来做 PNG 编码。依赖关系理清后安装命令就明确了sudo apt install -y pkg-config sudo apt install -y libpixman-1-dev sudo apt install -y libfreetype6-dev libfontconfig1-dev sudo apt install -y libpng-dev libjpeg-dev zlib1g-dev注意这里的-dev后缀。Ubuntu 的软件包体系里同一个库会拆成运行时包和开发包。运行时包只包含.so文件和二进制比如libpng12-0开发包则包含头文件和编译链接所需的符号文件比如libpng-dev。编译 Cairo 需要的是开发包。很多人configure时报“找不到 libpng”或“cannot find header”多半就是只装了运行时包没装开发包。2.3 用 pkg-config 提前验证依赖是否齐全依赖装完后先不要急着 configure写一个小脚本把所有关键依赖过一遍。这能帮你提前暴露问题省得在 configure 阶段被一个“no”卡住。for pkg in cairo freetype2 fontconfig x11 pixman-1 libpng libjpeg zlib glib-2.0; do echo $pkg pkg-config --modversion $pkg 2/dev/null || echo not found done正常输出应该是一个个版本号。如果某个包显示not found说明它的 dev 包还没装或者 pkg-config 的搜索路径没覆盖到它。这里还要提醒一句pkg-config 里使用的库名如freetype2、pixman-1与 apt 包名如libfreetype6-dev、libpixman-1-dev不是一一对应的不要因为包名不同就以为装错了。3. 编译方案选型与源码下载3.1 自编译与系统包三种方案的取舍在 Ubuntu 下获得 Cairo 库其实有两条很简单的路我在开头也提过。这里把完整决策逻辑写出来大家可以根据自己情况选。方案一sudo apt install libcairo2-dev。这是最快的方式直接拿来开发大多数场景都够用。缺点是你只能接受发行版编译时固定的参数比如 Cairo 默认开启哪些后端、是否生成静态库、依赖哪些版本的系统库。方案二安装源码包后执行dpkg-buildpackage重新构建。这种方式能拿到发行版修补过的源码适合想微调编译参数的人。缺点是需要拉取整套构建依赖环境配置繁琐而且最终生成物还是发行版风格的包跟前一种方案的收益差距不大。方案三官方源码自编译。自由度最高可以指定编译参数、安装目录、开启或关闭后端也可以只生成静态库。缺点是需要自己处理依赖后续更新也要自己跟进新版本。我做自编译的核心动机是需要一个纯静态的 Cairo 库同时关闭 X11 等用不到的后端。系统预编译包做不到这一点重编发行版源码包也绕不开它的参数限制所以只能走第三条路。提示如果你不确定自己是否需要自编译最简单判断标准是你是否有任何“必须设置为非默认”的需求。如果没有直接 apt 安装就好。3.2 源码版本与下载地址确认Cairo 的官网发布页在cairographics.org/releases/所有正式版本和开发版本都在这里。选择版本时建议选最新的稳定 release。截止写作时Cairo 主线已经到 1.18.x 系列具体版本号请以官网为准不要使用-rc或-git版本它们不适合作为基准环境。下载并解压cd /opt/build wget https://cairographics.org/releases/cairo-1.18.0.tar.xz wget https://cairographics.org/releases/cairo-1.18.0.tar.xz.sha1 sha1sum -c cairo-1.18.0.tar.xz.sha1 tar -xJf cairo-1.18.0.tar.xz cd cairo-1.18.0这里有个小细节tar -xJf是解压.tar.xz格式如果是.tar.gz应该用tar -xzf。别小看这个字母解压失败时的报错几乎都是“文件格式无法识别”。解压后我先看一眼README和NEWS文件。这两个文件记录了当前版本的功能变化尤其 NEWS 文件会列出默认启用的后端、新增的 API 和废弃的行为。对于老项目升级来说这个信息比任何博客教程都准确。3.3 configure 参数详解与裁剪策略进入源码目录后先运行一次./configure --help不要跳过这步。它会把所有可配置项完整列出来相当于官方字典。重点看几类与 surface 后端相关的--enable-*和--disable-*与文字渲染相关的--enable-freetype、--enable-fontconfig安装路径相关--prefix静态/动态库相关选项。我自己实际使用的配置组合如下./configure \ --prefix/opt/cairo \ --enable-static \ --disable-shared \ --with-xno \ --enable-pdfyes \ --enable-pngyes \ --enable-freetypeyes \ --enable-fontconfigyes \ --enable-svgyes逐项解释为什么这么选--prefix/opt/cairo指定独立安装目录。这样头文件、库文件、pkg-config 文件都集中在一个地方之后不需要了删除整个目录即可不会污染系统。--enable-static --disable-shared本次目标是静态库所以只编静态版本。得到的.a文件在链接阶段直接打进可执行文件目标环境不需要额外安装 Cairo 动态库。--with-xno本机不涉及 X11 窗口渲染关闭 X11 后端减少依赖检查。--enable-pdfyes保留 PDF 后端。哪怕当前项目没用到后续做报表导出时能用上。--enable-pngyesPNG 是光栅化验证的重要手段。image surface 输出成 PNG 后可以快速查看渲染结果是否正确。--enable-freetypeyes --enable-fontconfigyes项目里需要绘制文字标注必须保留文本渲染能力。--enable-svgyes保留 SVG 输出便于生成矢量结果做差异比较。有一点要提醒--enable-static和--disable-shared同时使用会导致只生成.a文件不生成.so文件。如果后续你还需要链接动态库这两个选项就不要一起用。配置之前想清楚最终交付形态是静态集成还是动态加载。configure 输出结束后会生成Makefile和config.h。config.h是编译过程中的核心配置头文件Cairo 的代码会根据它决定启用哪些代码路径。千万不要手动编辑这个文件一旦重新执行 configure 就会被覆盖。如果你需要调整宏定义应该在 configure 阶段通过参数完成。4. 正式编译与安装4.1 configure 执行与输出解读配置命令执行后耐心看完输出不要一路扫到底。重点看关键的几项配置是否被正确探测到checking for X11... no checking for FreeType... yes checking for Fontconfig... yes checking for PNG support... yes如果 X11 显示 no说明关闭成功FreeType、Fontconfig 显示 yes说明依赖探测成功PNG 显示 yes说明 libpng 正确被找到。如果 PNG 显示 no但你确实安装了libpng-dev那多半是 pkg-config 的路径问题参考后面第 6 章的排查方法。configure 本身一般几十秒到一两分钟就能完成。如果长时间卡住或者某一项一直在测试网络优先检查本地环境是否满足要求。configure 阶段是最容易出错的阶段但绝大多数错误都是由于依赖缺失或版本过低引起的错误信息通常会给得很明确。4.2 make 编译过程与常见异常定位configure 通过后执行make -j$(nproc)-j$(nproc)表示用 CPU 的全部核心并行编译。Cairo 源码不算特别大完整编译在我的机器上大概一两分钟。并行编译时注意观察是否有报错。编译中常见的异常和处理方式找不到头文件比如pixman.h先确认libpixman-1-dev是否安装再确认pkg-config --cflags pixman-1是否能输出头文件路径。undefined reference to系列错误通常是链接阶段缺少某些库重点检查编译命令里是否有遗漏的-l参数。内联汇编相关的错误或__attribute__不支持多见于用较老版本的 GCC 编译新版 Cairo建议升级 GCC 或换用系统默认 GCC 版本。这类问题的大多数根因是依赖库路径不在默认搜索范围内。如果你把库装到了非标准路径比如/opt/cairo之外的某个地方需要手动设置PKG_CONFIG_PATHexport PKG_CONFIG_PATH/opt/cairo/lib/pkgconfig:$PKG_CONFIG_PATH设置完再重新运行 configure 或 make很多“找不到头文件”的问题会直接消失。这是一个几乎每个编库的人都会遇到的坑。4.3 make install 与安装后的目录核对编译通过后执行sudo make install如果--prefix指定的目录没有写权限就需要加 sudo。装完后检查目录结构ls /opt/cairo/lib ls /opt/cairo/include ls /opt/cairo/lib/pkgconfig正常情况会在lib下看到libcairo.a静态库include下看到cairo.h和一系列cairo-*.h头文件lib/pkgconfig下看到cairo.pc。cairo.pc文件是整个安装里最重要的文件之一。它记录了三组关键信息prefixCairo 安装根目录Libs和Libs.private链接时需要的库参数Cflags编译时需要的头文件路径。尤其是Libs.private静态链接时会用到。Cairo 静态库本身不包含那些后端实现链接器需要知道 libcairo.a 内部引用了哪些其他库比如-lpixman-1、-lfreetype、-lfontconfig。pkg-config --static --libs cairo会把Libs和Libs.private一并输出直接供编译命令使用。5. 验证编译结果与链接测试5.1 用 pkg-config 验证库可用性编译安装完成后不要急着写业务代码先做一轮最小验证。第一步就是确认 pkg-config 能识别新安装的 Cairoexport PKG_CONFIG_PATH/opt/cairo/lib/pkgconfig pkg-config --modversion cairo pkg-config --cflags --libs cairo pkg-config --static --libs cairo第一行输出版本号第二行输出编译和动态链接参数第三行在静态链接时使用会额外输出Libs.private中的依赖库。如果你忘记了PKG_CONFIG_PATH的设置pkg-config --modversion cairo很可能返回系统自带版本或直接报 not found。这是最容易让新手误以为“库没装成功”的时刻其实库就在那里只是 pkg-config 没找到它。5.2 最简编译链接示例写一个最简单的程序验证自编译的 Cairo 库真的能用。创建一个 320x240 的 ARGB32 图像画布用白色填充背景绘制一条蓝色横线输出为 PNG#include cairo.h #include math.h int main(void) { cairo_surface_t *surface cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 320, 240); cairo_t *cr cairo_create(surface); cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); cairo_paint(cr); cairo_set_source_rgb(cr, 0.2, 0.4, 0.9); cairo_move_to(cr, 30, 120); cairo_line_to(cr, 280, 120); cairo_set_line_width(cr, 4.0); cairo_stroke(cr); cairo_surface_write_to_png(surface, test.png); cairo_destroy(cr); cairo_surface_destroy(surface); return 0; }编译命令gcc test.c -o test \ $(pkg-config --cflags --libs cairo)运行时如果生成test.png且没有报错说明 Cairo 的链接和运行都没问题。查看 test.png应该是白色背景中央有一条平滑的水平线。如果运行时报error while loading shared libraries: libcairo.so.2: cannot open shared object file说明你链接的是自编译动态库但系统加载器不知道新库路径。解决办法是把/opt/cairo/lib加入动态库搜索路径export LD_LIBRARY_PATH/opt/cairo/lib:$LD_LIBRARY_PATH ./test这个报错在静态链接场景不会出现因为静态库已经打进可执行文件。但如果你编的是动态库这一步不可避免。如果不想每次手动 export可以在/etc/ld.so.conf.d/下新建配置文件并写入库路径然后执行sudo ldconfig让系统持久记住该路径。5.3 功能验证绘制 PNG 与检查输出文件最小示例只验证了基本绘图路径。我会再跑一段覆盖更多功能的验证代码重点检查文本渲染和渐变效果#include cairo.h #include math.h int main(void) { cairo_surface_t *surface cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 400, 300); cairo_t *cr cairo_create(surface); cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); cairo_paint(cr); cairo_pattern_t *grad cairo_pattern_create_linear(0, 0, 400, 300); cairo_pattern_add_color_stop_rgb(grad, 0.0, 0.2, 0.6, 1.0); cairo_pattern_add_color_stop_rgb(grad, 1.0, 1.0, 0.4, 0.2); cairo_rectangle(cr, 50, 50, 300, 200); cairo_set_source(cr, grad); cairo_fill(cr); cairo_pattern_destroy(grad); cairo_select_font_face(cr, Sans, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); cairo_set_font_size(cr, 28); cairo_set_source_rgb(cr, 0, 0, 0); cairo_move_to(cr, 20, 45); cairo_show_text(cr, Hello Cairo); cairo_surface_write_to_png(surface, test_full.png); cairo_destroy(cr); cairo_surface_destroy(surface); return 0; }重点检查test_full.png是否出现平滑渐变和文字。文字能正常显示说明 FreeType 和 Fontconfig 链路没问题渐变正常说明 image surface 的合成路径正常。如果文本没有显示但颜色矩形正常问题大多出在字体配置。可以先用fc-list | head查看系统字体列表如果没有输出或系统压根没装字体文字渲染会静默失败不会报错只会画不出来。测试机至少要装一种基础字体比如sudo apt install -y fonts-dejavu-core6. 常见问题与排查经验6.1 依赖探测失败pkg-config 与 PKG_CONFIG_PATH这个问题的出场率最高几乎十个编译报错里有一半都跟它相关。症状是 configure 输出中某个依赖显示 no或者编译时头文件找不到、链接库失败但库明明已经安装。产生这个现象的原因几乎都是 pkg-config 没找到对应的.pc文件。我的排查步骤是固定的用pkg-config --list-all | grep 库名确认该库的 pc 文件是否可见用pkg-config --debug针对具体库名输出去向检查PKG_CONFIG_PATH是否包含该 pc 文件所在目录检查 pc 文件是否存在并可读。例如export PKG_CONFIG_PATH/opt/cairo/lib/pkgconfig pkg-config --debug cairo 21 | head -20如果输出里没有/opt/cairo/lib/pkgconfig说明环境变量没生效。注意 pkg-config 默认搜索路径是/usr/lib/pkgconfig、/usr/share/pkgconfig等其他路径一律靠PKG_CONFIG_PATH手动补充。这条经验在安装任何第三方库时都适用不限于 Cairo。6.2 configure 提示版本过低或找不到版本号Cairo 的 configure 脚本对版本号有强校验。比如 pixman 版本低于要求会直接终止并给出明确提示。排查方向先看系统版本pkg-config --modversion pixman-1如果版本确实低sudo apt install libpixman-1-dev更新如果 pkg-config 找不到 pixman-1检查是否是安装包名过旧旧版 Ubuntu 的包名可能是libpixman1-dev如果是源码编译了更高版本 pixman确保PKG_CONFIG_PATH指向新版本的 pc 文件。有一个容易被忽略的点pkg-config 找到的第一个同名 pc 文件会直接生效不会合并两个目录的同名库。如果你在/usr/local和/opt各装了一份 pixman一定要确认PKG_CONFIG_PATH里的目录顺序。顺序错了版本校验就可能失败。6.3 动态库运行时报找不到 .so 文件这个报错我在前面提到过处理方式也给了。这里补充两个细节第一libcairo.so.2是 Cairo 的 SONAME 版本不是文件名版本。安装后通常会有libcairo.so.2.x.x这样的具体版本文件并生成libcairo.so.2符号链接。如果make install没生成这个符号链接运行阶段就会找不到库。检查/opt/cairo/lib目录里的符号链接是否完整。第二如果系统里同时存在系统版 Cairo 和自编译 Cairo加载器会按照LD_LIBRARY_PATH顺序选择先找到的库。想确认实际加载的是哪个库ldd test | grep cairo输出会显示libcairo.so.2 /opt/cairo/lib/libcairo.so.2或系统路径。如果显示的是系统路径说明你的LD_LIBRARY_PATH没把自编译目录放在最前面。6.4 静态链接时出现未定义引用自编译静态库后编译阶段通过链接时报一堆undefined reference to pixman_...或undefined reference to FcFontSetCreate这不是你的编译出了问题而是没有把私有依赖库带全。Cairo 静态库本身不包含那些后端实现链接时需要追加对应库。正确做法是用gcc test.c -o test_static \ $(pkg-config --cflags --static --libs cairo)这个命令会输出-lcairo -lpixman-1 -lfreetype -lfontconfig -lpng -lz等一串库。如果某个依赖库缺失可以加-Wl,--verbose查看链接过程确认具体缺失符号属于哪个库然后安装对应 dev 包。还有一类容易忽略的-lm是数学库Cairo 的代码里大量使用sin、cos、sqrt等函数如果链接脚本里漏了-lm也会产生未定义引用。pkg-config --static --libs cairo的输出大概率会包含它务必保留完整参数。6.5 并行编译时的随机性失败使用make -j$(nproc)时偶尔会遇到莫名其妙的编译错误比如某个头文件生成顺序不对或者某个临时文件被过早清理。遇到这种情况先降到串行编译试一次make clean make -j1如果串行编译通过说明是并行构建的时序问题。对于 Cairo 这种成熟项目并行问题通常发生在特定旧版本或特殊文件系统上比如网络挂载目录。解决方法是尽量在本地磁盘编译不要放在 NFS 或容器共享目录里。另外重新编译前一定记得make clean增量编译遗留的中间文件可能影响后续构建结果。7. 跨场景扩展与进一步探索7.1 把自编译库集成到项目构建脚本编译完成后最有价值的事情是把pkg-config集成到自己的项目构建脚本里让项目不再依赖绝对路径手工指定头文件和库文件。一个典型的编译脚本片段export PKG_CONFIG_PATH/opt/cairo/lib/pkgconfig CFLAGS$(pkg-config --cflags --static cairo) LIBS$(pkg-config --libs --static cairo) gcc main.c $CFLAGS -o app $LIBS如果你的项目使用 CMake可以在CMakeLists.txt里这样写set(ENV{PKG_CONFIG_PATH} /opt/cairo/lib/pkgconfig) find_package(PkgConfig REQUIRED) pkg_check_modules(CAIRO REQUIRED IMPORTED_TARGET cairo) target_link_libraries(app PRIVATE PkgConfig::CAIRO)pkg_check_modules会读取cairo.pc自动处理头文件路径和库路径。注意set(ENV{PKG_CONFIG_PATH} ...)必须放在find_package之前否则 CMake 可能找到系统自带的 Cairo。如果修改过PKG_CONFIG_PATH但仍找到旧版本考虑删除CMakeCache.txt后重新配置。7.2 定制更多后端与文本支持如果后续想扩展 Cairo 的渲染能力可以重新执行 configure 并开启更多后端。常见的方向--enable-xlib在 X11 环境下直接渲染窗口表面--enable-ps输出 PostScript--enable-qt提供 Qt 后端--enable-gl接入 OpenGL 表面利用 GPU 加速渲染。新增后端不会影响已有功能重新配置编译安装即可。每次调整配置建议重新跑一遍最小示例验证新后端是否真的被编入。从实践经验来说Xlib 后端在 Ubuntu 桌面环境下最容易遇到头文件路径问题。原因是 X11 头文件通常分散在/usr/include/X11下pkg-config 不一定默认找到。如果开启--enable-xlib失败先检查libx11-dev和libxext-dev是否安装。确认后再重新 configure一般都能过。7.3 加入单元测试与回归测试Cairo 自带一套测试体系可以在编译后执行make check运行官方测试。这个步骤很有价值能验证当前编译配置下各后端是否正确工作。测试会生成大量图片通过对比output目录与reference目录的差异来判断结果。如果某些用例失败不一定意味着编译有问题也可能是在缺少字体或特定依赖环境下才失败。比如缺少某种 CJK 字体时与文字相关的测试用例就会失败但这不一定会影响你项目的实际使用。如果你在做一个依赖 Cairo 的自研项目建议把关键渲染逻辑写成回归测试。做法用 Cairo 生成一组固定输入下的 PNG提交到仓库作为基准图之后每次改版都重新生成并与基准对比。图片对比可以借助 ImageMagick 的compare命令像素差异超过阈值则视为失败。这是排查 Cairo 渲染 bug 最有效的手段之一。8. 版本、构建目录与长期维护的一些体会编译 Cairo 只是一个开始真正麻烦的是如何在长期迭代中保持一致。我的习惯是每次编译都记录下 configure 参数、系统环境版本号、依赖列表甚至保存config.log。这样半年后再回来看到当时的信息能快速定位为什么当时选择某些选项。如果你是通过源码编译并安装到了/opt/cairo想卸载也很方便删除整个目录即可。ldconfig的配置和PKG_CONFIG_PATH里相关条目手动清理一下系统就会恢复到原状。相比用 apt 安装后卸载还要担心依赖被连带删除自编译到独立目录的维护成本确实低很多。在实际使用中我遇到过不少次“项目换台机器就编译不过”的情况。根因几乎都是依赖库版本不一致。我的经验是尽量在干净的容器或独立目录里保存一份完整的编译记录包括所有相关 deb 包的版本列表dpkg -l | grep -E libcairo|libpixman|libfreetype|libfontconfig|libpng /opt/build/deps.txt保存这份文件的好处是可以在新环境里一键对比缺失或改动的依赖。对于需要长期维护的项目这比任何注释都有用。最后再分享一个细节Cairo 的官方文档和示例程序比大多数博客教程都值得读。编译完成后花点时间翻一翻官网的 API 文档能帮你更快理解 surface、context、pattern 这些核心概念的组织方式。很多看似高级的用法其实都是基础概念的组合而 Cairo 最迷人的地方恰恰在于它用少量核心对象覆盖了大量渲染场景。真正吃透它你的绘图类项目会轻松很多。