【Linux我做主】make和makefile自動化構建

make和makefile自動化構建

  • make和makefile自動化構建
  • github地址
  • 前言
  • 背景介紹
    • 為什么需要make和makefile?
  • make和makefile解析
    • 什么是make和makefile
    • 依賴關系和依賴方法
      • 核心語法結構
      • 簡單演示
        • 編譯
        • 清理
      • 多階段編譯示例
    • make時執行的順序
      • 場景1:clean目標在前(特殊情況)
      • 場景2:總構建目標在前(一般情況)
    • make如何實現不編譯未被修改的文件
      • 場景引入
      • make實現原理
        • stat命令查看文件的屬性
        • 三種時間:
          • 1. Access Time (atime)
          • 2. Modify Time (mtime)
          • 3. Change Time (ctime)
          • **對比總結**
          • **實際應用場景**
          • 文件 = 文件屬性 + 文件內容
        • touch命令會修改相關的時間
      • **操作時間戳的命令**
    • 項目清理
      • 編寫清理規則
      • makefile中的特殊符號
    • 總結make的構建原理
  • 結語

make和makefile自動化構建

github地址

有夢想的電信狗

前言

在Linux環境下開發中,makemakefile是構建復雜項目的核心工具。本文將深入解析其工作原理,并通過實例演示如何編寫高效的自動化構建規則。


背景介紹

為什么需要make和makefile?

回顧我們編譯單個文件時,例如main.c,使用如下命令:

gcc main.c -o main

單個文件,我們如此編譯尚且可以。

但是,當一個項目中有成百上千個源文件時,這樣子手動編譯難免有些不夠優雅。

手動輸入命令容易顯得有些繁瑣,且容易出錯

makemakefile就是為了解決這樣的問題的。

makemakefile的功能和優勢:

  • 大型項目管理:當工程包含數百個源文件時,手動編譯和鏈接效率極低。
  • 自動化編譯:通過定義規則明確編譯順序和依賴關系,make命令可一鍵完成全量構建。
  • 跨平臺協作makefileUnix/Linux世界的通用構建語言,被所有主流IDE支持。

make和makefile解析

什么是make和makefile

  • make是一個命令工具,是一個解釋makefile中指令的命令工具,一般來說,大多數的IDE都有這個命令,比如:DelphimakeVisual C++nmakeLinuxGNUmake。可見,makefile都成為了一種在工程方面的自動化構建方法。

  • makefile是一個文件,是一個按照特定規則編寫的文件,當makefile編寫完成后,make可以識別文件中的內容進行相應的操作。

  • make是一條命令,是一個可執行程序。

  • makefile是一個當前目錄下的文件,和make搭配使用,完成項目自動化構建。其中makefile命名為makefileMakefile均可,首字母M/m不區分大小寫。

依賴關系和依賴方法

核心語法結構

target1: prerequisitesrecipe
target1: prerequisitesrecipe
target1: prerequisitesrecipe
# ......
targetn: prerequisitesrecipe
  1. 目標(Target):要構建的目標

    • 最終產物(可執行文件)或中間產物(.o文件)
    • 支持偽目標(.PHONY target)用于執行操作
    • 示例:.PHONY修飾clean, install等非文件目標
  2. 依賴項(Prerequisites):構建目標所需的依賴文件項

    • 構建目標所需的文件(如.c.o文件)
    • 顯式聲明:直接列出的依賴文件,支持使用通配符*
    • 隱式依賴:通過變量或通配符自動推導
    • 順序敏感:依賴列表的順序影響構建優先級
  3. 配方(Recipe):生成目標所用到的shell命令。

    • 必須以Tab開頭(4空格會導致語法錯誤)
    • 每條命令在獨立shell中執行,每條當前形成當前target所需要的方法,稱為依賴方法。該方法一般是Linux下的命令。
    • 使用@前綴抑制命令回顯

簡單演示

編譯

有以下源程序mycode.c
在這里插入圖片描述
在這里插入圖片描述
輸入以下指令:我們的單個源程序就跑起來了。

make
./mycode

在這里插入圖片描述

