UIS8910DM平臺的編譯系統

  這裏所說的編譯系統是一種籠統的說法,大體上包含構建系統和編譯工具集合。編譯工具集合就是大家熟悉的編譯器、彙編器、連接器等,該平臺使用的是GCC,具體路徑位於prebuilt/win32/gcc-arm-none-eabi,這裏就不多說了。下面我們主要講講該平臺的構建系統(build system)。

  講到構建系統,大家比較熟悉就是makefile了,它通過Makefile語言編寫的腳本,組織代碼、資源,調用編譯工具集合及其它工具,共同完成最終目標的實現。這個最終目標可以是庫文件、可執行的應用軟件、不同格式的可燒寫的嵌入式固件等等。實際上,每個IDE裏都有一套自己的構建工具,比如VS的nmake,注重效率的Ninja,Mac系統的xcode等等。有些軟件工程直接通過一個單一的構建工具完成系統構建,優點是簡單,缺點是缺乏靈活、跨平臺移值工作量大。Linux內核是通過Kconfig和makefile組成構建系統的,kconfig用於配置、make主導生成最終的內核鏡像。對於那些希望實現跨平臺的軟件工程而言,直接使用makefile明顯帶來移值工作的大量增加,爲了解決這個問題,出現如cmake、autotool這樣的工具,這些工具的語言語法相對簡單,通過它們自動生成makefile、nmake、Ninja、xcode所對應的腳本,完成最終目標的構建。也就說,cmake、autotool這樣的工具是位於make、nmake、Ninja、xcode等工具的上層。

  UIS8910DM平臺爲了實現固件功能的可靈活配置、同時支持linux和Windows的編譯環境、又能提高編譯效率,採用 KConfig + cmake + Ninja組成它的構建系統。

KConfig

  KConfig最大的作用就是實現軟件項目的配置。在linux內核中,KConfig在編譯前會生成2個文件:一個是autoconf.h,用於C代碼的宏定義;一個是???,是makefile配置項。通過這兩個文件,實現對軟件項目的配置。有人會說。通過簡單自己手寫Makefile和.h文件,也可以實現這些功能,這是沒錯的,但這樣會帶來有幾個問題:

  1. 沒有可視化的工具進行清晰可見的配置。
  2. 在配置時需要人爲考慮依賴關係,比如需要支持USB storage功能,前提是USB功能,通過KConfig可以清晰得知這種依賴關係,甚至在配置時自動依據這個關係完成相關配置。
  3. 自動同步Makefile和.h文件關聯性。

  當然,KConfig不單單可以導出makefile腳本,還可以導出cmake腳本,本平臺就是通過kconfiglib.py這個腳本內的功能導出相應的cmake腳本:target.cmake
  本平臺通過運行menuconfig.bat來對項目進行可視化的配置(命令是 menuconfig.bat <target_name>),配置完成後會生成或者更新target/<target_name>/目錄下target.config文件,通過minconfig.py腳本可以將target.config中與默認配置相同的選項清除掉,僅保留與默認配置不一致的項。
  在SDK根目錄下的CMakeLists.txt中,通過以下腳本將KConfig完成的配置轉化爲cmake可以識別的配置:target.cmake,這一步在cmake ../.. -G Ninja 這一操作中完成的。

# Process and include target config

set(TARGET_CONFIG ${SOURCE_TOP_DIR}/target/${BUILD_TARGET}/target.config)
set(TARGET_CMAKE ${BINARY_TOP_DIR}/target.cmake)
execute_process(
COMMAND python3 ${tools_dir}/cmakeconfig.py ${TARGET_CONFIG} ${TARGET_CMAKE}
WORKING_DIRECTORY ${SOURCE_TOP_DIR}
)
include(${TARGET_CMAKE})

cmake

  cmake是一種更高層次的構建工具,也是更爲通用的構建工具,基於它可以構建跨平臺的編譯環境。
  本平臺通過cmake/extension.cmake這個文件擴展很多cmake的功能函數。比如relative_glob、beautify_c_code等等。基於cmake的這些功能,將每個軟件功能模塊各自生成爲一個靜態庫,最後鏈接這些靜態庫生成最終的目標固件。基本上components下的每個子目錄都會生成一個或者多個靜態庫,生成的靜態庫位於out/<project_target>/lib目錄下。
  最終固件的生成腳本位於SDK主目錄的CMakeLists.txt中,從這段腳本上看,我們可以爲一個項目配置多個不同的NV,以適配不同的RF硬件,該編譯系統能把適用於不同RF硬件的固件都生成出來。

