簡介make命令和makefile文件

来源:https://www.cnblogs.com/tongye/archive/2018/11/11/9921654.html
-Advertisement-
Play Games

一、為什麼要用到 make 命令和 makefile 文件 在 Linux 下編寫一個程式,每次編譯都需要在命令行一行一行的敲命令。如果是一個很小的程式還好說,命令不怎的複雜,編譯速度也挺快,但是對於大型程式來說,這樣無疑很麻煩,且不說可能會敲錯命令,有時候僅僅改動了一個小地方,卻需要將整個程式全部 ...


一、為什麼要用到 make 命令和 makefile 文件

  在 Linux 下編寫一個程式,每次編譯都需要在命令行一行一行的敲命令。如果是一個很小的程式還好說,命令不怎的複雜,編譯速度也挺快,但是對於大型程式來說,這樣無疑很麻煩,且不說可能會敲錯命令,有時候僅僅改動了一個小地方,卻需要將整個程式全部重新編譯一遍,顯然很浪費時間。Linux 提供了 make 命令來解決上述問題,它會在必要時重新編譯所有受改動影響的源文件。同時,還提供了一個 makefile 文件,它告訴 make 命令如何構建應用程式。這裡用一個簡單的例子提前演示一下:

/* hello.c */
#include <unistd.h> #include <stdio.h> #include <stdlib.h> int main() { printf("hello world!\n"); exit(0); }
/* Makefile */
hello: hello.c gcc
-o hello.s -S hello.c gcc -o hello.o -c hello.s gcc -o hello hello.o clean: -rm hello hello.s hello.o

  這裡提供了兩段代碼,第一段代碼是一個簡單的 HelloWorld 程式,第二段代碼是為這個程式編寫的一個 makefile 文件。此時,只需要在命令行輸入 make 命令,就可以對源文件 hello.c 進行編譯,如下:

  執行 make 命令時,make 命令會讀取 makefile 文件,並按照 makefile 文件中給出的命令來創建文件,同時會在執行時將命令列印到標準輸出。執行完 make 命令後,源文件所在目錄下多了三個文件:hello、hello.o 和 hello.s,其中 hello 是可執行文件,使用命令 ./hello 即可查看程式的輸出結果。這和直接在命令行使用 gcc 命令所得到的結果是一樣的,而且,當你修改了源文件時,也只需要再次使用 make 命令即可重新編譯,十分方便。 

 

二、make 命令

  make 命令用於從一個名為 makefile 的文件中獲得構建一個程式的依賴關係。make 命令會根據 makefile 文件來確定目標文件的創建順序以及正確的規則調用順序。

make 命令的一些常用參數

1)-k 參數:

  使用 -k 參數可以讓 make 命令在發現錯誤時仍然繼續執行,而不是在檢測到第一個錯誤時就停下來。利用這個選項可以在一次操作中發現所有未編譯成功的源文件;

2)-n 參數:

   使用 -n 參數,讓 make 命令輸出將要執行的操作步驟,而不是真正執行這些操作;

3)-f 參數:

  使用 -f 參數,後面可以接一個文件名,用於指定一個文件作為 makefile 文件。如果沒有使用 -f 選項,則 make 命令會在當前目錄下查找名為 makefile 的文件,如果該文件不存在,則查找名為 Makefile 的文件。 

 

三、makefile 文件

  makefile 文件由一組依賴關係規則構成。每個依賴關係都由一個目標(即將要創建的文件)和一個該目標所依賴的源文件組成;規則描述瞭如何通過這些依賴文件創建目標。簡單的來說,makefile 文件的寫法如下:

target: prerequisites
    command1
    command2
    ...

  其中,target 是即將要創建的目標(通常是一個可執行文件),target 後面緊跟一個冒號,prerequisite 是生成該目標所需要的源文件(依賴),一個目標所依賴的文件可以有多個,依賴文件與目標之間以及各依賴文件之間用空格或製表符 Tab 隔開,這些元素組成了一個依賴關係。隨後的命令 command 就是規則,也就是 make 需要執行的命令,它可以是任意的 shell 命令。另外,makefile 文件中,註釋以 # 號開頭,一直延續到該行的結束

3.1 依賴關係

  依賴關係定義了最終應用程式里的每個文件與源文件之間的關係。一個依賴關係列表由目標和該目標的零個或多個依賴組成,語法是:先寫目標,然後接一個冒號,再用一個空格或製表符隔開,最後是用空格或製表符隔開的依賴文件列表,如下:

target: prerequisite1 prerequisite2 prerequisite3 ...

  依賴關係表明瞭這樣一件事:目標文件 target 依賴於文件 prerequisite1、prerequisite2、prerequisite3 ...,即,要生成 target,需要有這幾個依賴文件的存在,而且,若其中一個依賴文件發生了改變,則需要重新生成 target。目標所依賴的文件可以有一個或多個,也可以沒有依賴文件 —— 該目標總被認為是過時的,在執行 make 命令時,若指定了該目標,則該目標所對應的規則將總被執行(如目標 clean)。

  makefile 文件中可以有很多個目標,每個目標都有自己對應的規則。make 命令預設創建的是 makefile 文件中的第一個目標。也可以自己指定一個目標讓 make 命令去創建,只需要將該目標的名字作為參數放到 make 命令之後即可(如常用的 make clean)。實際上,更好的做法是,將 makefile 文件中的第一個目標定義為 all,然後再 all 後面列出其他從屬目標,這將告訴 make 命令,在未指定特定目標時,預設情況下將創建哪個目標。此外,使用目標 all ,還可以使 make 命令一次性創建多個文件,這取決於 all 後面所接的從屬目標的個數。

  舉個例子說明一下文件與文件之間的依賴關係:

/* sum.c */
#include <stdio.h>
#include <stdlib.h>

extern int add(int i,int j);

int main()
{
  printf("%d\n",add(1,2));
  exit(0);
}

/* add.c */
#include <stdio.h>

int add(int i,int j)
{
  int k;
  k = i + j;
  return k;
}

  這是一個簡單的加法程式,包含兩個文件:sum.c 和 add.c,其中,sum.c 中的 main 函數調用了 add.c 中的 add 函數。這個程式的依賴關係表如下:

sum: sum.o add.o
sum.o: sum.c stdio.h stdlib.h
add.o: add.c stdio.h

  其中,最終所需要的目標文件是 sum,sum.o 和 add.o 是依賴 —— 要生成目標文件 sum ,需要先生成 sum.o 和 add.o。同樣的,作為目標的 sum.o 依賴於 sum.c、stdio.h 和 stdlib.h;add.o 依賴於 add.c 和 stdio.h。這組依賴關係形成了一個層次結構,它顯示了源文件之間的關係。

  可以看出來,如果 add.c 發生了改變,那麼就需要重新編譯 add.o,而由於 add.o 發生了改變,目標文件 sum 也需要被重新創建,同時,由於 add.c 的改變並沒有影響到 sum.o(sum.o 不依賴於 add.c),因此,sum.o 並不需要被重新編譯。也就是說,通過使用 makefile 文件和 make 命令,我們可以實現,只重新編譯所有受到改動影響的源文件,沒有受到影響的源文件不必重新編譯。這比把整個程式全部重新編譯一遍顯然要快上很多,尤其是對於大型程式。

 

3.2 規則 

  makefile 文件里另一部分內容是規則,它們定義了目標的創建方式。 規則的內容可以是任意的 shell 命令。關於規則,有以下兩點需要註意:

1)規則所在行必須以製表符 tab 開頭,不能用空格

2)規則所在行最好不要以空格結尾,可能會導致 make 命令執行失敗;

3)如果一行不足以寫下所有內容,需要在每行代碼的結尾加上一個反斜杠符 “\”,以讓所有的命令在邏輯上處於同一行。

兩個特殊字元 - 和 @:

  1)在規則中,若命令之前加上了符號 “-”,則表明 make 命令將忽略該命令產生的所有錯誤;

  2)若在命令之前加上了符號“@”,則表明 make 在執行該命令前,不會將該命令顯示在標準輸出上。

/* Makefile */
all: sum sum: sum.o add.o gcc
-o sum add.o sum.o sum.o: sum.c gcc -c sum.c add.o: add.c gcc -c add.c
clean:
-rm sum sum.o add.o

  這是 3.1 中 sum.c 程式的 makefile 文件。其中 gcc 、rm 命令等行就是規則,它們告訴了 make 命令將如何去創建目標。

兩個特殊的目標:clean 和 install 

  目標 clean 和 install 是兩個特殊的目標,它們並不用於創建文件,而是有其他用途。

  目標 clean 在前面已經提到過,它使用 rm 命令來刪除目標文件。rm 命令通常以減號 - 開頭,表示讓 make 命令忽略該命令的執行結果,這意味著,即使由於文件不存在而導致 rm 命令返回錯誤,命令 make clean 也能成功執行。

  目標 install 用於按照命令的執行順序將應用程式安裝到指定的目錄,還是用上面的 sum.c 程式來演示一下目標 install 的用法:

all: sum

# 安裝目錄
INSTDIR = /tmp

sum: sum.o add.o
    gcc -o sum add.o sum.o
sum.o: sum.c
    gcc -c sum.c
add.o: add.c
    gcc -c add.c
clean:
    rm sum sum.o add.o

install: sum
    @if [ -d $(INSTDIR) ];\
    then\
            cp sum $(INSTDIR);\
            chmod a+x $(INSTDIR)/sum;\
            chmod og-w $(INSTDIR)/sum;\
            echo "Installed in $(INSTDIR)";\
    else\
            echo "The directory $(INSTDIR) dose not exist!";\
    fi

  使用這個 makefile 文件,make 命令將會把 sum 安裝到目錄 /tmp 下(實際上,應用程式一般是安裝在 /usr/local/bin 下的,這裡為了方便就放到 /tmp 下了) 。執行 make install 命令,將得到如下結果:

  輸出結果顯示 sum 已被成功安裝到了 /tmp 目錄下(實際上就是把可執行文件 sum 複製到 /tmp 目錄下)。再進入 /tmp 目錄查看,可以看到可執行文件 sum,其文件許可權是 rwxr-xr-x,與 makefile 文件中所設置的一致。

 

3.3 makefile 文件中的巨集 

  在 makefile 文件中定義一個巨集很簡單,如下:

MACRONAME=value

  這裡定義了一個巨集 MACRONAME,引用巨集的方法是使用 $(MACRONAME) 或 ${MACRONAME} 。使用巨集定義,可以讓 makefile 文件的可移植性更強。除了自己定義一些巨集以外,make 命令還內置了一些特殊的巨集定義,使得 makefile 文件變得更加簡潔:

         巨集           說明
$? 當前目標所依賴的文件列表中比當前目標文件還要新的文件
$@ 當前目標的名字
$< 當前依賴文件的名字
$* 不包括尾碼名的當前依賴文件的名字

  除了在 makefile 文件裡面定義巨集以外,還可以調用 make 命令時,在命令行上給出巨集定義。命令行上的巨集定義將 覆蓋在 makefile 文件中的巨集定義。需要註意的是,在 make 命令後接巨集定義時,巨集定義必須以單個參數的形式傳遞,因此,需要避免在巨集定義中使用空格或加引號。 

 

參考資料:

《Linux 程式設計 第四版》

 https://www.ibm.com/support/knowledgecenter/zh/ssw_aix_71/com.ibm.aix.cmds3/make.htm


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 第一章 第一個C#程式 ******************C#程式*************** ①:建立項目:文件-->新建-->項目-->c#-->控制台程式(項目名/文件存儲位置)-->確定 ①:c#程式 namespace:命名空間; 相當於java中的package(聲明包) using ...
  • 三大框架房很好看絕代風華搜狗科技華東師範撒的發空間撒地方是否 ...
  • 註意:本文背景為 Linq to sql 。文中ie指代IEnumerable,iq指代IQueryable。 IQueryable 和 IEnumerable 的區別 IQueryable延時執行;擴展方法接受的是Expression(必須要能轉成sql,否則報錯) IEnumerable延時執行 ...
  • 在.NET Core框架中使用NLog組件記錄日誌,寫資料庫,寫文件!!! ...
  • " 【.NET Core項目實戰 統一認證平臺】開篇及目錄索引 " 這篇文章,我們將從Ocelot的中間件源碼分析,目前Ocelot已經實現那些功能,還有那些功能在我們實際項目中暫時還未實現,如果我們要使用這些功能,應該如何改造等方面來說明。 一、Ocelot源碼解讀 在使用一個組件前,最好我們要了 ...
  • [TOC] 算術運算符     在任何一門形式的語言中均會存在算術運算的情況,Shell常見的運算符如下所示: | 運算符 | 含義 | | | | | + \ / % | 加 減 乘 除 求餘 | | \ \ | 冪運算 | | ++ | 自增 自減 | | && & 124; ...
  • Linux 學習-電腦基礎 一、描述電腦的組成及其功能。 電腦系統是由硬體(Hardware)和軟體(Software )兩部分組成。 硬體: 從硬體基本結構上來講,電腦是由運算器、控制器、存儲器、輸入設備、輸出設備五大部分組成的,每一部分分別按要求執行特定的基本功能。 1、運算器(算數邏輯 ...
  • 關閉觸摸 關閉觸摸和按鍵 打開 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...