#创作者激励#[触觉智能RK3568]OpenHarmony NDK工具(上)

时间:2021-01-30 00:55:07

【本文正在参加2023年第一期优质创作者激励计划】

在OpenHarmony应用开发中选择Native C ++开发方式需要使用OpenHarmony NDK工具,或者想移植一个C/C ++的三方库到OpenHarmony中也可以使用NDK。NDK使用到的编译工具是cmake,也就是CMakeLists.txt那一套。Native C ++应用开发方式可以做直接编译三方库的so库再利用NAPI框架实现能力的调用(只需要在三方库原生的CMakeLists.txt中修改小部分的内容就可以实现)。


(目录)

一、OpenHarmony NDK

  • NDK (原生开发套件) 是一套工具,使开发者能够在 OpenHarmony hap应用中使用 C/C++ 代码。
  • NDK提供了一系列的工具可以帮助开发者快速的开发C/C++的动态库、静态库和可执行文件。
  • OpenHarmony 应用开发的Native C++开发方式就要依赖NDK。NDK被包含在OpenHarmony SDK中。可以在DevEco Studio使用 NDK 将 C/C ++ 代码编译到so库中,然后使用 DevEco Studio 的构建插件hvigor-ohos-plugin将so库打包到 Hap 中。ArkTS代码随后可以通过NAPI框架调用SO库中的函数。 #创作者激励#[触觉智能RK3568]OpenHarmony NDK工具(上)#创作者激励#[触觉智能RK3568]OpenHarmony NDK工具(上)

二、获取NDK的方式

2.1 从每日构建中获取

  • 每日构建地址: http://ci.openharmony.cn/dailys/dailybuilds

  • 组件形态选择ohos-sdk,版本选择最新版本的sdk一般是没有问题的(但是笔者之前遇到下载的ndk中的clang工具找不到libatomic.so无法工作的情况的情况) #创作者激励#[触觉智能RK3568]OpenHarmony NDK工具(上)

  • 下载解压后可以得到如下文件,根据linux或者windows端解压不同文件得到sdk #创作者激励#[触觉智能RK3568]OpenHarmony NDK工具(上)

2.2 编译源码得到SDK中的NDK

安装依赖
./build/build_scripts/env_setup.sh

执行完上述命令后记得执行source ~/.bashrc或者重启终端
source ~/.bashrc

安装编译SDK需要的依赖包(编译镜像的时候是不依赖这些包的)
sudo apt-get install libxcursor-dev libxrandr-dev libxinerama-dev

./build.sh --product-name ohos-sdk --ccache --build-target ohos_ndk

写文章提的issue https://gitee.com/openharmony/build/issues/I6H8IO?from=project-issue

  • 在对应的目录底下找到编译成功的NDK,相关路径out/sdk/packages/ohos-sdk/linux/native,根据linux或者windows端解压不同文件得到sdk

#创作者激励#[触觉智能RK3568]OpenHarmony NDK工具(上)

二、NDK目录

native
   ├── NOTICE.txt                                        声明文件
   ├── build
   │     └── cmake
   │           ├── ohos.toolchain.cmake             ---->编译的工具链
   │           └── sdk_native_platforms.cmake       ---->编译的工具链(在DevEco Studio中编译打包so要用到)                 
   ├── build-tools                                  ---->cmake编译工具所在目录(NDK提供的编译工具)
   ├── llvm                                         ---->编译器所在目录(NDK提供的编译工具)
   ├── sysroot                                      ---->编译器的 sysroot 目录,存放 SDK 内部的已经包含的库和对应的头文件
   ├── ndk_system_capability.json                   ---->NDK自带so库能力描述文件
   ├── nativeapi_syscap_config.json                 ---->调用NDK自带so库能力相关头文件
   ├── docs                                         ---->调用NDK自带so库能力相关文档
   └── oh-uni-package.json                          ---->SDK 信息描述
  • llvm中bin目录下的编译器有
