Makefile教程(附通用模板)

工程目錄

工程目錄如圖,build文件夾是編譯出來的

.
├── app
│   ├── imx6ul.lds
│   ├── main.c
│   ├── makefile
│   └── start.S
├── bsp
│   ├── clk
│   │   ├── bsp_clk.c
│   │   └── bsp_clk.h
│   ├── delay
│   │   ├── bsp_delay.c
│   │   └── bsp_delay.h
│   └── led
│       ├── bsp_led.c
│       └── bsp_led.h
├── build
│   ├── bsp_clk.o
│   ├── bsp_delay.o
│   ├── bsp_led.o
│   ├── led_bsp.bin
│   ├── led_bsp.elf
│   ├── led_bsp.lst
│   ├── main.o
│   └── start.o
└── imx6ul├── cc.h├── fsl_common.h├── fsl_iomuxc.h├── imx6ul.h└── MCIMX6Y2.h



Makefile源碼

#   $@  表示目標文件;
#   $^  表示所有的依賴文件;
#   $<  表示第一個依賴文件;#   =   延時賦值,該變量只有在調用的時候,才會被賦值;
#   :=   直接賦值,與延時賦值相反,使用直接賦值的話,變量的值定義時就已經確定了;
#   ?=  若變量的值為空,則進行賦值,通常用于設置默認值;
#   +=  追加賦值,可以往變量后面增加新的內容。# 定義交叉編譯器變量
CROSS_COMPILER ?= arm-linux-gnueabihf-# 定義編譯選項
CFLAGS = -Wall -Wextra -std=c11 -O2# 定義目標文件
TARGET = led_bsp# 定義連接腳本文件路徑
LD_SCRIPT = -T./imx6ul.lds# 定義目標文件夾
BUILD_DIR := ../buildSRC_DIRS := ./
INC_DIRS := ../imx6ul
LIB_DIRS := ../lib# 擴展源文件夾列表
SUBDIRS := clk led delay
SRC_DIRS += $(addprefix ../bsp/, $(SUBDIRS))
VPATH := $(SRC_DIRS)# 擴展頭文件夾列表
INC_DIRS := $(addprefix -I, $(INC_DIRS))
INC_DIRS += $(addprefix -I, $(SRC_DIRS))# 擴展庫文件夾列表
LIB_DIRS := $(addprefix -L, $(LIB_DIRS))# 定義需要鏈接的庫
#LIBS = -lm -lpthread# 查找所有的源文件
SRCS_S := $(shell find $(SRC_DIRS) -name '*.S')
SRCS_C := $(shell find $(SRC_DIRS) -name '*.c')
# 去掉路徑 只保存文件名
NOT_DIR_SRCS_S := $(notdir  $(SRCS_S))
NOT_DIR_SRCS_C := $(notdir  $(SRCS_C))
# 將.c .S替換成.o
OBJS_S := $(patsubst %.S, $(BUILD_DIR)/%.o, $(NOT_DIR_SRCS_S))
OBJS_C := $(patsubst %.c, $(BUILD_DIR)/%.o, $(NOT_DIR_SRCS_C))
OBJS := $(OBJS_S) $(OBJS_C)# 默認目標 鏈接所有.o
$(BUILD_DIR)/$(TARGET): $(OBJS)$(CROSS_COMPILER)ld $(LD_SCRIPT) $(LIB_DIRS) $(LIBS)  -o $@.elf $^ # 編譯成.o
$(OBJS_C) : $(BUILD_DIR)/%.o : %.c$(CROSS_COMPILER)gcc $(CFLAGS) $(INC_DIRS) -c -o $@ $<$(OBJS_S) : $(BUILD_DIR)/%.o: %.S$(CROSS_COMPILER)gcc $(CFLAGS) $(INC_DIRS) -c -o $@ $<# 生成bin文件
bin: $(BUILD_DIR)/$(TARGET)$(CROSS_COMPILER)objcopy -O binary $<.elf $<.bin# 生成反匯編文件
disassemble: $(BUILD_DIR)/$(TARGET)$(CROSS_COMPILER)objdump --source --all-headers --demangle --line-numbers --wide $<.elf > $<.lst# 生成空間信息
size: $(BUILD_DIR)/$(TARGET)$(CROSS_COMPILER)size --format=berkeley $<.elf # all目標生成目標文件、bin文件和反匯編文件
all: $(BUILD_DIR)/$(TARGET) bin disassemble size# 清理規則,用于清除生成的目標文件、可執行文件、二進制文件和反匯編文件
clean:rm -rf $(BUILD_DIR)# 確保編譯目標文件夾存在
$(BUILD_DIR):mkdir -p $(BUILD_DIR)# 編譯之前先創建目標文件夾
$(OBJS): | $(BUILD_DIR).PHONY: bin disassemble size all clean



