欢迎加入开源鸿蒙PC社区:Harmony PC 开发者社区
欢迎在PC社区平台申请新建项目:OpenHarmony PC Developer - 开源代码托管,代码协作 - AtomGit
如有项目源码,可上传至 AtomGit 仓库,并在博文内附上仓库链接。

Cling 为什么不能单独编译

Cling 是交互式 C++ 解释器,但 1.3 版本不是一个可以独立运行 cmake 的小工程。它必须作为 LLVM monorepo 的外部项目,与对应的 Clang 前端、ORC JIT 和资源头文件一起构建。本文记录在 HarmonyOS PC(AArch64)上的适配思路,重点是解释器真正执行 C++ 表达式,而不是只把一个名为 cling 的命令复制到设备上。

本文使用 Cling v1.3 与 cling-llvm20-20260119-01 配套源码。两份官方归档的 SHA-256 写在配方的 conandata.yml,适配配方、补丁和消费者测试托管在 AtomGit 仓库 中。发布文章时应优先引用这两个版本和 AtomGit 仓库的当前提交,不能把另一套 LLVM 主线源码当成等价替代。

HarmonyOS PC 上的三类关键问题

第一类问题是宿主平台识别。Conan 工具链把 CMake 系统名映射为 HarmonyOS,但 LLVM 20 的 config.guess 和 HandleLLVMOptions.cmake 只认识有限的 Unix-like 名称。适配补丁把常见 AArch64 结果规范化为 aarch64-unknown-linux-ohos,并让 HarmonyOS 进入 LLVM 的 Unix 分支。Cling 自己还依赖 CMake 的 UNIX 变量来开启局部 exceptions 和 C++ 头路径探测,因此配方只在 OHOS/HarmonyOS 路径设置项目需要的 UNIX=ON,不把异常和 RTTI 全局强行打开。

第二类问题是目标图。Cling 的 UserInterface 目录在上游被放在测试开关下面,但 driver 在关闭全量测试时仍会链接 clingUserInterface。CMake 找不到内部目标后,会把裸名称静默降级为 -lclingUserInterface,最后在链接阶段才失败。修复做法是把运行时 UserInterface 目标移出测试条件,同时仍关闭庞大的 lit 测试构建;这不是增加一个外部 Conan 依赖。Clang 的 libclang C API、c-index-test 和 c-arcmt-test 也不是 Cling 的运行时依赖,配方明确关闭它们,避免版本软链接和悬空 -llibclang。

第三类问题是嵌入式 Clang 的系统头。历史真机日志中,--version 和 -noruntime 可以通过,但默认输入先报 features.h 找不到,随后退出 139。根因不是 JIT 先坏了,而是配置期和运行时只保留了路径名含 ++ 的 libc++ 目录,丢掉了架构 sysroot 与通用 sysroot。当前修复在 OHOS/HarmonyOS 下按稳定顺序补回两级 sysroot,去掉尾部斜杠后去重,并把私有特性宏定义到真正编译 CIFactory.cpp 的对象目标。相邻 clang 输出非空并不代表它完整,必须检查是否包含 features.h 所在目录。

一个真正调用 libcling 的消费者

下面的程序来自本版本 test_package/embedding.cpp,不是只打印版本号的空测试。它创建 cling::Interpreter,执行 6 * 7,再读取 cling::Value 的结果。编译时请使用 Conan 生成的 CMakeDeps/CMakeToolchain,让头文件、libcling 和 Clang resource headers 来自同一个包前缀。

#include <cling/Interpreter/Interpreter.h>
#include <cling/Interpreter/Value.h>

#include <iostream>
#include <string>

int main(int argc, char** argv) {
    if (argc != 3) {
        std::cerr << "usage: cling_embedding <cling> <prefix>\n";
        return 2;
    }

    const std::string include_arg = std::string("-I") + argv[2] + "/include";
    const char* args[] = {argv[1], "-std=c++17", include_arg.c_str()};
    cling::Interpreter interpreter(3, args, argv[2]);
    if (!interpreter.isValid()) return 3;

    cling::Value value;
    if (interpreter.evaluate("6 * 7", value) !=
        cling::Interpreter::kSuccess) return 4;
    if (value.castAs<long long>() != 42) return 5;

    std::cout << "CLING_EMBED_RESULT=42\n";
    return 0;
}

