当前位置: 首页 > news >正文

Windows下CMake通过鸿蒙SDK交叉编译三方库

前言

华为鸿蒙官方的文章CMake构建工程配置HarmonyOS编译工具链 中介绍了在Linux平台下如何使用CMake来配置鸿蒙的交叉编译环境,编译输出在Harmony中使用的第三方so库以及测试demo。

本文主要是在Windows下实现同样的操作。由于平台差异的原因,有些细节的配置会有不同。

CMake简介

CMake是一个跨平台的构建工具,用于管理构建过程、编译、链接和打包软件项目,它可以生成Makefile等用于不同操作系统和编译器的构建脚本。CMake的配置过程是跨平台的,因此可以在不同的操作系统上运行,例如Linux、Windows和macOS。

CMake构建过程可分为以下三个主要步骤:

  • 配置(Configuration):配置阶段是CMake解析CMakeLists.txt文件的过程。在配置阶段,CMake会读取CMakeLists.txt文件,并执行其中的命令。CMakeLists.txt文件是CMake的核心,其定义了项目的构建规则和依赖关系。
  • 生成(Generation):生成阶段是CMake根据配置阶段的结果,生成实际构建文件的过程。在生成阶段,CMake会将CMakeLists.txt文件中定义的构建规则和依赖关系转为构建工具可以理解的形式。
  • 构建(Build):构建阶段是使用构建工具(如Make或DevEco Studio)根据生成的构建文件,编译源代码并链接生成目标文件的过程。在构建阶段,构建工具会读取生成的构建文件,按照其中定义的规则和依赖关系,执行实际的编译和链接操作。

cJSON源码准备

同样, 我们这里也使用开源的三方库cJSON进行编译。
源码地址在这里
可以使用git 克隆到本地,或者直接下载源码压缩包到本地,解压到本地
在这里插入图片描述

环境准备

这里我使用的是上篇博文中使用的HarmonyOS SDK V4.1.7版本进行编译,注意,SDK文件夹存放的路径名称中一定不能包含空格。我是直接存放在D盘根目录,如下:
在这里插入图片描述
然后还需要准备mingw编译器,在如果是Qt开发者,安装Qt的时候可以选择直接安装mingw工具,如果没有的话,可以自行下载安装一个:地址
在这里插入图片描述

开始编译

我自己在编译过程中遇到很多问题,踩了挺多坑的,为了方便理解,当前博文中也一步步的从头开始,将遇到的错误问题全部抛出来。

进入到cJSON源码目录,创建一个编译的目录 build,然后进入到build目录, 鼠标右键->在终端中打开:
在这里插入图片描述
或者通过cmd终端然后进入到build目录。

然后在终端中输入命令:

D:/HarmonyOS-4.1.7/11/native/build-tools/cmake/bin/cmake.exe -DCMAKE_TOOLCHAIN_FILE=D:/HarmonyOS-4.1.7/11/native/build/cmake/ohos.toolchain.cmake -DCMAKE_C_COMPILER=D:/HarmonyOS-4.1.7/11/native/llvm/bin/clang.exe -DCMAKE_CXX_COMPILER=D:/HarmonyOS-4.1.7/11/native/llvm/bin/clang++.exe -DOHOS_ARCH=arm64-v8a ..

以下是分段展示,方便查看:

D:/HarmonyOS-4.1.7/11/native/build-tools/cmake/bin/cmake.exe
-DCMAKE_TOOLCHAIN_FILE=D:/HarmonyOS-4.1.7/11/native/build/cmake/ohos.toolchain.cmake
-DCMAKE_C_COMPILER=D:/HarmonyOS-4.1.7/11/native/llvm/bin/clang.exe
-DCMAKE_CXX_COMPILER=D:/HarmonyOS-4.1.7/11/native/llvm/bin/clang++.exe
-DOHOS_ARCH=arm64-v8a …

