【鸿蒙 PC三方库构建系统】解决 OpenHarmony SHA 库编译问题:从动态链接错误到静态链接优化

欢迎大家加入开源鸿蒙PC社区

项目地址:https://atomgit.com/oh-tpc/pc_sha

问题背景

在 OpenHarmony 平台上编译 SHA 加密库时,遇到了一个典型的动态链接错误。这个问题不仅影响了库的正常编译,还导致生成的可执行文件无法在设备上运行。本文将详细记录问题排查过程和解决方案。

问题描述

初始症状

执行 ./build.sh sha 命令后,虽然编译过程显示成功,但在实际运行生成的可执行文件时出现以下错误:

$ ./sha_test
Error loading shared library libsha.so: No such file or directory (needed by ./sha_test)
Error relocating ./sha_test: sha512_224: symbol not found
Error relocating ./sha_test: sha512_256: symbol not found
Error relocating ./sha_test: sha1_begin: symbol not found
...

$ ./pwd2key
Error loading shared library libsha.so: No such file or directory (needed by ./pwd2key)
Error relocating ./pwd2key: hmac_sha_begin: symbol not found

错误分析

通过错误信息可以识别出两个关键问题:

  1. 动态库加载失败:程序运行时找不到 libsha.so
  2. 符号未定义:即使加载了库,程序所需的函数符号也不存在

问题排查过程

1. 检查构建配置

首先检查了 HPKBUILD 文件,了解构建配置:

pkgname=sha
pkgver=3ee0d88fc4f629b2e084f1b4cbf22cd3597542fb
archs=("armeabi-v7a" "arm64-v8a")
source="https://github.com/BrianGladman/sha.git"

2. 分析 CMake 配置

查看 sha_ohos.patch 文件中的 CMake 配置:

add_library(sha SHARED sha1.c sha2.c hmac.c)
add_library(sha_static STATIC sha1.c sha2.c hmac.c)

add_executable(hmac hmac_test.c)
target_link_libraries(hmac PRIVATE sha)

add_executable(pwd2key pwd2key.c)
target_link_libraries(pwd2key PRIVATE sha)

add_executable(sha_test sha_test.c)
target_link_libraries(sha_test PRIVATE sha)

add_executable(sha256sum shasum.c)
target_link_libraries(sha256sum PRIVATE sha)

发现问题:所有可执行文件都链接到了动态库 libsha.so,而不是静态库 libsha_static.a

3. 验证动态链接依赖

使用 llvm-readelf 工具检查生成的可执行文件:

$ llvm-readelf -d sha_test | grep -i "needed"
0x0000000000000001 (NEEDED)       Shared library: [libsha.so]
0x0000000000000001 (NEEDED)       Shared library: [libc.so]

确认了可执行文件确实依赖于 libsha.so

解决方案

方案选择

针对动态链接问题,我们有两种解决方案:

方案一:设置库路径

  • 优点:保持动态链接的优势
  • 缺点:需要在运行时设置 LD_LIBRARY_PATH,增加部署复杂度

方案二:使用静态链接

  • 优点:可执行文件独立运行,无需额外配置
  • 缺点:文件体积稍大

考虑到 OpenHarmony 设备的部署便利性,我们选择了方案二:静态链接

实施步骤

1. 修改构建补丁文件

编辑 sha_ohos.patch,将所有可执行文件改为链接静态库:

-add_executable(hmac hmac_test.c)
-target_link_libraries(hmac PRIVATE sha)
+add_executable(hmac hmac_test.c)
+target_link_libraries(hmac PRIVATE sha_static)

-add_executable(pwd2key pwd2key.c)
-target_link_libraries(pwd2key PRIVATE sha)
+add_executable(pwd2key pwd2key.c)
+target_link_libraries(pwd2key PRIVATE sha_static)

-add_executable(sha_test sha_test.c)
-target_link_libraries(sha_test PRIVATE sha)
+add_executable(sha_test sha_test.c)
+target_link_libraries(sha_test PRIVATE sha_static)

-add_executable(sha256sum shasum.c)
-target_link_libraries(sha256sum PRIVATE sha)
+add_executable(sha256sum shasum.c)
+target_link_libraries(sha256sum PRIVATE sha_static)
2. 清理并重新构建
# 清理旧的构建产物
rm -rf usr/sha output
rm -rf thirdparty/sha/sha-*
rm -f usr/hpk_build.csv

# 重新构建
./build.sh sha
3. 验证修复结果

构建完成后,再次检查动态链接依赖:

$ llvm-readelf -d usr/sha/arm64-v8a/bin/sha_test | grep -i "needed"
0x0000000000000001 (NEEDED)       Shared library: [libc.so]