运行参数中的第一个路径必须是包内 bin/cling,第二个路径必须是同一包的根目录。只把可执行文件复制出来会让 Cling 找不到 lib/clang/20 resource headers;应使用完整安装布局,并在鸿蒙PC上对包内 ELF 以及生成的 cling_embedding 消费者完成签名后再执行。

最小的 CMake 接线如下,保存为 CMakeLists.txt 后即可复用上面的消费者:

cmake_minimum_required(VERSION 3.15)
project(cling_consumer LANGUAGES CXX)

find_package(cling CONFIG REQUIRED)
add_executable(cling_embedding embedding.cpp)
target_compile_features(cling_embedding PRIVATE cxx_std_17)
target_link_libraries(cling_embedding PRIVATE cling::cling)

同一目录还需要一个最小的 consumer conanfile.py,让依赖和运行时环境可重复生成:

from conan import ConanFile


class ClingConsumer(ConanFile):
    settings = "os", "arch", "compiler", "build_type"
    generators = "CMakeDeps", "CMakeToolchain", "VirtualRunEnv"

    def requirements(self):
        self.requires("cling/1.3")

先在交叉构建主机上用 Conan 生成 CMakeDeps、CMakeToolchain 和 VirtualRunEnv。OHOS_PROFILE 必须是已存在且明确设置 os=OHOS、AArch64/armv8、HarmonyOS sysroot 与编译器的 host profile;不能省略它而落回 Windows/x86_64 默认 profile。

OHOS_PROFILE=ohos-aarch64  # replace with an existing OHOS/AArch64 profile
conan install . -pr:h="$OHOS_PROFILE" -pr:b=default --output-folder=build --build=never
cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmake
cmake --build build --parallel 2

构建产物和完整 Cling 包需要先按目标设备要求签名,再通过已授权的设备传输/运行入口放到 HarmonyOS PC。Conan 的 consumer 生成阶段不会自动替消费者 ELF 签名;应沿用配方中的 llvm-objcopy 清理 .codesign 和 binary-sign-tool sign -selfSign 1 流程,并在替换前回读签名 section。以下命令应在设备端执行,consumer 和 prefix 都指向同一份已签名闭包;不要在 Windows/Linux 主机上直接执行 AArch64 ELF:

prefix=/data/local/tmp/cling-package  # replace with an authorized writable task directory
consumer="$prefix/bin/cling_embedding"
export LD_LIBRARY_PATH="$prefix/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
"$consumer" "$prefix/bin/cling" "$prefix"

也可以在设备端加载 Conan 生成的 conanrun 环境脚本后运行消费者。若依赖预检没有通过,应先补齐已发布的目标包,不要用 --build=missing 把缺失的闭包隐藏在本地源码构建中。

新手适配教程:环境、过程、结论与 FAQ

环境:为什么它属于高难库

Cling 的难点不是代码量,而是依赖和运行时边界同时存在。构建机需要 Conan 2、CMake、Ninja、Python 和 HarmonyOS SDK,host profile 要明确指定 os=OHOS、arch=armv8、Clang 与 sysroot;运行机则是 AArch64 鸿蒙PC。除此之外,还必须锁定匹配的 LLVM/Clang 源码、resource headers、libcling 和签名工具。少一个组件,程序可能在链接期通过、启动后却找不到 features.h 或 JIT 资源。这个“多仓版本必须完全对齐”的条件,是普通 CMake 小库没有的复杂度。

过程:按证据链逐步推进

  1. 先用 --build=never 做依赖预检,并记录两个源码归档的 SHA-256;不能让 Conan 在缺包时静默回退源码构建。
  2. 用 OHOS host profile 生成 CMakeDeps、CMakeToolchain 和 VirtualRunEnv,检查 CMake 实际采用的 sysroot,而不是只看命令返回 0。
  3. 编译 cling、libcling 和 embedding 消费者,确认消费者链接的是当前包导出的 cling::cling,并保留 Clang resource headers 的相对目录。
  4. 对包内 ELF 和消费者完成目标设备签名,再把 bin、lib、lib/clang/20 整体传到鸿蒙PC;最后运行消费者并记录 CLING_EMBED_RESULT=42、测试分母、运行 ID 和清理状态。
  5. 只有上述结果属于同一次候选和设备运行,才把全屏桌面截图绑定到文章。截图缺失时应保持待绑定,而不是拿主机终端图补证据。

