掌握Linux項目自動化構建:從零入門make與Makefile

在這里插入圖片描述

文章目錄

      • 前言:
    • 一、初識自動化構建工具
      • 1.1 什么是make/Makefile?
      • 1.2 快速體驗
    • 二、深入理解核心機制
      • 2.1 依賴關系與依賴方法
      • 2.2 偽目標的妙用
      • 2.3 具體語法
        • a.makefile的基本雛形
        • b.makefile推導原則!
    • 三、更加具有通用型的makefile
      • 1. 變量定義部分
      • 2. 編譯規則部分
      • 3. 模式規則(通配規則)
      • 4. 偽目標(`.PHONY`)
      • 5. 完整執行流程示例
      • 6. 新手常見問題
      • 總結
    • 四、高手必備的實用技巧
      • 1.調試 Makefile
      • 2. 常見問題與解決方案
        • Q1:修改頭文件后 `make` 不重新編譯?
        • Q2:如何指定其他名稱的 Makefile?
        • Q3:如何實現跨平臺編譯?

前言:

不會寫Makefile的程序員,就像不會用筷子的美食家——永遠嘗不到工程化開發的精髓。

在Windows環境下我們習慣使用Visual Studio等IDE的一鍵編譯,但在Linux開發環境中,掌握Makefile就像獲得了一把打開高效開發之門的鑰匙。它能讓你:

  1. 實現真正的自動化編譯 - 一個命令完成整個項目的構建
  2. 提升編譯效率 - 只重新編譯修改過的文件
  3. 管理復雜項目 - 輕松處理多文件、多目錄的依賴關系
  4. 跨平臺移植 - 一套構建規則適應不同開發環境

一、初識自動化構建工具

1.1 什么是make/Makefile?

在Linux開發中,make是一個智能編譯命令,而Makefile是它的配置文件。這對組合就像烹飪食譜:

  • Makefile是菜譜(記錄食材和步驟)
  • make是廚師(按菜譜自動執行)

1.2 快速體驗

步驟演示:3分鐘完成第一個自動化構建

  1. 創建測試文件
# test.c
#include <stdio.h>
int main() {printf("Hello Makefile!\n");return 0;
}
  1. 編寫Makefile
# 基礎版Makefile
mytest: test.cgcc test.c -o mytest.PHONY: clean
clean:rm -f mytest
  1. 一鍵編譯運行
$ make       # 自動編譯
$ ./mytest   # 運行程序
hello Makefile!
$ make clean # 清理項目

二、深入理解核心機制

2.1 依賴關系與依賴方法

核心思想:依賴關系和依賴方法,形成目標文件。

mytest: test.c         # 依賴關系gcc test.c -o mytest  # 依賴方法

理解這兩個概念是掌握Makefile的關鍵:

eg:月底了,沒錢了,要讓爸爸打錢。

概念生活案例技術解釋
依賴關系“我是你兒子”目標文件與源文件的關聯
依賴方法“打錢”生成目標文件的具體命令

這兩者必須同時存在,事情才能辦成!

2.2 偽目標的妙用

.PHONY標記的特殊目標:

.PHONY: clean
clean:rm -f mytest
  • 總是執行清理命令
  • 避免與同名文件沖突
  • 支持make clean獨立執行

2.3 具體語法

a.makefile的基本雛形
mytest: test.cgcc test.c -o mytest.PHONY: clean
clean:rm -f mytest
  • mytest是目標文件,test.c是依賴文件,而有多個依賴文件就是依賴文件列表;

  • mytest:test.c是依賴關系;

  • clean也是目標文件,依賴文件是空的,下面是方法;

    make會自定向下掃描makefile文件,默認形成第一個目標文件

    如果想指定形成,make targetname

  • .PHONY是偽目標,所依賴的方法:總是被執行的!

    1.為什么沒有.PHONY修飾的目標文件,第一次可以編譯,之后就不可以去編譯了?

    • 因為要提高效率。

    2.它是怎么做到的?

    • 首次編譯:目標文件(如可執行文件)不存在,Make工具會直接執行編譯命令生成該文件。

    • 后續編譯:Make工具會比較目標文件和其依賴文件(如源文件)的最后修改時間(Modify Time)

      • 若依賴文件比目標文件新(例如源文件被修改過),則重新編譯。

      • 若目標文件較新或兩者時間相同,則跳過編譯,認為輸出已是最新。

    3.我們要是想再次編譯呢?

    • 手動更新文件時間戳可觸發編譯:

      touch test.c
      make
      
  • makefile的注釋我們用#來注釋;

  •   stat test.c //顯示文件test.c的詳細屬性信息File: ‘test.c’Size: 1024      	Blocks: 8          IO Block: 4096   regular fileDevice: 801h/2049d	Inode: 1234567    Links: 1Access: (0644/-rw-r--r--)  Uid: ( 1000/    your_username)   Gid: ( 1000/    your_groupname)Access: 2024-01-01 12:00:00.000000000 +0800Modify: 2024-01-02 13:00:00.000000000 +0800Change: 2024-01-02 13:00:00.000000000 +0800Birth: -
    

    文件=內容+屬性

    • 改變內容Modify,Access time變化,改變屬性Change time變化。

    如何手動更新時間戳?

    • 修改 atime
      touch -a test.c  # 僅更新 atime
      
    • 修改 mtime
      touch -m test.c  # 僅更新 mtime
      
    • 觸發 ctime 更新
      chmod +x test.c  # 修改權限(必然更新 ctime)
      
