前言
OpenHarmony是由開放原子開源基金會(OpenAtom Foundation)孵化及運營的開源項目,目標是面向全場景被啼、全連接帜消、全智能時代、基于開源的方式浓体,搭建一個智能終端設(shè)備操作系統(tǒng)的框架和平臺泡挺,促進萬物互聯(lián)產(chǎn)業(yè)的繁榮發(fā)展。最近在學習OpenHarmony源代碼命浴,個人認為學習有三個階段粘衬,分別是看、實操咳促、寫(歸納總結(jié))稚新,本著追求學習的終極目標,因此有了這篇文章跪腹。
一褂删、OpenHarmony編譯框架特點
OpenHarmony編譯框架是基于模塊化的,從大到小依次劃分為產(chǎn)品冲茸、子系統(tǒng)集(或領(lǐng)域)屯阀、子系統(tǒng)缅帘、部件、模塊难衰、特性钦无。這種模塊化的樹狀編譯框架,非常方便根據(jù)目標產(chǎn)品硬件資源的大小進行靈活的裁剪盖袭,從而實現(xiàn)“統(tǒng)一OS失暂,彈性部署”的目標。
1.產(chǎn)品(product)
產(chǎn)品是基于解決方案為基于開發(fā)板的完整產(chǎn)品鳄虱,主要包含產(chǎn)品對OS的適配弟塞、部件拼裝配置、啟動配置和文件系統(tǒng)配置等拙已。build.sh編譯的時候通過--product-name編譯選項指定决记;hb編譯的時候通過hb set進行設(shè)置。
#適用于標準(即L2或standard)系統(tǒng)編譯
./build.sh --product-name rk3568 --ccache
cd build #進入源碼下build目錄
hb set #執(zhí)行hb set命令倍踪,選擇對應(yīng)的產(chǎn)品名稱
hb build #執(zhí)行hb build命令系宫,進行編譯
2.子系統(tǒng)集(domain)
OpenHarmony技術(shù)架構(gòu)中有四大子系統(tǒng)集:“系統(tǒng)基本能力子系統(tǒng)集”、“基礎(chǔ)軟件服務(wù)子系統(tǒng)集”建车、“增強軟件服務(wù)子系統(tǒng)集”笙瑟、“硬件服務(wù)子系統(tǒng)集”。四大子系統(tǒng)不會直接出現(xiàn)在編譯選項或者參數(shù)中癞志,而是有對應(yīng)的一級源代碼文件夾:“系統(tǒng)基本能力子系統(tǒng)集”對應(yīng)源碼foundation文件夾往枷;“基礎(chǔ)軟件服務(wù)子系統(tǒng)集”和“硬件服務(wù)子系統(tǒng)集”對應(yīng)源碼base文件夾;“增強軟件服務(wù)子系統(tǒng)集”對應(yīng)源碼domains文件夾凄杯。
.
├── applications //應(yīng)用程序
├── arkcompiler //ark編譯器
├── base //“基礎(chǔ)軟件服務(wù)子系統(tǒng)集”和“硬件服務(wù)子系統(tǒng)集”
├── build //編譯目錄
├── build.py -> build/lite/build.py //軟鏈接
├── build.sh -> build/build_scripts/build.sh //軟鏈接错洁,標準系統(tǒng)編譯入口
├── commonlibrary //通用庫
├── developtools //開發(fā)工具
├── device //芯片相關(guān)
├── docs //文檔md文件目錄
├── drivers //驅(qū)動文件
├── foundation //“系統(tǒng)基本能力子系統(tǒng)集”
├── ide //ide
├── interface //接口
├── kernel //內(nèi)核,liteos-m戒突,liteos-a屯碴,linux,uniproton
├── napi_generator //native api相關(guān)
├── prebuilts //編譯工具路徑
├── productdefine //產(chǎn)品定義
├── qemu-run -> vendor/ohemu/common/qemu-run //qemu模擬器運行腳本
├── test //測試用例
├── third_party //三方庫
└── vendor //產(chǎn)品
3.子系統(tǒng)(subsystem)
子系統(tǒng)是一個邏輯概念膊存,它具體由對應(yīng)的部件構(gòu)成导而。在多設(shè)備部署場景下,支持根據(jù)實際需求裁剪某些非必要的子系統(tǒng)或部件隔崎。在build/subsystem_config.json中定義今艺。
{
"arkui": {
"path": "foundation/arkui", //子系統(tǒng)源碼路徑
"name": "arkui" //子系統(tǒng)名稱
},
"ai": {
"path": "foundation/ai",
"name": "ai"
},
"distributeddatamgr": {
"path": "foundation/distributeddatamgr",
"name": "distributeddatamgr"
},
"security": {
"path": "base/security",
"name": "security"
},
"startup": {
"path": "base/startup",
"name": "startup"
},
"hiviewdfx": {
"path": "base/hiviewdfx",
"name": "hiviewdfx"
},
"kernel": {
"path": "kernel",
"name": "kernel"
},
"thirdparty": {
"path": "third_party",
"name": "thirdparty"
}
...
}
** 4.部件(component)**
部件對子系統(tǒng)的進一步拆分,可復用的軟件單元爵卒,它包含源碼虚缎、配置文件、資源文件和編譯腳本钓株;能獨立構(gòu)建实牡,以二進制方式集成陌僵,具備獨立驗證能力的二進制單元。部件由對應(yīng)源碼文件夾下的bundle.json文件進行定義创坞。以napi部件為例foundation/arkui/napi/bundle.json
{
"name": "@ohos/napi",
"description": "Node-API (formerly N-API) is an API for build native Addons",
"version": "3.1",
"license": "Apache 2.0",
"publishAs": "code-segment",
"segment": {
"destPath": "foundation/arkui/napi"
},
"dirs": {},
"scripts": {},
"component": {
"name": "napi", //部件名稱
"subsystem": "arkui", //所屬子系統(tǒng)
"syscap": [
"SystemCapability.ArkUI.ArkUI.Napi",
"SystemCapability.ArkUI.ArkUI.Libuv"
],
"features": ["napi_enable_container_scope"], //部件特性
"adapted_system_type": [
"standard"
],
"rom": "5120KB", //部件rom大小
"ram": "10240KB",//部件ram大小
"deps": { //部件依賴
"components": [ //部件依賴的部件
"hiviewdfx_hilog_native",
"hilog"
],
"third_party": [//部件依賴的三方庫
"jerryscript",
"libuv",
"node",
"bounds_checking_function",
"v8"
]
},
"build": {
"group_type": {
"base_group": [
"http://foundation/arkui/napi:napi_packages",
"http://foundation/arkui/napi:napi_packages_ndk"
],
"fwk_group": [],
"service_group": []
},
"inner_kits": [//部件對外暴露的接口碗短,用于其它部件或者模塊進行引用
{
"header": {
"header_base": "http://foundation/arkui/napi/interfaces/kits",
"header_files": [
"napi/native_api.h"
]
},
"name": "http://foundation/arkui/napi:ace_napi"
},
{
"header": {
"header_base": "http://foundation/arkui/napi/interfaces/inner_api",
"header_files": [
"napi/native_common.h",
"napi/native_node_api.h"
]
},
"name": "http://foundation/arkui/napi:ace_napi"
},
{
"header": {
"header_base": "http://foundation/arkui/ace_engine/frameworks/core/common/",
"header_files": [
"container_scope.h"
]
},
"name": "http://foundation/arkui/napi:ace_container_scope"
}
],
"test": [
"http://foundation/arkui/napi:napi_packages_test",
"http://foundation/arkui/napi/sample/native_module_systemtest:systemtest",
"http://foundation/arkui/napi/test/unittest:unittest"
]
}
}
}
5.模塊(module)
模塊就是編譯子系統(tǒng)的一個編譯目標,部件也可以是編譯目標题涨。模塊屬于哪個部件偎谁,在gn文件中由part_name指定。
ohos_shared_library("ace_napi") { //ace_napi為模塊名携栋,同時也是編譯目標
deps = [ ":ace_napi_static" ] //模塊的依賴搭盾,被依賴的對象即使沒有被subsystem顯式包含咳秉,也會被編譯
public_configs = [ ":ace_napi_config" ] //模塊配置參數(shù)婉支,比如cflag
if (!is_cross_platform_build) {
public_deps = [ "http://third_party/libuv:uv" ]
}
subsystem_name = "arkui" //模塊所屬部件所屬子系統(tǒng)名稱
part_name = "napi" //模塊所屬部件名稱,一個模塊只能屬于一個部件
}
6.特性(feature)
特性是部件用于體現(xiàn)不同產(chǎn)品之間的差異澜建。通常不同特性可以定義不同編譯宏或者代碼向挖,從而影響到源代碼中define的特性。
vender/hihope/rk3568_mini_system/config.json
ohos_shared_library("ace_napi") { //ace_napi為模塊名炕舵,同時也是編譯目標
deps = [ ":ace_napi_static" ] //模塊的依賴何之,被依賴的對象即使沒有被subsystem顯式包含,也會被編譯
public_configs = [ ":ace_napi_config" ] //模塊配置參數(shù)咽筋,比如cflag
if (!is_cross_platform_build) {
public_deps = [ "http://third_party/libuv:uv" ]
}
subsystem_name = "arkui" //模塊所屬部件所屬子系統(tǒng)名稱
part_name = "napi" //模塊所屬部件名稱溶推,一個模塊只能屬于一個部件
}
foundation/communication/dsoftbus/bundle.json
{
"name": "@openharmony/dsoftbus",
"version": "3.1.0",
"description": "dsoftbus",
...
"component": {
"name": "dsoftbus",
"subsystem": "communication",
"adapted_system_type": [
"mini",
"small",
"standard"
],
"features": [
"dsoftbus_feature_conn_p2p",
"dsoftbus_feature_disc_ble",
"dsoftbus_feature_conn_br",
"dsoftbus_feature_conn_ble",
"dsoftbus_feature_lnn_net",
"dsoftbus_feature_trans_udp_stream",
"dsoftbus_feature_trans_udp_file",
"dsoftbus_get_devicename",
"dsoftbus_feature_product_config_path",
"dsoftbus_feature_ifname_prefix",
"dsoftbus_feature_lnn_wifiservice_dependence",
"dsoftbus_standard_feature_dfinder_support_multi_nif",
"dsoftbus_feature_protocol_newip"
],
},
foundation/communication/dsoftbus/core/adapter/core_adapter.gni
if (dsoftbus_get_devicename == false) {//特性取值不同,影響編譯不同代碼
bus_center_core_adapter_src += [ "$dsoftbus_root_path/core/adapter/bus_center/src/lnn_settingdata_event_monitor_virtual.cpp" ]
bus_center_core_adapter_inc +=[ "$dsoftbus_root_path/core/adapter/bus_center/include" ]
bus_center_core_adapter_deps += []
} else {
bus_center_core_adapter_src += ["$dsoftbus_root_path/core/adapter/bus_center/src/lnn_settingdata_event_monitor.cpp","$dsoftbus_root_path/core/adapter/bus_center/src/lnn_ohos_account.cpp",]
bus_center_core_adapter_inc += ["$dsoftbus_root_path/adapter/common/bus_center/include","$dsoftbus_root_path/core/adapter/bus_center/include","http://foundation/distributeddatamgr/relational_store/interfaces/inner_api/rdb/include","http://foundation/distributeddatamgr/relational_store/interfaces/inner_api/dataability/include","http://base/account/os_account/interfaces/innerkits/ohosaccount/native/include/",]
bus_center_core_adapter_deps += ["${ability_base_path}:want","${ability_base_path}:zuri","${ability_runtime_inner_api_path}/dataobs_manager:dataobs_manager","${ability_runtime_path}/frameworks/native/ability/native:abilitykit_native","http://base/account/os_account/frameworks/ohosaccount/native:libaccountkits","http://base/account/os_account/frameworks/osaccount/native:os_account_innerkits","http://foundation/distributeddatamgr/data_share/interfaces/inner_api:datashare_consumer","http://foundation/distributeddatamgr/data_share/interfaces/inner_api/common:datashare_common","http://foundation/distributeddatamgr/relational_store/interfaces/inner_api/dataability:native_dataability","http://foundation/distributeddatamgr/relational_store/interfaces/inner_api/rdb:native_rdb",]
}
7.各部分關(guān)系
一個產(chǎn)品(product) 可以包含 1~n個子系統(tǒng)(subsystem)奸攻,一個子系統(tǒng)可以包含1~n個部件(component)蒜危,一個**部件**可以包含1~n個模塊(module),不同產(chǎn)品的中的相同部件可以編譯不同的特性(feature)睹耐,子系統(tǒng)集(domain)在源代碼一級根目錄有體現(xiàn)辐赞。
二、OpenHarmony構(gòu)建工具介紹
OpenHarmony構(gòu)建工具由shell腳本硝训、python腳本响委、gn、ninjia窖梁、clang/llvm等構(gòu)成赘风。GN is “Generate Ninja” 一個用來生成.ninja 的工具,直接編寫.ninja文件難度較大纵刘,且非常乏味贝次。Ninja 原意是忍者的意思,它是一個專注于速度的小型構(gòu)建工具彰导,利用gn生成的.ninja文件作為輸入蛔翅。clang/llvm執(zhí)行真正的編譯和鏈接工作敲茄,clang負責編譯前端,llvm負責編譯優(yōu)化和后端(通常編譯工具分前端山析、優(yōu)化堰燎、后端)。 GN的語法相對比較簡單笋轨,有點面向?qū)ο缶幊陶Z言的思想秆剪;Ninja號稱比make編譯速度更快,推測原因make編譯過程有大量的延時變量和預(yù)置變量爵政,需要在編譯過程進行推導其值仅讽,因此需要消耗大量cpu資源進行計算,形如$@钾挟,$^洁灵,$<,$\*掺出,$徽千?
。補充一點:每個.c 和.c++文件是獨立編譯的汤锨,編譯過程彼此之間并不進行通信双抽,因此可進行并行編譯。編譯和鏈接過程及常見的問題如何解決闲礼,后續(xù)單獨出一期牍汹,此處先挖個坑。
三柬泽、OpenHarmony構(gòu)建過程
Openharmony完整的編譯構(gòu)建流程主要可以分成以下五個大階段:Preloder慎菲、Loader、GN聂抢、Ninja钧嘶、Post build。Preloader和Loader階段主要是執(zhí)行python腳本preloader.py和loader.py琳疏,Preloader階段根據(jù)vendor倉的產(chǎn)品配置config.json文件對產(chǎn)品配置進行解析有决,并將解析結(jié)果輸出到out/preloader/{product_name}目錄下;Loader階段進行部件化配置的加載空盼,將部件的編譯gn文件书幕,并將解析結(jié)果輸出到out/{product_name}/build_configs文件夾下。GN階段以.gn和.gni文件作為輸入揽趾,通過GN工具生成.ninja文件台汇,輸出到out/{product_name}/obj目錄下。Ninja階段以.ninja文件作為輸入,通過Ninja工具生調(diào)用clang/llvm編譯工具鏈編譯生成目標苟呐,如靜態(tài)庫out/{product_name}/obj目錄下痒芝,共享庫out/{product_name}/ {part_name}目錄下,可執(zhí)行程序牵素。又可以分為10個小階段:prebuild严衬、preload、load笆呆、pre_target_generate请琳、target_generate、post_target_generate赠幕、pre_target_compilation俄精、target_compilation、post_target_compilation榕堰、post_build竖慧。
hb/modules/interface/build_module_interface.py
def run(self):
try:
self._prebuild()
self._preload()
self._load()
self._pre_target_generate()
self._target_generate()
self._post_target_generate()
self._pre_target_compilation()
self._target_compilation()
except OHOSException as exception:
raise exception
else:
self._post_target_compilation()
finally:
self._post_build()
四、OpenHarmony構(gòu)建過程逆向分析
存儲中的鏡像(如flash或emmc)一般由芯片廠家提供的燒錄工具或者產(chǎn)線生產(chǎn)過程通過專用編程器寫入相應(yīng)分區(qū)局冰。OpenHarmony編譯完成后鏡像img文件所在的目錄out/{product_name}/package/phone/image测蘑。鏡像img文件一般由打包工具按照一定的規(guī)則將輸入文件夾(含文件夾目錄層級)和文件夾下所有文件(如庫文件灌危、可執(zhí)行文件康二、配置文件、啟動腳本文件)整體打包而成勇蝙,打包過程需要考慮文件系統(tǒng)格式沫勿,在產(chǎn)品啟動過程中會使用mount進行掛載,因此需要考慮文件夾和文件的層級關(guān)系及文件夾味混、庫文件产雹、可執(zhí)行文件、配置文件翁锡、啟動腳本文件的權(quán)限蔓挖。這些文件夾、文件從何而來馆衔?文件夾直接在宿主機采用mkdir創(chuàng)建瘟判,庫文件、可執(zhí)行文件編譯完成以后直接copy到對應(yīng)文件夾中角溃,其它配置或者腳本也是提前準備或者編譯過程生成拷获,然后copy到對應(yīng)文件夾中。
out/rk3568/packages/phone# tree . -L 1
.
├── chip_prod
├── data
├── hisysevent
├── images
├── NOTICE_FILES
├── NOTICE_module_info.json
├── NOTICE.txt
├── NOTICE.txt.md5.stamp
├── notice_verify_result.out
├── NOTICE.xml
├── NOTICE.xml.gz
├── ramdisk
├── root
├── sa_profile
├── sys_prod
├── system
├── system_install_modules.json
├── system_install_parts.json
├── system_module_info.json
├── system_modules_list.txt
├── system_notice_files.zip
├── system.zip
├── updater
└── vendor
build/ohos/images/mkimage# tree . -L 1
.
├── chip_prod_image_conf.txt
├── dac.txt
├── debug
├── imkcovert.py
├── mkcpioimage.py
├── mkextimage.py
├── mkf2fsimage.py
├── mkimages.py
├── __pycache__
├── ramdisk_image_conf.txt
├── README.txt
├── sys_prod_image_conf.txt
├── system_image_conf.txt
├── updater_image_conf.txt
├── updater_ramdisk_image_conf.txt
├── userdata_image_conf.txt
└── vendor_image_conf.txt