- 编译器
- 编程语言
【免费下载链接】cangjie_compiler
仓颉编译器源码及 cjdb 调试工具。
本文围绕仓颉编译器仓库中的third_party/README.md(使用的开源软件说明),系统梳理 cangjie_compiler 对 LLVM、FlatBuffers、libboundscheck、MinGW-w64 四个开源组件的引入方式、版本基线与 CMake 构建参数,并结合仓库内的构建脚本与调用点源码,说明每个第三方库在编译器中的实际用途、产物依赖关系,以及如何手动准备第三方源码进行构建。
第三方依赖总览
仓颉编译器的第三方依赖集中在third_party/目录,由 third_party/CMakeLists.txt 统一作为 CMake 子目标(ExternalProject)引入。各依赖的定位如下:
| 组件 | 来源基线 | 在编译器中的角色 | 关键构建脚本 |
|---|---|---|---|
| libboundscheck | OpenHarmonythird_party_bounds_checking_function,版本OpenHarmony-v6.0-Release | 内存安全函数库,提供securec系列安全接口 | BoundsCheck.cmake |
| flatbuffers | OpenHarmonythird_party_flatbuffers | 编译器数据(CHIR、AST、宏消息等)的序列化/反序列化 | Flatbuffer.cmake |
| LLVM | 官方llvmorg-15.0.4(commit5c68a1cb123161b54b72ce90e7975d95a8eaf2a4) | 编译器后端(cjnative 代码生成、clang_rt 运行时库、lldb/cjdb 调试器) | llvmPatch.diff、third_party/CMakeLists.txt |
| MinGW-w64 | OpenHarmonythird_party_mingw-w6412.0.0 | Windows 版 SDK 携带的静态库/运行期 DLL,链接目标文件生成 Windows 可执行程序 | AddMinGWLibs.cmake |
从构建拓扑看,third_party/CMakeLists.txt通过ExternalProject_Add(cjnative ...)组织出三条前置依赖链:cangjie-demangler(仓颉符号反混淆库)、boundscheck、boundscheck-static,LLVM 构建完成后再把这三类产物拷贝进 LLVM 源码树(utils/demangle、utils/boundscheck)参与链接(见 third_party/CMakeLists.txt#L288-L310)。
libboundscheck:内存安全函数库
代码来源
libboundscheck 是 OpenHarmony 社区的边界检查/内存安全函数库,仓库源码基线为OpenHarmony-v6.0-Release版本。编译器及周边组件以**包含头文件 + 链接库(动态库或静态库)**的方式使用它。
顶层 CMakeLists.txt#L74-L89 在配置阶段处理了源码获取:若third_party/boundscheck目录不存在,会自动以--branch OpenHarmony-v6.0-Release克隆源码;随后把 BoundsCheck.cmake 配置复制为该目录下的CMakeLists.txt,使 boundscheck 成为 CMake 子目标自动完成构建。
在编译器中的使用方式
从源码结构看,libboundscheck 的securec安全接口被编译器多处直接调用,例如 CHIR 解释器中的 BCHIRInterpreter.cpp、BCHIRIntrinsic.cpp 以及工具链实现 MinGW_CJNATIVE.cpp。
对用户程序而言,boundscheck 是通过 Driver 工具链在链接阶段注入的。以 Linux cjnative 工具链为例,链接命令会显式追加libboundscheck-static.a:
// src/Driver/Toolchains/CJNATIVE/Linux_CJNATIVE.cpp tool.AppendArg(FileUtil::JoinPath(cangjieLibPath, "libboundscheck-static.a")); // 或 tool.AppendArg("-l:libboundscheck-static.a");Windows(MinGW)与 macOS 工具链中同样存在对应的libboundscheck-static.a链接逻辑(见 Darwin_CJNATIVE.cpp#L196、MinGW_CJNATIVE.cpp#L188)。
构建细节
BoundsCheck.cmake 为该库生成了两条目标:boundscheck(SHARED)与boundscheck-static(STATIC),并配置了一组安全编译选项:
- 共享库启用
-fstack-protector-all,非 Darwin 平台链接时附加-Wl,-z,relro,-z,now,-z,noexecstack; - Release 构建启用
-D_FORTIFY_SOURCE=2 -O2,统一执行-sstrip; - MinGW 交叉构建下,由于 MSVCRT 已提供大部分安全函数,只编译
memset_s.c、snprintf_s.c、vsnprintf_s.c、secureprintoutput_a.c四个文件,避免符号重定义; - 一个值得注意的约束:当编译器开启了 ASan/HWASan 时,会主动从 boundscheck 的编译选项中移除
-fsanitize=address/-fsanitize=hwaddress(见 BoundsCheck.cmake#L13-L19),因为安全库自身若被插桩会产生大量误报。
FlatBuffers:编译器数据的序列化框架
代码来源
FlatBuffers 是高效的跨平台、跨语言序列化库。仓颉语言使用它完成编译器数据到指定格式的二进制序列化与反序列化,使用方式同样是"包含头文件 + 链接库"。
在编译器中的使用范围
从源码搜索看,FlatBuffers 的使用面覆盖编译器多个数据链路:
- CHIR 序列化:CHIRSerializer.cpp、CHIRDeserializer.cpp;
- AST 序列化与模块缓存(.cjo):src/Modules/ASTSerialization/ 下的 ASTWriter、ASTLoader 等;
- 宏展开消息:MacroEvalMsgSerializer.cpp、NodeSerialization.cpp;
- 增量编译缓存:CachedDataSerialization.cpp、DependencySerialization.cpp。
对应的 schema 定义集中在 schema/ 目录,包括 CjoFormat.fbs、CachedASTFormat.fbs、MacroMsgFormat.fbs、StdxChirFormat.fbs 等。
构建与仓颉专属代码生成
Flatbuffer.cmake 使用 ExternalProject 引入 flatbuffers:若third_party/flatbuffers/CMakeLists.txt已存在则直接使用本地源码,否则从 OpenHarmonythird_party_flatbuffers仓按固定 commit 克隆。构建时关闭测试与flathash,仅构建必要目标并安装。
其PATCH_COMMAND会执行 ApplyCangjieIdlPackagePatch.cmake:这是一个仓颉专属的源码改写脚本,把 flatbuffers 上游src/idl_gen_cangjie.cpp(Cangjie 语言代码生成后端)中硬编码的package std.ast改写为基于.fbsnamespace 的映射逻辑(ASTFormat → std.ast、CHIRFormat → stdx.chir、SyntaxFormat → stdx.syntax),并让生成的 table 统一import flatbuffers.*。
改写后的 flatc 在 schema/CMakeLists.txt#L13-L29 中被调用,对每个*.fbs文件执行:
flatc --no-warnings -c -o <build>/flatbuffers <xxx>.fbs产出<build>/flatbuffers/<NAME>_generated.h,供 Frontend、CHIR、Macro、Modules、IncrementalCompilation 等模块通过FLATBUFFERS_INCLUDE_DIR使用。安装阶段还会把flatc、include/flatbuffers头文件以及.fbsschema 一并安装到 SDK 的third_party/flatbuffers目录,方便标准库(std.ast)消费方复用。
手动准备 flatbuffers 源码
开发者也可以手动下载 flatbuffers 源码,构建项目时直接使用third_party/flatbuffers目录源码:
mkdir -p third_party/flatbuffers cd third_party/flatbuffers git clone <OpenHarmony third_party_flatbuffers 仓库地址> -b master ./仓库地址以
third_party/README.md原文为准(OpenHarmony 的 third_party_flatbuffers 镜像)。
LLVM:后端、运行时库与调试器的基座
LLVM 是仓颉编译器中体量最大的第三方依赖,同时承担三个职责:cjnative 后端的静态库(链接进 cjc)、compiler-rt 运行时库(链接进用户程序)、lldb(构建 cjdb 调试器)。
版本基线
当前基于官方llvmorg-15.0.4(对应 commit5c68a1cb123161b54b72ce90e7975d95a8eaf2a4)开源版本修改实现。从仓库自带的 llvmPatch.diff 统计,patch 覆盖约 862 个文件,改动集中在llvm/lib、llvm/test、llvm/include、lldb/source、compiler-rt/lib等目录,可以推断其中既有仓颉后端所需的 LLVM 库功能扩展,也有 lldb/cjdb 调试器适配。
双来源通道
为了兼顾日常开发管理与 OpenHarmony 版本构建,LLVM 在构建时有两种来源(见 third_party/CMakeLists.txt#L158-L164):
| 通道 | 代码仓 | 适用场景 |
|---|---|---|
默认:Cangjie/llvm-project(分支main) | 仓颉社区维护的 LLVM 代码仓 | 日常代码开发、检视和管理 |
--use-oh-llvm-repo:OpenHarmonythird_party_llvm-project(分支master)+llvmPatch.diff | 官方开源版本 | OpenHarmony 构建版本 |
对应的 CMake 开关为顶层option(CANGJIE_USE_OH_LLVM_REPO ...),默认OFF(见 CMakeLists.txt#L53)。patch 的自动化应用逻辑在 ApplyLLVMPatch.cmake 中:先git diff --quiet检测工作区是否干净,若干净则git reset --hard 5c68a1cb123161b54b72ce90e7975d95a8eaf2a4回到基线 commit,再执行git apply --reject --whitespace=fix llvmPatch.diff。官方说明中强调:llvmPatch.diff基于仓颉 LLVM 仓的改动验证后生成,每个版本都会保证 patch 可用;LLVM 版本升级需结合 OpenHarmony 社区开源软件升级要求共同评估可行性。
此外,若开发者在third_party/llvm-project或自定义的CANGJIE_CJNATIVE_SOURCE_DIR(顶层 CMakeLists.txt#L71-L73 定义了默认值)中已提供 LLVM 源码,则跳过下载步骤,直接以该目录为SOURCE_DIR构建(ExternalProject_Add(cjnative ...)的EXISTS ${CANGJIE_CJNATIVE_SOURCE_DIR}分支)。
构建流程与关键参数
LLVM 以 ExternalProject 方式构建,核心 CMake 参数(见 third_party/CMakeLists.txt#L190-L269)包括:
LLVM_ENABLE_PROJECTS:默认lld|clang|compiler-rt;开启编译器 ASan(CANGJIE_ENABLE_ASAN/ASAN_COV)时收敛为仅lld(运行时库另行单独构建,见下文);LLVM_TARGETS_TO_BUILD=ARM|AArch64|X86,同时构建多目标以支持交叉编译;LLVM_BUILD_LLVM_DYLIB=ON/LLVM_LINK_LLVM_DYLIB=ON:构建libLLVM.so供 cjdb 等链接;- 链接进 cjc 的 22 个静态库白名单
LLVM_LIB_NAMES:LLVMLinker、LLVMIRReader、LLVMAsmParser、LLVMTransformUtils、LLVMBitWriter、LLVMAnalysis、LLVMProfileData、LLVMDebugInfoDWARF、LLVMObject、LLVMMC、LLVMCore、LLVMSupport、LLVMDemangle等(见 third_party/CMakeLists.txt#L41-L64); - 安装的二进制同样采用白名单策略
LLVM_BIN_INSTALL_PATTERN,按用途分组注释:opt/llc(通用编译)、lld/ld.lld/lld-link(链接与 LTO)、llvm-ar、llvm-link/llvm-lto(LTO)、llvm-cov(--coverage功能)、llvm-profdata/llvm-profgen(PGO)、llvm-as/llvm-dis/lli/llvm-objdump/llvm-objcopy等(编译器开发者调试用途); - cjdb 相关:开启
CANGJIE_BUILD_CJDB时追加-DLLVM_ENABLE_RTTI=ON、termcap/ncurses 选项;若 cjdb 为 Debug 而 LLVM 为 Release,还需-DLLVM_ENABLE_DUMP=ON,避免 LLDB 调试构建引用 LLVM debug-only 的dump()函数导致未定义引用(见 third_party/CMakeLists.txt#L223-L235); - MinGW 交叉场景追加
LLVM_SPLIT_LLVM_DYLIB=ON、CROSS_TOOLCHAIN_FLAGS_LLVM_NATIVE等参数,并将 Windows 运行期 DLL(libLLVM-15.dll、libgcc_s_seh-1.dll等)纳入安装白名单。
构建完成后,POST_BUILD步骤通过 ExtractRtlib.cmake 从third_party/llvm/lib中抽取 clang_rt 运行时库到输出lib/目录,按平台选取:
libclang_rt.builtins.a(x86_64/Darwin)、libclang_rt.profile.a(coverage 支持);- 非 Windows/iOS 平台的
libclang_rt.fuzzer_no_main.a(fuzz 测试); - 按
CANGJIE_SANITIZER_SUPPORT选项抽取libclang_rt-asan.a、libclang_rt-tsan.a、libclang_rt-hwasan.a; - ASan 场景下由于 clang-rt 不会再生成
clang_rt-profile,会额外再构建一个不带 ASan 的cjnative-rtlib项目来补供 coverage 库(见 third_party/CMakeLists.txt#L477-L512)。
抽取结果最终install到lib/<target>_cjnative目录(modules/<output_lib_dir>与lib/${output_lib_dir}),随 SDK 一起发布。
手动准备 LLVM 源码
按third_party/README.md原文,两种方式二选一:
方式一:OpenHarmony 仓 + patch(OpenHarmony 构建版本)
mkdir -p third_party/llvm-project cd third_party/llvm-project git clone -b master --depth 1 <OpenHarmony third_party_llvm-project 仓库地址> ./ git fetch --depth 1 origin 5c68a1cb123161b54b72ce90e7975d95a8eaf2a4 git checkout 5c68a1cb123161b54b72ce90e7975d95a8eaf2a4 git apply --reject --whitespace=fix ../llvmPatch.diff方式二:直接拉取仓颉 LLVM 仓(默认方式)
mkdir -p third_party/llvm-project cd third_party/llvm-project git clone -b main --depth 1 <Cangjie llvm-project 仓库地址> ./构建项目时,则直接使用third_party/llvm-project目录源码进行构建(即上文EXISTS ${CANGJIE_CJNATIVE_SOURCE_DIR}分支)。
MinGW-w64:Windows SDK 的静态库来源
仓颉 Windows 版 SDK 携带 MinGW 中的部分静态库文件,与仓颉代码生成的目标文件链接在一起,为用户生成最终可调用 Windows API 的可执行二进制文件。该部分产物基于third_party_mingw-w6412.0.0(commitfeea9a87fa42591b298b18fe0e07198f0b8c2f63)编译,并被打包至仓颉发布包中。
使用要点:
- 仅 Windows 目标平台需要:编译目标平台为 Windows 时才依赖该组件;
- 前置构建:MinGW-w64 需在构建编译器之前完成,并在构建编译器时指定其编译产物路径(
--target-sysroot/--target-toolchain,参考仓库构建指导书中"编译 mingw-w64 及配套工具链"一节); - 构建侧的处理逻辑在 AddMinGWLibs.cmake:若
third_party/binary/windows-x86_64-mingw.tar.gz不存在(且非集成构建的 LFS 环境),会浅克隆 binary-deps 仓并git lfs pull拉取该 tar 包,解包后把 MinGW 的dll/目录拷贝到third_party/llvm/bin,与上面 LLVM 安装白名单中的 Windows DLL(libLLVM-15.dll等)配套,最终随 SDK 发布。
构建选项与源码布局速查
结合third_party/README.md与仓库 CMake 实现,常见控制项汇总如下:
| 选项/变量 | 位置 | 作用 |
|---|---|---|
CANGJIE_USE_OH_LLVM_REPO(--use-oh-llvm-repo) | CMakeLists.txt#L53 | 切换为 OpenHarmony LLVM 仓 +llvmPatch.diff构建 |
CANGJIE_CODEGEN_CJNATIVE_BACKEND | CMakeLists.txt#L38 | 是否构建 cjnative 后端(默认 ON),决定 LLVM 子目标是否启用 |
CANGJIE_BUILD_CJDB | 顶层选项 | 是否构建 cjdb(lldb),影响 LLVM 的 RTTI/DUMP/ncurses 参数 |
CANGJIE_SKIP_BUILD_CLANG_RT | CMakeLists.txt#L41 | 交叉编译等场景跳过 clang_rt 库构建 |
CANGJIE_CJNATIVE_SOURCE_DIR | CMakeLists.txt#L71-L73 | 手动指定的 LLVM 源码目录(默认third_party/llvm-project) |
CANGJIE_SANITIZER_SUPPORT | 顶层选项 | asan/tsan/hwasan,决定抽取哪份 clang_rt 库 |
手动准备源码时约定的目录布局:
third_party/ ├── llvm-project/ # LLVM 源码(llvm/ 子目录为源码根) ├── flatbuffers/ # flatbuffers 源码 ├── boundscheck/ # libboundscheck 源码(缺失时自动克隆) ├── llvmPatch.diff # 随仓库携带的 LLVM patch └── cmake/ # 各依赖的 ExternalProject 脚本小结
third_party/README.md所描述的四个开源组件在仓颉编译器中各自承担明确职责:libboundscheck 提供内存安全函数并在 Driver 链接阶段注入用户程序;FlatBuffers 支撑 CHIR、AST 缓存、宏消息等编译器数据的序列化链路,并通过仓颉专属的 idl 补丁实现.fbs → 仓颉包的代码生成;LLVM 以 15.0.4 为基线提供 cjnative 后端、clang_rt 运行时与 cjdb 调试器,且通过"仓颉 LLVM 仓 / OpenHarmony 仓 + llvmPatch.diff"双通道保证日常开发与 OpenHarmony 版本构建的一致性;MinGW-w64 则为 Windows 发布包提供静态库与运行期 DLL。全部依赖均以 CMake ExternalProject 子目标方式纳入统一构建,理解 third_party/CMakeLists.txt 中的白名单与依赖链,是阅读和定制仓颉编译器第三方集成逻辑的入口。
- 编译器
- 编程语言
【免费下载链接】cangjie_compiler
仓颉编译器源码及 cjdb 调试工具。
相关推荐
scrcpy 安卓投屏完整教程:免 Root,5 分钟用键鼠控制手机
scrcpy 安卓投屏完整教程:免 Root,5 分钟用键鼠控制手机 scrcpy 是一款免费开源的工具,专门解决安卓手机投屏到电脑这件事:把手机屏幕实时镜像到
音视频Faster-Whisper:如何实现4倍速语音转录的技术揭秘
Faster Whisper:如何实现4倍速语音转录的技术揭秘 在AI语音转录领域,速度与精度的平衡一直是开发者面临的挑战。今天我要为你深入剖析一个革命性的解决
人工智能语音音频本地部署HLA-NoVR:无需VR设备畅玩《半条命:Alyx》的终极解决方案
HLA NoVR:无需VR设备畅玩《半条命:Alyx》的终极解决方案 还在为昂贵的VR设备而望而却步吗?HLA NoVR项目为你带来了革命性的游戏体验,让《半条
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考