b.makefile推導原則!
  • make會進行依賴關系的推導,直到依賴文件是存在的。推導的過程我們類似于一個 將依賴方法不斷入棧,推導完畢,出棧執行方法!
  • 典型處理流程:
需要更新
無需更新
終極目標
檢查依賴
依賴存在?
查找下級依賴
對比時間戳
執行編譯
跳過編譯

三、更加具有通用型的makefile

BIN=mytest
#SRC=$(shell ls *.c)
SRC=$(wildcard *.c)
OBJ=$(SRC:.c=.o)
CC=gcc
RM=rm -f$(BIN):$(OBJ)@$(CC) $^ -o $@@echo "鏈接 $^ 成 $@"
%.o:%.c@$(CC) -c $<@echo "編譯 ... $< 成 $@".PHONY:clean
clean:@$(RM) $(OBJ) $(BIN).PHONY:test
test:@echo $(BIN)@echo $(SRC)@echo $(OBJ)

下面我會逐行詳細解釋這個 Makefile 的每一部分.

1. 變量定義部分

BIN=mytest
#SRC=$(shell ls *.c)
SRC=$(wildcard *.c)
OBJ=$(SRC:.c=.o)
CC=gcc
RM=rm -f
代碼解釋
BIN=mytest定義變量 BIN,表示最終生成的可執行文件名(這里是 mytest)。
#SRC=$(shell ls *.c)注釋掉的代碼:用 ls 命令獲取所有 .c 文件(不推薦,可能有空格問題)。
SRC=$(wildcard *.c)正確做法:使用 wildcard 函數獲取當前目錄下所有 .c 文件列表。
OBJ=$(SRC:.c=.o)SRC 中的 .c 替換為 .o,得到目標文件列表(如 main.cmain.o)。
CC=gcc定義變量 CC,表示使用的編譯器(這里是 gcc)。
RM=rm -f定義變量 RM,表示刪除命令(-f 表示強制刪除,不提示)。

類比:

  • BIN 像是最終產品的名字(比如“汽車”)。
  • SRC 是原材料清單(所有 .c 文件,比如“發動機.c、輪胎.c”)。
  • OBJ 是加工后的零件(.o 文件,比如“發動機.o、輪胎.o”)。

2. 編譯規則部分

$(BIN):$(OBJ)@$(CC) $^ -o $@@echo "鏈接 $^ 成 $@"
代碼解釋
$(BIN):$(OBJ)目標文件 $(BIN) 依賴于所有 .o 文件($(OBJ))。
@$(CC) $^ -o $@$^ 表示所有依賴文件(.o 文件),$@ 表示目標文件($(BIN))。
實際執行:gcc main.o utils.o -o mytest
@echo "鏈接..."打印提示信息(@ 表示不顯示命令本身,只輸出結果)。

關鍵符號:

  • $^:所有依賴文件的集合(比如 main.o utils.o)。
  • $@:當前目標文件名(比如 mytest)。

3. 模式規則(通配規則)

%.o:%.c@$(CC) -c $<@echo "編譯 ... $< 成 $@"
代碼解釋
%.o:%.c模式規則:所有 .o 文件依賴于同名的 .c 文件(如 main.o 依賴 main.c)。
@$(CC) -c $<$< 表示第一個依賴文件(這里是 .c 文件)。
實際執行:gcc -c main.c(生成 main.o)。
@echo "編譯..."打印編譯過程信息。