FileCheck    clang-format      ld64.lld        lldb-vscode      llvm-cxxfilt     llvm-objdump   llvm-strip       yaml2obj
clang        clang-tidy        lld             llvm-addr2line   llvm-dis         llvm-profdata  llvm-symbolizer
clang++      clangd            lld-link        llvm-ar          llvm-lib         llvm-ranlib    not
clang-12     count             lldb            llvm-as          llvm-link        llvm-readelf   sancov
clang-check  dsymutil          lldb-argdumper  llvm-cfi-verify  llvm-modextract  llvm-readobj   sanstats
clang-cl     git-clang-format  lldb-mi         llvm-config      llvm-nm          llvm-size      scan-build
clang-cpp    ld.lld            lldb-server     llvm-cov         llvm-objcopy     llvm-strings   scan-view

三、linux下使用NDK编译库文件和可执行文件

3.1 使用NDK编译一个简单demo

  • 在这里使用这个OpenHarmony仓库的这个demo https://gitee.com/openharmony/third_party_musl/tree/master/ndk-test/ndk-test/src/shared-library 这个demo编译前的目录结构
shared-library            
├── CMakeLists.txt      外部CMakeLists.txt    
├── include             头文件目录
│   └── shared
│       └── Hello.h      
└── src                 源文件目录
    ├── CMakeLists.txt  内部CMakeLists.txt  
    ├── Hello.cpp
    └── main.cpp
  • 外部CMakeLists.txt
#cmake的版本
CMAKE_MINIMUM_REQUIRED(VERSION 3.16)
#工程名称
PROJECT(HELLO_LIBRARY)
#添加一个子目录并构建该子目录
ADD_SUBDIRECTORY(src)

cmake的内置命令是不区分大小写的,因此add_subdirectory与ADD_SUBDIRECTORY作用一致。但是cmake的所有变量都是区分大小写的

  • 内部CMakeLists.txt
#设置可执行文件输出路径
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/output)
# 设置so库文件输出路径
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/output)

############################################################
# Create a library
############################################################

#SHARED表示生成的是动态库,动态库的名字是hello_shared_library。生成动态库的源文件是Hello.cpp
ADD_LIBRARY(hello_shared_library SHARED 
	Hello.cpp
	)
#为生成的动态库添加一个别名,后续hello::library可使用来替代hello_shared_library
ADD_LIBRARY(hello::library ALIAS hello_shared_library)

#为指定目标hello_shared_library添加头文件搜索路径(这个指定目标决不能是alias target,也就是指定的别名hello::library)
TARGET_INCLUDE_DIRECTORIES(hello_shared_library
	PUBLIC 
	${PROJECT_SOURCE_DIR}/include
	)

############################################################
# Create an executable
############################################################

# 使用指定的源文件main.cpp创建出一个可执行文件hello_shared_binary 
ADD_EXECUTABLE(hello_shared_binary
	main.cpp
	)

#TARGET_LINK_LIBRARIES指令的作用为将目标文件与库文件进行链接
#将可执行文件hello_shared_binary与库文件hello::library进行链接
TARGET_LINK_LIBRARIES( hello_shared_binary
	PRIVATE 
	hello::library
	)	

3.2 进行cmake编译

3.2.1 NDK自带的cmake编译工具添加到环境变量

1、第一种方法:

#将其临时加入环境变量中(适用于临时想用用NDK)
export PATH=$PATH:/ohos-sdk/linux/native/build-tools/cmake/bin(你自己解压的NDK目录)

2、第二种方法:

#将其永远加入环境变量中
#打开.bashrc文件
vim ~/.bashrc
#在文件最后添加cmake路径,该路径是自己的放置文件的路径,之后保存退出
export PATH=/ohos-sdk/linux/native/build-tools/cmake/bin:$PATH
#在命令行执行source ~/.bashrc使环境变量生效
source ~/.bashrc

3、查看环境变量添加是否成功

 cmake -version

#创作者激励#[触觉智能RK3568]OpenHarmony NDK工具(上) 可知cmake的版本是3.16.5 ,所以编写CMakeLists.txt可参考的链接为 https://cmake.org/cmake/help/v3.16/guide/tutorial/