说明:
我这里使用的是HarmonyOS SDK目录下的cmake,由于我没有设置环境变量,所以都是用的绝对路径。

  • -DCMAKE_TOOLCHAIN_FILE:交叉编译配置文件路径,设置为ohos工具链配置文件
  • -DCMAKE_C_COMPILER:配置鸿蒙SDK的C编译器
  • -DCMAKE_CXX_COMPILER:配置鸿蒙SDK的C++编译器
  • -DOHOS_ARCH:配置交叉编译的CPU架构,一般为arm64-v8a(编译64位的三方库)或armeabi-v7a(编译32位的三方库),本示例中设置编译为64位的cJSON库

执行命令后,报错:

PS F:\OpenHarmony\QTHarmony\Demo\cJSON-master\cJSON-master\build> D:/HarmonyOS-4.1.7/11/native/build-tools/cmake/bin/cmake.exe -DCMAKE_TOOLCHAIN_FILE=D:/HarmonyOS-4.1.7/11/native/build/cmake/ohos.toolchain.cmake -DCMAKE_C_COMPILER=D:/HarmonyOS-4.1.7/11/native/llvm/bin/clang.exe -DCMAKE_CXX_COMPILER=D:/HarmonyOS-4.1.7/11/native/llvm/bin/clang++.exe -DOHOS_ARCH=arm64-v8a ..
-- Building for: Visual Studio 16 2019
-- The C compiler identification is MSVC 19.29.30038.1
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.29.30037/bin/Hostx64/x64/cl.exe
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.29.30037/bin/Hostx64/x64/cl.exe -- broken
CMake Error at D:/HarmonyOS-4.1.7/11/native/build-tools/cmake/share/cmake-3.16/Modules/CMakeTestCCompiler.cmake:60 (message):The C compiler"C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.29.30037/bin/Hostx64/x64/cl.exe"is not able to compile a simple test program.It fails with the following output:Change Dir: F:/OpenHarmony/QTHarmony/Demo/cJSON-master/cJSON-master/build/CMakeFiles/CMakeTmpRun Build Command(s):C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/MSBuild/Current/Bin/MSBuild.exe cmTC_22cc6.vcxproj /p:Configuration=Debug /p:Platform=x64 /p:VisualStudioVersion=16.0 /v:m && 用于 .NET Framework 的 Microsoft (R) 生成引擎版本 16.10.2+857e5a733版权所有(C) Microsoft Corporation。保留所有权利。用于 x64 的 Microsoft (R) C/C++ 优化编译器 19.29.30038.1 版版权所有(C) Microsoft Corporation。保留所有权利。cl /c /W1 /WX- /diagnostics:column /O2 /D __MUSL__ /D "CMAKE_INTDIR=\"Debug\"" /D _MBCS /Gm- /MD /GS /fp:precise /Zc:wchar_t /Zc:forScope /Zc:inline /Fo"cmTC_22cc6.dir\Debug\\" /Fd"cmTC_22cc6.dir\Debug\vc142.pdb" /external:env:EXTERNAL_INCLUDE /external:W1 /Gd /TC /errorReport:queue  -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -fno-addrsig -Wa,--noexecstack -Wformat -Werror=format-security -O0 -g -fno-limit-debug-info "F:\OpenHarmony\QTHarmony\Demo\cJSON-master\cJSON-master\build\CMakeFiles\CMakeTmp\testCCompiler.c"cl : 命令行 error D8021: 无效的数值参数“/Wa,--noexecstack” [F:\OpenHarmony\QTHarmony\Demo\cJSON-master\cJSON-master\build\CMakeFiles\CMakeTmp\cmTC_22cc6.vcxproj]CMake will not be able to correctly generate this project.
Call Stack (most recent call first):CMakeLists.txt:4 (project)
-- Configuring incomplete, errors occurred!

错误原因是由于在Windows下CMake默认在Windows上选择Visual Studio生成器,而非鸿蒙NDK所需的Ninja或MinGW生成器,并且-Wa,–noexecstack是Clang/Linux平台的参数,MSVC无法识别。