可以看到:

  • 我們不需要輸入繁瑣的gcc編譯指令,只需要輸入make就自動可以幫助我們編譯完成。
  • 輸入make的本質還是執行了gcc編譯指令。
清理
  • makefile文件中定義了clean目標的依賴方法時,輸入make clean即可完成程序文件的清理。
    在這里插入圖片描述

多階段編譯示例

有如下makefile
在這里插入圖片描述

  • 依賴鏈mycode.c → mycode.i → mycode.s → mycode.o → mycode
  • 編譯流程:預處理→編譯→匯編→鏈接
    在這里插入圖片描述

make時執行的順序

找到
未找到
make命令
查找Makefile
解析第一個規則
報錯退出
構建依賴樹
執行拓撲排序
遍歷所有節點
需要構建?
執行配方
跳過
更新時間戳
$ make
  1. 從終極目標mycode開始逆向解析
  2. 檢查mycode是否存在或需要更新
  3. 遞歸檢查mycode.smycode.imycode.c的依賴關系
  4. 按依賴鏈順序執行編譯命令

場景1:clean目標在前(特殊情況)

在這里插入圖片描述

場景2:總構建目標在前(一般情況)

在這里插入圖片描述

觀察以上結果,可以看到,只執行make時,卻執行了clean
執行make mycode,又得到了正確的編譯結果。這是為什么呢?

由上我們可以總結歸納出:

  • make后面要跟上構建的target名。
  • make后面什么都不跟時,默認尋找Makefile中第一個target的依賴關系,執行其依賴方法。
  • make targetNamemake后面跟上target的名字時,該命令可以無視makefile中的出現次序,構建指定為targeName的目標文件
  • 建議
    • 建議將要生成的可執行程序作為第一個依賴關系,這樣只輸入make即可完成構建
    • 建議將clean放在最后,防止他人的誤操作。

make如何實現不編譯未被修改的文件

場景引入

觀察一下場景:

  • 我們在make一次之后,如果沒有對源文件進行修改,就無法再次make了。
    在這里插入圖片描述
    在這里插入圖片描述
    這是因為沒有必要
  • 如果源文件沒有被修改,再次編譯得到的結果還是一樣的。
  • make設計出這樣的功能,是為了提高編譯效率節省編譯的時間開銷

那么,以上功能是如何實現的呢?

make實現原理

可以思考下,如果讓我們自己實現這樣的功能,我們的思路會是怎么樣的?

思路大致如下:

  • 通常情況下,我們一定是由源文件編譯形成可執行文件。先有源文件,才會有可執行文件

  • 因此,一般而言(不通過命令改變文件的修改時間),源文件的最近修改時間,一定比可執行文件的最近修改時間要更老!!!

  • 因此,只需要比較可執行程序的最近修改時間和源文件的最近修改時間即可。

    • (此處用.exe代替可執行程序,Linux下是編譯形成的有可執行權限的文件)

    • 最近修改時間,.exe新于.c,說明源文件時老的,不需要重新編譯

    • 最近修改時間,.exe老于.c,說明源文件時新的,需要重新編譯

    • 而一般而言,.exe.c的最近修改時間是不會一樣的,除非通過命令來統一修改。

  • 因此,如果我們更改了源文件,歷史上曾經還有可執行文件,那么源文件的最近修改時間,一定比可執行程序要新!

而文件的最近修改時間屬于文件屬性的一部分。

stat命令查看文件的屬性

在這里插入圖片描述

**我們今天先只關注文件屬性中的時間,其他的屬性暫不展開敘述。**以下是簡介:

Linux/Unix 文件系統中,每個文件都有三個與時間相關的重要屬性,可以通過 stat 命令查看。以下是它們的詳細解釋:


三種時間:
1. Access Time (atime)

? 定義:文件最后一次被 訪問(讀取)的時間
? 觸發場景
? 用 catless 查看文件內容
? 用 grep 搜索文件內容
? 程序讀取文件(如腳本執行、軟件加載配置文件)
? 例外:如果使用 mount -o noatime 掛載文件系統,訪問時間不會更新(提高性能)


2. Modify Time (mtime)

