Harmony PC 开发者社区欢迎加入开源鸿蒙PC社区 https://harmonypc.csdn.net/欢迎在PC社区平台申请新建项目https://atomgit.com/OpenHarmonyPCDeveloper/欢迎在PC社区平台申请新建项目OpenHarmony PC Developer - 开源代码托管,代码协作 - AtomGit本文记录 LLVM LLD 15.0.4 在 HarmonyOS PC AArch64 上的适配与真机消费者验证。一、交付结果LLD 是 LLVM 项目中的高性能链接器。它并非一个独立的小型库而是 LLVM monorepo 的工具链组件构建和测试横跨 CMake 平台判断、多个目标后端、lit 测试框架以及 ELF、COFF、Mach-O、WebAssembly 等测试矩阵。项目内容上游项目LLVM Project上游版本15.0.4上游地址GitHub - llvm/llvm-project: The LLVM Project is a collection of modular and reusable compiler and toolchain technologies. · GitHub目标平台HarmonyOS PC / AArch64交付分支feat/lld-15.0.4合入 PRMR #9167交付提交705d16b8e9a2e1854b8a4bdeb049830b839c605c图 1LLD 15.0.4 适配 PR 已合入页面同时展示上游信息、测试统计和评审状态。本文不把“能编译”当作适配完成。一个链接器制品至少要经过四层验证源码能在目标工具链下构建、上游测试按平台边界分类、Conan 包能从制品仓取得、包内程序能在真机被下游实际调用。后文的五张图片正好对应这四层证据。二、从零理解 LLD、LLVM 与 Conan 的关系初次接触这个项目时最容易误解的一点是LLD 并不是单独下载一个小仓库后直接make的工具。它位于llvm-project单仓中依赖 LLVM 的公共构建框架和工具组件。可以把本次交付拆为三层LLVM monorepo 源码 - CMake/Ninja 构建出 LLD 系列二进制 - Conan 配方将 bin/ 下程序打包为 lld/15.0.4 - 下游在 HarmonyOS PC 下载并调用包内 ld.lld其中lld是通用驱动入口ld.lld是 GNU 风格链接器入口还可能包含lld-link、ld64.lld、wasm-ld等不同目标格式的入口。本文真机消费者选用ld.lld因为它适合验证 AArch64 ELF 链接链路。对于初学者建议先记住下面三个概念概念本文中的含义不能混淆的对象上游源码LLVM 15.0.4 的官方llvm-project源码Conan 缓存中的已打包制品SDK 工具系统已安装的 clang、lld 等工具本次 LLD PR 产生的包内二进制Conan 制品ohpcd远端的lld/15.0.4二进制包本地源码构建目录中的临时ld.lld后续验证始终用路径来区分它们只有.conan2/p/.../bin/ld.lld才是本次从制品仓下载的 LLD。三、为什么这是高难度适配这次工作不是把CC改成 clang 后重新编译即可完成主要有四类困难上游假设HarmonyOS PC 上的实际差异处理方式平台识别覆盖既有 Unix 系统aarch64:HarmonyOS未被完整识别补充config.guess和 LLVM CMake 平台分类测试可使用常规管道行为grep -q提前退出可能使写端收到SIGPIPE使用 FileCheck 代替依赖提前关闭的管道检查Python 脚本保留 Python 2 除法语义Python 3 的/返回浮点数将随机边界计算改为//整数除法POSIX 权限位行为稳定HMDFS 的chmod u-w语义不同将已证实无法稳定复现的权限用例按边界处理XPASS 仍保留阻断能力具体修改包括增加 HarmonyOS AArch64 平台识别使配置阶段获得正确目标信息。在HandleLLVMOptions中补充CMAKE_SYSTEM_NAMEHarmonyOS分类使编译和链接选项进入正确的 Unix-like 分支。将 Mach-O dead-strip 测试中的grep -q管道检查转换为 FileCheck消除 OHOS 上的管道提前关闭干扰。将random.randint(0, frame_size / 16 - 4)修正为random.randint(0, frame_size // 16 - 4)解决 Python 3 的TypeError。3.1 平台识别为什么必须优先解决大型 CMake 项目不会只在一个位置判断操作系统。config.guess用于识别构建环境CMake 的CMAKE_SYSTEM_NAME又决定编译选项、链接选项和条件测试。若只修改其中一个位置可能出现“配置成功但编译参数不完整”或“能构建但测试条件走错分支”的假成功。本次在两个层面补齐 HarmonyOS首先让 AArch64 HarmonyOS 环境能够被稳定识别再让 LLVM 的平台选项逻辑把HarmonyOS纳入 Unix-like 分类。这样做的目标不是修改上游行为而是把原本未覆盖的平台显式纳入已有的合理分支。3.2 为什么一个 Python 除法也会阻塞链接器适配LLD 自身主要由 C 实现但测试和辅助生成工具会调用 Python。Python 2 中整数相除返回整数Python 3 中/返回浮点数。因此下面代码在 Python 3 中会把float传给需要整数范围的random.randintrandom.randint(0, frame_size / 16 - 4)正确的修复不是把异常吞掉也不是临时降低 Python 版本而是明确表达整数语义random.randint(0, frame_size // 16 - 4)这类问题的价值在于它可复用任何历史脚本中“数量、索引、对齐、页数、随机边界”一类的除法都应先检查它是否依赖 Python 2 整数语义。3.3 HMDFS 权限差异如何处理某些上游 LTO 用例通过chmod u-w让文件变为不可写再断言链接器或相关工具产生Permission denied。这实际验证的是底层文件系统的权限语义而不完全是 LLD 算法。HarmonyOS PC 的 HMDFS 环境中权限位行为与常规 Linux 本地文件系统不完全一致。正确处理流程是先做最小权限实验再将无法稳定复现的用例单独记录为平台边界不能将其删除也不能把“没有触发预期权限错误”伪装成 LLD 功能通过。若以后环境改变导致预期失败意外通过XPASS 仍应作为回归信号保留。四、HarmonyOS PC 真机环境真机不是服务器交叉编译截图。下图可见 HarmonyOS PC 桌面、终端窗口、HarmonyOS内核标识、aarch64架构和 Conan 版本。图 2HarmonyOS PC 真机环境uname -a、uname -m和conan --version分别确认系统、AArch64 架构和 Conan 2.29.1。4.1 最小环境检查开始前应在真机终端检查以下项目而不是假定开发机、服务器和真机环境一致uname -a uname -m conan --version command -v clang command -v binary-sign-tool本次交付对应的包设置是OHOS / armv8 / Release / clang 15 / C17 / libc。这组设置不仅描述编译器版本也决定 Conan 会选择哪个二进制 package ID。只要 C 标准或 C 运行库不同Conan 就会把它当作不同的二进制兼容配置。4.2 构建阶段的关键约束LLD 15.0.4 的构建入口是 CMake 和 Ninja。适配时只启用本次需要的 LLD 项目避免把完整 LLVM 工具链、文档和不相关绑定全部带入构建闭包。配置的核心含义如下LLVM_ENABLE_PROJECTSlld 只构建 LLD 项目 LLVM_INCLUDE_TESTSON 保留 LLD lit 测试入口 LLVM_BUILD_TESTSOFF 不额外构建 LLVM C 单元测试目标 LLVM_DEFAULT_TARGET_TRIPLE... 设定 OHOS AArch64 默认目标 LLVM_PARALLEL_LINK_JOBS2 限制大对象链接时的内存峰值LLVM_BUILD_TESTSOFF并不表示“没有测试”。LLD 的主验证入口是check-lld对应的 lit 测试两者属于不同层次。把它们混为一谈是解释 LLVM 测试结果时最常见的错误之一。五、从 ohpcd 制品仓下载 LLD 制品先在真机下载已经发布的 LLD 制品而不是运行 SDK 目录中同名的ld.lldconan download lld/15.0.4:* -rohpcd下载成功后Conan 返回完整的 recipe revision、package ID 和 package revision。该制品的目标设置为osOHOS、archarmv8、compilerclang、compiler.version15、compiler.cppstd17、compiler.libcxxlibc。conan cache path lld/15.0.4#recipe_revision:package_id#package_revision图 3真机从ohpcd下载 86.1 MB 的 LLD 制品包安装完成后定位到本地 Conan 缓存。5.1 如何读懂下载输出下载输出中有三段标识建议在问题排查时完整保留lld/15.0.4#recipe_revision :package_id #package_revisionrecipe_revision标识配方版本package_id由 profile 的设置和选项计算得到package_revision标识该二进制包的修订版本。图 3 中的包 ID 是6b129b068851896169fae42d399fa922d239ce8a。它不是随意的缓存目录名而是与 OHOS AArch64、clang 15、C17、libc 配置绑定的二进制身份。5.2 为什么必须用download而不是只看仓库网页网页只能说明项目存在不能说明当前 HarmonyOS PC 能否拿到目标架构和 ABI 对应的包。conan download真实执行了远端获取、包解压和本地安装图 3 中的Package installed、下载体积和本地缓存路径共同证明制品可获得。如果命令报Recipe not found说明远端未发布配方如果显示Missing binary说明配方存在但当前 profile 没有匹配包。两类失败的处理方向完全不同不能混在一起。六、以消费者运行环境调用制品中的 LLD下载成功不等于消费者可用。必须使用与制品一致的 host settings 生成 Conan 运行环境避免默认 profile 选择到不同的 C ABI 包conan install --requireslld/15.0.4 -rohpcd --buildnever \ -s:harcharmv8 \ -s:hbuild_typeRelease \ -s:hcompilerclang \ -s:hcompiler.version15 \ -s:hcompiler.cppstd17 \ -s:hcompiler.libcxxlibc \ -s:hosOHOS \ -s:hos.version6.0 \ -g VirtualRunEnv -of. . ./conanrun.sh command -v ld.lld ld.lld --version关键检查是command -v ld.lld必须指向.conan2/p/.../bin/ld.lld而不是 SDK 的/data/service/hnp/bin/ld.lld。图 4VirtualRunEnv生成成功ld.lld指向 Conan 缓存内的制品并正确输出 LLD 15.0.4。6.1 这一步曾遇到的真实失败直接执行conan install --requireslld/15.0.4时真机的默认 profile 使用了compiler.cppstdgnu14和compiler.libcxxlibstdc11。Conan 因此计算出一个不同的 package ID并提示No compatible configuration found。这不是制品仓下载失败也不是 LLD 不能在鸿蒙上运行而是消费者请求的 ABI 与已发布制品不一致。显式传入cppstd17与libc后Conan 命中图 3 下载的包生成conanrun.sh随后ld.lld --version成功输出 LLD 15.0.4。这个案例说明遇到Missing binary时先对比“远端包的 settings”和“当前 profile 的 settings”不要立刻使用--buildmissing。后者会把本应验证远端制品的问题变成一次本地重编译失去制品消费验证的意义。6.2 如何确认没有误用 SDK 自带 LLD设备 SDK 同时提供/data/service/hnp/bin/ld.lld。一开始若只运行command -v ld.lld很容易命中 SDK 程序该程序还可能因自己的动态库环境而无法加载libxml2.so.16。这既不能证明本 PR 的制品正确也不能作为本次 LLD 的失败结论。正确顺序是先执行. ./conanrun.sh再检查command -v ld.lld只有路径落在 Conan 缓存中的包目录才继续运行版本命令和消费者链接。七、最小消费者链接、签名和真机运行为证明制品中的 LLD 确实参与了下游链接创建最小 C 消费者程序并将 Conan 包内的ld.lld绝对路径显式传给 clangLLD_PKG$(conan cache path lld/15.0.4#recipe_revision:package_id#package_revision) LLD_BIN$LLD_PKG/bin/ld.lld clang -fuse-ld$LLD_BIN ./lld_consumer.c -o ./lld_consumer /data/service/hnp/bin/readelf -h ./lld_consumer | grep -E Class:|Machine: /data/service/hnp/bin/binary-sign-tool sign \ -inFile ./lld_consumer \ -outFile ./lld_consumer \ -selfSign 1 ./lld_consumer printf consumer_exit%s\n $?这里有一个容易踩到的环境问题SDK clang 在仅使用-fuse-ldlld时可能优先调用 SDK 目录自身的链接器而不是当前PATH中的 Conan 制品。因此本验证使用-fuse-ld$LLD_BIN显式锁定包内链接器。图 5消费者程序由 Conan 制品内的ld.lld链接readelf确认ELF64 / AArch64自签名成功后输出LLD Conan consumer: PASS退出码为 0。7.1 消费者源码为什么要足够小最小消费者只调用puts并返回 0。它不用于证明复杂 C 运行库功能而是为了把结论收敛到一条可观察链路C 源码被 clang 编译clang 把链接阶段交给指定的 Conanld.lld最终产物是 AArch64 ELF经签名后能在真机运行。#include stdio.h int main(void) { puts(LLD Conan consumer: PASS); return 0; }使用最小输入的好处是若失败可以立即区分为“编译器/链接器/系统运行时/签名”哪一层的问题而不会被业务逻辑、第三方库或网络条件干扰。7.2 为什么传递绝对 linker 路径clang -fuse-ldlld看起来合理但 SDK clang 的工具查找逻辑可能优先定位 SDK 安装目录中的lld即使当前 shell 的PATH已经由 Conan 更新。实际验证中这会命中 SDK 自带的、运行时依赖不完整的 linker。因此使用clang -fuse-ld$LLD_BIN ./lld_consumer.c -o ./lld_consumer$LLD_BIN是通过完整 Conan 包引用计算出的.../.conan2/p/.../bin/ld.lld。这使链接器来源可审计也避免同名工具覆盖。7.3 为什么签名和运行缺一不可readelf -h只能证明文件是ELF64 / AArch64还不能证明它满足设备的执行要求。HarmonyOS PC 上ELF 需要通过binary-sign-tool进行自签名。图 5 中连续出现“添加 codesign section 成功”“写入签名数据成功”“消费者输出 PASS”“退出码为 0”因此它覆盖了链接、架构、签名和运行四个阶段。八、上游测试口径与边界LLD 的上游测试不是单一平台的简单总数。lld/test同时包含 Windows、macOS、PPC64 等目标和系统专属测试OHOS AArch64 的结果不能替代这些平台语义。MR #9167 的测试台账以独立 lit 用例为中心源码目录审查口径为 2690 项其中Inputs等夹具文件不是独立断言。文章中应始终区分上游测试发现数、当前配置实际实例化数、实际运行通过数、平台阻塞项和预期失败项不能将可执行集合的成功表述为“所有上游平台测试全部通过”。典型平台边界包括 Windows DIA/PDB、system-windows、macOSxar/system-darwin、PPC64 TOC 指令语义以及 HMDFS 权限位行为。这些项目应保留首错、适用平台和恢复条件而不是改写为通过。8.1 为什么不能只报一个百分比LLD 的测试目录含有测试输入、夹具、目标格式专属用例和真实断言。下面四个数字表达的不是同一件事口径应回答的问题源码发现数上游目录里有多少可能的测试文件或入口独立用例数哪些项目真正拥有独立 RUN 行或断言OHOS 实际运行数当前配置在 AArch64/OHOS 上注册并执行了多少平台阻塞数哪些用例需要 Windows、macOS、PPC64 或特定工具才能恢复MR 台账采用 2690 项上游目录审查口径并单独记录 2679 项独立实例化用例。文章刻意不把跨平台阻塞项从分母中抹掉也不把某个子集合成功替换成“上游全量成功”。这是工具链项目比普通库更需要遵守的测试表达纪律。8.2 测试失败的标准排查顺序出现 lit 失败时建议按以下顺序定位先确认测试实际使用的是本次构建产生的工具而不是系统同名工具保存完整 RUN 命令、首个失败断言、退出码和临时目录判断失败是目标平台差异、缺少外部工具、文件系统语义还是 LLD 输出本身变化对平台阻塞项写出恢复条件例如“需要 Windows DIA SDK”或“需要 PPC64 后端语义”只有在根因确定且修复可复现后才修改补丁或测试期望。这种顺序比“先把失败跳过”更慢一点但能防止把真实兼容性缺陷误归类为环境问题。九、可复用流程清单对于后续需要发布 Conan 工具型制品的 HarmonyOS PC 适配可以复用以下流程固定官方源码版本、下载地址和 SHA-256。枚举构建入口、测试入口和平台判断文件先完成平台识别。明确区分“构建 LLVM 单元测试”和“运行 LLD lit 测试”。以 Conan 配方打包工具并保留bin/中真实可执行程序。在真机执行conan download确认远端确实存在目标 ABI 的二进制包。用与制品一致的 profile 执行conan install --buildnever防止隐式本地重建掩盖问题。通过VirtualRunEnv和绝对路径确认消费者使用的确实是包内工具。用最小消费者完成编译、链接、AArch64 ELF 检查、签名和运行。在文章中分别呈现 PR、真机、下载、包内执行和消费者运行证据。十、结论LLD 15.0.4 的适配覆盖了 HarmonyOS 平台识别、LLVM CMake 分类、Python 3 脚本兼容、HMDFS 权限测试边界和跨平台测试矩阵处理。真机侧形成了完整的可复核链路HarmonyOS PC AArch64 - 从 ohpcd 下载 lld/15.0.4 制品 - Conan VirtualRunEnv 解析包内 ld.lld - 显式使用该 ld.lld 链接消费者 - ELF64/AArch64 校验 - binary-sign-tool 自签名 - 真机运行并返回 0十一、FAQQ1为什么不能直接运行command -v ld.lld系统 SDK 也可能提供同名链接器。必须先确认路径指向.conan2/p/.../bin/ld.lld否则无法证明运行的是本次下载的 Conan 制品。Q2为什么conan install会提示没有兼容包Conan 二进制包由 OS、架构、编译器版本、C 标准和 C 运行库等共同确定。本制品为cppstd17与libc消费者 profile 若使用gnu14或libstdc11会计算出另一个 package ID需要显式对齐设置。Q3为什么链接后还要签名HarmonyOS PC 对 ELF 运行有签名要求。签名成功并在真机运行证明的不只是“链接器生成了文件”而是该文件能够作为实际 ELF 交付物运行。Q4为什么 clang 要传入 LLD 的绝对路径SDK clang 可能优先选择自身安装目录下的 linker。-fuse-ld$LLD_BIN将链接动作固定到 Conan 制品中的 LLD避免同名 SDK 工具干扰验证结论。Q5conan download成功后为什么conan install仍可能失败download能证明某个包存在并已经被下载install会根据当前 profile 重新计算需要的 package ID。若编译器版本、cppstd、libcxx、架构或操作系统版本不同就可能下载到了 A 包却请求 B 包。应按图 3 的 settings 显式对齐 profile。Q6能否使用--buildmissing解决缺包可以用于开发阶段构建源码但不能用于“验证远端制品仓已发布并可消费”的截图。本文的真机消费环节使用--buildnever一旦远端没有匹配包就立即报错结论更可信。Q7为什么图 5 中既使用 clang 又使用 LLDclang 负责 C 源码编译、sysroot 和启动文件选择LLD 负责最终链接。-fuse-ld$LLD_BIN保留 clang 驱动的目标平台配置同时把关键链接步骤明确交给 Conan 包内的 LLD。这是验证链接器制品比手工拼接crt*.o、动态链接器和 libc 参数更稳妥的方式。