1. 程式人生 > >linux中的make命令解釋集錦

linux中的make命令解釋集錦

無論是在Linux還是在Unix環境中,make都是一個非常重要的編譯命令。不管是自己進行專案開發還是安裝應用軟體,我們都經常要用到make或make install。利用make工具,我們可以將大型的開發專案分解成為多個更易於管理的模組,對於一個包括幾百個原始檔的應用程式,使用make和 makefile工具就可以簡潔明快地理順各個原始檔之間紛繁複雜的相互關係。而且如此多的原始檔,如果每次都要鍵入gcc命令進行編譯的話,那對程式設計師來說簡直就是一場災難。

    而make工具則可自動完成編譯工作,並且可以只對程式設計師在上次編譯後修改過的部分進行編譯。因此,有效的利用make和 makefile工具

可以大大提高專案開發的效率。同時掌握make和makefile之後,您也不會再面對著Linux下的應用軟體手足無措了。
  但令人遺憾的是,在許多講述Linux應用的書籍上都沒有詳細介紹這個功能強大但又非常複雜的編譯工具。在這裡我就向大家詳細介紹一下make及其描述檔案makefile
Makefile檔案
  

    Make工具最主要也是最基本的功能就是通過makefile檔案來描述源程式之間的相互關係並自動維護編譯工作。而makefile 檔案需要按照某種語法進行編寫,檔案中需要說明如何編譯各個原始檔並連線生成可執行檔案,並要求定義原始檔之間的依賴關係makefile 檔案是許多編譯器--包括 Windows NT 下的編譯器--維護編譯資訊的常用方法,只是在整合開發環境中,使用者通過友好的介面修改 makefile 檔案而已。
  在 UNIX 系統中,習慣使用 Makefile 作為 makfile 檔案

。如果要使用其他檔案作為 makefile,則可利用類似下面的 make 命令選項指定 makefile 檔案
  $ make -f Makefile.debug
  例如,一個名為prog的程式由三個C原始檔filea.c、fileb.c和filec.c以及庫檔案LS編譯生成,這三個檔案還分別包含自己的標頭檔案a.h 、b.h和c.h。通常情況下,C編譯器將會輸出三個目標檔案filea.o、fileb.o和filec.o。假設filea.c和fileb.c都要宣告用到一個名為defs的檔案,但filec.c不用。即在filea.c和fileb.c裡都有這樣的宣告:
  #include "defs"
  那麼下面的文件就描述了這些檔案之間的相互聯絡:
  ---------------------------------------------------------
   #It is a example for describing makefile
   prog : filea.o fileb.o filec.o

   cc filea.o fileb.o filec.o -LS -o prog
   filea.o : filea.c a.h defs
   cc -c filea.c
   fileb.o : fileb.c b.h defs
   cc -c fileb.c
   filec.o : filec.c c.h
   cc -c filec.c
  ----------------------------------------------------------
  這個描述文件就是一個簡單的makefile檔案
  從上面的例子注意到,第一個字元為 # 的行為註釋行。第一個非註釋行指定prog由三個目標檔案filea.o、fileb.o和filec.o連結生成。第三行描述瞭如何從prog所依賴的檔案建立可執行檔案。接下來的4、6、8行分別指定三個目標檔案,以及它們所依賴的.c和.h檔案以及defs檔案。而5、7、9行則指定了如何從目標所依賴的檔案建立目標。

 
  當filea.c或a.h檔案在編譯之後又被修改,則 make 工具可自動重新編譯filea.o,如果在前後兩次編譯之間,filea.C 和a.h 均沒有被修改,而且 test.o 還存在的話,就沒有必要重新編譯。這種依賴關係在多原始檔的程式編譯中尤其重要。通過這種依賴關係的定義,make 工具可避免許多不必要的編譯工作。當然,利用 Shell 指令碼也可以達到自動編譯的效果,但是,Shell 指令碼將全部編譯任何原始檔,包括那些不必要重新編譯的原始檔,而 make 工具則可根據目標上一次編譯的時間和目標所依賴的原始檔的更新時間而自動判斷應當編譯哪個原始檔
