Buildroot官方全英文使用手冊的連結是https://buildroot.org/downloads/manual/manual.html,需要知道每一個細節的朋友,可以仔細查閱,這篇文章隻是我自己從中提煉出來的一下快速上手的技巧。
如何在現有項目加入自己的APP
Buildroot從零開始建構的過程還是很複雜的,以後的文章會一步步介紹。我們先來看看如何在現有項目中加入一個自己的應用的建構方法,快速上手。實際上,快速添加應用包的方法,在官方網站也有一份英文文檔:https://buildroot.org/downloads/manual/manual.html#adding-packages 詳細的原理可以參考這篇文檔。
這裡以加入自己的demo_app應用為例,在mini2440_defconfig的項目下,加入demo_app的package,将demo_app的應用源代碼編譯生成到rootfs根檔案系統中。建構方法如下:
1. 在buildroot/package/ 下執行 mkdir demo_app ,建立demo_app 的檔案夾
Figure1 在package/ 目錄下建立demo_app/
2. 在demo_app 中touch Config.in , touch demo_app.mk 建立這兩個檔案,注意,檔案名很關鍵,demo_app.mk要小寫,而且不能亂取其它名字,因為Buildroot架構有一套根據命名,展開app package的規則,是以buildroot裡面建構項目,一定要遵守文章中的命名規則,否則會有各種報錯。
Figure2 添加Config.in 與 demo_app.mk 檔案
3. 在package/Config.in 中加入 source "package/demo_app/Config.in" ,以便将demo_app 的配置檔案包含到Buildroot的package中來管理。
Figure3 在packahe/Config.in 中加入demo_app的Config.in
4. 在package/demo_app/Config.in 這個類似Kconfig的配置檔案中,按照命名格式和Linux Kernel 的 Kconfig檔案規範,加入自己的配置變量,參考代碼如下:
1. config BR2_PACKAGE_DEMO_APP
2. bool"demo app"
3. help
4. demo app to show
這段配置中,命名規則也同樣重要,BR2_PACKAGE_DEMO_APP是demo_app 可被Buildroot識别編譯成package的配置變量。Package應用一定要以BR2_PACKAGE_作為開頭,以DEMO_APP即demo_app的大寫來填充這個變量名,這樣才能被Buildroot命名架構識别、展開,才能通過make menuconfig來配置。
bool是變量的類型,即隻要true(編譯選中,false(編譯未選中),兩種情況,和Kconfig的規則是一樣的,後面的字元串和help都是在make menuconfig時的提示文本。
實際上,在Config.in中,可以參考linux Kernel的Kconfig檔案,根據文法規範,加入自己的配置邏輯和其它可配置的變量(比如app的下載下傳位址連結),在此就不詳細說了,大家可以參考其它的package/的Config.in檔案的寫法,這裡隻說重點,就是BR2_PACKAGE_DEMO_APP這個變量一定要有,一定要被選上才能編譯。
5. 在demo_app.mk中,按照Makefile檔案的格式和文法規範,編寫demo_app的上層建構規則,demo_app.mk的參考代碼如下:
1. ################################################################################
2. #
3. # demo app
4. #
5. ################################################################################
6. DEMO_APP_VERSION = master
7. DEMO_APP_SITE_METHOD = git
8. DEMO_APP_SITE = /mnt/sdb/git_repo/demo_app
9. DEMO_APP_SOURCE = demo_app-$(DEMO_APP_VERSION).tar.gz
10. DEMO_APP_ALWAYS_BUILD = YES
11. DEMO_APP_INSTALL_STAGING = YES
12. DEMO_APP_CFLAGS =
13. DEMO_APP_LDFLAGS =
14. OUT_BIN = demo_app
15. DEMO_APP_MAKE_FLAGS += \
16. CROSS_COMPILE="$(CCACHE) $(TARGET_CROSS)" \
17. CC=$(TARGET_CC) \
18. OUT_BIN=$(OUT_BIN) \
19. AR=$(TARGET_AR) \
20. STRIP=$(TARGET_STRIP) \
21. CFLAGS=$(DEMO_APP_CFLAGS) \
22. LDFLAGS=$(DEMO_APP_LDFLAGS) \
23. STAGING_DIR=$(STAGING_DIR) \
24. TARGET_DIR=$(TARGET_DIR)
25.
26. define DEMO_APP_BUILD_CMDS
27. $(MAKE) clean -C $(@D)
28. $(MAKE) $(DEMO_APP_MAKE_FLAGS) -C $(@D)
29. endef
30.
31. define DEMO_APP_INSTALL_TARGET_CMDS
32. $(INSTALL) -m 0755 -D $(@D)/$(OUT_BIN) $(TARGET_DIR)/usr/bin
33. endef
34.
35. $(eval $(generic-package))
注意,demo_app.mk并不能實際代替demo_app源代碼的Makefile檔案,它隻是一個上層的make檔案,告訴Buildroot,應該到哪個地方拿源代碼,應該如何解壓源代碼,應該給源代碼中的Makefile中的變量傳遞哪些編譯參數,編譯出來的庫和bin檔案,應該安裝到rootfs的哪個路徑下。具體demo_app源代碼是如何一步一步編譯的,還得靠demo_app源代碼本身的Makefile去做。
這段makefile代碼大概有什麼規範呢:
a) 所有的變量都已DEMO_APP_ 開頭,這樣Buildroot才能夠通過命名架構去解析
b) _VERSION結尾的變量,是下載下傳demo_app源代碼的版本号, _SITE_METHOD結尾的變量是demo_app變量的下載下傳方法,_SITE結尾的變量是demo_app的下載下傳位址,其它的變量是幹嘛用的,可以慢慢查閱官方手冊。
c) 所有define 并以_CMDS結尾的代碼塊,類似函數的東西,實際上是建構過程中會被Buildroot架構執行的指令,這些指令到底有哪些,具體也得讀手冊。當然這些類似函數,開頭也得是DEMO_APP_, Buildroot中命名規則很重要,重要的話說三遍。
d) _BUILD_CMDS結尾的函數,是建構過程函數,一般是給demo_app源代碼傳遞編譯和連結選項,調用源代碼的Makefile執行編譯。
e) INSTALL_TARGET_CMDS結尾的函數,就是demo_app編譯完之後,自動安裝的執行,一般是讓Buildroot把編譯出來庫和bin檔案安裝到指定的目錄。
f) $(eval$(generic-package)) 最核心的就是這個東西了,一定不能夠漏了,不然demo_app是編譯不出來的,這個函數就是把整個demo_app.mk建構腳本,通過Buildroot架構的方式,展開到Buildroot/目錄下的Makfile中,生成demo_app的建構目标(建構目标是什麼,還記得Makefile中的定義嗎?)。
g) 實際上,這些建構命名架構還有$(eval $(generic-package))這個黑魔法,都在package/pkg-generic.mk 這個檔案中,generic-package是這個檔案最後的調用的函數生成的,其它 _BUILD_CMDS,INSTALL_TARGET_CMDS這些函數如何被Buildroot架構嵌入的, 之前那些變量是如何被調用的,在package/pkg-generic.mk中都能找到,但是還是要一定的Makefile功底才能讀懂這個的,以後再解釋package/pkg-generic.mk的架構原理。
講了這麼多條規範,那麼這段makefile代碼大概是什麼意思呢?
這段代碼描述的流程是, 通過Git clone的方法從/mnt/sdb/git_repo/demo_app這個目錄下的git倉庫中拿到demo_app的源代碼-->傳遞編譯參數,并且編譯demo_app(DEMO_APP_BUILD_CMDS函數做的事情)-->把編譯出來的bin檔案安裝到$(TARGET_DIR)/usr/bin目錄下(DEMO_APP_INSTALL_TARGET_CMDS函數做的事情)。
為什麼我們自己不用寫從git倉庫下載下傳demo_app源代碼的函數呢,實際上是Buildroot幫我們寫好了,在package/ pkg-download.mk 檔案裡面,是以我們隻有通過DEMO_APP_SITE_METHOD和DEMO_APP_SITE設定下載下傳的方法和位址就可以。至于為什麼DEMO_APP_VERSION是master,了解git的朋友應該看得明白,就是git clone之後會checkout到master版本,其實也就是master分支最新的版本啦,當然也可以換成自己的版本号,前提是該版本号存在,能夠用git checkout 切換過去。
這段代碼的執行前提是要在Linux上搭建自己的git倉庫,維護自己的demo_app源代碼,在用Buildroot前,git倉庫是現成的。
但是不熟悉git 的朋友怎麼辦呢?其實還有其它方法,demo_app.mk的代碼稍做修改:
Figure4 采用file方法下載下傳源代碼
主要,DEMO_APP_SITE_METHOD改成了file,這樣就不用建構git參考,可以用file,也就是直接cp的方法,把源代碼拷貝到buildroot中來。但是buildroot到哪裡去cp源代碼呢,實際上,這裡不是DEMO_APP_SITE = /mnt/sdb/git_repo/demo_app這個位址,這個地方被我注釋掉了。
在buildroot/下 makemenuconfig --> Build options -->Mirrors and Download locations 可以看到以下的畫面:
Figure5 設定file方法cp檔案的路徑
隻有按照上面的格式,也就是file:// + 你的檔案絕對路徑的位址的格式配置這個選項,然後儲存,就OK,之後Buildroot就知道去該路徑下找源代碼包了。
另外記得,一定要把demo_app的源代碼壓縮包儲存到該路徑下,并且名字一定要和DEMO_APP_SOURCE變量的名字一樣哦!
Figure6 demo_app 源代碼的存放路徑
6. demo_app的源代碼
demo_app就是一個hello world 程式參考的makefile和源代碼如下:
其中Makefie會被demo_app.mk中的DEMO_APP_BUILD_CMDS函數調用,Makefie中的變量參數的值都可以通過DEMO_APP_BUILD_CMD傳入。
Figure7 demo_app 的Makefie
Figure8 demo_app.c 源代碼
7. 建構方法
a). make mini2440_defconfig --> makemenuconfig --> Target packages下選中demo app --> make demo_app
Figure9 menuconfig中選中 demo app,
make demo_app這個指令,實際上是隻是編譯demo_app以及demo_app依賴鍊上的package, 當然,toolchain會被所有package依賴,是以buildroot會先編譯toolchain。
編譯完成後,會發現buildroot/output/build/目标下的demo_app-master目錄,即demo_app編譯後現場,以及在buildroot/output/target/usr/bin/目錄下,安裝好的編譯出來的demo_appbin檔案。并且确實是ARM交叉工具鍊編譯出來的。
Figure10 demo_app 源代碼編譯現場路徑
Figure11 安裝好的demo_app bin檔案
至此,在Buildroot中添加app package的過程就完成了。
如何編譯基于現有項目的最小系統
Buildroot 一次make all要把整個系統編譯出來,真麻煩,我隻想要一個可以boot起來的最小系統,不需要什麼其它package,它有什麼快捷方式可以辦到嗎?這個當然問buildroot,我們可以這麼做。
make help 看看buildroot怎麼說
Figure12 make help 之後的buildroot系統提示
以下是buildroot的help指令提示,其中有一項是
make allnopackageconfig
在make xxx_defconfig 之後,執行make allnopackageconfig,那麼再make all就可以隻編toolchain,boot,kernel,busybox,rootfs這個幾個能構成系統啟動的最小系統的子產品。
當然,在make mini2440_defconfig時,由于mini2440的toolchain是toolchain-buildroot,即buildroot從零開始制作工具鍊,而不是toolchain-external,即buildroot使用已經制作好的工具鍊,這樣的話,如果toolchain還沒有在前一次生成,則make allnopackageconfig 再make all之後編譯過程會報錯,因為制作零制作toolchain需要編譯某些package作為原材料,而這些package被make allnopackageconfig去掉了。
已經制作好工具鍊,或者采用toolchain-external模式的情況下,make allnopackageconfig 編譯最小系統是沒用問題的。
Buildroot實用技巧與指令
最後看看buildroot有哪些實用技巧:
make help
-之前示範過了,列印出幫助菜單
make show-targets
- 顯示出本次配置所要編譯所有的目标,這些目标可以單獨作為子產品,用 make <pkg-target> 指令進行單獨編譯。從這條指令的顯示結果來看,mini2440_defconfig需要編譯uclibc(微型C庫),busybox等目标,當然demo_app也是一個編譯目标,是我在menocunfig時候加進去的,是以可以用make demo_app來編譯。
Figure13 make show-targets 的顯示結果
make <pkg-target>
- 單獨編譯某個pkg子產品以及其依賴的子產品,比如make demo_app
make pkg-rebuild
- 重新編譯pkg
make pkg-extract
- 隻下載下傳解壓pkg,不編譯,pkg解壓後放在 output/build/目錄對應的pkg-dir目錄下
make pkg-source
- 隻下載下傳某pkg,然後不做任何事情
其它還有很多快捷指令,在package/pkg-generic.mk中都能找到,這些快捷指令實際是是由pkg-指令這種命名架構合成的,更詳細的内容請參考手冊和package/pkg-generic.mk。