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