Makefile檔案作為一種描述文件一般需要包含以下內容:
  ◆ 巨集定義
  ◆ 原始檔之間的相互依賴關係
  ◆ 可執行的命令
  Makefile中允許使用簡單的巨集指代原始檔及其相關編譯資訊,在Linux中也稱巨集為變數。在引用巨集時只需在變數前加$符號,但值得注意的是,如果變數名的長度超過一個字元,在引用時就必須加圓括號()。
  下面都是有效的巨集引用:
  $(CFLAGS)
  $2
  $Z
  $(Z)
  其中最後兩個引用是完全一致的
  需要注意的是一些巨集的預定義變數,在Unix系統中,$*、[email protected]、$?和$1zap
   /usr/bin/make -dp | grep -v TIME>2zap
   diff 1zap 2zap
   rm 1zap 2zap

   lint: dosys.c donamc.c file.c main.c misc.c version.c gram.c
   $(LINT) dosys.c donamc.c file.c main.c misc.c version.c
   gram.c
   rm gram.c
   arch:
   ar uv /sys/source/s2/make.a $(FILES)
  ----------------------------------------------------------
  通常在描述檔案中應象上面一樣定義要求輸出將要執行的命令。在執行了make命令之後,輸出結果為:
  $ make
  cc -c version.c
  cc -c main.c
  cc -c donamc.c
  cc -c misc.c
  cc -c file.c
  cc -c dosys.c
  yacc gram.y
  mv y.tab.c gram.c
  cc -c gram.c
  cc version.o main.o donamc.o misc.o file.o dosys.o gram.o
  -LS -o make
  13188+3348+3044=19580b=046174b
  最後的數字資訊是執行"@size make"命令的輸出結果。之所以只有輸出結果而沒有相應的命令列,是因為"@size make"命令以"@"起始,這個符號禁止列印輸出它所在的命令列。

 
  描述檔案中的最後幾條命令列
在維護編譯資訊方面非常有用。其中"print"命令列的作用是列印輸出在執行過上次"make print"命令後所有改動過的檔名稱。系統使用一個名為print的0位元組檔案來確定執行print命令的具體時間而巨集$?則指向那些在print 檔案改動過之後進行修改的檔案的檔名。如果想要指定執行print命令後,將輸出結果送入某個指定的檔案,那麼就可修改P的巨集定義:
  

    make print "P= cat>zap"


  在Linux中大多數軟體提供的是原始碼,而不是現成的可執行檔案,這就要求使用者根據自己系統的實際情況和自身的需要來配置、編譯源程式後,軟體才能使用。只有掌握了make工具,才能讓我們真正享受到到Linux這個自由軟體世界的帶給我們無窮樂趣。
==========================================
Makefile 初探
==========================================
    Linux 的核心配置檔案有兩個,一個是隱含的.config檔案,嵌入到主Makefile中;另一個是include/linux/autoconf.h,嵌入到各個c原始檔中,它們由make config、make menuconfig、make xconfig這些過程建立

    幾乎所有原始檔都會通過linux/config.h而嵌入autoconf.h,如果按照通常方法建立檔案依賴關係 (.depend),只要更新過autoconf.h,就會造成所有原始碼的重新編繹。
為了優化make過程,減少不必要的重新編繹,Linux開發了專用的mkdep工具,用它來取代gcc來生成.depend檔案。mkdep在處理原始檔時,忽略linux/config.h這樣的標頭檔案,識別原始檔巨集指令中具有"CONFIG_"特徵的行。例如,如果有"#ifdef CONFIG_SMP"這樣的行,它就會在.depend檔案中輸出$(wildcard /usr/src/linux/include/config/smp.h)。
    include/config/下的檔案是另一個工具 split-include從autoconf.h中生成,它利用autoconf.h中的CONFIG_標記,生成與mkdep相對應的檔案。例如,如果autoconf.h中有"#undef CONFIG_SMP"這一行,它就生成include/config/smp.h檔案,內容為"#undef CONFIG_SMP"。這些檔名只在.depend檔案中出現,核心原始檔是不會嵌入它們的。每配置一次核心,執行split-include一次。 split-include會檢查舊的子檔案的內容,確定是不是要更新它們。這樣,不管autoconf.h修改日期如何,只要其配置不變,make就不會重新編繹核心。
如果系統的編繹選項發生了變化,Linux也能進行增量編繹。為了做到這一點,make每編繹一個原始檔時生成一個 flags檔案。例如編繹sched.c時,會在相同的目錄下生成隱含的.sched.o.flags檔案。它是Makefile的一個片斷,當make 進入某個子目錄編繹時,會搜尋其中的flags檔案,將它們嵌入到Makefile中。這些flags程式碼測試當前的編繹選項與原來的是不是相同,如果相同,就將自已對應的目標檔案加入FILES_FLAGS_UP_TO_DATE列表,然後,系統從編繹物件表中刪除它們,得到 FILES_FLAGS_CHANGED列表,最後,將它們設為目標進行更新。

