一、编译内存过高问题
问题现象
编译构建时,内存或CPU占用过高,导致出现DevEco Studio运行卡顿、延迟等现象。
解决措施
在并行模式下执行hvigor构建,可以通过修改hvigor-config.json5文件进行优化配置:
ruby
"properties": {
// 配置为0,表示不启用内存缓存配置,默认为4,数值越低,内存中缓存数据越少
"hvigor.pool.cache.capacity" : 0,
// 默认配置为cpu核数-1,包含ohos.arkCompile.maxSize4,值越小,占用内存越少
"hvigor.pool.maxSize" : 5,
// 默认配置值为5, 值越小,占用内存越少
"ohos.arkCompile.maxSize": 3,
// 默认配置值为true, 表示开启内存缓存,占用内存较多,配置为false,关闭内存缓存,占用内存较少
"hvigor.enableMemoryCache" : false
}
说明
当配置项"hvigor.pool.maxSize"和"ohos.arkCompile.maxSize"的值改小,"hvigor.enableMemoryCache"改为false后,可能会导致编译时长增加,请耐心等待。
如果以上修改没有取得明显的效果,可以使用非并行的模式来执行编译:
- 在菜单栏点击"File > Settings > Build, Execution, Deployment > Build Tools > Hvigor",取消勾选"Execute tasks in parallel mode (may require larger heap size)"。
- 流水线场景中,在命令行最后增加 --no-parallel,示例:hvigorw assembleHap --no-parallel
二、构建报错"Cannot read properties of undefined(reading 'xxx')"
问题现象
编译构建时,出现报错"Cannot read properties of undefined(reading 'xxx')"。
解决措施
打开堆栈信息排查hvigorconfig.ts文件和hvigorfile.ts文件里的代码,里面是否使用了未定义的属性。
堆栈打开方法:项目根目录/hvigor/hvigor-config.json5文件中配置如下内容:
vbnet
"debugging": {
"stacktrace": true /* Disable stacktrace compilation. Value: [ true|false ]. Default:false*/
}
如果上述文件中并未排查出问题,请及时向官方提单反馈。
三、构建报错"Duplicated files found in module xxx"
问题现象
编译构建时,出现报错"Duplicated files found in module xxx. This may cause unexpected errors at runtime"。
问题原因
构建时存在不同版本的同名so文件。比如将har模块产物里的so文件拷贝到entry模块的libs目录下,这时har模块里有一个libhar.so,entry模块里也有一个libhar.so,再配置entry依赖har,构建entry就会出现报错。
解决措施
使用select、pickFirsts、pickLasts等配置选中要使用的so文件:
- select提供native产物的精准选择能力,优先级高于excludes、pickFirsts等配置项
- pickFirsts、pickLasts按照.so文件的优先级顺序,打包最高优先级的.so文件
- 优先级顺序是指依赖收集的顺序,越晚被收集优先级越高
基于上面的例子,可以在entry的build-profile.json5中添加配置select选中har模块中的so文件,package选中包名为"har"的模块, include选中"libhar.so"文件。
四、构建报错"input module releaseType is different"
问题现象
打包APP时,提示"input module releaseType is different"。
解决措施
根据报错日志的Warning信息所提示的模块名称,检查模块间的apiReleaseType字段是否一致。
该apiReleaseType字段由编译构建工具自动生成,保存在HAP/HSP包的module.json文件中。首先确认各模块间该字段是否一致,如果存在不一致的情况,需要将应用的各个模块,使用相同版本的SDK重新打包,然后打包APP。
五、构建报错"debug is different"
问题现象
打包APP时,提示"debug is different"。
解决措施
根据报错日志的Warning信息所提示的模块名称,检查模块间的debug字段是否一致,尤其需要关注本地模块和外部引用模块之间是否一致。
- 该debug字段由编译构建工具自动生成,保存在HAP/HSP包的module.json文件中,首先确认各模块间该字段是否一致。
- 编译工具根据设置的Build Mode选项生成debug标识,可以通过此处进行设置。
六、构建报错"proxy data is duplicated"
问题现象
打包APP时,提示"uri datashareproxy://bundleName/** in proxy data is duplicated"。
七、CMake Error: The following variables are used in this project, but they are set to NOTFOUND
问题现象
当在原生项目中使用find_path时,可能会报此错误。
解决措施
这个问题是因为在OpenHarmony SDK提供的CMake交叉编译配置文件(ohos.toolchain.cmake)中,搜索路径被限制在了CMAKE_SYSROOT。
如果需要添加搜索路径,可以在CMakeList.txt中使用list API添加自定义路径。例如,添加D:demo到搜索路径:
objectivec
list(APPEND CMAKE_FIND_ROOT_PATH_MODE_INCLUDE "D:demo")
添加路径后,就可以使用find_path在D:demo目录中搜索文件了。
八、NDK工程构建方式
OpenHarmony NDK默认使用CMake作为构建系统,随包提供了符合OpenHarmony工具链的基础配置文件ohos.toolchain.cmake,用于预定义CMake变量来简化开发者配置。
常用的NDK工程构建方式
1. 从源码构建
- 可以使用DevEco Studio提供的C++应用模板,用DevEco Studio来编译构建
- 也可以使用命令行CMake来编译构建
2. 使用预构建库构建
ohos.toolchain.cmake简介
ohos.toolchain.cmake是OpenHarmony NDK提供给CMake的toolchain脚本,里面预定义了编译OpenHarmony应用需要设置的编译参数,如交叉编译设备的目标、C++运行时库的链接方式等;这些参数在调用CMake命令时,可以从命令行传入,来改变默认编译链接行为。
常用参数如下表:
参数 | 类型 | 说明 |
---|---|---|
OHOS_STL | c++shared/c++ static | libc++的链接方式。默认为c++shared。c++ shared表示采用动态链接libc++shared.so;c++ static表示采用静态链接libc++_static.a |
OHOS_ARCH | armeabi-v7a/arm64-v8a/x86_64 | 设置当前Native交叉编译的目标架构,当前支持的架构为armeabi-v7a/arm64-v8a/x86_64 |
OHOS_PLATFORM | OHOS | 选择平台。当前只支持OpenHarmony平台 |
上述参数最终会控制Clang的交叉编译命令,产生合适的命令参数:
- --target={arch}-linux-ohos参数,通知编译器生成相应架构下符合OpenHarmony ABI的二进制文件
- --sysroot={ndk_root}/sysroot参数,告知编译器OpenHarmony系统头文件的所在位置
NDK通过CMake和Ninja编译应用的C/C++代码的核心过程
- 根据CMake配置脚本以及build-profile.json5中配置的externalNativeOptions构建参数,与缓存中的配置比对后,生成CMake命令并执行CMake
- 执行Ninja,按照makefile执行编译和链接,将生成的.so以及运行时依赖的.so同步到输出目录,完成构建过程
CMakeLists.txt示例
通过DevEco Studio模板工程创建的NDK工程中,包含默认生成的CMakeLists.txt脚本,如下所示:
bash
# the minimum version of CMake.
cmake_minimum_required(VERSION 3.4.1)
project(MyApplication)
# 定义一个变量,并赋值为当前模块cpp目录
set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
# 添加头文件.h目录,包括cpp,cpp/include,告诉cmake去这里找到代码引入的头文件
include_directories(${NATIVERENDER_ROOT_PATH}
${NATIVERENDER_ROOT_PATH}/include)
# 声明一个产物libentry.so,SHARED表示产物为动态库,hello.cpp为产物的源代码
add_library(entry SHARED hello.cpp)
# 声明产物entry链接时需要的三方库libace_napi.z.so
# 这里直接写三方库的名称是因为它是在ndk中,已在链接寻址路径中,无需额外声明
target_link_libraries(entry PUBLIC libace_napi.z.so)
externalNativeOptions配置
模块级build-profile.json5中externalNativeOptions参数是NDK工程C/C++文件编译配置的入口,可以通过path指定CMake脚本路径、arguments配置CMake参数、cppFlags配置C++编译器参数、abiFilters配置编译架构等。
json
"apiType": "stageMode",
"buildOption": {
"arkOptions": {
},
"externalNativeOptions": {
"path": "./src/main/cpp/CMakeLists.txt",
"arguments": "",
"cppFlags": "",
"abiFilters": [
"arm64-v8a",
"armeabi-v7a",
"x86_64"
],
}
}
九、CPP编译报错"A 'unknown type name' error has occurred"
问题现象
在编译HarmonyOS C++项目时,报错提示"A 'unknown type name' error has occurred"。
解决措施
在编译HarmonyOS C++项目时,遇到"unknown type name"错误通常表示编译器无法识别某个类型。这可能是因为类型未定义、未包含相关的头文件,或者包含的头文件路径不正确。以下是定位和解决这个问题的步骤:
-
检查是否包含头文件 确保所有必要的头文件都已正确包含在源文件中。例如,如果您正在使用某个自定义类型或库提供的类型,请确保在使用该类型的文件中包含了相关的头文件。
示例:
arduino// main.cpp #include "myLibrary.h" int main() { MyType obj; // 使用自定义类型 return 0; } // myLibrary.h #ifndef MY_LIBRARY_H #define MY_LIBRARY_H class MyType { public: MyType() {} void doSomething(); }; #endif
-
检查头文件路径 确保CMakeLists.txt中正确设置了头文件的搜索路径。可以通过include_directories添加头文件目录。
示例CMakeLists.txt:
scsscmake_minimum_required(VERSION 3.10) project(MyProject) set(CMAKE_CXX_STANDARD 17) # 添加头文件目录 include_directories(${CMAKE_SOURCE_DIR}/include) # 添加源文件 add_library(myProgram SHARED src/main.cpp src/myLibrary.cpp)
-
清理和重新生成构建文件 有时,构建文件可能会损坏或丢失符号定义。尝试清理构建目录并重新生成构建文件:
hvigorw clean
或手动删除模块下.cxx目录。
-
启用详细编译输出 为了解详细的编译过程,可以启用更详细的输出。在CMakeLists.txt中添加以下内容:
scssset(CMAKE_VERBOSE_MAKEFILE ON)
-
检查编译输出日志 Ninja默认生成.ninja_log文件,其中包含构建过程的详细信息。你可以检查这个日志文件以了解构建过程中的问题:
bashcat .cxx/default/default/arm64-v8a/.ninja_log
-
使用CMake的message函数调试 可以在CMakeLists.txt文件中添加message函数来打印一些调试信息,以确保路径和变量正确设置。
示例:
bashmessage(STATUS "Source directory: ${CMAKE_SOURCE_DIR}") message(STATUS "Include directories: ${CMAKE_INCLUDE_PATH}")
通过上述步骤,您可以定位和解决unknown type name问题。在使用CMake、Ninja和LLVM编译C++项目时,确保所有头文件正确包含并设置正确的头文件路径是关键。
十、Ninja: error: mkdir(...) no such file or directory
问题现象
HarmonyOS鸿蒙Next rn工程报错:
perl
ERROR: Failed :entry:default@buildNativeWithNinja
ERRPR: Tools execution failed
ninja: error: mkdir(rn/patches/... // ///__/ ... )no such file or directory
解决措施
rn工程路径太长导致报错,请修改一下工程路径,缩短路径长度后再重新尝试。
十一、编译第三方库micro-ecc报错
问题现象
编译三方c++库micro-ecc时,报错:
vbnet
warning: argument unused during compilation: '--gcc-toolchain=/Users/shen/Library/Huawei/Sdk/openharmony/11/native/llvm' [-Wunused-command-line-argument]
In file included from /Users/shen/kecode/mars/mars/xlog/crypt/micro-ecc-master/uECC.c:177: /Users/shen/kecode/mars/mars/xlog/crypt/micro-ecc-master/asm_arm.inc:85:36: error: '.syntax divided' arm assembly not supported
"adcs %[carry], %[carry] \n\t"
note: instantiated into assembly here
.syntax divided
error原因分析
micro-ecc库中的ARM汇编代码使用了.syntax divided语法,而鸿蒙NDK工具链可能不支持这种ARM汇编语法。
解决措施
- 参考新版本编译:gitee.com/openharmony...
- 如果问题仍然存在,可以尝试修改汇编代码,移除.syntax divided指令,或者寻找不包含汇编代码的micro-ecc版本。
十二、ld.lld: error: unable to find library
问题现象
引入第三方so文件时,报错:
vbnet
[OHOS ERROR] ld.lld: error: unable to find library -lstdc++
[OHOS ERROR] clang-15: error: linker command failed with exit code 1 (use -v to see invocation)
解决措施
这个错误通常是由于链接器无法找到指定的库文件导致的。在HarmonyOS鸿蒙Next开发环境中,ld.lld是LLVM项目中的链接器。要解决这个问题,可以按照以下步骤进行排查:
- 检查库路径:确保库文件路径正确,并在编译命令中通过-L选项指定库文件所在的目录。
- 库文件存在:确认所需的库文件确实存在于指定路径中,且文件名正确。
- 库文件权限:确保库文件具有正确的读取权限。
- 环境变量:检查LD_LIBRARY_PATH环境变量是否包含库文件所在的路径。
- 安装缺失的库:如果是系统库缺失,可以尝试安装相应的开发包。例如,对于缺少libstdc++的问题,可以安装libstdc++-dev包。
如果问题仍未解决,可以检查构建系统的配置文件和日志,进一步定位问题。
十三、C/C++项目三方依赖库未打包入HAP
问题现象
C/C++项目中引用的第三方依赖库没有被正确打包到HAP文件中。
解决措施
-
检查build-profile.json5中的nativeLib配置,确保collectAllLibs设置正确:
json"nativeLib": { "collectAllLibs": true }
collectAllLibs设为true表示不限制后缀,收集所有文件;设为false(默认值)表示只收集.so文件。
-
检查是否正确配置了filter选项,确保没有排除需要打包的库文件:
json"filter": { "excludes": [], "pickFirsts": ["**/*.so"], "enableOverride": true }
-
确保在CMakeLists.txt中正确链接了第三方库,并且库文件存在于正确的目录中。
十四、静态库模块中src/main/cpp目录下的文件未打包进HAR
问题现象
静态库模块中src/main/cpp目录下的C/C++文件没有被正确打包到HAR文件中。
解决措施
-
确保在模块的build-profile.json5中正确配置了nativeLib:
json"buildOption": { "nativeLib": { "collectAllLibs": true, "excludeFromHar": false } }
excludeFromHar设为false表示将.so文件包含在HAR中。
-
检查CMakeLists.txt中是否正确设置了库的输出路径,确保生成的静态库位于正确的位置。
-
确保在模块的build-profile.json5中正确配置了externalNativeOptions,指定了正确的CMakeLists.txt路径。
十五、编译报错"ninja: error: unknown target 'tinyplay'"
问题现象
编译OpenHarmony的tinyplay模块时,报错:
vbnet
[OHOS ERROR] ninja: error: unknown target 'tinyplay'
解决措施
- 确认你的OpenHarmony代码库是否已经完整下载,没有缺失文件。
- 检查你的编译环境是否正确配置,特别是GN和Ninja的路径是否正确设置。
- 尝试重新编译整个OpenHarmony代码库,或者手动编译tinyplay模块。
- 可以在OpenHarmony社区中寻求帮助,以便更快地解决问题。
十六、编译构建常见问题总结
1. 编译内存过高
- 调整hvigor-config.json5中的内存相关配置
- 关闭并行编译模式
2. 构建配置错误
- 检查hvigorconfig.ts和hvigorfile.ts中的未定义属性
- 通过配置stacktrace查看详细错误信息
3. 文件冲突问题
- 使用select、pickFirsts、pickLasts解决so文件冲突
- 确保模块间releaseType和debug字段一致
4. CMake配置问题
- 正确设置头文件搜索路径
- 检查CMake变量是否正确定义
5. 第三方库问题
- 确保第三方库与鸿蒙系统兼容
- 正确配置库文件路径和链接选项
6. 路径问题
- 避免过长的工程路径
- 确保文件路径中不包含特殊字符
通过以上解决方案,可以解决鸿蒙开发中大部分CMake/Ninja编译相关的问题。在遇到编译错误时,建议首先查看详细的错误日志,根据错误信息定位问题原因,然后采取相应的解决措施。如果问题仍然无法解决,可以参考鸿蒙官方文档或在开发者社区寻求帮助。