前言
華為鴻蒙官方的文章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 平臺;