Linux 下 make 命令是系統管理員和程式設計師用的最頻繁的命令之一。管理員用它通過命令列來編譯和安裝很多開源的工具,程式設計師用它來管理他們大型複雜的專案編譯問題。本文我們將用一些例項來討論 make 命令背後的工作機制。

Make 如何工作的

對於不知道背後機理的人來說,make 命令像命令列引數一樣接收目標。這些目標通常存放在以 “Makefile” 來命名的特殊檔案中,同時檔案也包含與目標相對應的操作。更多資訊,閱讀關於 Makefiles 如何工作的系列文章。

當 make 命令第一次執行時,它掃描 Makefile 找到目標以及其依賴。如果這些依賴自身也是目標,繼續為這些依賴掃描 Makefile 建立其依賴關係,然後編譯它們。一旦主依賴編譯之後,然後就編譯主目標(這是通過 make 命令傳入的)。

現在,假設你對某個原始檔進行了修改,你再次執行 make 命令,它將只編譯與該原始檔相關的目標檔案,因此,編譯完最終的可執行檔案節省了大量的時間。

Make 命令例項

下面是本文所使用的測試環境:

OS —— Ubunut 13.04
Shell —— Bash 4.2.45
Application —— GNU Make 3.81

下面是工程的內容:

$ ls 
anotherTest.c Makefile test.c test.h

下面是 Makefile 的內容:

all: test 

test: test.o anotherTest.o 
    gcc -Wall test.o anotherTest.o -o test

test.o: test.c 
    gcc -c -Wall test.c 

anotherTest.o: anotherTest.c 
    gcc -c -Wall anotherTest.c 

clean: 
    rm -rf *.o test

現在我們來看 Linux 下一些 make 命令應用的例項:

1. 一個簡單的例子

為了編譯整個工程,你可以簡單的使用 make 或者在 make 命令後帶上目標 all

$ make 
gcc -c -Wall test.c 
gcc -c -Wall anotherTest.c 
gcc -Wall test.o anotherTest.o -o test

你能看到 make 命令第一次建立的依賴以及實際的目標。

如果你再次檢視目錄內容,裡面多了一些 .o 檔案和執行檔案:

$ ls 
anotherTest.c anotherTest.o Makefile test test.c test.h test.o

現在,假設你對 test.c 檔案做了一些修改,重新使用 make 編譯工程:

$ make 
gcc -c -Wall test.c 
gcc -Wall test.o anotherTest.o -o test

你可以看到只有 test.o 重新編譯了,然而另一個 Test.o 沒有重新編譯。

現在清理所有的目標檔案和可執行檔案 test,你可以使用目標 clean:

$ make clean
rm -rf *.o test

$ ls
anotherTest.c Makefile test.c test.h

你可以看到所有的 .o 檔案和執行檔案 test 都被刪除了。

2. 通過 -B 選項讓所有目標總是重新建立

到目前為止,你可能注意到 make 命令不會編譯那些自從上次編譯之後就沒有更改的檔案,但是,如果你想覆蓋 make 這種預設的行為,你可以使用 -B 選項。

下面是個例子:

$ make
make: Nothing to be done for `all’.

$ make -B
gcc -c -Wall test.c
gcc -c -Wall anotherTest.c
gcc -Wall test.o anotherTest.o -o test

你可以看到儘管 make 命令不會編譯任何檔案,然而 make -B 會強制編譯所有的目標檔案以及最終的執行檔案。

3. 使用 -d 選項列印除錯資訊

如果你想知道 make 執行時實際做了什麼,使用 -d 選項。

這是一個例子:

$ make -d | more
GNU Make 3.81
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.

This program built for x86_64-pc-linux-gnu
Reading makefiles…
Reading makefile `Makefile’…
Updating makefiles….
Considering target file `Makefile’.
Looking for an implicit rule for `Makefile’.
Trying pattern rule with stem `Makefile’.
Trying implicit prerequisite `Makefile.o’.
Trying pattern rule with stem `Makefile’.
Trying implicit prerequisite `Makefile.c’.
Trying pattern rule with stem `Makefile’.
Trying implicit prerequisite `Makefile.cc’.
Trying pattern rule with stem `Makefile’.
Trying implicit prerequisite `Makefile.C’.
Trying pattern rule with stem `Makefile’.
Trying implicit prerequisite `Makefile.cpp’.
Trying pattern rule with stem `Makefile’.
--More--

這是很長的輸出,你也看到我使用了 more 命令來一頁一頁顯示輸出。

4. 使用 -C 選項改變目錄

你可以為 make 命令提供不同的目錄路徑,在尋找 Makefile 之前會切換目錄的。

這是一個目錄,假設你就在當前目錄下:

$ ls 
file file2 frnd frnd1.cpp log1.txt log3.txt log5.txt
file1 file name with spaces frnd1 frnd.cpp log2.txt log4.txt

但是你想執行的 make 命令的 Makefile 檔案儲存在 ../make-dir/ 目錄下,你可以這樣做:

$ make -C ../make-dir/ 
make: Entering directory `/home/himanshu/practice/make-dir’ 
make: Nothing to be done for `all’. 
make: Leaving directory `/home/himanshu/practice/make-dir