$ llvm-readelf -d usr/sha/arm64-v8a/bin/hmac | grep -i "needed"
0x0000000000000001 (NEEDED)       Shared library: [libc.so]

$ llvm-readelf -d usr/sha/arm64-v8a/bin/pwd2key | grep -i "needed"
0x0000000000000001 (NEEDED)       Shared library: [libc.so]

验证成功:所有可执行文件现在只依赖于系统库 libc.so,不再依赖 libsha.so

构建产物

文件结构

usr/sha/
├── arm64-v8a/
│   ├── bin/
│   │   ├── hmac
│   │   ├── pwd2key
│   │   ├── sha256sum
│   │   └── sha_test
│   ├── include/
│   │   └── sha/
│   │       ├── brg_endian.h
│   │       ├── brg_types.h
│   │       ├── hmac.h
│   │       ├── pwd2key.h
│   │       ├── rdtsc.h
│   │       ├── sha1.h
│   │       └── sha2.h
│   ├── lib/
│   │   ├── libsha.so
│   │   ├── libsha_static.a
│   │   └── cmake/
│   └── hnp.json
└── armeabi-v7a/
    └── (相同结构)

输出文件

output/
├── arm64-v8a/
│   ├── sha.hnp
│   └── sha_3ee0d88fc4f629b2e084f1b4cbf22cd3597542fb.tar.gz
└── armeabi-v7a/
    ├── sha.hnp
    └── sha_3ee0d88fc4f629b2e084f1b4cbf22cd3597542fb.tar.gz

额外修复

在解决主要问题的过程中,还发现并修复了以下问题:

1. Shebang 错误

问题:脚本文件第一行使用了错误的 shebang

#!/bin/env bash  # 错误

修复

#!/usr/bin/env bash  # 正确

影响的文件:

  • build.sh
  • envset.sh

2. 环境变量设置缺失

问题setarm32ENV() 函数缺少 HNP_TOOL 环境变量设置

修复

setarm32ENV() {
    # ... 其他环境变量
    export HNP_TOOL=${OHOS_SDK}/toolchains/hnpcli  # 添加这一行
    # ...
}

3. 环境配置加载缺失

问题HPKBUILD 文件缺少 source envset.sh

修复

source envset.sh  # 添加这一行

测试验证

在鸿蒙设备上测试

将生成的可执行文件部署到 OpenHarmony 设备后,测试结果:

# 在设备上运行
$ ./sha_test
SHA-1 tests: OK
SHA-224 tests: OK
SHA-256 tests: OK
SHA-384 tests: OK
SHA-512 tests: OK

$ ./hmac
HMAC tests: OK

$ ./pwd2key
Password to key derivation: OK

$ ./sha256sum test.txt
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855  test.txt

测试结论:所有功能正常,问题已完全解决。

技术要点总结

1. 动态链接 vs 静态链接

特性 动态链接 静态链接
文件大小
内存占用 低(多进程共享)
部署复杂度 高(需管理库路径)
更新便利性 高(只更新库) 低(需重新编译)
适用场景 系统库、频繁更新的库 独立应用、工具程序

2. OpenHarmony 构建系统

  • HPKBUILD:定义包的元数据和构建过程
  • build.sh:主构建脚本,负责环境设置和依赖管理
  • envset.sh:架构相关的环境变量设置
  • build_hpk.sh:实际的构建执行脚本

3. 跨平台编译注意事项

  • 使用正确的工具链(OpenHarmony NDK)
  • 设置正确的编译器和链接器参数
  • 处理不同架构(armeabi-v7a, arm64-v8a)的差异
  • 确保运行时库的可用性

最佳实践建议

1. 对于工具类程序

建议优先使用静态链接,因为:

  • 部署简单,无需额外配置
  • 避免库版本冲突
  • 适合独立运行的小工具

2. 对于库文件

建议同时提供动态库和静态库:

  • 动态库供其他程序链接
  • 静态库用于构建独立程序

3. 构建配置管理

  • 使用补丁文件管理第三方库的修改
  • 保持原始代码的完整性
  • 便于版本升级和问题追踪

相关资源

总结

通过将动态链接改为静态链接,成功解决了 SHA 库在 OpenHarmony 平台上的编译和运行问题。这个过程不仅修复了当前的 bug,还优化了构建配置,使得生成的程序更加独立和易于部署。

这次问题的解决过程展示了:

  1. 系统化的问题排查方法
  2. 对动态链接和静态链接的深入理解
  3. OpenHarmony 构建系统的使用经验
  4. 跨平台编译的注意事项

希望这篇文章能帮助遇到类似问题的开发者快速定位和解决问题。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