- 大家好,我是一名即將本科畢業(yè)的OpenHarmony開發(fā)者,去年暑假利用了兩個(gè)月時(shí)間移植了一個(gè)語(yǔ)音處理的三方庫(kù)Speexdsp到OpenHarmony標(biāo)準(zhǔn)系統(tǒng)。主要為其編寫了
build.gn
使其加入了OpenHarmony編譯體系(基于ninja和gn),Speexdsp在linux下是使用構(gòu)建工具configure、makefile構(gòu)建的。移植的難點(diǎn)并不在于.c和.h以及cflags、idflags的分析,而在于重新熟悉一套編譯構(gòu)建體系,而且當(dāng)時(shí)可參考的資料并不太多。 - 筆者最近為Speexdsp編寫了
CMakeLists.txt
,使用OpenHarmony的NDK工具編譯出來(lái)so動(dòng)態(tài)庫(kù)和可執(zhí)行文件,并且成功在開發(fā)板上運(yùn)行,現(xiàn)將經(jīng)驗(yàn)分享如下:
speexdsp移植完畢已提交至openhamrony sig倉(cāng)庫(kù):https://gitee.com/openharmony-sig/contest/tree/master/2022_OpenHarmony_thirdparty/speexdsp
(筆者也沒想到會(huì)繼續(xù)續(xù)寫三方庫(kù)方面的文章,學(xué)無(wú)止境,希望能夠幫助更多人了解OpenHarmony,加入OpenHarmony生態(tài))
- NDK (原生開發(fā)套件) 是一套工具,使開發(fā)者能夠在 OpenHarmony hap應(yīng)用中使用 C/C++ 代碼。它提供了一系列的工具可以幫助開發(fā)者快速的開發(fā)C/C++的動(dòng)態(tài)庫(kù)、靜態(tài)庫(kù)和可執(zhí)行文件。
- OpenHarmony 應(yīng)用開發(fā)的Native C++開發(fā)方式就要依賴NDK。NDK被包含在OpenHarmony SDK中??梢栽?a href="http://wenjunhu.com/outside?redirect=https://developer.harmonyos.com/cn/docs/documentation/doc-guides-V3/ohos-deveco-studio-overview-0000001263280421-V3?catalogVersion=V3" target="_blank">DevEco Studio使用 NDK 將 C/C ++ 代碼編譯到so庫(kù)中,然后使用 DevEco Studio 的構(gòu)建插件hvigor-ohos-plugin將so庫(kù)打包到 Hap 中。ArkTS代碼隨后可以通過(guò)NAPI框架調(diào)用SO庫(kù)中的函數(shù)。
- 深開鴻郭岳峰老師開發(fā)的OCRDemo就通過(guò)NAPI調(diào)用了C++的三方庫(kù)Tesseract的能力,而這個(gè)庫(kù)本身還依賴leptonica、libjpeg、libpng、libtiff等C/C ++ 等四方庫(kù)。如果重新編寫build.gn移植到OpenHarmony,工作量巨大。
- Tesseract (Apache 2.0 License)是一個(gè)可以進(jìn)行圖像OCR識(shí)別的C ++ 庫(kù)
- OpenHarmony集成OCR三方庫(kù)實(shí)現(xiàn)文字提取
1. 編寫build.gn與編寫CMakeLists.txt移植到OpenHarmony兩者的區(qū)別
- 1、編譯環(huán)境不同,編譯工具
- 編寫build.gn方式,編譯環(huán)境是在OpenHarmony源碼中,編譯時(shí)使用到的是源碼中的編譯工具。
- 編寫CMakeLists.txt的移植方式實(shí)際上是Native C++應(yīng)用開發(fā)方式的一種,并且NDK是SDK的一部分,編譯so時(shí)候?qū)嶋H上使用的是NDK的編譯工具。
- 2、so安裝的地方不一樣
- 編寫build.gn方式,三方庫(kù)編譯出來(lái)的so和測(cè)試用例可以打包進(jìn)入OpenHarmony固件中。
- 編寫CMakeLists.txt方式,編譯出來(lái)的實(shí)際上會(huì)被打包進(jìn)入hap應(yīng)用中,hap再安裝到OpenHarmony操作系統(tǒng)上完成三方庫(kù)so能力的調(diào)用。
- 3、編寫CMakeLists.txt比編寫build.gn更容易
- build.gn總有各種各樣的編譯器標(biāo)志要加入以消除編譯報(bào)錯(cuò),開發(fā)者學(xué)習(xí)成本比較高
- CMakeLists.txt方式開發(fā)者則相對(duì)熟悉,對(duì)于原生庫(kù)就是camke構(gòu)建的三方庫(kù),只需要對(duì)原生庫(kù)已有的CMakeLists.txt做少量修改,比如刪除與其他操作系統(tǒng)有關(guān)的部分(筆者說(shuō)的就是AOSP)。
2. 使用OpenHarmony的NDK工具移植Speexdsp到Speexdsp
- 在windows端的IDE上調(diào)用NDK
- 創(chuàng)建Native C++工程,但是先不寫NAPI和ArkTS的部分,先為C/C ++的三方庫(kù)編寫CMakeLists.txt(如果三方庫(kù)本身就是cmake構(gòu)建的,但也要對(duì)CMakeLists.txt進(jìn)行少量的修改,詳細(xì)請(qǐng)參考該樣例 https://gitee.com/openharmony-sig/knowledge_demo_temp/tree/master/FA/OCRDemo)。 然后編譯hap應(yīng)用來(lái)調(diào)用SDK中的NDK工具。
3. 創(chuàng)建Native C++工程使用SDK中的NDK工具
創(chuàng)建Native C++工程參考:三方庫(kù)移植之NAPI開發(fā)[3]通過(guò)IDE開發(fā)NAPI工程
-
1、打開IDE Deveco Studio,創(chuàng)建一個(gè)Native C++工程。
-
2、SDK選擇API9,model選擇Stage。新建的Native C++工程有一個(gè)默認(rèn)的hello world教程
3.1 將Speexdsp加入Native C++工程,在庫(kù)中編寫頂層CMakeLists.txt生成動(dòng)態(tài)庫(kù)
-
1、將speexdsp源碼移動(dòng)到Native C++工程entry\\src\\main\\cpp目錄,cpp目錄專門用于存放C/C ++代碼。
-
2、刪除Speexdsp中無(wú)關(guān)的代碼讓代碼結(jié)構(gòu)簡(jiǎn)潔。Speexdsp中有一些無(wú)關(guān)的代碼,例如和win32、macO上運(yùn)行的有關(guān)代碼,甚至還有塞班系統(tǒng)symbian上的代碼。(不管了先刪除,不知道Speexdsp的開源協(xié)議允不允許筆者這樣做,但是看著亂亂的目錄結(jié)構(gòu),筆者希望這樣讓自身的思路清晰一些。)
# 目錄結(jié)構(gòu)說(shuō)明
cpp
├─include # .h文件
├─libspeexdsp # .c文件
│ └─CMakeLists.txt # 筆者編寫的用來(lái)生成可執(zhí)行文件庫(kù)的CMakeLists.txt
├─BUILD.gn # 筆者之前寫的BUILD.gn,現(xiàn)在拿來(lái)參考寫CMakeLists.txt
├─CMakeLists.txt # 筆者編寫的用來(lái)生成動(dòng)態(tài)庫(kù)的CMakeLists.txt
├─config.h # Speexdsp原生庫(kù)在linux下編譯構(gòu)建生成的配置文件
├─speexdsp_api.txt # Speexdsp的api列表
└─speedsp_tested_api.txt
-
3、編寫頂層在CMakeLists.txt生成動(dòng)態(tài)庫(kù)
# CMake的最小版本要求
cmake_minimum_required(VERSION 3.4.1)
# 腳本中set是將普通變量、緩存變量或者環(huán)境變量設(shè)置為指定的值。
# 從CMake v3.1開始,可以CMAKE_CXX_STANDARD變量設(shè)置C++標(biāo)準(zhǔn)
set(CMAKE_CXX_STANDARD 11)
# 項(xiàng)目名稱
project(speexdsp)
# 添加cflags信息
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-implicit-function-declaration")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-pointer-sign")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-c99-extensions")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-variable")
# cflags信息
# 這個(gè)命令是針對(duì)所有類型編譯器的,也就是說(shuō)這里添加的選項(xiàng)會(huì)在所有的編譯器中運(yùn)用,比如-std=c++11是針對(duì)C++的編譯器參數(shù),也會(huì)被運(yùn)用在C語(yǔ)言編譯器中
# 通過(guò)在CMakeLists.txt文件中添加add_compile_options命令可以起到添加參數(shù)的作用
add_compile_options(-g -O2 -fvisibility=hidden -Wno-implicit-function-declaration -Wno-pointer-sign -Wno-c99-extensions -Wno-unused-variable)
# 頭文件
set(INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
# 設(shè)定編譯宏 -D
add_definitions(-DHAVE_CONFIG_H)
############################################################
# 創(chuàng)建so動(dòng)態(tài)庫(kù)
# 源文件
# CMAKE_CURRENT_SOURCE_DIR指的CMakeLists.txt當(dāng)前所在的目錄
set(SHARED_LIB_SRC "${CMAKE_CURRENT_SOURCE_DIR}/libspeexdsp/preprocess.c"
"${CMAKE_CURRENT_SOURCE_DIR}/libspeexdsp/jitter.c"
"${CMAKE_CURRENT_SOURCE_DIR}/libspeexdsp/mdf.c"
"${CMAKE_CURRENT_SOURCE_DIR}/libspeexdsp/fftwrap.c"
"${CMAKE_CURRENT_SOURCE_DIR}/libspeexdsp/filterbank.c"
"${CMAKE_CURRENT_SOURCE_DIR}/libspeexdsp/resample.c"
"${CMAKE_CURRENT_SOURCE_DIR}/libspeexdsp/buffer.c"
"${CMAKE_CURRENT_SOURCE_DIR}/libspeexdsp/scal.c"
"${CMAKE_CURRENT_SOURCE_DIR}/libspeexdsp/smallft.c")
add_library(speexdsp SHARED ${SHARED_LIB_SRC})
target_include_directories(speexdsp PRIVATE ${INCLUDE_DIR})
############################################################
# 鏈接數(shù)學(xué)庫(kù)-lm
# 如果為所有target統(tǒng)一指定編譯時(shí)要鏈接的庫(kù)用LINK_LIBRARIES
# 為每個(gè)target單獨(dú)指定編譯時(shí)要鏈接的庫(kù)用TARGET_LINK_LIBRARIES
link_libraries(-lm)
target_link_libraries(speexdsp PUBLIC m)
# 使用add_subdirectory()將子目錄添加到構(gòu)建
add_subdirectory(libspeexdsp)
3.2 在庫(kù)中編寫底層CMakeLists.txt生成可執(zhí)行文件,用來(lái)驗(yàn)證so庫(kù)是否運(yùn)行正常
- 在.c源文件目錄添加CMakeLists.txt用來(lái)編譯出可執(zhí)行文件,用來(lái)驗(yàn)證使用NDK移植三方庫(kù)到OpenHarmony標(biāo)準(zhǔn)系統(tǒng)是否成功。如下:
cmake_minimum_required(VERSION 3.4.1)
project(test)
#生成執(zhí)行二進(jìn)制文件,生成testdenoise測(cè)試用例
ADD_EXECUTABLE(testdenoise testdenoise.c)
# 將二進(jìn)制文件鏈接到生成的動(dòng)態(tài)庫(kù)
TARGET_LINK_LIBRARIES(testdenoise PUBLIC speexdsp)
# 將二進(jìn)制文件鏈接的庫(kù)文件
link_libraries(-lm)
# 添加編譯器標(biāo)志
add_compile_options(-g -O2 -fvisibility=hidden)
# 生成testecho測(cè)試用例
ADD_EXECUTABLE(testecho testecho.c)
TARGET_LINK_LIBRARIES(testecho PUBLIC speexdsp)
link_libraries(-lm)
add_compile_options(-g -O2 -fvisibility=hidden)
# 生成testjitter測(cè)試用例
ADD_EXECUTABLE(testjitter testjitter.c)
TARGET_LINK_LIBRARIES(testjitter PUBLIC speexdsp)
link_libraries(-lm)
add_compile_options(-g -O2 -fvisibility=hidden)
# 生成testresample測(cè)試用例
ADD_EXECUTABLE(testresample testresample.c)
TARGET_LINK_LIBRARIES(testresample PUBLIC speexdsp)
link_libraries(-lm)
add_compile_options(-g -O2 -fvisibility=hidden)
# 生成testresample2測(cè)試用例
ADD_EXECUTABLE(testresample2 testresample2.c)
TARGET_LINK_LIBRARIES(testresample2 PUBLIC speexdsp)
link_libraries(-lm)
add_compile_options(-g -O2 -fvisibility=hidden)
3.3 在庫(kù)外的CMakeLists.txt中添加代碼使能speexdsp編譯
-
1、 新建的Native C++工程是有一個(gè)默認(rèn)的Hello World模板的,在entry\\src\\main\\cpp目錄下有一個(gè)CMakeLists.txt,需要在其中添加代碼使能speexdsp編譯
在entry\\src\\main\\cpp\\CMakeLists.txt中主要做兩件事情
# 添加子目錄speexdsp
add_subdirectory(speexdsp)
# 添加鏈接libspeexdsp.so動(dòng)態(tài)庫(kù)
# 把動(dòng)態(tài)庫(kù)libentry.so鏈接到動(dòng)態(tài)庫(kù)libspeexdsp.so
target_link_libraries(entry PUBLIC libace_napi.z.so speexdsp)
- 2、如果不添加代碼,則speexdsp的動(dòng)態(tài)庫(kù)和可執(zhí)行用例編譯不出來(lái)
3.4 執(zhí)行編譯命令編譯動(dòng)態(tài)庫(kù)和測(cè)試用例
-
1、在IDE上方工具欄選擇
編譯hap
進(jìn)行so和測(cè)試用例的編譯 -
2、編譯結(jié)果在entry\\build\\default\\intermediates\\cmake\\default\\obj目錄下
├─arm64-v8a
│ libc++_shared.so
│ libentry.so
│ libspeexdsp.so
│ testdenoise
│ testecho
│ testjitter
│ testresample
│ testresample2
│
└─armeabi-v7a
libc++_shared.so
libentry.so
libspeexdsp.so
testdenoise
testecho
testjitter
testresample
testresample2
- 3、為什么會(huì)IDE中的NDK會(huì)編譯出64位和32位的動(dòng)態(tài)庫(kù)和可執(zhí)行文件呢?因?yàn)镺penHarmony操作系統(tǒng)有32位和64位,這樣是為了hap能在不同位數(shù)的OpenHarmony版本上運(yùn)行。
3.5 根據(jù)32位和64位的OpenHarmony版本推送相應(yīng)的so和可執(zhí)行文件到開發(fā)板上
如何分辨開發(fā)板上OpenHarmony版本是64位還是32位?和linux的方式是一樣。用
getconf WORD_BIT
和getconf LONG_BIT
獲得word和long的位數(shù)。64位系統(tǒng)中分別得到32和64。32位系統(tǒng)中分別得到32和32。
-
1、筆者開發(fā)板上燒錄的是32位的OpenHarmony Beta5版本
-
因此需要將Native C++工程目錄下的entry\\build\\default\\intermediates\\cmake\\default\\obj\\armeabi-v7a中的libspeexdsp.so和testdenoise、testecho、testjitter、testresample、testresample2推送到設(shè)備端的data目錄
-
-
2、通過(guò)與ohos版本匹配的hdc_std工具,將編譯生成的庫(kù)以及測(cè)試用的可執(zhí)行文件推送到開發(fā)板的data目錄
hdc_std shell mount -o remount,rw / ## 重新加載系統(tǒng)為可讀寫
hdc_std file send testdenoise /data ## 推送可執(zhí)行文件testdenoise到data目錄
hdc_std file send libspeexdsp /data ## 推送libspeexsdp.so到data目錄
- 3、執(zhí)行testdenoise可執(zhí)行文件(其它測(cè)試用例的執(zhí)行請(qǐng)參考 移植speexdsp到OpenHarmony標(biāo)準(zhǔn)系統(tǒng)⑤)
- 通過(guò)分析testdenoise.c源碼,執(zhí)行測(cè)試程序時(shí)需要指定一份輸入的不為空的8000Hz的input.pcm音頻,并且需要指定一份空的輸出的output.pcm音頻。rk3568上運(yùn)行,執(zhí)行語(yǔ)句如下:
./testdenoise < input.pcm > output.pcm
-
4、測(cè)試結(jié)果:對(duì)比輸入的input.pcm和輸出的outpu.pcm的波形圖和聲譜圖,噪聲已經(jīng)被消除。pc端和rk3568開發(fā)板運(yùn)行testdenoise可執(zhí)行程序效果一致??蓤?zhí)行文件運(yùn)行成功,使用OpenHarmonyNDK移植三方庫(kù)Speexdsp成功
知識(shí)點(diǎn)附送
1、AIP8的應(yīng)用如何更改為API9支持64位版本
1.1 API8只支持32位,API9支持32位和64位。
-
以該P(yáng)R https://gitee.com/openharmony/applications_app_samples/pulls/759 學(xué)習(xí)將api8應(yīng)用適配適配Arm64
-
1、修改build-profile.json5 ,將
compileSdkVersion
和compatibleSdkVersion
屬性由8改為9-
compileSdkVersion
指定OpenHarmony應(yīng)用/服務(wù)編譯時(shí)的SDK版本 -
compatibleSdkVersion
指定OpenHarmony應(yīng)用/服務(wù)兼容的最低SDK版本
-
-
2、修改entry/build-profile.json5,abi添加64位
arm64-v8a
-
abiFilters
用于設(shè)置本機(jī)的ABI編譯環(huán)境
-
-
3、修改entry/src/main/config.json,設(shè)備類型改為默認(rèn)
-
4、這個(gè)pr改動(dòng)了XComponent/entry/src/main/cpp/common/plugin_common.h文件,plugin_common.h文件和hilog調(diào)試的功能有關(guān)。
2、編譯構(gòu)建子系統(tǒng)如何增加編譯構(gòu)建arm64選擇
以該issue https://gitee.com/openharmony/build/issues/I53E9I 來(lái)學(xué)習(xí)
- 分別在hb工具和build.sh腳本添加--target-cpu選項(xiàng)
電源服務(wù)子系統(tǒng)支持64位
https://gitee.com/openharmony/powermgr_power_manager/issues/I55094
graphic子系統(tǒng)適配64位編譯
https://gitee.com/openharmony/graphic_graphic_2d/issues/I53720
-
移植
+關(guān)注
關(guān)注
1文章
379瀏覽量
28130 -
編譯
+關(guān)注
關(guān)注
0文章
657瀏覽量
32870 -
OpenHarmony
+關(guān)注
關(guān)注
25文章
3722瀏覽量
16313
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論