基本編譯規則

編譯過程

在GCC中,每個編譯階段都有對應的指令來執行。以下是每個階段對應的GCC指令:

  1. 預處理(Preprocessing)gcc -E 這個指令告訴GCC只進行預處理,生成預處理后的代碼,而不執行后續的編譯、匯編和鏈接步驟。生成的預處理文件通常以.i為擴展名

  2. 編譯(Compiling)gcc -S 這個指令告訴GCC只進行編譯,將源代碼轉換為匯編代碼,而不執行匯編和鏈接步驟。生成的匯編語言文件通常以.s為擴展名

  3. 匯編(Assembling)gcc -c 這個指令告訴GCC只進行匯編,將匯編語言代碼轉換為目標文件,而不執行鏈接步驟。生成的目標文件通常以.o為擴展名

  4. 鏈接(Linking)ld 這個指令執行完整的編譯鏈接過程,將多個目標文件以及可能的庫文件鏈接在一起,生成最終的可執行文件。可通過指定輸入的目標文件和庫文件來完成鏈接過程,并使用 -o 選項來指定輸出文件名



Makefile基本規則

規則定義了如何根據源文件生成目標文件,規則通常由三個部分組成:目標(target)、依賴關系(dependencies)和命令(commands)

以下是規則的一般格式:

codetarget: dependenciescommand
  • 依賴全部存在時,才會執行command
  • 程序會從默認規則開始執行,也是為了生成第一個目標(一般都是可執行文件)
  • 當依賴不存在時,就會自動去別的規則中的目標中去尋找,以此類推
  • .PHONY聲明了偽目標,例如make all,這樣做的好處是,可以避免與同名的文件或目錄發生沖突,同時確保這些目標能夠被正確地執行


常用函數和語句

sheel

result := $(shell command)

會創建一個shell進程執行command,并將結果返回到result

需要注意執行效率,此函數可能會被多次調用到



wildcard(匹配文件名并返回列表)

$(wildcard pattern)

