鴻蒙的驅(qū)動(dòng)子系統(tǒng)-3-驅(qū)動(dòng)相關(guān)模塊的編譯
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
打開并查看 //vendor/hisilicon/hispark_taurus/config.json, 這是小型系統(tǒng)Hi3516開發(fā)板的產(chǎn)品配置表,仔細(xì)查看與驅(qū)動(dòng)緊密相關(guān)的子系統(tǒng)和組件有:
- {
- "subsystem": "kernel",
- "components": [
- { "component": "liteos_a", "features":[] }
- ]
- },
- {
- "subsystem": "drivers",
- "components": [
- { "component": "drivers_framework", "features":[] },
- { "component": "adapter_uhdf", "features":[] },
- { "component": "peripheral_display", "features":[] },
- { "component": "peripheral_input", "features":[] },
- { "component": "peripheral_sensor", "features":[] },
- { "component": "peripheral_wlan", "features":[] }
- ]
- },
- {
- "subsystem": "vendor",
- "components": [
- { "component": "hi3516dv300_init", "features":[] },
- { "component": "hardware", "features":[] },
- { "component": "middleware", "features":[] }
- ]
- },
結(jié)合//build/lite/components/目錄下對應(yīng)的 json文件,列出下表:

上表包含了整個(gè)驅(qū)動(dòng)子系統(tǒng)的編譯相關(guān)內(nèi)容,互相交叉,關(guān)系稍微有點(diǎn)復(fù)雜,我花了一點(diǎn)時(shí)間做了梳理,先把一些要點(diǎn)做一下總結(jié):
1. //drivers/framework/ 目錄是純代碼目錄,不包含編譯配置腳本文件,對該目錄代碼文件的編譯配置文件都在 //drivers/adapter/目錄下了,分成兩部分:
- uhdf 部分是編譯framework部署在用戶空間的代碼,見上表中adapter_uhdf部分。
- khdf 部分是編譯framework部署在內(nèi)核空間的代碼,上表中沒有體現(xiàn)出來,但是在編譯 liteos_a:kernel 的時(shí)候,會(huì)通過kernel模塊的mk去include這里的 ./khdf/liteos/目錄下的mk,從而觸發(fā)khdf部分的編譯。
2. liteos_a:kernel 和framework的khdf部分的編譯,會(huì)由 hi3516dv300_init 組件的編譯來觸發(fā),最終生成了OHOS_Image*四個(gè)鏡像文件。上表只做了簡單地描述,可以去閱讀和分析//device/hisilicon/build/hi3516dv300/ 目錄下的幾個(gè)編譯腳本,順著編譯流程去做理解,下文會(huì)做進(jìn)一步地展開分析。
3. //drivers/peripheral/ 目錄下的幾個(gè)模塊,會(huì)被編譯成對應(yīng)的動(dòng)態(tài)鏈接庫文件,部署到 rootfs/usr/lib/目錄下。
4. hardware和middleware兩個(gè)組件,都是根據(jù)各自目錄下的 BUILD.gn和build.sh腳本,對相關(guān)目錄的代碼進(jìn)行編譯,或者對子目錄下的預(yù)編譯庫文件做選擇,最終將庫文件拷貝到項(xiàng)目輸出根目錄下,打包生成rootfs時(shí),部署到rootfs/usr/lib/目錄下
上面1.uhdf和3/4的編譯輸出,都部署在鴻蒙系統(tǒng)的用戶空間,直接閱讀編譯腳本基本上就可以理解了,本文就不做詳細(xì)分析了。
而1.khdf和2的編譯有密切的相關(guān)性,其輸出一并打包到OHOS系統(tǒng)鏡像中,下面就來詳細(xì)看一下。
從 hi3516dv300_init 組件的編譯腳本 //device/hisilicon/build/hi3516dv300/BUILD.gn 入手:
- build_ext_component("hi3516dv300_image") {
- exec_path = rebase_path(".", root_build_dir)
- outdir = rebase_path("$root_out_dir")
- command = "./build.sh ${outdir} ${device_path} ${board} ${ohos_kernel_type} ${ohos_build_compiler}"
- deps = [ "//kernel/liteos_a:kernel" ]
- }
依賴liteos_a:kernel組件,執(zhí)行這里的build.sh,根據(jù)參數(shù),拷貝一組.so文件后,執(zhí)行make。查看Makefile和hi3516dv300.mak,可以知道這是要編譯 sdk_init和system_init 并打包生成 OHOS_Image 鏡像。
編譯liteos_a:kernel組件,入口則在 //kernel/liteos_a/BUILD.gn,
- build_ext_component("make") {
- exec_path = rebase_path(".", root_build_dir)
- tee_enable = "false"
- if (board_name == "hi3516dv300" && enable_tee_ree) {
- tee_enable = "tee"
- }
- prebuilts = "sh build.sh ${board_name} ${ohos_build_compiler} ${root_build_dir} ${ohos_build_type} ${tee_enable} \"${device_company}\" \"${product_path}\""
- outdir = rebase_path(get_path_info(".", "out_dir"))
- command = "make clean OUTDIR=$outdir && make rootfs VERSION=\"${ohos_version}\" -j 16 OUTDIR=$outdir"
- }
根據(jù)build的參數(shù),到 //kernel/liteos_a/tools/build/config/ 目錄下尋找一個(gè)匹配的config文件,拷貝到 //kernel/liteos_a/.config,但這還不是.config的全部,執(zhí)行make時(shí),根據(jù)Kconfig的配置,層層將編譯內(nèi)核的默認(rèn)配置收集匯總到.config文件內(nèi),driver部分就包含了:
- ######################## config options os drivers ########################
- menu "Driver"
- config DRIVERS
- bool "Enable Driver"
- default y
- help
- Answer Y to enable LiteOS support driver.
- source "../../kernel/liteos_a/bsd/dev/usb/Kconfig"
- source "../../drivers/adapter/khdf/liteos/Kconfig"
這就把 //drivers/adapter/khdf/ 模塊的編譯配置包含進(jìn)來了,并且由這個(gè)Kconfig關(guān)聯(lián)驅(qū)動(dòng)模塊的其他Kconfig:
- source "../../drivers/adapter/khdf/liteos/model/bus/usb/Kconfig"
- source "../../drivers/adapter/khdf/liteos/test/Kconfig"
- source "../../drivers/adapter/khdf/liteos/model/display/Kconfig"
- source "../../drivers/adapter/khdf/liteos/model/input/Kconfig"
- source "../../drivers/adapter/khdf/liteos/model/sensor/Kconfig"
- source "../../device/hisilicon/drivers/Kconfig"
經(jīng)過這一步,編譯內(nèi)核的所有配置項(xiàng)都集中到了.config文件中。
再看 //kernel/liteos_a/config.mk:
- -include $(LITEOSTOPDIR)/tools/build/mk/los_config.mk
打開這個(gè) los_config.mk,找到driver部分:
- ################################## Driver Option Begin #################################
- ifeq ($(LOSCFG_DRIVERS_HDF), y)
- include $(LITEOSTOPDIR)/../../drivers/adapter/khdf/liteos/hdf_lite.mk
- endif
【*】再打開這個(gè)hdf_lite.mk,找到下面這段:
- HAVE_VENDOR_CONFIG := $(shell if [ -d $(LITEOS_SOURCE_ROOT)/vendor/$(patsubst "%",%,$(LOSCFG_DEVICE_COMPANY))/$(patsubst "%",%,$(LOSCFG_PRODUCT_NAME))/config ]; then echo y; else echo n; fi)
- ifeq ($(LOSCFG_DRIVERS_HDF_TEST), y)
- include $(LITEOS_DRIVERS_HDF)/test/test_lite.mk
- # test
- LITEOS_BASELIB += -lhdf_test
- LIB_SUBDIRS += $(LITEOS_DRIVERS_HDF)/test
- #//drivers/adapter/khdf/liteos/test,通過Makefile可以編譯驅(qū)動(dòng)子系統(tǒng)的測試文件
- LITEOS_BASELIB += -lhdf_test_config
- LIB_SUBDIRS += $(LITEOS_SOURCE_ROOT)/vendor/$(LOSCFG_DEVICE_COMPANY)/$(LOSCFG_PRODUCT_NAME)/config/hdf_test
- #//vendor/hisilicon/hispark_taurus/config/hdf_test
- #這里并不顯式地去編譯hdf_config,即顯式地執(zhí)行Makefile,
- #而是通過hdf_test/hdf_test.hcs 里面的 #include "../hdf.hcs" 去將其編譯到
- # ./out/hispark_taurus/ipcamera_hispark_taurus/obj/kernel/liteos_a/lib/libhdf_test_config.a 里面去
- else
- # config
- LITEOS_BASELIB += -lhdf_config
- ifeq ($(HAVE_VENDOR_CONFIG), y)
- LIB_SUBDIRS += $(LITEOS_SOURCE_ROOT)/vendor/$(LOSCFG_DEVICE_COMPANY)/$(LOSCFG_PRODUCT_NAME)/config
- #要是上面LOSCFG_DRIVERS_HDF_TEST是 n,不編譯hdf_test/,這里才會(huì)顯式地編譯 hdf_config,執(zhí)行這個(gè)目錄下的Makefile指令,
- # ./out/hispark_taurus/ipcamera_hispark_taurus/obj/kernel/liteos_a/lib/libhdf_config.a 里面去
- else
- LIB_SUBDIRS += $(LITEOS_SOURCE_ROOT)/device/$(LOSCFG_DEVICE_COMPANY)/$(LOSCFG_PRODUCT_NAME)/config
- endif
- endif
通過參數(shù)對路徑下的config進(jìn)行確認(rèn),HAVE_VENDOR_CONFIG 是存在的,也就是y,上面的.config中,LOSCFG_DRIVERS_HDF_TEST也是默認(rèn)配置為y的,會(huì)跑# test這個(gè),而不是# config。
LIB_SUBDIRS += //vendor/hisilicon/hispark_taurus/config/hdf_test
而不是 //device/hisilicon/hispark_taurus/sdk_liteos/config 下的 config 目錄。
【**】進(jìn)入//vendor/hisilicon/hispark_taurus/config/hdf_test/目錄查看 Makefile 文件:
- include $(LITEOSTOPDIR)/../../drivers/adapter/khdf/liteos/lite.mk
- MODULE_NAME := hdf_test_config
- LOCAL_HCS_ROOT := $(shell pwd)
- LOCAL_PLATFORM_HCS_SRC := hdf_test.hcs
- include $(HDF_DRIVER)
再去打開這個(gè)lite.mk,最后面有一句:
- HDF_DRIVER = $(HDF_ROOT_DIR)/adapter/khdf/liteos/hdf_driver.mk
再打開這個(gè)hdf_driver.mk
- HAVE_VENDOR_CONFIG := $(shell if [ -d $(LITEOS_SOURCE_ROOT)/vendor/$(patsubst "%",%,$(LOSCFG_DEVICE_COMPANY))/$(patsubst "%",%,$(LOSCFG_PRODUCT_NAME))/config ]; then echo y; else echo n; fi)
- ifeq ($(LOCAL_HCS_ROOT),)
- ifeq ($(HAVE_VENDOR_CONFIG), y)
- LOCAL_HCS_ROOT := $(abspath $(LITEOSTOPDIR)/../../vendor/$(patsubst "%",%,$(LOSCFG_DEVICE_COMPANY))/$(patsubst "%",%,$(LOSCFG_PRODUCT_NAME))/config)
- else
- LOCAL_HCS_ROOT := $(abspath $(LITEOSTOPDIR)/../../device/$(patsubst "%",%,$(LOSCFG_DEVICE_COMPANY))/$(patsubst "%",%,$(LOSCFG_PRODUCT_NAME))/config)
- endif
- endif
所以LOCAL_HCS_ROOT是vendor的://vendor/hisilicon/hispark_taurus/config
而不是device目錄下的 //device/hisilicon/hispark_taurus/sdk_liteos/config
回到上面【**】 //vendor/hisilicon/hispark_taurus/config/hdf_test/Makefile 文件,要編譯 hdf_test.hcs,打開該文件:
- #include "../hdf.hcs"
- #include "hdf_test_manager/device_info.hcs"
- #include "gpio_test_config.hcs"
- #include "i2c_test_config.hcs"
- #include "spi_test_config.hcs"
- #include "uart_test_config.hcs"
- #include "hdf_config_test.hcs"
- #include "sdio_test_config.hcs"
- #include "emmc_test_config.hcs"
- #include "pwm_test_config.hcs"
也就是編譯hdf_test目錄下的 測試相關(guān)的 hcs 之外,還編譯上一級(jí)目錄的 hdf.hcs,再打開這個(gè) hdf.hcs 文件:
- #include "../../../../device/hisilicon/hispark_taurus/sdk_liteos/config/i2c/i2c_config.hcs"
- #include "../../../../device/hisilicon/hispark_taurus/sdk_liteos/config/gpio/gpio_config.hcs"
- #include "../../../../device/hisilicon/hispark_taurus/sdk_liteos/config/uart/uart_config.hcs"
- #include "../../../../device/hisilicon/hispark_taurus/sdk_liteos/config/sdio/sdio_config.hcs"
- #include "../../../../device/hisilicon/hispark_taurus/sdk_liteos/config/emmc/emmc_config.hcs"
- #include "../../../../device/hisilicon/hispark_taurus/sdk_liteos/config/watchdog/watchdog_config.hcs"
- #include "../../../../device/hisilicon/hispark_taurus/sdk_liteos/config/usb/usb_config.hcs"
- #include "../../../../device/hisilicon/hispark_taurus/sdk_liteos/config/rtc/rtc_config.hcs"
- #include "../../../../device/hisilicon/hispark_taurus/sdk_liteos/config/spi/spi_config.hcs"
- #include "../../../../device/hisilicon/hispark_taurus/sdk_liteos/config/pwm/pwm_config.hcs"
- #include "../../../../device/hisilicon/hispark_taurus/sdk_liteos/config/dmac/dmac_config.hcs"
- #include "device_info/device_info.hcs"
- #include "wifi/wlan_platform.hcs"
- #include "wifi/wlan_chip_hi3881.hcs"
- #include "lcd/lcd_config.hcs"
- #include "input/input_config.hcs"
- #include "sensor/sensor_config.hcs"
- #include "../../../../vendor/huawei/hdf/sample/config/uart/uart_config.hcs"
- #include "../../../../vendor/huawei/hdf/sample/config/device_info/device_info.hcs"
從這里可以看出,//device/hisilicon/hispark_taurus/sdk_liteos/config 目錄下的 hcs 文件,除了device_info、input、lcd、wifi四個(gè)模塊并不參與編譯之外,大部分都會(huì)得到編譯,而這四個(gè)模塊在vendor目錄下都有對應(yīng)的 hcs 來替代。實(shí)際上對比一下device和vendor目錄下的這四個(gè)模塊,差別不大。
最后面的兩句include hdf/sample 的hcs,就是前文《小型系統(tǒng)驅(qū)動(dòng)示例程序的編譯和驗(yàn)證》中添加進(jìn)來的,編譯示例程序的hcs文件。
全工程搜索文件 hdf.hcs 和 device_info.hcs:
- ohos@ubuntu:~/Ohos/B_LTS$ find ./ -name hdf.hcs
- ./device/hisilicon/hispark_aries/sdk_liteos/config/hdf.hcs
- ./device/hisilicon/hispark_taurus/sdk_liteos/config/hdf.hcs 【不編譯】
- ./device/qemu/arm_virt/config/hdf.hcs
- ./vendor/hisilicon/hispark_aries/config/hdf.hcs
- ./vendor/hisilicon/hispark_taurus/config/hdf.hcs 【編譯,hdf_test.hcs -->> hdf.hcs】
- ohos@ubuntu:~/Ohos/B_LTS$find ./ -name device_info.hcs
- ./device/hisilicon/hispark_aries/sdk_liteos/config/device_info/device_info.hcs
- ./device/hisilicon/hispark_taurus/sdk_liteos/config/device_info/device_info.hcs【不編譯】
- ./device/qemu/arm_virt/config/device_info/device_info.hcs
- ./vendor/huawei/hdf/sample/config/device_info/device_info.hcs【編譯,device_info.hcs -->> sample/.../device_info.hcs】
- ./vendor/hisilicon/hispark_aries/config/device_info/device_info.hcs
- ./vendor/hisilicon/hispark_aries/config/hdf_test/hdf_test_manager/device_info.hcs
- ./vendor/hisilicon/hispark_taurus/config/device_info/device_info.hcs 【編譯,hdf.hcs -->> device_info.hcs】
- ./vendor/hisilicon/hispark_taurus/config/hdf_test/hdf_test_manager/device_info.hcs 【編譯,hdf_test.hcs -->> hdf_test_manager/device_info.hcs】
把無關(guān)的先去除,剩下的就是就是上面幾個(gè)了。
上面就是對驅(qū)動(dòng)子系統(tǒng)的驅(qū)動(dòng)配置和設(shè)備樹描述文件(.hcs)的編譯關(guān)系的梳理,上面【*】提到的 hdf_driver.mk 的作用,就是配置編譯工具,將 *.hcs 配置文件編譯成 *_hex.c,再編譯成 *.o和 *.hcb 文件,存放在:項(xiàng)目輸出根目錄下的/obj/kernel/liteos_a/obj/vendor/hisilicon/hispark_taurus/config/hdf_test_config/config/目錄下。
至于驅(qū)動(dòng)子系統(tǒng)部署在內(nèi)核空間部分代碼的編譯,則需要到 //drivers/adapter/khdf/liteos/Makefile 來查看:
- include $(LITEOSTOPDIR)/config.mk #//kernel/liteos_a/config.mk
- include ./lite.mk #HDF_DRIVER = $(HDF_ROOT_DIR)/adapter/khdf/liteos/hdf_driver.mk 上面有展開
- MODULE_NAME := hdf
- HDF_FRAMEWORKS = ../../../framework
根據(jù)source,編譯出libhdf.a靜態(tài)鏈接庫文件到 //out/.../obj/kernel/liteos_a/lib/libhdf.a,生成OHOS_Image鏡像時(shí)將其鏈接進(jìn)去。
而//device/hisilicon/drivers/lite.mk 則描述了具體的驅(qū)動(dòng)模塊代碼編譯成對應(yīng)的靜態(tài)庫文件,文件末尾的:
- LITEOS_BASELIB += -lhdf_uart_sample
- LIB_SUBDIRS += $(LITEOSTOPDIR)/../../vendor/huawei/hdf/sample/platform/uart
就是前文《小型系統(tǒng)驅(qū)動(dòng)示例程序的編譯和驗(yàn)證》添加上去的,讓例子程序的內(nèi)核部分參與編譯,生成靜態(tài)庫文件,生成OHOS_Image鏡像時(shí)將其鏈接進(jìn)去。
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)