指定MinGW Makefiles作为生成器

所以需要在cmake命令中强制使用鸿蒙工具链的生成器,在这里我们先使用mingw作为生成器。

修改cmake命令,如下:

D:/HarmonyOS-4.1.7/11/native/build-tools/cmake/bin/cmake.exe -G "MinGW Makefiles" -DCMAKE_TOOLCHAIN_FILE=D:/HarmonyOS-4.1.7/11/native/build/cmake/ohos.toolchain.cmake -DCMAKE_C_COMPILER=D:/HarmonyOS-4.1.7/11/native/llvm/bin/clang.exe -DCMAKE_CXX_COMPILER=D:/HarmonyOS-4.1.7/11/native/llvm/bin/clang++.exe -DCMAKE_MAKE_PROGRAM=D:/Qt/Tools/mingw810_64/bin/mingw32-make.exe -DOHOS_ARCH=arm64-v8a ..

分段展示如下:

D:/HarmonyOS-4.1.7/11/native/build-tools/cmake/bin/cmake.exe -G “MinGW Makefiles”
-DCMAKE_TOOLCHAIN_FILE=D:/HarmonyOS-4.1.7/11/native/build/cmake/ohos.toolchain.cmake
-DCMAKE_C_COMPILER=D:/HarmonyOS-4.1.7/11/native/llvm/bin/clang.exe
-DCMAKE_CXX_COMPILER=D:/HarmonyOS-4.1.7/11/native/llvm/bin/clang++.exe
-DCMAKE_MAKE_PROGRAM=D:/Qt/Tools/mingw810_64/bin/mingw32-make.exe
-DOHOS_ARCH=arm64-v8a …

以上cmake命令中添加了 -G "MinGW Makefiles" ,显式指定了mingw作为生成器,并且设置-DCMAKE_MAKE_PROGRAM 指定了mingw编译器的路径。

清理build目录下上一次失败运行生成缓存文件,然后再次运行:

这时候就顺利执行成功了:
在这里插入图片描述
然后再执行编译命令,编译Release版本:

cmake --build . --config Release

可以编译成功了:
在这里插入图片描述
在build目录就可以看到编译生成的so文件了:
在这里插入图片描述

至此,本文的目标 编译任务已经完成。

前面提到,还可以指定Ninja作为生成器,并且跟mingw有差异,那接下来感兴趣的可以继续一起来看看使用Ninja会遇到的问题。

使用Ninja作为生成器

接下来我们使用Ninja作为生成器,修改cmake命令如下:

D:/HarmonyOS-4.1.7/11/native/build-tools/cmake/bin/cmake.exe -G "Ninja" -DCMAKE_TOOLCHAIN_FILE=D:/HarmonyOS-4.1.7/11/native/build/cmake/ohos.toolchain.cmake -DCMAKE_C_COMPILER=D:/HarmonyOS-4.1.7/11/native/llvm/bin/clang.exe -DCMAKE_CXX_COMPILER=D:/HarmonyOS-4.1.7/11/native/llvm/bin/clang++.exe -DCMAKE_MAKE_PROGRAM=D:/Qt/Tools/Ninja/ninja.exe -DOHOS_ARCH=arm64-v8a ..

分段展示如下 方便查看:

D:/HarmonyOS-4.1.7/11/native/build-tools/cmake/bin/cmake.exe -G “Ninja”
-DCMAKE_TOOLCHAIN_FILE=D:/HarmonyOS-4.1.7/11/native/build/cmake/ohos.toolchain.cmake
-DCMAKE_C_COMPILER=D:/HarmonyOS-4.1.7/11/native/llvm/bin/clang.exe
-DCMAKE_CXX_COMPILER=D:/HarmonyOS-4.1.7/11/native/llvm/bin/clang++.exe
-DCMAKE_MAKE_PROGRAM=D:/Qt/Tools/Ninja/ninja.exe
-DOHOS_ARCH=arm64-v8a …