结论:哪些话可以让读者信服

出现 42,说明解释器初始化、资源头查找、表达式求值和结果读取形成了闭环;同时有 lit 回读,才能进一步说明官方测试清单的终态。这个闭环仍不代表所有 LLVM 工具、所有 JIT 优化路径或 GUI 集成都完成。高难性应由“配套 LLVM 版本 + CMake 目标图修复 + sysroot/resource 运行时闭包 + 签名设备执行”共同证明,而不是用补丁数量或一条 --version 输出替代。

FAQ

Q:为什么 cling --version 通过仍可能崩溃? A:它没有覆盖解释器初始化和 JIT 资源加载,features.h 或 resource headers 缺失会在真实求值时暴露。Q:能否只复制 bin/cling? A:不能,必须保留同一包前缀的动态库和 Clang 资源目录。Q:Windows 能直接运行 AArch64 产物吗? A:不能,Windows 只负责交叉构建和静态检查。Q:为什么要保留失败记录? A:高难适配需要证明根因和修复边界,删掉“版本通过但 JIT 失败”的历史会让结论失去可复核性。

测试结果如何避免混淆

当前 validation/cling-1.3/r151-readback 的官方 lit 回读记录了 193 个正式 lit 条目和 14 个 helper source,总数 207;193 个条目中有 165 PASS、15 UNSUPPORTED、13 XFAIL,FAIL、XPASS、ERROR 和 TIMEOUT 均为 0。这里的 UNSUPPORTED 与 XFAIL 是测试框架允许的终态,不应改写成 PASS,也不应把 193 个条目重复加到 207 之外。该回读还记录了 CLING_OFFICIAL_LIT_JIT_RESULT=42,说明至少有一个真实 JIT 表达式完成了执行。

包消费者则是另一套分母:52 个独立 C++ smoke 进程、1 个版本入口和 1 个 libcling embedding 入口,共 54 个。归档早期笔记仍保留“上游 0/207、消费者 54/54”的旧阶段描述,不能与 r151 的 207 项回读拼接成一份新报告。发布时请在图片和正文中同时写明证据目录、生成日期和分母来源;如果只引用旧笔记,就只能声称旧阶段的范围。

构建与运行边界

一个常见的 Conan 流程是:先在隔离 home 中解析 LLVM 与 Cling 的精确源码,使用单一 profile 生成 CMake toolchain,再构建 Cling、libcling 和必要的 resource headers。构建日志通过只构建合同目标来控制时间,不把未交付的 LLVM fuzzer 或无关工具混进包。Windows 或 Linux 主机上的配置成功只能证明接线正确,不能证明鸿蒙PC上的 JIT、W^X、签名和 sysroot 路径可用。

运行截图

以下图片来自同一台 HUAWEI MateBook Pro(HAD-W32)的 HarmonyOS 6.1.0.117 图形会话。第一张先确认设备上的原生 Clang 目标为 aarch64-unknown-linux-ohos,并回读 resource directory;这一步说明 JIT 运行时面对的是鸿蒙PC工具链,而不是主机编译器。

第二张记录已签名消费者、包内 cling 和 libcling.so 的实际大小,并给出消费者 SHA-256。它把截图中的程序绑定到明确的设备文件闭包。

第三张是修复前的真实诊断现场:原生编译器探测受到环境和系统头路径影响,终端出现 new file not found、标准库版本提取失败以及 CLING_EMBED_RC=4。这张图只能用来说明问题和定位过程,不能作为通过证据。

清除遗留 LD_PRELOAD、补齐 resource headers/sysroot 搜索顺序后,本文 embedding.cpp 交叉编译得到的 arm64 消费者加载 Cling 1.3 包内 libcling.so,实际完成 6 * 7 求值并输出 CLING_EMBED_RESULT=42、CLING_EMBED_RC=0。

最后保留一张带设置页的完整桌面总览,可同时核对 USB 调试页面、HiShell 和鸿蒙PC任务栏。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