HarmonyOS NEXT系列之编译三方C/C++库

编译三方C/C++库

〇、前言

熟悉主流编程语言的开发者,相比心里对 C/C++ 语言的非跨平台性,早已有所深刻体会。虽然,C/C++ 代码无法像 Python 或 Java 那样一次编写到处运行,但却允许进行制品定制:即为目标平台量身定做输出相应的制品

而 HarmonyOS NEXT 系统,就是 C/C++ 代码编译的目标平台中的一种,而 HarmonyOS NEXT 项目中,使用 C/C++ 代码的方式,一种是直接在 NDK 模块中编写相应的 C/C++ 代码,另一种则是以 NDK 模块为桥梁将三方库集成到项目中;而在第二种方式中,必须先有一个能够在 HarmonyOS NEXT 平台上进行运行的库文件:xxxx.so

而本篇正是要向大家普及如何将一个三方 C/C++ 库编译成 HarmonyOS NEXT 平台中能够直接使用的方法库。

一、新建 C/C++ 项目

这里推荐从零开始进行体验,也即是由自己一手创建一个新的 C/C++ 项目,为了方便源代码进行编译,需要使用 CMake 工具作为项目管理工具。

1、目录设置

使用 CMake 管理项目的 C/C++ 项目,在项目根目录中都会创建一个 CMakeLists.txt 文件,我们以该文件为参照,在同级目录中新建src目录和include目录,最终的项目目录结构如下:

txt 复制代码
project-root:
	- src/
	- include/
	- CMakeLists.txt

2、更新 CMakeLists.txt

对于新增的目录,默认情况下,都不会被 CMake 所识别到,需要通过 CMakeLists 文件去引入,比如,在上面的目录结构中,想要 include 目录下的所有头文件、以及src目录下的所有源文件,都能在当前项目中使用,就需要在 CMakeLists 中添加如下内容:

cmake 复制代码
file(GLOB_RECURSE SOURCES "src/*.cpp")
include_directories(include)
add_library(${PROJECT_NAME} SHARED library.cpp
        ${SOURCES}
)

另外,为了规范制品输出目录,不妨在 CMakeLists 文件末尾加上这样一段代码:

cmake 复制代码
# 输出设置
set_target_properties(${PROJECT_NAME} PROPERTIES
        LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/libs/${OHOS_ARCH}
        OUTPUT_NAME "${PROJECT_NAME}"
        SUFFIX ".so"
)

OHOS_ARCH 指代目标平台的芯片架构,以 HarmonyOS NEXT 来说,就是arm64-v8a,最终,完整的 CMakeLists 文件如下:

cmake 复制代码
cmake_minimum_required(VERSION 3.27)
project(HMOSThirdLib)

set(CMAKE_CXX_STANDARD 17)
# 工具链和平台配置
set(CMAKE_TOOLCHAIN_FILE
        "/Applications/DevEco-Studio.app/Contents/sdk/default/openharmony/native/build/cmake/ohos.toolchain.cmake"
        CACHE STRING "" FORCE)

set(CMAKE_INSTALL_PREFIX "/output/HMOSThirdLib" CACHE PATH "" FORCE)
set(OHOS_ARCH "arm64-v8a" CACHE STRING "" FORCE)
# 标准配置(需放在工具链设置之后)
enable_language(C CXX)
file(GLOB_RECURSE SOURCES "src/*.cpp")
include_directories(include)
add_library(HMOSThirdLib SHARED library.cpp
        ${SOURCES}
)
# 输出设置
set_target_properties(HMOSThirdLib PROPERTIES
        LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/libs/${OHOS_ARCH}
        OUTPUT_NAME "HMOSThirdLib"
        SUFFIX ".so"
)

3、编写C/C++ 方法

在 include 目录下,新建一个 simple.h 文件,而 src 目录下则相应地创建一个 simple.cpp 文件,记住,头文件和源文件一定要同名。在 simple.h 中声明一个方法原型:

cpp 复制代码
/*
 * Copyright (c) 2025 彭友聪
 * HMOSThirdLib is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
 * NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 * IDE: CLion
 * Project:  HMOSThirdLib
 * File:     simple.h
 * @author:  御承扬
 * @Email: 2923616405@qq.com
 * @Date:    2025/8/10
 * @Time:    13:58
 * 
 * */

//
// Created by pengyoucong on 2025/8/10.
//

#ifndef HMOSTHIRDLIB_SIMPLE_H
#define HMOSTHIRDLIB_SIMPLE_H
const char* simpleReturnString();
#endif //HMOSTHIRDLIB_SIMPLE_H

对应的simple.cpp,对该方法进行具体实现:

cpp 复制代码
/*
 * Copyright (c) 2025 彭友聪
 * HMOSThirdLib is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
 * NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 * IDE: CLion
 * Project:  HMOSThirdLib
 * File:     simple.cpp
 * @author:  御承扬
 * @Email: 2923616405@qq.com
 * @Date:    2025/8/10
 * @Time:    14:00
 * 
 * */

//
// Created by pengyoucong on 2025/8/10.
//
#include "simple.h"
const char* simpleReturnString() {
    return "simpleReturnString:尝试将C/C++源码编译成鸿蒙平台库文件";
}