说明:
以上命令中显式指定了 -G “Ninja”,并且通过 -DCMAKE_MAKE_PROGRAM指定了ninja.exe的安装路径。

执行命令后又报错,信息如下:

-- Performing Test FLAG_SUPPORTED_fvisibilityhidden
-- Performing Test FLAG_SUPPORTED_fvisibilityhidden - Success
-- Configuring done
CMake Error at CMakeLists.txt:130 (add_library):The install of the cjson target requires changing an RPATH from the buildtree, but this is not supported with the Ninja generator unless on anELF-based platform.  The CMAKE_BUILD_WITH_INSTALL_RPATH variable may be setto avoid this relinking step.CMake Error at CMakeLists.txt:130 (add_library):The install of the cjson target requires changing an RPATH from the buildtree, but this is not supported with the Ninja generator unless on anELF-based platform.  The CMAKE_BUILD_WITH_INSTALL_RPATH variable may be setto avoid this relinking step.

问题原因:
1.RPATH 冲突​

CMake 提示 The install of the cjson target requires changing an RPATH from the build tree…,表明在安装(make install)时需要修改构建目录中的RPATH(运行时库搜索路径)。但 ​Ninja 在 Windows 上不支持修改非 Windows 原生二进制(如 Linux/鸿蒙的ELF 格式)的 RPATH​

2.​工具链配置冲突​

鸿蒙的 ohos.toolchain.cmake
可能默认启用了CMAKE_BUILD_WITH_INSTALL_RPATH(要求构建时使用安装后的 RPATH),而 Windows 上的
Ninja 无法处理此操作

解决方案是,禁用RPATH,在cmake命令中新增参数:

-DCMAKE_SKIP_RPATH=ON \
-DCMAKE_SKIP_INSTALL_RPATH=ON \
-DCMAKE_BUILD_WITH_INSTALL_RPATH=OFF

完整命令如下:

D:/HarmonyOS-4.1.7/11/native/build-tools/cmake/bin/cmake.exe -G "Ninja" -DCMAKE_TOOLCHAIN_FILE=D:/HarmonyOS-4.1.7/11/native/build/cmake/ohos.toolchain.cmake -DCMAKE_C_COMPILER=D:/HarmonyOS-4.1.7/11/native/llvm/bin/clang.exe -DCMAKE_CXX_COMPILER=D:/HarmonyOS-4.1.7/11/native/llvm/bin/clang++.exe -DCMAKE_MAKE_PROGRAM=D:/Qt/Tools/Ninja/ninja.exe -DOHOS_ARCH=arm64-v8a -DCMAKE_SKIP_RPATH=ON -DCMAKE_SKIP_INSTALL_RPATH=ON -DCMAKE_BUILD_WITH_INSTALL_RPATH=OFF ..

分段展示如下:

D:/HarmonyOS-4.1.7/11/native/build-tools/cmake/bin/cmake.exe -G “Ninja”
-DCMAKE_TOOLCHAIN_FILE=D:/HarmonyOS-4.1.7/11/native/build/cmake/ohos.toolchain.cmake
-DCMAKE_C_COMPILER=D:/HarmonyOS-4.1.7/11/native/llvm/bin/clang.exe
-DCMAKE_CXX_COMPILER=D:/HarmonyOS-4.1.7/11/native/llvm/bin/clang++.exe
-DCMAKE_MAKE_PROGRAM=D:/Qt/Tools/Ninja/ninja.exe -DOHOS_ARCH=arm64-v8a
-DCMAKE_SKIP_RPATH=ON
-DCMAKE_SKIP_INSTALL_RPATH=ON
-DCMAKE_BUILD_WITH_INSTALL_RPATH=OFF …

再次执行命令,可以顺利通过,然后再执行编译命令:cmake --build . --config Release
即可完成。

技术延伸

