您好,登錄后才能下訂單哦!
怎么進行Makefile分析,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。
Makefile是一個名為GNU-Make軟件所需要的腳本文件,該腳本文件可以指導Make軟件控制arm-gcc等工具鏈去編譯工程文件最終得到可執行文件,幾乎所有的Linux發行版都內置了GNU-Make軟件,VScode等多種IED也內置了Make程序。
你見到的xxx.mk文件或者Makefile都統稱為Makefile腳本文件。
Makefile的規則如下,這里的[TAB]指鍵盤上的TAB按鍵,不是空格,如果在命令前輸入了空格則會造成錯誤,并且在Makefile中TAB鍵不能隨意使用:
目標 : 依賴
[TAB]命令
例如:
Hello :
@echo “Hello”
這時執行make命令就會輸出一條語句”Hello”,Hello是目標,依賴為空,為了生成目標,需要執行echo “Hello”語句,從而導致輸出Hello。
例如:假設我們有一個Hello.c C語言源文件,需要將其編譯不鏈接為Hello.o文件,最后在進行連接,Makefile內容如下:
Hello.out : Hello.o
gcc -o Hello.out Hello.o
Hello.o : Hello.c
gcc -c -o Hello.o Hello.c
這時執行make命令,make解釋器發現目標為“Hello.out”,但是生成Hello.out需要Hello.o,發現目錄下找不到“Hello.o”,就向下查找是否有生成Hello.o的規則,找到了,發現”Hello.o”依賴于”Hello.c”,在目錄下也找到了Hello.c,就執行語句“gcc -c -o Hello.o Hello.c”生成”Hello.o”,只要編譯過程不出錯,即可得到”Hello.o”,這時可以執行“gcc -o Hello.out Hello.o“生成”Hello.out”
這里可以用分析一個C語言或Java語言程序來類比,一般都是根據程序是執行流來進行分析,也就是先找到main函數,因為main函數是程序的執行入口,Makefile也有執行入口,在執行make命令時,make解釋器默認搜索當前目錄下名為“Makefile”的文件,找到后,執行生成第一個目標的命令及生成其依賴所需的命令。
這里選擇在SDK/Targets目錄中STM32L431_BearPi工程中的GCC目錄下的Makefile開始分析。
第1行到第140行都是設置一些變量和導入一些makefile文件(其中也沒有任何規則,都是進行一些變量的設置),第143行是第一條規則
當我們執行make或make all時,就開始生成all目標,其依賴于BUILD_DIR(GCC/build)目錄中的TARGET(Huawei_LiteOS).elf文件,BUILD_DIR和TARGET為兩個變量,一開始就被賦值,如下圖所示,實際使用時$(變量)會被替換為變量的值,例如$(TARGET).elf最終會被替換為Huawei_LiteOS.elf。
可是Huawei_LiteOS.elf還不存在,make只好繼續向下查找是否有生成Huawei_LiteOS.elf的規則,好在第147行的目標為Huawei_LiteOS.elf,這就是生成Huawei_LiteOS.elf的規則,該規則依賴為$(OBJ_DIRS) $(C_OBJ) $(S_OBJ)分別對應三個目錄,這三個目錄都不存在,所以make只好繼續向下查找,它發現第152行正好為目標是該目錄的規則,就創建了該目錄,解決了$(OBJ_DIRS)這個依賴,接著該處理$(C_OBJ)這個依賴
Make向下查找依賴發現位于第156行出現生成這個以來的規則,這里的$(C_OBJ):$(BUILD_DIR)/%.o:%.c對應makefile中的靜態模式,我這里簡單的說一下,大家如果想深入了解可以自行百度。
靜態模型的格式如下:
目標列表: 與目標列表相匹配的模型: 與依賴相匹配的模型
[TAB]命令
來看一個例子,
目標列表中有foo.o、bar.o和test.s三個值,首先將匹配%.o的模型找出來,test.s不匹配就被遺棄了,將匹配的foo.o和bar.o替換為foo.c和bar.c,最終這一條規則等于執行了下列這兩條規則,為什么要這樣做呢?你可以試想以下,假設目標列表中有幾千個文件,這樣做的話是不是就可以少寫很多規則:
回到LiteOS_Lab的Makefile上來,156行將C_OBJ變量中的符合build/xxx.o格式的文件作為xxx.c格式的依賴,C_OBJ變量的賦值如下圖所示:
$(patsubst PATTERN, REPLACEMENT, TEXT)函數的作用是模式替換,將TEXT中以空格隔開的每個單詞(文件名),符合PATTERN格式的替換為REPLACEMENT格式,例如第124行,將所有的C_SOURCE變量中的文件名,凡是只要在SDK/ iot_link目錄下的都替換為.o后綴,SDK/ iotlink目錄中有一個符合該模型的文件,link_main.c,在執行該規則對應的命令時,目標文件為link_main.o,第125和126行同上。
這里以link_main.c為例向大家講解指令,經過模式替換后規則如下:
link_main.o: link_main.c
$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(@:%.o=%.lst) $< -o $@
這里的CC是指arm-none-eabi-gcc,CFLAGS是指各類編譯參數,例如-MMD -MP -Wno-missing-braces,$(@:%.o=%.lst)函數的作用是將$@目標符合%.o模型的值替換為%. lst,這里就將link_main.o替換link_main. lst,$<是指第一個依賴,$@是指目標,組合的命令后如下:
arm-none-eabi-gcc -c -MMD -MP -Wno-missing-braces -Wa,-a,-ad,-alms=link_main. lst link_main.c -o link_main.o。一句話來說就是將所有的.c源文件編譯不鏈接生成.o文件和.lst文件,等待后續進一步操作。
第160和161行的操作類似于上面的操作,將所有的匯編文件都編譯不鏈接生成.o文件等待后續進一步操作。
第147到149行規則所需的依賴全部都生成好了,可以開始執行該規則的命令,將所有依賴通過LDFLAGS變量中的值鏈接生成Huawei_LiteOS.elf文件并列出程序文件中各段的大小。
LDFLAGS變量中通過MCU變量定義了內核相關參數,例如ARM架構的版本以及是否支持硬件浮點數運算等參數,如下圖所示,如果你需要將工程移植到不是STM32L431系類的MCU上,就需要修改MCU變量的值。
LDFLAGS變量中通過LDSCRIPT變量讀取os.ld鏈接腳本來控制程序該如何鏈接,每個段應該存放在程序中的何處,在os.ld鏈接腳本中還指明了MCU的RAM和FLASH大小及起始位置,我們在進行移植時也需要修改。
Huawei_LiteOS.elf文件是第143至145行規則的依賴,將該elf文件轉換為Huawei_LiteOS.hex和Huawei_LiteOS.bin文件,即可燒錄。
現在大家應該明白make控制下的整個程序編譯過程了吧,以及Makefile文件起到的作用,我們再來看看前面的include導入的文件,如下圖所示:
首先導入了.config文件,這由Kconfig軟件讀取用戶通過圖形化配置的各項參數信息生成的,其中包含了對SDK中各組件參數的配置信息,如下圖所示:
以AT組件為例,CONFIG_AT_ENABLE=y代表使能AT組件;CONFIG_AT_DEVNAME="atdev"將AT組件用到的串口以"atdev"注冊到driver層中;CONFIG_AT_OOBTABLEN=6 OOB表的長度配置為6個,這時用于接收異步數據的結構體,意味著我們最多能配置6個特定字符串,當這時字符串出現時調用相應處理函數進行處理;CONFIG_AT_RECVMAXLEN=1024將AT框架中的接收緩存區大小配置為1024字節,如果你的MCU資源受限可以減少這里的大小;CONFIG_AT_TASKPRIOR=10將AT任務的優先級配置為10,注意:這里只有第35行這條語句會影響Make的編譯,其余語句是為了記錄用戶做了哪些配置和生成iot_config.h所用。
.config文件中所有的組件配置都和上面分析的一致,如果組件沒有被使能如下圖所示:
相信大家看到這里又有新的疑問了,這些配置是如何影響到程序的編譯呢?回到前面的第70行include $(SDK_DIR)/iot_link/iot.mk,來看看這個SDK/iot_link目錄下的iot.mk文件中有什么你就有答案了,如下圖所示:
?
該Makefile將每個組件所屬文件夾下的Makefile也導入進來了,我們還是以AT框架為例,第31行,導入at目錄下的at.mk文件,該Makefile內容如下圖所示:
看到了吧,第7行與前面的CONFIG_AT_ENABLE=y變量相對應,ifeq ($(CONFIG_AT_ENABLE),y)語句的意思是如果CONFIG_AT_ENABLE變量的值為y,則將ifeq到endif之間的語句全部執行。
第8至9行將at目錄下所有.c文件添加到C_SOURCES變量中,注意這里用的是+=是追加上去。
第11至12行將at目錄下所有.h文件所在路徑(注意是路徑,通過-I參數指定頭文件所在的路徑,這樣編譯器才能找到頭文件,否則會因為找不到頭文件導致編譯失敗)添加到C_INCLUDES變量中,注意這里用的是+=是追加上去。
第14至14行將-D CONFIG_AT_ENABLE=1文本追加到C_DEFS變量中。
這三個變量大家都很眼熟吧,這就是工程目錄/GCC目錄中Makefile中的那三個變量,如下圖所示:
這樣AT組件中的所有源文件和頭文件就參與了編譯。
回到第三個include,include $(MAKEFILE_DIR)/project.mk,這是用于包含(引入)工程目錄/GCC目錄下的project.mk,該Makefile部分內容如下圖所示:
主要用于包含Hal庫中的文件以及用戶自己添加進去的文件,這也是移植時需要進行修改的文件之一,大家可以仿照我前面分析的方法自己分析一下。最終所有被添加進入的.c源文件會被追加到C_SOURCES變量中,所有.h頭文件所在的路徑會被追加到C_INCLUDES變量中。
SDK中所有的Makefile文件都不需要也不能進行修改,只需要修改工程中的三個Makefile,.config(這個不用手動修改,可以通過圖形化配置進行修改),Makefile(根據目標MCU修改MCU相關的參數即可,也就是MCU這個變量的值),project.mk(根據目標MCU修改、添加或刪除庫文件以及用戶文件以及最后的C_DEFS變量即可)。
看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。