你能看到 make 命令首先切到特定的目錄下,在那執行,然後再切換回來。

5. 通過 -f 選項將其它檔案看作 Makefile

如果你想將重新命名 Makefile 檔案,比如取名為 my_makefile 或者其它的名字,我們想讓 make 將它也當成 Makefile,可以使用 -f 選項。

make -f my_makefile

通過這種方法,make 命令會選擇掃描 my_makefile 來代替 Makefile。

一、確認已經裝好了GCC和Make的軟體包

可以使用whereis命令檢視:

如果whereis  gcc和whereis  make命令有結果,說明安裝了這兩個軟體,可以繼續往下做。

二、使用GCC編譯執行一個HelloWorld程式(只涉及單個檔案)

可以在任何一個目錄編寫C程式然後編譯執行,我這個例項在自己主目錄進行:

然後就進入了編寫程式的介面:

按下鍵盤”i”進入編輯介面,然後輸入程式:

按ESC(進入命令列模式),然後輸入”:wq”,冒號表示開始輸入命令,字母w代表儲存檔案,字母q代表退出編輯器:

按回車退出vim編輯器,退回到終端,以下是之後的編譯執行截圖:

三、使用GCC編譯執行一個多檔案程式(包含主程式和子程式)

這裡我們要寫兩個C程式檔案,一個檔案裡面寫個被調函式,另外一個檔案中main函式呼叫第一個檔案的函式,如下所示:

ex_display.c的程式碼如下,同樣的寫完後ESC然後輸入:wq退出:

輸入如下的main函式程式碼:

然後儲存退出,如下是編譯執行過程:

四、使用Makefile解決多檔案編譯執行的問題

正如上節的紅框框裡面所敘述,如果一個程式涉及的檔案很多的話,每個都得寫出來,很是麻煩,所以Makefile就出現了,請看教程:

進入makefile的編輯介面後,輸入如下內容:

然後儲存退出,執行make命令:

五、Makefile和shell script方法的對比

有人說,我把之前的所有命令,全寫到shell script裡面,不就達到Makefile的效果了,沒錯確實最終效果是相同的,但是Makefile卻有這些好處:

  • 簡化編譯執行的命令(並沒有gcc –c的過程)
  • 一次make後,下次只會編譯改動的檔案,其它的檔案不會再編譯了

其它還有一些優點,不過這第二個優點,對於大型專案來說,好處太大了!


相關推薦

linuxmake命令解釋集錦

無論是在Linux還是在Unix環境中,make都是一個非常重要的編譯命令。不管是自己進行專案開發還是安裝應用軟體,我們都經常要用到make或make install。利用make工具,我們可以將大型的開發專案分解成為多個更易於管理的模組,對於一個包括幾百個原始檔的應用程式

Linuxmake命令詳解

原文地址:https://www.computerhope.com/unix/umake.htm About make make is a utility(實用的) for building and maintaining groups of programs 

linuxmake命令的簡單使用以及Makefile檔案的書寫

Makefile    會不會寫makele,從一個側面說明了一個是否具備完成大型工程的能力。    一個工程中的源件不計數,其按型別、功能、模組分別放在若干個目錄中,makele定義了一系列的規則來指

linuxdig命令返回結果解釋

dig  baidu.com 返回 下面說明各項意義: ; <<>> DiG 9.3.6-P1-RedHat-9.3.6-20.P1.el5_8.6 <<>> baidu.com ;; global options:  

Linux命令 make -f 是什麼意思

二、Makefile的檔名 預設的情況下,make命令會在當前目錄下按順序找尋檔名為“GNUmakefile”、“makef ile”、“Makefile”的檔案,找到了解釋這個檔案。在這三個檔名中,最好使用“Mak efile”這個檔名,因為,這個檔名第一個字元為大寫,這樣有一種顯目的感覺。最好 不