關鍵符號:

  • $<:當前依賴的第一個文件(比如 main.c)。

4. 偽目標(.PHONY

.PHONY:clean
clean:@$(RM) $(OBJ) $(BIN).PHONY:test
test:@echo $(BIN)@echo $(SRC)@echo $(OBJ)
代碼解釋
.PHONY:clean聲明 clean 是一個偽目標(不生成實際文件,僅執行命令)。
@$(RM) $(OBJ) $(BIN)刪除所有 .o 文件和可執行文件 $(BIN)(實際執行:rm -f main.o mytest)。
.PHONY:test聲明 test 是偽目標,用于調試變量。
@echo $(BIN)...打印變量 BINSRCOBJ 的值(檢查變量是否正確)。

為什么用 .PHONY
如果目錄下恰好有一個名為 clean 的文件,Make 會認為 clean 已是最新而不執行命令。加上 .PHONY 可以強制執行。

5. 完整執行流程示例

假設目錄下有 main.cutils.c

  1. 首次運行 make

    • 根據 %.o:%.c 規則,編譯所有 .c 文件生成 .o 文件:
      gcc -c main.c -o main.o
      gcc -c utils.c -o utils.o
      
    • 根據 $(BIN):$(OBJ) 規則,鏈接 .o 文件生成 mytest
      gcc main.o utils.o -o mytest
      
  2. 運行 make clean

    • 刪除所有 .o 文件和 mytest
      rm -f main.o utils.o mytest
      
  3. 運行 make test

    • 打印變量值(用于調試):
      echo mytest
      echo main.c utils.c
      echo main.o utils.o
      

6. 新手常見問題

  1. 為什么用 wildcard 而不用 ls

    • ls *.c 可能因文件名含空格或特殊字符出錯,wildcard 是 Makefile 內置的安全函數。
  2. $^$< 的區別?

    • $^:所有依賴文件(用于鏈接階段)。
    • $<:第一個依賴文件(用于編譯單個 .c 文件時)。
  3. @ 的作用?

    • 禁止命令回顯(Make 默認會打印執行的命令,@ 讓終端只顯示命令的輸出)。

總結

  • 變量:定義文件名、工具命令等(BIN, SRC, CC)。
  • 規則:指定目標和依賴關系(目標:依賴)。
  • 自動變量$@(目標)、$^(所有依賴)、$<(第一個依賴)。
  • 偽目標.PHONY 聲明非文件目標(如 clean)。

通過這個 Makefile,你可以:

  1. 編譯所有 .c 文件生成可執行文件 mytest
  2. 清理生成的文件(make clean)。
  3. 調試變量值(make test)。

四、高手必備的實用技巧

1.調試 Makefile

$ make -n   # 顯示將要執行的命令
$ make -d   # 顯示詳細調試信息
  • 作用:Makefile 默認會隱藏執行的命令(只顯示結果),可以通過以下方式調試:
    • make -n:僅打印命令但不執行(模擬運行)。
    • make --debug:顯示詳細的執行過程(如依賴檢查、規則匹配)。

2. 常見問題與解決方案

Q1:修改頭文件后 make 不重新編譯?
main.o: main.c header.h  # 顯式聲明頭文件依賴$(CC) -c $< -o $@
  • 問題原因
    Makefile 默認只檢查 .c 文件的修改時間,如果 header.h 被修改但未聲明依賴,不會觸發重新編譯。
  • 解決方案
    在目標規則中顯式列出所有依賴的頭文件(如上例),或通過 gcc -MM 自動生成依賴關系(推薦)。
Q2:如何指定其他名稱的 Makefile?
make -f MyMakefile  # 使用自定義文件名(如 MyMakefile)
  • 適用場景
    項目中有多個構建配置文件(如 MakefileMyMakefile),需指定其中一個執行。
Q3:如何實現跨平臺編譯?
ifeq ($(OS),Windows_NT)  # 判斷是否為 WindowsRM = del /Q         # Windows 刪除命令
elseRM = rm -f          # Linux/macOS 刪除命令
endif
  • 作用
    根據操作系統動態切換命令,避免平臺兼容性問題(如 rm 在 Windows 中不可用)。
  • 擴展:還可用于設置不同的編譯器、路徑分隔符等。

📌 小貼士:優秀的Makefile就像項目說明書,能讓您的代碼更易于維護和協作!

希望這篇指南能幫助您開啟自動化構建之旅!如有疑問,歡迎在評論區交流討論~
在這里插入圖片描述

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

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

相關文章

深度分頁優化思路

深度分頁優化思路 思考以下問題 查詢以下SQL的流程是怎么樣的呢&#xff1f; 為什么只查詢10條數據需要7秒&#xff1f; # 查詢時間7秒 SELECT * FROM user ORDER BY age LIMIT 1000000, 10問題分析 為什么分頁查詢隨著翻頁的深入&#xff0c;會變得越來越慢。 其實&#xff0…

使用 Vite 提升前端開發體驗:入門與配置指南

在現代前端開發中&#xff0c;構建工具的選擇對開發效率和項目性能有著至關重要的影響。Vite 是一個新興的前端構建工具&#xff0c;由 Vue.js 的作者尤雨溪開發&#xff0c;旨在通過利用現代瀏覽器的原生 ES 模塊特性&#xff0c;提供更快的開發服務器啟動速度和更高效的熱更新…

MYSQL基本語法使用

目錄 一、mysql之DML 增加語句 刪除語句和truncate 更新語句 replace語句 select查詢語句 二、select多種用法 查詢時的別名使用 分組 分組后的篩選 結果排序 分頁功能 分表 多表關聯查詢 練習題 一、單表查詢 二、多表查詢 前面已經學習了mysql的安裝和基本語…

自動化測試selenium(Java版)

1.準備工作 1.1.下載瀏覽器 自動化測試首先我們要準備一個瀏覽器,我們這里使用谷歌(chrome)瀏覽器. 1.2.安裝驅動管理 每一個瀏覽器都是靠瀏覽器驅動程序來啟動,但是瀏覽器的版本更新非常快,可能我們今天測試的是一個版本,第二天發布了一個新的版本,那么我們就要重構代碼,很…

HarmonyOS Next應用架構設計與模塊化開發詳解

引言 在HarmonyOS Next開發中&#xff0c;合理的應用架構設計和模塊化開發是構建高效、可維護應用的關鍵。本文將深入探討HarmonyOS Next應用的架構設計思路&#xff0c;并通過實際代碼示例展示如何實現模塊化開發。 應用架構設計 HarmonyOS Next應用通常采用分層架構設計&…

伊利工業旅游4.0,近距離感受高品質的魅力

3月24日&#xff0c;在2025年第112屆全國糖酒會&#xff08;簡稱春糖&#xff09;前夕&#xff0c;伊利集團“可感知高品質探尋薈”活動在成都召開&#xff0c;記者走進伊利在西南地區最大的乳制品生產基地—邛崍工廠&#xff0c;零距離見證液態奶、酸奶、冷飲等乳制品的誕生&a…

測試用例生成平臺通過大模型升級查詢功能,生成智能測試用例

在測試工作中&#xff0c;查詢功能是各類系統的核心模塊&#xff0c;傳統的測試用例編寫往往耗時且重復。如何讓老舊平臺煥發新活力&#xff1f;本文將結合大模型技術&#xff0c;通過用戶輸入的字段信息&#xff0c;自動化生成高效、精準的測試用例。同時&#xff0c;我們還將…

基于javaweb的SpringBoot雪具商城系統設計與實現(源碼+文檔+部署講解)

技術范圍&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬蟲、數據可視化、小程序、安卓app、大數據、物聯網、機器學習等設計與開發。 主要內容&#xff1a;免費功能設計、開題報告、任務書、中期檢查PPT、系統功能實現、代碼編寫、論文編寫和輔導、論…

【AI學習筆記】Coze平臺實現將Excel文檔批量導入數據庫全過程

背景前搖&原視頻教程&#xff1a; 最近看到很多同學都在用Coze平臺操作數據&#xff0c;我也想了解一下工作流的搭建和數據處理過程&#xff0c;但是一下子又看不懂太復雜的邏輯&#xff0c;于是上B站搜索相關的基礎教程。 Coze官方教程&#xff1a; 之前有看過Coze平臺…

【Axure高保真原型】縱向圖片輪播

今天和大家分享縱向圖片輪播的原型模版&#xff0c;載入后會自動循環輪播&#xff0c;鼠標移入圖片后停止輪播&#xff0c;可以通過點擊上下箭頭&#xff0c;向上或向下滑動切換上一張或下一張圖片&#xff0c;也可以點擊右側小圓點快速切換至對應圖片……具體效果可以打開下方…

力扣32.最長有效括號(棧)

32. 最長有效括號 - 力扣&#xff08;LeetCode&#xff09; 代碼區&#xff1a; #include<stack> #include<string> /*最長有效*/ class Solution { public:int longestValidParentheses(string s) {stack<int> st;int ans0;int ns.length();st.push(-1);fo…

如何在 React 項目中使用React.lazy和Suspense實現組件的懶加載?

大白話如何在 React 項目中使用React.lazy和Suspense實現組件的懶加載&#xff1f; 在 React 項目里&#xff0c;有時候組件功能多、體積大&#xff0c;要是一次性把所有組件都加載進來&#xff0c;網頁加載速度就會變慢。而 React 提供了 React.lazy 和 Suspense 這兩個好東西…

ffmpeg-將多個視頻切片成一個新的視頻

使用 ffmpeg 工具可以輕松完成將多個視頻切片合并為一個新的視頻。以下是實現這一目標的具體步驟和命令。 步驟概覽 1、將多個視頻切片。 2、創建文本文件列出切片的視頻片段。 3、使用 ffmpeg 合并這些切片為一個新的視頻。 一&#xff1a;安裝 ffmpeg 確保你的系統中已經安…

【第2月_day10】Pandas數據查看與選擇

以下是專為小白設計的 Pandas數據查看與選擇 學習內容&#xff0c;從基礎到應用逐步講解&#xff0c;附帶清晰示例和注意事項&#xff1a; 一、數據查看&#xff1a;快速了解你的數據 1. head() 和 tail() 作用&#xff1a;查看數據的前幾行或后幾行&#xff0c;默認顯示5行。…

Jetpack LiveData 使用與原理解析

一、引言 在 Android 開發中&#xff0c;數據的變化需要及時反映到界面上是一個常見的需求。然而&#xff0c;傳統的方式可能會導致代碼復雜、難以維護&#xff0c;并且容易出現內存泄漏等問題。Jetpack 組件中的 LiveData 為我們提供了一種優雅的解決方案&#xff0c;它是一種…

Unity2D 五子棋 + Photon聯網雙人對戰

開發環境配置 Unity版本2022.3 創建Photon賬號以及申請Photon中國區服務 官網申請賬號&#xff1a;Multiplayer Game Development Made Easy Photon Engine 中國區服務&#xff1a; 光子引擎photonengine中文站 成都動聯無限科技有限公司(vibrantlink.com) 導入PUN2插件以及…

(UI自動化測試web端)第二篇:元素定位的方法_css定位之屬性選擇器

看代碼里的【find_element_by_css_selector( )】( )里的表達式怎么寫&#xff1f; 文章介紹了第四種寫法屬性選擇器 &#xff0c;你要根據網頁中的實際情況來判斷自己到底要用哪一種方法來進行元素定位。每種方法都要多練習&#xff0c;全都熟了之后你在工作當中使用起來元素定…

預編譯能否 100%防 sql 注入?

&#x1f31f; 什么是 SQL 注入&#xff1f; SQL 注入&#xff08;SQL Injection&#xff09;是指攻擊者利用特殊輸入&#xff0c;讓數據庫執行它本來不應該執行的代碼&#xff0c;從而獲取或篡改數據。 就像在考試的時候偷偷改題目&#xff0c;讓老師改成你想要的內容&#…

第十五章 | Layer2、Rollup 與 ZK 技術實戰解析

&#x1f4da; 第十五章 | Layer2、Rollup 與 ZK 技術實戰解析 ——構建下一代高性能區塊鏈應用&#xff0c;從 Solidity 到 zkSync&#xff01; ? 本章導讀 Layer2 和零知識證明&#xff08;ZK&#xff09;正成為區塊鏈發展的核心方向。 隨著主網 Gas 居高不下、TPS 無法滿…

2025-03-26 學習記錄--C/C++-PTA 6-3 求鏈式表的表長

合抱之木&#xff0c;生于毫末&#xff1b;九層之臺&#xff0c;起于累土&#xff1b;千里之行&#xff0c;始于足下。&#x1f4aa;&#x1f3fb; 一、題目描述 ?? 6-3 求鏈式表的表長 本題要求實現一個函數&#xff0c;求鏈式表的表長。 函數接口定義&#xff1a; &…