# Create pac for all variants
foreach(nvmvariant ${CONFIG_NVM_VARIANTS}) build_modem_image(${nvmvariant})
    set(nvname ${NVM_VARIANT_${nvmvariant}_NVMITEM})
    set(pac_config ${out_hex_dir}/${nvmvariant}.json)
    set(pac_file ${out_hex_dir}/${BUILD_TARGET}-${nvmvariant}-${nvname}_${BUILD_RELEASE_TYPE}.pac) pac_init_fdl(init_fdl ${pac_config})
    pac_nvitem_8910(nvitem_8910 ${pac_config})
    if(DEFINED package_file_depends) 
		set(pac_package_file cfg-pack-cpio -i PACKAGE_FILE -p ${out_hex_dir}/${package_file_cpio} ${pac_config}) 
	endif()
    execute_process(
		COMMAND python3 ${pacgen_py} ${init_fdl} ${nvitem_8910} 
		cfg-image -i BOOTLOADER -a ${CONFIG_BOOT_FLASH_ADDRESS} -s ${CONFIG_BOOT_FLASH_SIZE}
                -p ${out_hex_dir}/boot.sign.img ${pac_config} 
		cfg-image -i AP -a ${CONFIG_APP_FLASH_ADDRESS} -s ${CONFIG_APP_FLASH_SIZE}
                -p ${out_hex_dir}/${BUILD_TARGET}.sign.img ${pac_config} 
		cfg-image -i PS -a ${CONFIG_FS_MODEM_FLASH_ADDRESS} -s ${CONFIG_FS_MODEM_FLASH_SIZE}
                -p ${out_hex_dir}/${nvmvariant}.img ${pac_config} 
		${pac_package_file}
        cfg-clear-nv ${pac_config}
        cfg-phase-check ${pac_config}
        cfg-nv -s ${CONFIG_NVBIN_FIXED_SIZE} -p ${out_hex_dir}/${nvmvariant}_nvitem.bin ${pac_config} 
		dep-gen --base ${SOURCE_TOP_DIR} ${pac_config} 
		OUTPUT_VARIABLE pac_dep
        OUTPUT_STRIP_TRAILING_WHITESPACE
        WORKING_DIRECTORY ${SOURCE_TOP_DIR} 
	)
    add_custom_command(OUTPUT ${pac_file} 
		COMMAND python3 ${pacgen_py} pac-gen ${pac_config} ${pac_file}
        DEPENDS ${pacgen_py} ${pac_config} ${pac_dep} 
		WORKING_DIRECTORY ${SOURCE_TOP_DIR} 
	)
    add_custom_target(${nvmvariant}_pacgen ALL DEPENDS ${pac_file}) 
endforeach() 

  爲了在C/C++代碼中引入開關配置,本平臺採用了cmake的configure_file機制。通過這個機制,可以將KConfig中定義的配置信息(通過target.cmake)引入到C/C++代碼中。
比如hal_config.h.in中的 #cmakedefine CONFIG_APPIMG_LOAD_FLASH,如果KConfig中CONFIG_APPIMG_LOAD_FLASH開啓,則C/C++代碼中CONFIG_APPIMG_LOAD_FLASH宏就會被定義。
又比如atr_config.h.in中的#cmakedefine CONFIG_ATR_URC_BUFF_SIZE @CONFIG_ATR_URC_BUFF_SIZE@,在C/C++代碼中的CONFIG_ATR_URC_BUFF_SIZE宏就引用了KConfig中定義的值。
  這種做法有個不好地方就是:C/C++代碼中引用這些宏的地方需要手動 include 相應的.h文件(通過.h.in生成的,位於out/<project_target>/include目錄)。

Ninja

  Ninja是一種類似於 make 的構建工具,它的主要特點是通過編譯任務並行組織,大大提高了構建速度。關於 Ninja 的詳細知識請查看相關網頁,這裏就不做描述。因爲在本平臺中,所有需要手動編寫的編譯腳本都是 cmake 腳本,通過 cmake 的 -G 命令將相關的cmake腳本轉化爲 Ninja 腳本,然後通過 Ninja 構建最終的目標固件。

  以上是本人關於UIS8910DM平臺編譯系統粗淺描述,不足和有誤的地方,望不吝指教。

發佈了4 篇原創文章 · 獲贊 12 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章