鸿蒙开发中CMake/Ninja编译问题与解决方案

一、编译内存过高问题

问题现象

编译构建时,内存或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.soentry模块里也有一个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字段是否一致,尤其需要关注本地模块和外部引用模块之间是否一致。

  1. 该debug字段由编译构建工具自动生成,保存在HAP/HSP包的module.json文件中,首先确认各模块间该字段是否一致。
  2. 编译工具根据设置的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++代码的核心过程

  1. 根据CMake配置脚本以及build-profile.json5中配置的externalNativeOptions构建参数,与缓存中的配置比对后,生成CMake命令并执行CMake
  2. 执行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"错误通常表示编译器无法识别某个类型。这可能是因为类型未定义、未包含相关的头文件,或者包含的头文件路径不正确。以下是定位和解决这个问题的步骤:

  1. 检查是否包含头文件 确保所有必要的头文件都已正确包含在源文件中。例如,如果您正在使用某个自定义类型或库提供的类型,请确保在使用该类型的文件中包含了相关的头文件。

    示例:

    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
  2. 检查头文件路径 确保CMakeLists.txt中正确设置了头文件的搜索路径。可以通过include_directories添加头文件目录。

    示例CMakeLists.txt:

    scss 复制代码
    cmake_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)
  3. 清理和重新生成构建文件 有时,构建文件可能会损坏或丢失符号定义。尝试清理构建目录并重新生成构建文件:

    复制代码
    hvigorw clean

    或手动删除模块下.cxx目录。

  4. 启用详细编译输出 为了解详细的编译过程,可以启用更详细的输出。在CMakeLists.txt中添加以下内容:

    scss 复制代码
    set(CMAKE_VERBOSE_MAKEFILE ON)
  5. 检查编译输出日志 Ninja默认生成.ninja_log文件,其中包含构建过程的详细信息。你可以检查这个日志文件以了解构建过程中的问题:

    bash 复制代码
    cat .cxx/default/default/arm64-v8a/.ninja_log
  6. 使用CMake的message函数调试 可以在CMakeLists.txt文件中添加message函数来打印一些调试信息,以确保路径和变量正确设置。

    示例:

    bash 复制代码
    message(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汇编语法。

解决措施

  1. 参考新版本编译:gitee.com/openharmony...
  2. 如果问题仍然存在,可以尝试修改汇编代码,移除.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项目中的链接器。要解决这个问题,可以按照以下步骤进行排查:

  1. 检查库路径:确保库文件路径正确,并在编译命令中通过-L选项指定库文件所在的目录。
  2. 库文件存在:确认所需的库文件确实存在于指定路径中,且文件名正确。
  3. 库文件权限:确保库文件具有正确的读取权限。
  4. 环境变量:检查LD_LIBRARY_PATH环境变量是否包含库文件所在的路径。
  5. 安装缺失的库:如果是系统库缺失,可以尝试安装相应的开发包。例如,对于缺少libstdc++的问题,可以安装libstdc++-dev包。

如果问题仍未解决,可以检查构建系统的配置文件和日志,进一步定位问题。

十三、C/C++项目三方依赖库未打包入HAP

问题现象

C/C++项目中引用的第三方依赖库没有被正确打包到HAP文件中。

解决措施

  1. 检查build-profile.json5中的nativeLib配置,确保collectAllLibs设置正确:

    json 复制代码
    "nativeLib": {
      "collectAllLibs": true
    }

    collectAllLibs设为true表示不限制后缀,收集所有文件;设为false(默认值)表示只收集.so文件。

  2. 检查是否正确配置了filter选项,确保没有排除需要打包的库文件:

    json 复制代码
    "filter": { 
      "excludes": [],
      "pickFirsts": ["**/*.so"],
      "enableOverride": true
    }
  3. 确保在CMakeLists.txt中正确链接了第三方库,并且库文件存在于正确的目录中。

十四、静态库模块中src/main/cpp目录下的文件未打包进HAR

问题现象

静态库模块中src/main/cpp目录下的C/C++文件没有被正确打包到HAR文件中。

解决措施

  1. 确保在模块的build-profile.json5中正确配置了nativeLib:

    json 复制代码
    "buildOption": {
      "nativeLib": {
        "collectAllLibs": true,
        "excludeFromHar": false
      }
    }

    excludeFromHar设为false表示将.so文件包含在HAR中。

  2. 检查CMakeLists.txt中是否正确设置了库的输出路径,确保生成的静态库位于正确的位置。

  3. 确保在模块的build-profile.json5中正确配置了externalNativeOptions,指定了正确的CMakeLists.txt路径。

十五、编译报错"ninja: error: unknown target 'tinyplay'"

问题现象

编译OpenHarmony的tinyplay模块时,报错:

vbnet 复制代码
[OHOS ERROR] ninja: error: unknown target 'tinyplay'

解决措施

  1. 确认你的OpenHarmony代码库是否已经完整下载,没有缺失文件。
  2. 检查你的编译环境是否正确配置,特别是GN和Ninja的路径是否正确设置。
  3. 尝试重新编译整个OpenHarmony代码库,或者手动编译tinyplay模块。
  4. 可以在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编译相关的问题。在遇到编译错误时,建议首先查看详细的错误日志,根据错误信息定位问题原因,然后采取相应的解决措施。如果问题仍然无法解决,可以参考鸿蒙官方文档或在开发者社区寻求帮助。

#鸿蒙开发资料领取

相关推荐
万少2 小时前
可可图片编辑 HarmonyOS(2) 选择图片和保存到图库
harmonyos
小小小小小星3 小时前
鸿蒙开发性能优化实战指南:从工具到代码全解析
性能优化·harmonyos
奶糖不太甜3 小时前
鸿蒙元应用与服务卡片技术文档及案例
harmonyos
特立独行的猫a3 小时前
C/C++三方库移植到HarmonyOS平台详细教程
c语言·c++·harmonyos·napi·三方库·aki
缘澄3 小时前
ArkUI基础篇-组件事件
harmonyos·arkui
鸿蒙先行者3 小时前
HarmonyOS与OpenHarmony区别分析
harmonyos
li理4 小时前
鸿蒙NEXT渲染控制全面解析:从条件渲染到混合开发
harmonyos
li理4 小时前
鸿蒙Next组件扩展全面解析:从构建函数到样式复用的完整指南
前端·harmonyos
博客园团队5 小时前
2025 HarmonyOS 创新赛正式启动,百万大奖等你挑战!
harmonyos