3.2.2 安装make

  • 如果没有安装make会出现以下报错,则执行sudo apt-get install make。(如果已经安装make,请忽略) #创作者激励#[触觉智能RK3568]OpenHarmony NDK工具(上)

3.2.3 cmake的几个参数

1、OHOS_STL参数,其类型可以是c++_sharedc++_static,默认是c++_shared #创作者激励#[触觉智能RK3568]OpenHarmony NDK工具(上)

2、OHOS_ARCH参数(设置应用程序二进制接口ABI),其类型是armeabi-v7ax86_64 ,默认值是arm64-v8a。每一种ABI定义了相应的二进制文件。

  • armeabi-v7a (选择这个是编译32位的二进制文件)
  • arm64-v8a (选择这个是编译64位的二进制文件)
  • x86_64 (现在不使用,OpenHarmony现在在适配x86的芯片)

3、OHOS_PLATFORM参数,其类型为OHOS(只能选择OHOS平台)

4、 CMAKE_TOOLCHAIN_FILE参数指向的是工具链文件所在的位置,就是ohos.toolchain.cmake的路径(对于编译不同平台二进制文件是很重要的)。

  • build目录中的工具链文件ohos.toolchain.cmake,cmake编译时需要读取该文件中的默认值,比如编译器的选择、编译平台,例如ohos.toolchain.cmake文件中,
# Common default settings
39:if(NOT DEFINED OHOS_PLATFORM_LEVEL)
   set(OHOS_PLATFORM_LEVEL 1)
   endif()
43:if(NOT DEFINED OHOS_TOOLCHAIN)
   set(OHOS_TOOLCHAIN clang)
   endif()
47:if(NOT DEFINED OHOS_STL)
   set(OHOS_STL c++_shared)
   endif()
51:if(NOT DEFINED OHOS_PIE)
   set(OHOS_PIE TRUE)
   endif()
55:if(NOT DEFINED OHOS_ARM_NEON)
   set(OHOS_ARM_NEON thumb)
   endif()
60:if(NOT DEFINED OHOS_ARCH)
   set(OHOS_ARCH arm64-v8a)
   endif()
  • 在编译时需要指出该文件的所在路径,以便于cmake在编译时定位到该文件。在编译的时候需要为cmake指定参数来控制编译目标的属性。

3.2.4 使用CMake进行构建,并传递工具链文件及cmake参数

# dmeo目录下创建build目录,用来放置cmake构建时产生的中间文件。
mkdir build && cd build

# 传递OHOS_STL(可选,默认就是c++_shared)、OHOS_ARCH、OHOS_PLATFORM、工具链文件
# CMAKE_TOOLCHAIN_FILE是ohos.toolchain.cmake具体放置的路径
# 这一步会检查CMakeLists.txt是否有语法错误 
# 不要忘记在ohos.toolchain.cmake路径后面加上 ..
cmake -D OHOS_STL=c++_shared -D OHOS_ARCH=armeabi-v7a -D OHOS_PLATFORM=OHOS -D CMAKE_TOOLCHAIN_FILE=/xxx/build/cmake/ohos.toolchain.cmake ..

cmake --build .

1、执行如下过程如下: #创作者激励#[触觉智能RK3568]OpenHarmony NDK工具(上)

2、可以注意到执行cmake --build .时会有warning: -Wunused-command-line-argument, 通过在内部的CMakeLists.txt中添加如下语句消除warning。

set(CMAKE_CXX_FLAGS "-Wno-unused-command-line-argument")

#创作者激励#[触觉智能RK3568]OpenHarmony NDK工具(上)

  • 注意:.c文件时是使用CMAKE_C_FLAGS,.cpp文件时是使用CMAKE_CXX_FLAGS

3、编译结果如下: 生成可执行文件和动态库 #创作者激励#[触觉智能RK3568]OpenHarmony NDK工具(上)

4、要编译静态库及其可执行文件,内部的CMakeLists.txt中添加如下语句