其中 pattern 是一個文件名模式,可以包含通配符(例如 *?

wildcard 函數會返回匹配 pattern 的文件列表,如果沒有匹配的文件,則返回空字符串。

以下是一個示例:

SRCS := $(wildcard src/*.c)

在這個示例中,$(wildcard src/*.c) 將匹配 src 目錄下所有以 .c 結尾的文件,并返回這些文件的列表給 SRCS 變量



foreach (遍歷執行)

用于在每個元素上執行操作,它的語法如下:

$(foreach var, list, text)
  • var 是一個變量名,用于保存列表中的每個元素
  • list 是一個空格分隔的元素列表
  • text 是要執行的文本

foreach 函數會遍歷列表中的每個元素,并將當前元素依次賦值給 var,然后執行 text 中的命令。在每次迭代中,text 中可以使用 var 來引用當前元素

在這個示例中, 會遍歷 FILES 列表中的每個文件名,并將其打印出來

FILES := file1.txt file2.txt file3.txt
$(foreach file, $(FILES), $(info File: $(file)))



addprefix(給列表加前綴)

用于在每個元素前添加一個前綴,它的語法如下:

makefileCopy code
$(addprefix prefix,names...)
  • prefix 是要添加的前綴
  • names 是一個空格分隔的元素列表

addprefix 函數會將 prefix 添加到 names 列表中的每個元素前面,并返回修改后的列表以下是一個示例:

makefileCopy codeFILES := file1.txt file2.txt file3.txt
$(addprefix prefix_, $(FILES))

在這個示例中,$(addprefix prefix_, $(FILES)) 會將 FILES 列表中的每個文件名前面都添加 prefix_ 前綴,得到一個新的列表。結果將是 prefix_file1.txt prefix_file2.txt prefix_file3.txt



查找所有源文件

第一步先是通過addprefix生成所有包含源文件的目錄,將其存在SRC_DIRS 中,并借助info 將其打印出來

SUBDIRS := clk led delay
SRC_DIRS += $(addprefix ../bsp/, $(SUBDIRS))$(info SRC_DIRS : $(SRC_DIRS))#結果如下
SRC_DIRS : ./ ../bsp/clk ../bsp/led ../bsp/delay



使用 find

? 通過如下命令即可找出SRC_DIRS 中的所有.c文件

SRCS_C := $(shell find $(SRC_DIRS) -name '*.c')$(info SRCS_C : $(SRCS_C))#結果如下
SRCS_C : ./main.c ../bsp/clk/bsp_clk.c ../bsp/led/bsp_led.c ../bsp/delay/bsp_delay.c

?

附上find的常見用法:

  1. 在當前目錄及其子目錄中搜索所有文件:

    find
    
  2. 在指定目錄中搜索所有文件:

    find /path/to/directory
    
  3. 在當前目錄及其子目錄中搜索所有 .txt 文件:

    find -name "*.txt"
    
  4. 在當前目錄及其子目錄中搜索所有大于 1MB 的文件:

    find -size +1M
    
  5. 在當前目錄及其子目錄中搜索所有修改時間在一天之內的文件:

    find -mtime -1
    
  6. 在當前目錄及其子目錄中搜索所有空文件:

    find -type f -empty
    

find 命令非常強大,它支持多種匹配條件和動作,可以根據實際需求來進行靈活的文件搜索和操作



使用wildcard和foreach

通過如下命令即可找出SRC_DIRS 中的所有.c文件

SRCS_C := $(foreach dir, $(SRC_DIRS), $(wildcard $(dir)/*.c))$(info SRCS_C : $(SRCS_C))#結果如下
SRCS_C : ./main.c ../bsp/clk/bsp_clk.c ../bsp/led/bsp_led.c ../bsp/delay/bsp_delay.c



notdir

用于從文件路徑中提取文件名部分,去除路徑。它的語法如下:

$(notdir names...)

其中 names 是一個空格分隔的文件路徑列表

notdir 函數會返回 names 中每個文件路徑的文件名部分,去除路徑信息

以下是一個示例:

SRCS := src/main.c src/foo.c src/bar.c
FILE_NAMES := $(notdir $(SRCS))

在這個示例中,$(notdir $(SRCS)) 將提取 SRCS 中每個文件路徑的文件名部分,結果將是 main.c foo.c bar.c



patsubst

用于在字符串中執行模式替換操作。它的語法如下:

$(patsubst pattern, replacement, text)

其中:

  • pattern 是要匹配的模式
  • replacement 是用于替換匹配模式的文本
  • text 是要進行模式替換的原始文本

patsubst 函數會查找 text 中與 pattern 匹配的部分,并將它們替換為 replacement

以下是一個示例:

SRCS := file1.c file2.c file3.c
OBJS := $(patsubst %.c, %.o, $(SRCS))

在這個示例中,$(patsubst %.c,%.o,$(SRCS)) 將把 SRCS 中的 .c 文件名替換為 .o 文件名,生成的 OBJS 變量會包含 file1.o file2.o file3.o


調用其他 Makefile

在 Makefile 中,可以通過 include 指令來引入其他的 Makefile。這樣做的主要目的是為了將大型項目拆分成更小的模塊,每個模塊對應一個獨立的 Makefile,方便管理和維護。同時,通過模塊化的方式,可以提高代碼的重用性和可維護性。

在 Makefile 中使用 include 指令的語法如下:

include other_makefile.mk

其中 other_makefile.mk 是要包含的其他 Makefile 的文件名。

通過引入其他的 Makefile,可以將項目拆分成多個模塊,每個模塊負責特定的功能或任務。這樣做有以下幾個優點:

  1. 模塊化管理:將項目拆分成多個模塊后,每個模塊可以獨立管理,減少了代碼的耦合度,方便團隊協作和代碼維護
  2. 代碼重用:通過將通用的功能和規則封裝在單獨的模塊中,可以提高代碼的重用性,避免重復編寫相同的代碼
  3. 可維護性:將項目拆分成多個模塊后,每個模塊的功能更加清晰明確,易于理解和維護。同時,可以針對每個模塊進行單獨的測試和調試

總之,通過引入其他的 Makefile,可以將大型項目拆分成更小的模塊,提高了代碼的組織性、可維護性和重用性,是一種良好的編程實踐。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/21576.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/21576.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/21576.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

軟考 系統架構設計師系列知識點之SOME/IP與DDS(1)

本文內容參考&#xff1a; 車載以太網 - SOME/IP簡介_someip-CSDN博客 https://zhuanlan.zhihu.com/p/369422441 什么是SOME/IP?_someip-CSDN博客 SOME/IP 詳解系列&#xff08;1&#xff09;—— 概述_some ip-CSDN博客 深入淺出SOME/IP協議&#xff1a;基本概念和原理-…

天童教育:停止內耗放松身心

如果一個人經常從自己身上找原因&#xff0c;經常攬下他人的過錯的責任&#xff0c;總是自我懷疑自我否定&#xff0c;認為自己不值得被愛。當被人誤解時會在心里悄悄附和&#xff0c;責怪自己。缺乏自信&#xff0c;沒辦法和他人有正常的交往&#xff0c;長期處于身心疲憊的狀…

Python與Python3的區別:深度剖析與全面解讀

Python與Python3的區別&#xff1a;深度剖析與全面解讀 在編程領域&#xff0c;Python和Python3是兩個常被提及的版本&#xff0c;它們之間既存在相似之處&#xff0c;又有著顯著的區別。本文將從四個方面、五個方面、六個方面和七個方面&#xff0c;深入剖析Python與Python3之…

OJ3376無盡的石頭問題

答案&#xff1a; #include<bits/stdc.h> using namespace std; const int N10e7; int fx(int n) {int sum0;while(n){sum(n%10);n/10;}return sum; } int main() {int t,n,x;cin>>t;while(t--){cin>>n;int count0;for(int i1;i<N;){if(in){cout<<…

在github上創建(上傳、關聯)自已的項目

目錄 創建一個github項目并進行開發。 1.github創建空項目 2. git clone 項目 3. 將項目關聯 創建一個github項目并進行開發。 1.github創建空項目 右邊的New 然后按步創建就行 2. git clone 項目 復制這個連接 然后在終端&#xff1a;git clone [剛才復制的連接] 3. 將…

解讀 Explainable Image Similarity Integrating Siamese Networks and Grad-CAM

給出論文&#xff08;Explainable Image Similarity Integrating Siamese Networks and Grad-CAM&#xff09;的內容解讀、代碼運行說明 論文鏈接&#xff1a;J. Imaging | Free Full-Text | Explainable Image Similarity: Integrating Siamese Networks and Grad-CAM (mdpi.c…

純網絡的系統能否定級備案?

很多單位想把網絡基礎設施進行定級備案和測評&#xff0c;但是不知道這樣可否&#xff1f; 目前湖北省是可以的。因為根據《定級指南》的術語解釋3.2對等級保護對象的定義是包括通信基礎設施的&#xff0c;也就是網絡基礎設施。其他地區目前有的地方可以有的地方不行&#xff…

2024年武漢東湖高新中級職稱報名時間是什么時候?

2024年武漢市東湖高新中級職稱上半年批次報名已經截止了&#xff0c;下半年東湖高新至少還有一次報名機會&#xff0c;所以各位東湖高新區評職稱的朋友們&#xff0c;不要錯過這次了。 2024年武漢東湖高新區中級職稱報名條件&#xff1a; 1.東湖高新區社保滿足1年&#xff0c;近…

進口不銹鋼氣動輸送泵-美國品牌

進口不銹鋼氣動輸送泵是一種利用壓縮空氣為動力&#xff0c;通過氣閥控制進行往復運動&#xff0c;將能量轉換為泵的動能&#xff0c;從而實現對液體或固體物料輸送的設備。以下是關于進口不銹鋼氣動輸送泵的詳細介紹&#xff1a; 一、產品特點 材質優良&#xff1a;主體部分…

seata源碼分析(03)_創建代理的過程

seata提供了ProxyUtil工具類為事務組件創建代理對象&#xff0c;在spring環境中&#xff0c;seata提供了GlobalTransactionScanner類和SeataAutoDataSourceProxyCreator為組件創建AOP代理&#xff0c;本文重點分析這兩個類。 ProxyUtil io.seata.integration.tx.api.util.Pro…

【中年危機】程序猿自救指南

中年危機&#xff0c;一個聽起來就充滿挑戰的詞匯&#xff0c;它不僅僅是一個年齡的標記&#xff0c;更是一個個人成長和職業發展的轉折點。 構架個人品牌&#xff1a; 學會打造IP個人品牌是職業生涯中的重要資產。在中年時期&#xff0c;你已經積累了豐富的經驗和知識&#x…

golang的http客戶端封裝

簡介 net/http 是 Go 語言標準庫的一部分&#xff0c;它提供了創建 HTTP 客戶端和服務器的能力。這個包通過簡化與 HTTP 協議的交互&#xff0c;讓開發者能夠方便地構建 HTTP 請求和響應&#xff0c;以及處理路由等任務。 本文以 net/http 包作為底層&#xff0c;封裝一個包含…

HTCC電路板是什么,有哪些主要應用領域

HTCC英文名稱是High-Temperature Co-Fired Ceramic&#xff0c;又稱高溫共燒多層陶瓷基板。因其具有導熱系數高、耐熱性好、熱膨脹系數小、機械強度高、絕緣性好、耐腐蝕等優勢&#xff0c;是保持高速增加的PCB線路板之一。 SPEA作為專業電路板測試設備方案服務商&#xff0c;公…

FY-SA-20237·8-WhyWeSpin

Translated from the Scientific American, July/August 2023 issue. Why We Spin (我們為什么旋轉) Primates may play with reality by twirling around 翻譯&#xff1a;靈長類動物有能力通過旋轉或旋轉運動來操縱或扭曲他們對現實的感知。 解釋&#xff1a; “Primates”…

Java生成指定長度驗證碼

生成指定長度驗證碼的簡單思路在Java中通常涉及以下幾個步驟&#xff1a; 1、定義字符池&#xff1a; 首先&#xff0c;需要定義一個包含所有可能字符的字符串&#xff0c;這個字符池通常包括數字(0-9)、大寫字母(A-Z)、小寫字母(a-z)。 例如&#xff1a; String chars "…

【開發心得】三步本地化部署llama3大模型

目錄 第一步&#xff1a;啟動ollama 第二步&#xff1a;啟動dify 第三步&#xff1a;配置模型&#xff08;截圖&#xff09; 最近llama3很火&#xff0c;本文追擊熱點&#xff0c;做一個本地化部署的嘗試&#xff0c;結果還成功了&#xff01; 當然也是站在別人的肩膀上&…

【運維項目經歷|027】PXE自動化部署與管理平臺

&#x1f341;博主簡介&#xff1a; &#x1f3c5;云計算領域優質創作者 &#x1f3c5;2022年CSDN新星計劃python賽道第一名 &#x1f3c5;2022年CSDN原力計劃優質作者 &#x1f3c5;阿里云ACE認證高級工程師 &#x1f3c5;阿里云開發者社區專…

Nginx企業級負載均衡:技術詳解系列(18)—— 作為上傳服務器

你好&#xff0c;我是趙興晨&#xff0c;97年文科程序員。 在上一期的技術分享中&#xff0c;我們探討了如何高效搭建Nginx下載服務器&#xff0c;并討論了長連接優化策略。那么今天&#xff0c;咱們進一步了解Nginx的另一面——作為上傳服務器的配置技巧。 作為上傳服務器&a…

怎么做好企業短信服務呢?(文字短信XML接口示例)

企業短信服務已經成為各行各業都信賴的行業推廣方式之一&#xff0c;并且短信行業也與時俱進的發展著&#xff0c;隨之而來的就是市場上短信平臺的數量也隨之增多。那么怎么在魚龍混雜的短信行業中選擇適合自己的企業短信服務平臺呢&#xff1f;企業短信服務平臺又適用于哪些應…

Django的PATH路徑轉換器

本書1-7章樣章及配套資源下載鏈接: https://pan.baidu.com/s/1OGmhHxEMf2ZdozkUnDkAkA?pwdnanc 源碼、PPT課件、教學視頻等&#xff0c;可以從前言給出的下載信息下載&#xff0c;大家可以評估一下。 在Django框架中&#xff0c;默認內置了一組PATH路徑轉換器&#xff0c;具…