尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

使用 Bazel 模块化集成 Skia:外部客户端构建指南

使用 Bazel 模块化集成 Skia:外部客户端构建指南 图形学【免费下载链接】skiaSkia is a complete 2D graphic library for drawing Text, Geometries, and Images. See documentation for contribution instructions.项目地址https://gitcode.com/gh_mirrors/ski/skia点击查看免费下载导读Skia 不仅提供了功能完备的 2D 图形 API还通过 Bazel 提供了一整套模块化构建规则允许外部项目在自有 C 工具链下按需组装自己需要的组件——从最轻量的核心路径运算、图像编解码到 Ganesh/Graphite 两种 GPU 后端乃至 Skottie 动画、SVG 渲染与 PDF 输出。本文以仓库中 example/external_client 这一官方示例为骨架逐步拆解外部客户端如何声明依赖、注入自定义用户配置、组装模块并最终构建出可运行的可执行文件读完后你将能在自己的 Bazel 工程中像“搭积木”一样集成 Skia。一、示例定位外部客户端如何“依赖并构建”Skiaexample/external_client/README.md 用三句话点明了整个示例的核心意图该目录演示了外部客户端如何使用自己的 C 工具链依赖并构建 Skia。先看WORKSPACE.bazel了解 setup 部分顺带快速浏览./custom_skia_config再看BUILD.bazel了解真正使用 Skia 模块化构建规则组装特定任务所需组件的规则。也就是说这个示例不是一个独立存在的可执行程序而是一份最小可复用的工程模板它模拟了一个“把 Skia 当作外部依赖的第三方项目”的完整布局。值得注意的是示例目前采用 Bazel 的 bzlmod 模式依赖声明实际位于 example/external_client/MODULE.bazel而custom_skia_config目录内保留了一个空的 example/external_client/custom_skia_config/WORKSPACE.bazel 以兼容传统工作区语义。整个示例目录结构如下example/external_client/ ├── MODULE.bazel # bzlmod 依赖声明含 skia 与 skia_user_config 的本地覆盖 ├── MODULE.bazel.lock ├── BUILD.bazel # 各示例可执行文件的组装规则 ├── custom_skia_config/ # 客户端自定义 Skia 配置模块 │ ├── BUILD.bazel # user_config cc_librarySK_USE_BAZEL_CONFIG_HEADER │ ├── SkUserConfig.h # 可自定义的构建期宏 │ ├── copts.bzl # DEFAULT_COPTS / DEFAULT_OBJC_COPTS │ ├── linkopts.bzl # DEFAULT_LINKOPTS │ └── WORKSPACE.bazel └── src/ # 各示例的 C 源码二、依赖声明bzlmod 下的 Skia 接入外部客户端与 Skia 的“连接点”全部集中在 example/external_client/MODULE.bazel其声明逻辑可分为四层2.1 基础构建规则依赖bazel_dep(name rules_cc, version 0.1.1) bazel_dep(name platforms, version 0.0.11)rules_cc提供cc_binary/cc_library等 C 规则platforms提供platforms//os:linux、platforms//os:macos等平台约束供后续select做平台差异化处理。2.2 引入 Skia 本体本地覆盖模拟真实拉取bazel_dep(name skia) local_path_override( module_name skia, path ../.., )注释中明确说明真实客户端应通过git_repository把 Skia 固定到某个 commit文件中给出了99822dd8249dfe3773cbd7ca56bb1767bf92fa22的示例而这里用local_path_override指向仓库根目录../..即 MODULE.bazel从而能够在仓库内直接以“外部客户端”的身份测试最新代码。2.3 注入客户端自己的配置模块bazel_dep(name skia_user_config) local_path_override( module_name skia_user_config, path custom_skia_config, )这是 Skia Bazel 集成的关键机制客户端必须提供一个名为skia_user_config的模块其中包含一个名为user_config的cc_library目标。Skia 的各模块会依赖这个目标从而把客户端定义的宏与编译选项“反向注入”到 Skia 自身的构建中。2.4 第三方依赖传递cpp_modules 扩展skia_deps use_extension(skia//bazel:cpp_modules.bzl, cpp_modules) skia_deps.from_file(deps_json skia//bazel:deps.json) use_repo( skia_deps, dawn, delaunator, dng_sdk, expat, freetype, harfbuzz, icu, icu4x, imgui, libavif, libgav1, libjpeg_turbo, libjxl, libpng, libwebp, libyuv, perfetto, piex, spirv_cross, spirv_headers, spirv_tools, vello, vulkan_headers, vulkan_tools, vulkan_utility_libraries, vulkanmemoryallocator, wuffs, zlib, )模块注释解释得直白bzlmod 不允许传递依赖因此一旦你的代码或间接通过 Skia 头文件直接包含这些第三方头文件就必须自行声明它们。示例通过use_extension调用 Skia 的cpp_modules模块扩展见 bazel/cpp_modules.bzl从 bazel/deps.json 一次性拉取 freetype、harfbuzz、icu、libpng、libjpeg_turbo、vulkan_headers、wuffs 等全部依赖仓库再用use_repo把需要的仓库句柄绑定到当前模块作用域。三、注入配置custom_skia_config 模块剖析README 提醒的“quick detour”./custom_skia_config是外部客户端定制 Skia 构建的唯一入口其组成如下。3.1 user_config 库构建期宏的注入点example/external_client/custom_skia_config/BUILD.bazel 定义了 Skia 要求的user_config目标config_setting( name debug_build, values {compilation_mode: dbg}, ) cc_library( name user_config, hdrs [SkUserConfig.h], defines [ SK_USE_BAZEL_CONFIG_HEADER, ] select({ :debug_build: [SK_DEBUG], //conditions:default: [SK_RELEASE], }), visibility [//visibility:public], )这里有两个关键点SK_USE_BAZEL_CONFIG_HEADER宏是硬性要求。它告诉 Skia 的构建系统使用客户端提供的SkUserConfig.h作为配置头而非 Skia 内置默认配置。从源码结构看Skia 各源码文件在包含配置头时会依据此宏切换路径详见 include/config/SkUserConfig.h 中罗列的可用宏清单。SK_DEBUG/SK_RELEASE通过selectcompilation_mode联动使用bazel build -c dbg时自动定义SK_DEBUG默认 fastbuild/opt 模式则定义SK_RELEASE无需手工维护。3.2 可选的编译/链接选项example/external_client/custom_skia_config/copts.bzl 提供DEFAULT_COPTS [-stdc20, -Wno-psabi]与DEFAULT_OBJC_COPTS []注释明确这些列表可以为空也可以使用select按平台差异化设置example/external_client/custom_skia_config/linkopts.bzl 提供DEFAULT_LINKOPTS []语义同上。3.3 自定义配置头example/external_client/custom_skia_config/SkUserConfig.h 目前是一个空模板仅用 include guard 包裹并注释“参见 include/config/SkUserConfig.h 了解可以在此处定义的宏”。外部客户端可以在此开启/关闭特定特性如SK_ENABLE_SKSL、各类字体后端开关等实现按需裁剪。四、模块化组装BUILD.bazel 中的 18 个示例目标example/external_client/BUILD.bazel 是示例的主体通过组合skia//:下不同模块目标演示了“不同任务只链接所需组件”的模块化哲学。全部目标归纳如下目标源文件依赖的 Skia 模块用途path_combinerpath_main.cppcore、pathops路径布尔运算png_decoderdecode_png_main.cppcore、png_decode_codec解码 PNGdecode_everythingdecode_everything.cppcore bmp/gif/ico/jpeg/jpegxl/png/wbmp/webp 全部解码 codec全格式解码write_text_to_pngwrite_text_to_png.cppcore、png_encode_codec 平台字体模块绘制文本并编码 PNGshape_textshape_text.cppcore、skparagraph_harfbuzz_skunicode、skunicode_icu等文本整形排版use_ganesh_glganesh_gl.cppcore、ganesh_gl 平台 GL 工厂Ganesh OpenGLuse_ganesh_vulkanganesh_vulkan.cppcore、ganesh_vulkanGanesh Vulkanuse_ganesh_metalganesh_metal.cppcore、ganesh_metalGanesh Metal仅 Appleuse_graphite_native_metalgraphite_native_metal.cppcore、graphite_native_metalGraphite Metaluse_graphite_metal_capturegraphite_metal_capture.cppcore、graphite_native_metalGraphite Metal 捕获use_graphite_native_vulkangraphite_native_vulkan.cppcore、graphite_native_vulkan、vulkan_headersGraphite Vulkanuse_log_testerlog_tester.cppcore日志通道验证仅 Appleuse_skresourcesuse_skresources.cppcore、skresources 编解码资源加载svg_with_primitivesvg_renderer.cppcore、svg_renderer、skshaper_core基础 SVG 渲染svg_with_harfbuzz同上core、svg_renderer、skshaper_harfbuzz、skunicode_icuHarfBuzz 整形版 SVGwrite_to_pdfwrite_to_pdf.cppcore、pdf_writer、pdf_jpeg_helpersPDF 输出play_skottieplay_skottie.cppcore、skottie、png_encode_codecLottie 动画播放4.1 最小依赖示例path_combinercc_library( name skia_core_and_pathops, deps [ skia//:core, skia//:pathops, ], ) cc_binary( name path_combiner, srcs [src/path_main.cpp], linkopts [-fuse-ldlld, -lpthread], deps [:skia_core_and_pathops], )注释明确写道“第一个示例只需要核心 Skia 功能与 pathops 模块”因此客户端把corepathops封装成本地cc_library再被可执行文件依赖——这是推荐的依赖组织方式。4.2 平台差异化依赖write_text_to_pngdeps [ skia//:core, skia//:png_encode_codec, ] select({ platforms//os:linux: [ skia//:fontmgr_fontconfig, skia//:freetype_support, ], platforms//os:macos: [skia//:fontmgr_coretext], //conditions:default: [skia//:fontmgr_empty_freetype], }),字体管理器因平台而异Linux 用 fontconfig FreeTypemacOS 用 CoreText其他平台回退到fontmgr_empty_freetype。对应源码 write_text_to_png.cpp 中也是用条件编译SK_FONTMGR_FONTCONFIG_AVAILABLE/SK_FONTMGR_CORETEXT_AVAILABLE来匹配这些模块提供的宏构建期宏与源码宏一一对应。4.3 GPU 后端与 Objective-C 辅助库use_ganesh_gl展示了完整的多平台链路Windows 链接gdi32/OpenGL32/user32Linux 链接GL/X11并分别选择ganesh_gl_win_factory、ganesh_glx_factory、ganesh_gl_mac_factory作为平台工厂macOS 还需要一个objc_library辅助目标 gl_context_helper引入OpenGLframework并通过-DGL_SILENCE_DEPRECATION压制废弃告警。Metal 类目标同理ganesh_metal_context_helper明确要求依赖MetalKitframework注释指出“不加入 MetalKit[*device newCommandQueue]会失败”。五、模块别名映射从skia//:xxx到真实源码示例中所有skia//:前缀目标在仓库根 BUILD.bazel 中均有对应的alias映射这是理解“模块化”落点的关键索引对外别名实际指向skia//:core//src/core:coreskia//:pathops//src/pathops:pathopsskia//:ganesh_gl//src/gpu/ganesh/gl:ganesh_glskia//:ganesh_metal//src/gpu/ganesh/mtl:ganesh_metalskia//:ganesh_vulkan//src/gpu/ganesh/vk:ganesh_vulkanskia//:graphite_native_metal//src/gpu/graphite/mtl:graphite_native_metalskia//:graphite_native_vulkan//src/gpu/graphite/vk:graphite_native_vulkanskia//:png_decode_codec:png_decode_libpng→//src/codec:png_decodeskia//:png_encode_codec:png_encode_libpng→//src/encode:png_encodeskia//:jpeg_decode_codec/jpeg_encode_codec//src/codec:jpeg_decode///src/encode:jpeg_encodeskia//:bmp/gif/ico/jpegxl/wbmp/webp_decode_codec//src/codec:*_decodeskia//:webp_encode_codec//src/encode:webp_encodeskia//:fontmgr_fontconfig/freetype_support/fontmgr_coretext/fontmgr_empty_freetype//src/ports:*注意一个细节png_decode_codec、png_encode_codec这两个别名已带有deprecation提示官方建议改用png_decode_libpng/png_encode_libpng仓库同时提供png_decode_rust/png_encode_rust等 Rust 实现备选。示例沿用旧别名保持了向后兼容。六、示例源码走读模块与 API 的对应关系6.1 路径布尔运算pathops 模块path_main.cpp 是pathops模块的最小用例用SkPathBuilder构造两个重叠三角形路径再调用Op(path1, path2, kIntersect_SkPathOp, combined)求交集并dump()输出。这验证了skia//:pathops仅需引入include/pathops/SkPathOps.h。6.2 文本渲染 PNG 编码write_text_to_png.cpp 串起了core、编码模块与字体模块的完整调用链SkSurfaces::Raster创建 100×50 光栅表面 → 按平台构造SkFontMgrSkFontMgr_New_FontConfig/SkFontMgr_New_CoreText→matchFamilyStyle(Roboto, ...)匹配字体 →canvas-drawString绘制 →SkPngEncoder::Encode写出。它同时是linkopts中-lpthread的用途样本Skia 内部线程相关符号需要 pthread。6.3 GPU 后端上下文ganesh_vulkanganesh_vulkan.cpp 演示 GPU 路径的最小骨架构造skgpu::VulkanBackendContext→GrDirectContexts::MakeVulkan创建 Ganesh 上下文 →SkSurfaces::RenderTarget创建 GPU 表面。文件头注释特别说明“缺少完整 Vulkan 初始化代码运行时不会成功但用于验证构建系统可编译链接”即这类目标是构建冒烟测试而非完整应用。6.4 Lottie 动画skottie 模块play_skottie.cpp 展示高层模块的易用性skottie::Animation::Make(input)解析 JSON → 按动画尺寸创建表面 → 逐帧animation-seek渲染并编码为 PNG整个流程只依赖skottie与png_encode_codec两个模块。七、构建与运行方式在example/external_client目录下或在仓库根使用--package_path定位目标按 Bazel 惯例即可构建任意示例bazel build //:path_combiner # 仅 core pathops bazel build //:decode_everything # 全部解码器 bazel build //:write_to_png # 文本 → PNG bazel build //:use_ganesh_vulkan # GPU 后端冒烟测试 bazel build -c dbg //:path_combiner # 调试构建自动注入 SK_DEBUG运行产物位于bazel-bin/下例如./bazel-bin/path_combiner # 打印路径交集结果 ./bazel-bin/write_text_to_png output.png # 生成 100×50 的 PNG ./bazel-bin/play_skottie anim.json 60 # 渲染 Lottie 前 60 帧几点实践提示示例普遍在linkopts中加入-fuse-ldlld指定 lld 链接器与-lpthread前者可依工具链情况移除Metal 相关目标通过target_compatible_with select(...)声明仅兼容 macOS/iOS在 Linux 上构建会直接报“incompatible”这是 Bazel 平台约束的常规用法若需要固定 Skia 版本参照 example/external_client/MODULE.bazel 顶部注释的git_repository方案替换local_path_override即可。八、总结example/external_client提供了一条清晰的“外部客户端集成 Skia”路径用 bzlmod 声明依赖、用skia_user_config注入配置、用skia//:模块别名按需组装、用select处理平台差异。其核心价值在于验证了 Skia 的 Bazel 构建真正做到了组件级裁剪——一个路径运算程序只需corepathops两个模块而完整的 GPU 后端、Skottie、SVG、PDF 能力都可以在需要时才引入。对于任何希望在自有 C 工具链中复用 Skia 的 Bazel 工程这套模板都值得直接复制改造。继续深入可阅读BUILD.bazel完整模块别名清单、include/config/SkUserConfig.h可自定义宏、bazel/cpp_modules.bzl 与 bazel/deps.json第三方依赖机制。赞分享图形学【免费下载链接】skiaSkia is a complete 2D graphic library for drawing Text, Geometries, and Images. See documentation for contribution instructions.项目地址https://gitcode.com/gh_mirrors/ski/skia点击查看免费下载相关推荐Bazel 外部构建系统集成规则 —— rules_foreign_ccBazel 外部构建系统集成规则 —— rules_foreign_cc 项目基础介绍 rules_foreign_cc 是一个开源项目旨在为 Bazel 提RIOT OS 构建系统扩展指南用 EXTERNAL_MODULE_DIRS 集成外部模块RIOT OS 构建系统扩展指南用 EXTERNAL_MODULE_DIRS 集成外部模块 RIOT 的构建系统默认只扫描仓库内 sys/ 、 drivers物联网嵌入式操作系统实时系统CARLA C 客户端实战指南构建示例、集成外部工程与底层 API 解析CARLA C 客户端实战指南构建示例、集成外部工程与底层 API 解析 本指南面向希望摆脱 Python 包装、直接用 C 驱动 CARLA 自动驾自动驾驶科研仿真创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表