? 定義文件內容最后一次被 修改 的時間
? 觸發場景
? 用編輯器修改文件內容
? 重定向輸出到文件(如 echo "text" > file
? 文件被程序寫入新數據
? 注意:修改文件內容會同時更新 change time(見下文)

示例

echo "new content" > myfile.txt  # 修改時間和change time均更新

3. Change Time (ctime)

? 定義:文件 元數據(metadata)(屬性)最后一次被修改的時間
? 觸發場景
? 修改文件權限(chmod
? 修改文件所有者(chown
? 創建硬鏈接
? 重命名文件
? 修改文件內容(因為文件大小等元數據變化)
? 注意ctime 不可通過 touch 直接修改,只能通過元數據操作間接更新

示例

chmod 644 myfile.txt  # change time更新

對比總結
時間類型簡稱觸發操作查看命令
Accessatime讀取文件內容stat -c %x filename
Modifymtime修改文件內容stat -c %y filename
Changectime修改文件屬性stat -c %z filename

實際應用場景
  1. 備份系統:通過 mtime 判斷文件內容是否變化,決定是否需要備份。
  2. 日志分析:通過 atime 追蹤可疑的文件訪問記錄。
  3. 調試問題:用 ctime 確認文件權限或所有權是否被意外修改。
  4. 恢復文件:結合三個時間戳分析文件歷史操作。

文件 = 文件屬性 + 文件內容

我們之前提到過,文件 = 文件屬性 + 文件內容,由上可以總結為:

  • 修改文件內容后,Modify時間會改變
  • 修改文件屬性后,Change時間會改變
  • 一項操作可能同時改變三種時間中的多個

三種時間,可以用acm來簡化記憶。

touch命令會修改相關的時間

在這里插入圖片描述


  • touch會修改文件屬性,修改后make便可再次編譯
  • make通過比較源文件和可執行文件最近修改時間的新舊來判定要不要進行編譯
  • 比較時將屬性中的時間轉化為Linux時間戳進行比較

在這里插入圖片描述


操作時間戳的命令

? 查看時間戳

stat filename	# 查看文件的屬性,屬性中包含有時間,filename代表系統中文件的名字

? 修改時間戳

touch -a filename  # 僅修改atime  即為Access時間
touch -m filename  # 僅修改mtime  即為Modify時間
touch -t 202301010000 filename  # 指定時間(格式:[[CC]YY]MMDDhhmm[.ss])

  • 高級知識

? relatime:現代 Linux 默認使用 relatime(僅當 atimemtimectime 舊時才更新,平衡性能與準確性)
? ext4 的納秒精度ext4 文件系統支持時間戳的納秒級記錄

  • 注意:touch命令可通過-a ``-m選項單獨修改一個文件的Access時間和Modify,但無法單獨修改文件的change時間
  • touch filename指令:無參數的 touch 命令會修改文件的三個時間。

項目清理

編寫清理規則

  • 實際上makefile的清理命令make clean我們已經一直在使用了。
    在這里插入圖片描述
.PHONY: clean
clean:rm -f mycode
  • clean是我們的targetrm -f mycode是目標的依賴方法,clean的依賴方法也可以是其他的命令。

前文我們提到,make通過比較源文件和可執行文件最近修改時間的新舊來判定要不要進行編譯,但如果我就是想讓一個target在每次make時都重新進行編譯,該怎么辦呢?這便是.PHONY的作用。

  • .PHONY聲明偽目標,避免與同名文件沖突
  • 強制執行:無論是否存在clean文件,make clean都會執行
  • .PHONY修飾的目標文件,只要輸入make,總是會被執行
    在這里插入圖片描述
  • 實際上不建議用.PHONY修飾總的目標文件,簡直用.PHONY修飾clean

makefile中的特殊符號

makefile中有很多特殊符號,本文只介紹三種特殊符號:@ $^ $@

  • @:@用于修飾依賴方法,使make之后,執行的命令不在終端中回顯。
  • $^ $@ 常用在依賴方法中:
    • $@用來表示依賴關系冒號左邊的內容。
    • $^用來表示依賴關系冒號右邊邊的內容。

在這里插入圖片描述


總結make的構建原理

  1. 查找Makefile:優先讀取Makefilemakefile
  2. 確定終極目標:解析第一個目標(示例中的hello
  3. 依賴樹分析:遞歸檢查所有依賴項是否存在
  4. 時間戳比對:若依賴文件比目標文件新,則觸發重新編譯
  5. 增量構建:僅重新編譯修改過的文件及其依賴鏈

結語

通過合理設計makefile,開發者可以:

  1. 實現一鍵式編譯,提升開發效率
  2. 利用增量編譯節省構建時間
  3. 規范項目的構建和清理流程

如果本文對你有幫助,歡迎點贊收藏,技術問題歡迎在評論區交流!
一鍵三連,好運連連!

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

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

相關文章

Qt 入門 5 之其他窗口部件

Qt 入門 5 之其他窗口部件 本文介紹的窗口部件直接或間接繼承自 QWidget 類詳細介紹其他部件的功能與使用方法 1. QFrame 類 QFrame類是帶有邊框的部件的基類。它的子類包括最常用的標簽部件QLabel另外還有 QLCDNumber、QSplitter,QStackedWidget,QToolBox 和 QAbstractScrol…

JAVA學習-多線程

線程 線程(Thread)是一個程序內部的一條執行流程。 程序中如果只有一條執行流程,那這個程序就是單線程的程序。 線程的常用方法及構造器: Thread提供的常用方法public void run() 線程的任務方法public void start() 啟動線程public String getName() …

Github 2025-04-19Rust開源項目日報 Top10

根據Github Trendings的統計,今日(2025-04-19統計)共有10個項目上榜。根據開發語言中項目的數量,匯總情況如下: 開發語言項目數量Rust項目10Python項目1Rust: 構建可靠高效軟件的開源項目 創建周期:5064 天開發語言:Rust協議類型:OtherStar數量:92978 個Fork數量:12000…

OpenLayers:視圖變換的方法

一、什么是視圖變換? 視圖變換就是指視圖的 extent(范圍)、center(中心點)、zoom(縮放級別)、 resolution(分辨率)、rotation(旋轉角)等參數發生…

數字孿生火星探測車,星際探索可視化

運用圖撲構建數字孿生火星探測車,高精度還原外觀與內部構造。實時映射探測車在火星表面的移動、探測作業及設備狀態,助力科研人員遠程監測、分析數據,為火星探索任務提供可視化決策支持。

【NLP 66、實踐 ? 基于Agent + Prompt Engineering文章閱讀】

你用什么擦干我的眼淚 莎士比亞全集 工業紙巾 還是你同樣泛紅的眼睛 —— 4.19 一、?【核心函數】定義大模型調用函數 call_large_model prompt:用戶傳入的提示詞(如 “請分析這篇作文的主題”),指導模型執行任務 client&…

黑馬Java基礎筆記-1

JVM,JDK和JRE JDK是java的開發環境 JVM虛擬機:Java程序運行的地方 核心類庫:Java已經寫好的東西,我們可以直接用。 System.out.print中的這些方法就是核心庫中的所包含的 開發工具: javac(編譯工具)、java&…

PR第一課

目錄 1.新建 2.PR內部設置 3.導入素材 4.關于素材窗口 5.關于編輯窗口 6.序列的創建 7.視頻、圖片、音樂 7.1 帶有透明通道的素材 8.導出作品 8.1 打開方法 8.2 導出時,需要修改的參數 1.新建 2.PR內部設置 隨意點開 編輯->首選項 中的任意內容&a…

Xcode16 調整 Provisioning Profiles 目錄導致證書查不到

cronet demo 使用的 ninja 打包,查找 Provisioning Profiles 路徑是 ~/Library/MobileDevice/Provisioning Profiles,但 Xcode16 把該路徑改為了 ~/Library/Developer/Xcode/UserData/Provisioning Profiles,導致在編譯 cronet 的demo 時找不…

【更新完畢】2025華中杯C題數學建模網絡挑戰賽思路代碼文章教學數學建模思路:就業狀態分析與預測

完整內容請看文末最后的推廣群 先展示文章和代碼、再給出四個問題詳細的模型 基于多模型下的就業狀態研究 摘要 隨著全球經濟一體化和信息技術的迅猛發展,失業問題和就業市場的匹配性問題愈加突出。為了解決這一問題,本文提出了一種基于統計學習和機器學…

[HOT 100] 1964. 找出到每個位置為止最長的有效障礙賽跑路線

文章目錄 1. 題目鏈接2. 題目描述3. 題目示例4. 解題思路5. 題解代碼6. 復雜度分析 1. 題目鏈接 1964. 找出到每個位置為止最長的有效障礙賽跑路線 - 力扣(LeetCode) 2. 題目描述 你打算構建一些障礙賽跑路線。給你一個 下標從 0 開始 的整數數組 obst…

2025年KBS SCI1區TOP:增強天鷹算法EBAO,深度解析+性能實測

目錄 1.摘要2.天鷹算法AO原理3.改進策略4.結果展示5.參考文獻6.代碼獲取 1.摘要 本文提出了增強二進制天鷹算法(EBAO),針對無線傳感器網絡(WSNs)中的入侵檢測系統(IDSs)。由于WSNs的特點是規模…

JavaScript數據類型簡介

在JavaScript中,理解不同的數據類型是掌握這門語言的基礎。數據類型決定了變量可以存儲什么樣的值以及這些值能夠執行的操作。JavaScript支持多種數據類型,每種都有其特定的用途和特點。本文將詳細介紹JavaScript中的主要數據類型,并提供一些…

性能比拼: Elixir vs Go(第二輪)

本內容是對知名性能評測博主 Anton Putra Elixir vs Go (Golang) Performance Benchmark (Round 2) 內容的翻譯與整理, 有適當刪減, 相關指標和結論以原作為準 這是第二輪關于 Elixir 和 Go 的對比測試。我收到了一份來自 Elixir 創作者的 Pull Request ,并且我認為…

接口自動化 ——fixture allure

一.參數化實現數據驅動 上一篇介紹了參數化,這篇 說說用參數化實現數據驅動。在有很多測試用例的時候,可以將測試用例都存儲在文件里,進行讀寫調用。本篇主要介紹 csv 文件和 json 文件。 1.讀取 csv 文件數據 首先創建 csv 文件&#xff…

`peft`(Parameter-Efficient Fine-Tuning:高效微調)是什么

peft(Parameter-Efficient Fine-Tuning:高效微調)是什么 peft庫是Hugging Face推出的用于高效參數微調的庫,它能在不調整模型全部參數的情況下,以較少的可訓練參數對預訓練模型進行微調,從而顯著降低計算資源需求和微調成本。以下從核心功能、優勢、常見微調方法、使用場…

編程常見錯誤歸類

上一篇講了調試&#xff0c;今天通過一個舉例回憶一下上一篇內容吧&#xff01; 1. 回顧&#xff1a;調試舉例 在VS2022、X86、Debug的環境下&#xff0c;編譯器不做任何優化的話&#xff0c;下?代碼執?的結果是啥&#xff1f; #include <stdio.h> int main() {int …

在windows上交叉編譯opencv供RK3588使用

環境 NDK r27、RK3588 安卓板子、Android 12 步驟操作要點1. NDK 下載選擇 r27 版本&#xff0c;解壓到無空格路徑&#xff08;如 C:/ndk&#xff09;2. 環境變量配置添加 ANDROID_NDK_ROOT 和工具鏈路徑到系統 PATH3. CMake 參數調整指定 ANDROID_NATIVE_API_LEVEL31、ANDRO…

淺析MySQL事務鎖

在 MySQL 中,事務鎖是用于確保數據一致性和并發控制的重要機制。事務鎖可以幫助防止多個事務同時修改同一數據,從而避免數據不一致和臟讀、不可重復讀、幻讀等問題。 以下是 MySQL 事務鎖的關鍵點總結: 事務鎖:用于確保數據一致性和并發控制。鎖的類型: 行級鎖:InnoDB,粒…

vue3 文件下載(excel/rar/zip)

安裝axios npm install axios 在項目中引入 import axios from axios; 1、get接口excel文件下載 const file_key ref() const downLoadExcel (value:any) > {//file_key.value value axios({method: "get",url: "/api/da/download_excel/",//url:…