
图形学图像处理【免费下载链接】skiaSkia is a complete 2D graphic library for drawing Text, Geometries, and Images.项目地址https://gitcode.com/gh_mirrors/skia1/skia点击查看免费下载本文聚焦 Skia 仓库中 expatC 语言 XML 解析库的自定义构建配置核心讲解bazel/external/expat/config目录的组成、expat_config.h中每个宏的含义以及这套配置如何通过 Bazel 的download_config_files规则与 GN 构建系统被消费。读完本文你将掌握 Skia 为第三方库提供定制配置头文件的完整工程模式并能在升级 expat 时正确更新与验证配置。一、为什么 Skia 需要一份自定义的 expat 配置expat 是 Skia 依赖的第三方库之一用于解析 XML 数据例如 SVG 与部分字体配置场景。和大多数 C 库一样expat 在编译时需要根据目标平台的能力生成一个名为expat_config.h的配置头文件——它记录了当前环境是否具备某些系统调用、头文件、字节序等信息直接决定xmlparse.c、xmltok.c等源码编译出的行为。关联文档 用两句话点明了这套配置的本质This file represents the custom configuration of how we build expat. The files here are symlinked from //third_party/expat/include/expat_config也就是说bazel/external/expat/config/目录承载的是Skia 构建 expat 的定制配置而配置文件的真正出处源文件位于third_party/expat/include/expat_config。这样拆分的原因在于Bazel 的 external 仓库repository不能直接引用 Skia 主仓库内部的文件因此 Skia 必须把配置以独立仓库的形式提供给 expat 的 Bazel 构建。二、配置目录的四个文件各自的职责bazel/external/expat/config/目录下共四个文件文件职责README.md说明目录用途即本篇讲解的关联文档expat_config.h真正被编译消费的配置头文件约 140 行宏定义BUILD.bazel用exports_files把expat_config.h暴露给外部使用者WORKSPACE.bazel将该目录声明为独立的 Bazel workspace其中 BUILD.bazel 的内容非常简短exports_files( [ expat_config.h, ], visibility [//visibility:public], )它只做一件事把expat_config.h声明为可被其他仓库引用的导出文件且对全局可见。这保证 expat 的外部构建例如以expat_config//:expat_config.h方式引用能够拿到该文件。而 WORKSPACE.bazel 的存在原因注释解释得很清楚# This blank WORKSPACE.bazel simply indicates that this folder is a distinct Bazel workspace # from the main Skia one. This avoids a circular dependency by having Skia depend on expat # and expat trying to use configuration files from Skia.关键设计这个几乎为空的WORKSPACE.bazel把bazel/external/expat/config标记为与 Skia 主仓库相互独立的 Bazel workspace从而避免Skia 依赖 expat、expat 又反过来从 Skia 取配置的循环依赖。这是 Bazel 多仓库构建中一种典型的解耦手法。三、expat_config.h 宏定义逐项解读expat_config.h 是这份配置的核心头部注释表明它Generated from expat_config.h.in by configure——即由 expat 自带的 autoconf 流程生成再由 Skia 维护到仓库中。按其作用可分为四类1. 功能开关宏决定编译出的能力宏本仓库取值含义XML_NS1启用 XML Namespaces 功能XML_DTD1启用参数实体parameter entity解析即 DTD 支持XML_CONTEXT_BYTES1024当前解析点周围保留多少字节上下文用于错误报告与实体解析XML_DEV_URANDOM1允许从/dev/urandom读取熵用于生成随机 IDXML_ATTR_INFO未定义不启用获取属性名/属性值字节偏移的扩展 API其中XML_NS与XML_DTD对应 expat 顶层构建脚本中的--enable-xml-ns、--enable-xml-dtd选项XML_CONTEXT_BYTES对应--with-xml-context-bytes。Skia 全部开启 Namespaces 与 DTD说明其 XML 处理场景需要完整的实体与命名空间支持。2. 环境探测宏平台能力检测结果这部分记录 configure 在生成环境上的探测结果包括字节序BYTEORDER 1234小端1234 LILENDIAN头文件存在性HAVE_DLFCN_H、HAVE_FCNTL_H、HAVE_INTTYPES_H、HAVE_STDINT_H、HAVE_STDIO_H、HAVE_STDLIB_H、HAVE_STRINGS_H、HAVE_STRING_H、HAVE_SYS_PARAM_H、HAVE_SYS_STAT_H、HAVE_SYS_TYPES_H、HAVE_UNISTD_H均定义为1系统调用与函数HAVE_GETPAGESIZE 1、HAVE_MMAP 1被显式关闭的项HAVE_ARC4RANDOM、HAVE_GETRANDOM、HAVE_SYSCALL_GETRANDOM、HAVE_ARC4RANDOM_BUF、HAVE_LIBBSD均被注释掉见下文的 patch 机制标准头文件STDC_HEADERS 1。注意这里有一个重要细节当前这份expat_config.h是面向 Linux 类环境的探测结果。例如它启用了HAVE_MMAP与/dev/urandomXML_DEV_URANDOM这些在 Windows 或 iOS 等平台上并不成立。因此这份配置并不具有跨平台普适性而是Skia 在默认构建环境下为 expat 准备的基线配置。3. 字节序条件编译WORDS_BIGENDIAN文件末尾有一段针对大端处理器的条件编译逻辑#if defined AC_APPLE_UNIVERSAL_BUILD # if defined __BIG_ENDIAN__ # define WORDS_BIGENDIAN 1 # endif #else # ifndef WORDS_BIGENDIAN /* # undef WORDS_BIGENDIAN */ # endif #endif它配合BYTEORDER 1234使用默认按小端Intel 系处理同时为 Apple Universal Binary同时包含大端与瘦二进制保留运行时判定路径。这样同一份头文件在 x86 与 PowerPC/ARM 大端变体上都能得到正确的字节序语义。4. 包信息宏版本与元数据PACKAGE expat、PACKAGE_NAME expat、PACKAGE_TARNAME expatPACKAGE_STRING expat 2.5.0、PACKAGE_VERSION 2.5.0、VERSION 2.5.0PACKAGE_BUGREPORT expat-bugslibexpat.orgLT_OBJDIR .libs/libtool 未安装库的存放子目录。这些宏表明本仓库锁定的是expat 2.5.0版本一致性由 roll 脚本保证见第六节。四、配置的真身third_party/expat/include/expat_configREADME 明确说明配置目录的文件symlinked from//third_party/expat/include/expat_config。在仓库中对应的真实文件是 third_party/expat/include/expat_config/expat_config.h其内容与bazel/external/expat/config/expat_config.h完全一致140 行、所有宏定义逐字相同。之所以采用源文件放在third_party/、Bazel 侧放一份符号链接或复制的布局是因为GN 构建也需要它Skia 的 GN 构建gn工具链通过third_party/expat/BUILD.gn直接把include/expat_config加入头文件搜索路径Bazel 构建需要独立分发Bazel 的 external 仓库无法读取主仓库内任意路径所以bazel/external/expat/config必须自成一个可被下载/引用的单元。两份文件内容同步的维护工作由自动化脚本完成见第六节开发者无需手工同步。五、GN 构建如何消费这份配置在 third_party/expat/BUILD.gn 中expat 的 GN 目标这样组织declare_args() { skia_use_system_expat is_official_build } import(../third_party.gni) if (skia_use_system_expat) { system(expat) { libs [ expat ] } } else { third_party(expat) { _src ../externals/expat public_defines [ XML_STATIC ] public_include_dirs [ ../externals/expat/expat/lib, include/expat_config, ] public [ $_src/expat/lib/expat.h ] sources [ $_src/expat/lib/ascii.h, ... $_src/expat/lib/xmlparse.c, $_src/expat/lib/xmlrole.c, $_src/expat/lib/xmltok.c, ... ] unused_sources [ $_src/expat/lib/xmltok_impl.c, $_src/expat/lib/xmltok_ns.c, ] } }关键点skia_use_system_expat is_official_build官方official构建默认使用系统安装的 expat非官方构建才走third_party自带源码路径public_include_dirs中加入include/expat_config使xmlparse.c等源文件通过#include expat_config.h时能命中 third_party/expat/include/expat_config/expat_config.h同时定义XML_STATIC用于在 Windows 上以静态库方式链接 expatxmltok_impl.c与xmltok_ns.c被列入unused_sources因为它们在 expat 源码里是条件包含进xmltok.c的不能独立编译——GN 构建刻意避免重复编译。六、配置如何分发到 Bazel 外部仓库download_config_files 规则Bazel 侧的分发机制位于 bazel/deps.bzl 的header_based_configs()函数def header_based_configs(): maybe( download_config_files, name expat_config, skia_revision 7b730016006e6b66d24a6f94eefe8bec00ac1674, files { BUILD.bazel: bazel/external/expat/config/BUILD.bazel, expat_config.h: third_party/expat/include/expat_config/expat_config.h, }, )它调用 download_config_files.bzl 中定义的download_config_filesrepository 规则。该规则的核心实现只有十几行def _download_config_files_impl(repo_ctx): for dst, src in repo_ctx.attr.files.items(): url https://raw.githubusercontent.com/google/skia/{}/{}.format(repo_ctx.attr.skia_revision, src) repo_ctx.download(url, output dst)即以指定的skia_revision为版本锚点从 Skia 仓库按映射关系把src路径的文件下载到 Bazel external 仓库的dst路径。映射表清楚地显示了源文件在third_party/对外暴露在bazel/external/的对应关系。规则文档还说明了一个重要事实Skia 自身并不直接使用这条规则而是用local_repository让配置在本仓库内直接可用这条规则的存在是为了让外部客户端无法引用 Skia 源码树内部路径的仓库也能独立获取这些配置。与之配套的还有 freetype、harfbuzz、icu 的同类配置它们统一由header_based_configs()管理。七、升级 expat 时如何更新配置roll-expat.sh 与两个 patch配置的更新不是手写的而是由 third_party/expat/roll-expat.sh 驱动。脚本的主要步骤依次为previousrev从DEPS中解析当前 expat 版本对应的 commitnextrev从 chromium 的 expat 镜像仓库 fetch 最新提交rolldeps更新DEPS中的版本并执行tools/git-sync-depsupdate_expat_config_h关键步骤——在 expat 源码目录中执行./buildconf.sh ./configure重新生成expat_config.h然后cp ${EXPAT_GIT_DIR}/expat/expat_config.h ${EXPAT_BUILD_DIR}/include/expat_config/ patch -d ${EXPAT_BUILD_DIR} -p3 ${EXPAT_BUILD_DIR}/0001-Do-not-claim-getrandom.patch patch -d ${EXPAT_BUILD_DIR} -p3 ${EXPAT_BUILD_DIR}/0002-Do-not-claim-arc4random_buf.patch即拷贝新生成的配置头文件到third_party/expat/include/expat_config/紧接着应用两个定制 patch0001-Do-not-claim-getrandom.patch把HAVE_GETRANDOM与HAVE_SYSCALL_GETRANDOM从定义改为注释——Skia 不希望 expat 依赖getrandom()系统调用0002-Do-not-claim-arc4random_buf.patch把HAVE_ARC4RANDOM_BUF改为注释——不依赖 BSD 风格的arc4random_buf()。这正是 expat_config.h 中这些宏被注释掉的原因configure 在开发机上探测到了这些函数但 Skia 出于可移植性和可控性主动放弃使用它们。patch 之后的文件既会git add回third_party/expat/include/expat_config/expat_config.h也会在后续通过header_based_configs()同步到bazel/external/expat/config。check_all_files_are_categorized校验 expat 的expat/lib/*.{c,h}与BUILD.gn中的源码清单一一对应防止升级后新增/删除了源文件而BUILD.gn未同步。八、小结这套配置模式的通用价值从bazel/external/expat/config这一小目录出发可以总结出 Skia 管理第三方库构建配置的完整闭环单一事实源配置头文件由 expat 的 autoconf 生成经roll-expat.sh拷贝进third_party/expat/include/expat_config/并通过 patch 定制双构建系统共享GN 通过public_include_dirs直接使用Bazel 通过download_config_files以skia_revision为锚点分发到bazel/external/expat/config/循环依赖隔离空WORKSPACE.bazel使配置目录成为独立 workspace切断了 Skia ↔ expat 的双向依赖可验证性check_all_files_are_categorized保证升级时源码清单与构建文件同步。对于任何需要在 Bazel 工程中为第三方 C/C 库提供定制配置头文件的开发者这套third_party源文件 bazel/external分发 repository 规则 独立 workspace的组合拳都是一份可以直接参考的工程范式。理解expat_config.h中每个宏XML_NS、XML_DTD、XML_CONTEXT_BYTES、BYTEORDER、各HAVE_*探测项的取值与含义也是在 Skia 中排查 XML 解析相关构建问题时的重要切入点。赞分享图形学图像处理【免费下载链接】skiaSkia is a complete 2D graphic library for drawing Text, Geometries, and Images.项目地址https://gitcode.com/gh_mirrors/skia1/skia点击查看免费下载相关推荐在 Skia 仓库中自定义 Bazel 构建配置bazel/user/buildrc 实战指南在 Skia 仓库中自定义 Bazel 构建配置bazel/user/buildrc 实战指南 导读 Skia 的 Bazel 构建系统为开发者预留了一个专属图形学使用Scarab管理Hollow Knight Mods时的常见问题排查指南使用Scarab管理Hollow Knight Mods时的常见问题排查指南 Scarab作为一款专为Hollow Knight设计的现代化Mod管理器以其直图形学图像处理深入 Skia 的 Bazel RBE 构建自建容器镜像、Hermetic 工具链与平台定义全解深入 Skia 的 Bazel RBE 构建自建容器镜像、Hermetic 工具链与平台定义全解 导读 Skia 使用 Bazel 作为构建系统并将大规模构图形学上一篇SlideSCI PPT插件科研工作者的终极效率神器3倍提升PPT制作速度下一篇xsv自动化测试单元测试、集成测试与性能测试创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考