############################################################
# Create a library
############################################################

#Generate the static library from the library sources
ADD_LIBRARY(hello_static_library STATIC 
	Hello.cpp
	)

TARGET_INCLUDE_DIRECTORIES(hello_static_library
	PUBLIC 
	${PROJECT_SOURCE_DIR}/include
	)

############################################################
# Create an executable
############################################################

# Add an executable with the above sources
ADD_EXECUTABLE(hello_static_binary 
	main.cpp
	)

# link the new hello_library target with the hello_binary target
TARGET_LINK_LIBRARIES( hello_static_binary
	PRIVATE 
	hello_static_library
	)	

编译结果如下,生成静态库及其可执行文件 #创作者激励#[触觉智能RK3568]OpenHarmony NDK工具(上)

5、编译64位的库文件和可执行文件,OHOS_ARCH参数选择arm64-v8a或者编译时不传递该参数。

3.4.5 使用CMake进行构建,选择ninja生成器并生成编译流程图

1、执行cmake -G查看linux环境下的生成器,ndk中自带的生成器是Ninja。

#创作者激励#[触觉智能RK3568]OpenHarmony NDK工具(上)

2、使用CMake进行构建时添加上-G "Ninja"

#创作者激励#[触觉智能RK3568]OpenHarmony NDK工具(上)

第一步:mkdir build && cd build

第二步:cmake -G "Ninja" -D OHOS_STL=c++_shared -D OHOS_ARCH=armeabi-v7a -D OHOS_PLATFORM=OHOS -D CMAKE_TOOLCHAIN_FILE=/xxx/build/cmake/ohos.toolchain.cmake ..

第三步:cmake --build .或者ninja -f build.ninja

执行完第二步后,build目录下会生成build.ninja,有了build.ninja可以使用ninja生成程序的编译流程图。

3、使用ninja工具生成库文件和可执行文件的编译流程图。

# 将libhello_shared_library.so动态库的编译流程转为dot
ninja -t graph libhello_shared_library.so > xxx.dot

# 将dot格式转化为png格式的流程图
dot -T png xxx.dot -o libhello_shared_library.so.png
# 将dot格式转化为svg格式的流程图
dot -T svg xxx.dot -o libhello_shared_library.so.svg

#创作者激励#[触觉智能RK3568]OpenHarmony NDK工具(上) 如果生成图片格式太小的话,可以生成svg格式到浏览器打开,这一点很重要,请参考该 issue

3.4.6 使用NDK中的cmake-gui进行图形化操作编译

1、native/build-tools/cmake/bin目录有cmake-gui,可以用它图形化传入编译参数进行编译。 #创作者激励#[触觉智能RK3568]OpenHarmony NDK工具(上)

2、首先点击Where is source code行的Browser Source,加载工程所在目录。 再点击Where to build the binarys行的Browser Source,加载点击“Where is source code”行的Browser Source,加载源码所在目录。 点击“Where to build the binarys行的Browser Source,加载工程所在目录下的build目录(没有就创建一个)。

3、点击Add Entry传入cmake 参数。勾选把旁边的Grouped选项。 #创作者激励#[触觉智能RK3568]OpenHarmony NDK工具(上)

4、点击Configure选择Current Generator生成器为Unix Makefiles

5、最后打开Where to build the binarys加载构建目录终端,执行make -j 8命令

make -j n含义是 让make最多允许n个编译命令同时执行,这样可以更有效的利用CPU资源。假设系统cpu是12核,在不影响其他工作的情况下,我们可以make -j 12将cpu资源充分利用起来,一般来说,最大并行任务数为cpu_num * 2。

#创作者激励#[触觉智能RK3568]OpenHarmony NDK工具(上)


写文章提的issue https://gitee.com/openharmony/third_party_musl/issues/I6JRBU?from=project-issue

本文作者:离北况归

想了解更多关于开源的内容,请访问:​

​51CTO 开源基础软件社区​

​https://ost.51cto.com/#bkwz​