Linux 常用命令

ln -s directory 沒有 開始 media 關機命令 範圍 後臺作業 解壓縮 命令基本格式: 命令提示符:[[email protected]/* */ ~]# root 代表當前的登錄用戶(linux當中管理員賬號是root)

Linuxawk命令的簡單用法

.cn inux total com mage 簡單 image 用法 int 一、用例1:   cat /proc/meminfo|grep "MemTotal"|awk ‘{print $2}‘   說明,$2表示第2位,$0表示全部,如需表示$,可用$$轉義。

linuxwc命令用法

字節 統計字符 -- 幫助信息 linux系統 count 沒有 標準 讀取 Linux系統中的wc(Word Count)命令的功能為統計指定文件中的字節數、字數、行數,並將統計結果顯示輸出。 1.命令格式: wc [選項]文件... 2.命令功能: 統計指定文件中的字節

linuxexpect命令詳解

linux運維expect介紹expect 是由Don Libes基於Tcl(Tool Command Language )語言開發的,主要應用於自動化交互式操作的場景,借助Expect處理交互的命令,可以將交互過程如:ssh登錄,ftp登錄等寫在一個腳本上,使之自動化完成。尤其適用於需要對多臺服務器執行相同

linuxtop命令

ont def comm 均值 code virt neutron load 共享 #top top命令的第一行“ top - 19:56:47 up 39 min, 3 users, load average: 0.00, 0.00,

Linuxdd命令的用法

dddd命令: convert and copy a file用法:dd?if=/PATH/FROM/SRC?of=/PATH/TO/DEST bs=#:?block?size,?復制單元大小 count=#:復制多少個bs of=file?寫到所命名的文件而不是到標準輸出 if=file?從所命名文件讀取而

linuxgrep命令

出行 red 文本搜索 grep命令 cin spa 組合 方式 小數 grep 是一種強大的文本搜索工具,它能使用正則表達式搜索文本,並把匹配的行打印出來。 grep常用用法 [root@www ~]# grep [-acinv] [--color=auto] ‘搜尋字

linuxwget命令

tags ogr don pan 還需 web 全部 remote 參數 Linux系統中的wget是一個下載文件的工具,它用在命令行下。對於Linux用戶是必不可少的工具,我們經常要下載一些軟件或從遠程服務器恢復備份到本地服務器。wget支持HTTP,HTTPS和FTP

Linux禁用命令歷史記錄

linux中 命令 -o 禁用 登錄 home hist history class 關閉history記錄功能 set +o history 打開history記錄功能 set -o history 清空記錄 history -c 記錄被清空,重新登錄後恢復。

Linuxsource命令的用法

立即生效 常常 new 重新登錄 核心 linu 用戶 成功 多次 source命令:   source命令也稱為“點命令”,也就是一個點符號(.)。source命令通常用於重新執行剛修改的初始化文件,使之立即生效,而不必註銷並重新登錄。因為lin

LinuxReadlink命令

.net padding order symbol 可執行文件 tro anon spa RM 原文地址:http://blog.csdn.net/liangxiaozhang/article/details/7356829 readlink是Linux系統中一個常用工具,

linux tr 命令的基礎運用

trtr命令可以看作是sed的簡化形式,可以用來替換刪除字符。tr - translate or delete characters常用的命令格式為:tr -c -d -s 字符1 字符2 <文件名 | -c | 用字符2替換字符1中不包含的字符(字符1補集) | -d | 刪除字符串1

linuxat命令詳解

at一次性計劃任務 at詳解 系統命令 at命令: 一:簡介: 計劃任務,在特定的時間執行某項工作,在特定的時間執行一次,需要安裝at服務,apt-get install at 二:時間定義: at允許使用一套相當復雜的指定時間的方法。● 能夠接受在當天的hh:mm(小時:分鐘)式的時間指定。假如

Linuxtouch命令使用(創建文件)

inf access -c -- modify 連續 技術分享 lin 路徑 touch命令有兩個功能: 1.用於把已存在文件的時間標簽更新為系統當前的時間(默認方式),它們的數據將原封不動地保留下來; 2.用來創建新的空文件。 語法 touch(選項)(參數) 選

Linux常用命令pipe

必須 強調 std 而且 ss命令 strong 目錄下的文件 文件 last 大多數linux命令處理數據後都會輸出到標準輸出,但是如果數據要經過系列列的步驟處理後,才是需要的數據個數,這種需求就需要管道來幫助完成。 管道命令使用"|"作為界定符,將界定符前的命令的執行結