二、编译库文件

由于 CMake 进行库文件编译的时候,会生成一些配置文件和中间文件,因此,为了不污染项目目录,可以在项目根目录下新建一个专门的目录,用于存放 CMake 输出的中间文件和配置文件,比如新建一个 hmos_ouput 目录,而后在命令行中打开该目录,并使用如下命令:

sh 复制代码
{HOMS_NDK_HOME}/native/build-tools/cmake/bin/cmake -DCMAKE_TOOLCHAIN_FILE={HOMS_NDK_HOME}/native/build/cmake/ohos.toolchain.cmake -DCMAKE_INSTALL_PREFIX=/output/HMOSThirdLib -DOHOS_ARCH=arm64-v8a .. -L

进行 cmake 编译,而编译成功之后,就会在 hmos_ouput 目录下生成 Makefile,有了这个Makefile后,同样在 hmos_ouput 目录下执行 make 命令,就可以得到最终的制品,而该制品会放在 CMakeLists 中设定的 libs/HMOSThirdLib.so,而由于执行 CMake 操作的目录在 homs_ouput 目录,所以生成的libs 也就在该目录下。

三、使用预编译库

找一个 HarmonyOS NEXT 项目,创建一个 NDK 模块,并将上述得到的 .so 文件即 C/C++ 预编译库,集成到该 NDK 模块中进行使用。

1、引入头文件

将 simple.h 文件从上面的C/C++项目中拷贝一份,并放到 NDK 模块的 src/main/cpp/include 中,为了保证 simple.h 文件能被检索到,修改 NDK 模块的 CMakeLists 文件,加上内容:

make 复制代码
include_directories(${NATIVERENDER_ROOT_PATH}
                    ${NATIVERENDER_ROOT_PATH}/include
                    )

2、引入库文件

接着,将 ibHMOSThirdLib.so 文件复制一份,并放到 NDK 模块根目录下的libs目录,相应的架构目录中,例如:

并将该库文件通过 CMakeLists 进行链接,即用 target_link_libraries(learnnapi PUBLIC libace_napi.z.so ${CMAKE_CURRENT_SOURCE_DIR}/../../../libs/${OHOS_ARCH}/libHMOSThirdLib.so) 进行设置。

3、在 NAPI 中使用 simpleReturnString 方法

由于在鸿蒙APP最终以ArkTS代码编写pages作为应用交互界面,必须先将纯C/C++ 代码通过 NAPI 进行转写才行,所以,我们有必要在 NDK 模块中新增一个 NAPI,不妨就叫 testGetMessage,具体操作如下:

3.1、新增NAPI

打开位于 /src/main/cpp 目录下的 napi_init.cpp 文件,在文件头处新增导包语句:#include "simple.h",并在合适位置新增如下一段代码:

cpp 复制代码
static napi_value testGetMessage(napi_env env, napi_callback_info info) {
    const char* message = simpleReturnString();
    napi_value result;
    napi_status status = napi_create_string_utf8(env, message, strlen(message), &result);
    return status == napi_ok ? result : nullptr;
}

将该方法注册到 napi_property_descriptor 中:

而 src/main/cpp/types/index.d.ts 中相应增加内容:

3.2、使用 NAPI

如上所示,在 entry 模块或其他 har 包模块,只需将 NDK 模块作为依赖添加到 oh-package.json 文件中,就可以用类似如下的代码去使用 NAPI:

ts 复制代码
import nativeModule from 'liblearnnapi.so'

export class NAPIAdapter {


  private constructor() {
  }
  static Add(x: number, y: number) {
    return nativeModule.add(x, y);
  }
  static NativeCallArkTs(param: number) {
    return nativeModule.nativeCallArkTS((x: number) => {
      return x + param;
    });
  }
  static createPerson(name: string, age: number, height: number) {
    return nativeModule.createPerson(name, age, height);
  }
  static parsePerson(param: object) {
    return nativeModule.parsePerson(param);
  }
  static testGetMessage() {
    return nativeModule.testGetMessage();
  }
}

将APP部署到真机上运行,打开日志窗口就可以看到对应的内容输出:

相关推荐
Q741_1472 分钟前
如何判断一个数是 2 的幂 / 3 的幂 / 4 的幂 / n 的幂 位运算 总结和思考 每日一题 C++的题解与思路
开发语言·c++·算法·leetcode·位运算·总结思考
小郝 小郝1 小时前
开启单片机
c语言·单片机·嵌入式硬件·学习·51单片机
源代码•宸2 小时前
C++高频知识点(十八)
开发语言·c++·经验分享·多线程·互斥锁·三次握手·字节对齐
mit6.8242 小时前
修复C++14兼容性问题& 逻辑检查
开发语言·c++
前端世界3 小时前
HarmonyOS 设备自动发现与连接全攻略:从原理到可运行 Demo
华为·harmonyos
无风听海3 小时前
HarmonyOS之module.json5功能详解
harmonyos·module.json5
HMS Core3 小时前
HarmonyOS SDK助力讯飞听见App能力建设
华为·harmonyos
许怀楠3 小时前
【C++】类和对象(下)
c++
danzongd3 小时前
浅谈C++ const
c++·内存·优化·汇编语言·计算机系统·寄存器