1.​RPATH 是什么​:
ELF 格式(Linux/鸿蒙)中嵌入的动态库搜索路径,Windows 的 PE 格式不支持此机制。
2.Ninja 的限制​:
在非 ELF 主机平台(如 Windows)编译 ELF 目标时,无法处理跨格式的 RPATH 重定向;
3.鸿蒙的特殊性​:
目标平台为 ARM64 ELF,但主机是 Windows,工具链需交叉编译,RPATH 操作需在鸿蒙设备运行时解析(无需在构建时处理)。

以上步骤中,使用Ninja生成器,我们禁用了RPATH,那么禁用过后编译出来的库会有什么问题吗?
1. ​运行时动态库查找机制失效​

  • RPATH 的作用​:RPATH 是嵌入在 ELF 文件(鸿蒙的动态库格式)中的路径信息,用于指导动态链接器(如鸿蒙的 ld-musl.so)在运行时查找依赖库的位置。
  • 禁用后的行为​:
    编译生成的库文件(如 libcjson.so)将不再包含任何自定义的运行时库搜索路径。若该库依赖其他三方库(例如 libz.so),且这些库未放置在鸿蒙系统的默认库路径(如 /system/lib)中,则运行时会出现 ​dlopen failed: library not found​ 错误。

2. ​依赖库部署灵活性降低​
若你的库是独立的三方库(如 libcjson.so),且不依赖其他外部库,则禁用 RPATH 无影响。
若你的库依赖其他非系统库​(如自行编译的 libfoo.so),则需手动将这些依赖库部署到鸿蒙设备的系统路径,或通过环境变量指定路径,否则无法运行

3. ​与鸿蒙动态共享包(HSP)机制的兼容性​
鸿蒙的 HSP(动态共享包)要求库文件能通过相对路径加载依赖(例如 $ORIGIN/…/lib)
。禁用 RPATH 后,此机制失效,需依赖鸿蒙的应用内 HSP 部署规范​(如固定目录结构)解决。

为什么 MinGW 无需禁用 RPATH?​

​1.格式兼容​:MinGW 的 GCC 工具链原生支持生成和处理 ELF 格式文件,而 RPATH 是 ELF 的核心特性之一;
​2.工具链一致性​:MinGW 的链接器(ld)与 Linux 环境一致,能直接解析 RPATH 指令,无需格式转换或兼容层;
3.​交叉编译友好​:作为跨平台编译器,MinGW 在设计上已考虑非 Windows 目标(如鸿蒙)的编译需求,而 MSVC 仅聚焦 Windows 平台;

相关文章:

  • 北京信创工委会获评“中小企业创新创业大赛优秀对接服务单位”,工委会副理事长单位悬镜安全获创客中国大赛决赛三等奖
  • uniapp处理后端返回的html字符串
  • element-plus限制日期可选范围(这里以7天为例)
  • 浅谈Apache HttpClient的相关配置和使用
  • 重生之拿着标准当令箭---[常见国内外设计标准有哪些]
  • 从0开始学习计算机视觉--Day04--损失函数
  • 【Linux指南】压缩、网络传输与系统工具
  • LinuxBridge的作用与发展历程:从基础桥接到云原生网络基石
  • 嵌入式项目:基于QT与Hi3861的物联网智能大棚集成控制系统
  • pandas---使用教程
  • docker小白自存-windows系统通过docker安装n8n-nodes-puppeteer
  • 基于GPS-RTK的履带吊车跑偏检测技术方案
  • Python网络自动化API接口统一库之napalm使用详解
  • Python打卡:Day38
  • 利用云雾自动化在智能无人水面航行器中实现自主碰撞检测和分类
  • redis配置文件-redis.conf
  • 【Docker】解决:构建(docker build)或重新运行容器时,丢失apt-get update问题
  • 【Docker基础】Docker容器管理:docker ps及其参数详解
  • HexHub开发运维利器Database, Docker, SSH, SFTP
  • 数据库外连接详解:方式、差异与关键注意事项