C編譯: makefile基礎

來源:互聯網
上載者:User
文章目錄
  •  

作者:Vamei 出處:http://www.cnblogs.com/vamei 歡迎轉載,也請保留這段聲明。謝謝!

 

在編譯一個大型項目的時候,往往有很多目標檔案、庫檔案、標頭檔以及最終的可執行檔。不同的檔案之間存在依賴關係(dependency)。比如當我們使用下面命令編譯時間:

$gcc -c -o test.o test.c

$gcc -o helloworld test.o

可執行檔helloworld依賴於test.o進行編譯的,而test.o依賴於test.c。

 依賴關係

在我們編譯一個大型項目時,我們往往要很多次的調用編譯器,來根據依賴關係,逐步編譯整個項目。這樣的方式是自下而上的,即先編譯下遊檔案,再編譯上遊檔案。

 

UNIX系統下的make工具用於自動記錄和處理檔案之間的依賴關係。我們不用輸入大量的"gcc"命令,而只需調用make就可以完成整個編譯過程。所有的依賴關係都記錄在makefile文字檔中。我們只需要make helloworld,make會根據依賴關係,自上而下的找到編譯該檔案所需的所有依賴關係,最後再自下而上的編譯。

(make有多個版本,本文將基於GNU make。make會自動搜尋目前的目錄下的makefile, Makefile或者GNUmakefile)

 

依賴

 

基本概念

我們使用一個樣本C語言檔案:

#include <stdio.h>/* * By Vamei * test.c for makefile demo */int main() {    printf("Hello world!\n");    return 0;}

 

下面是一個簡單的makefile

# helloworld is a binary filehelloworld: test.o
  echo "good"  gcc -o helloworld test.otest.o: test.c  gcc -c -o test.o test.c

 

觀察上面的makefile

  • #號起始的行是注釋行
  • target: prerequisite為依賴關係,即目標檔案(target)依賴於前提檔案(prerequisite)。可以有多個前提檔案,用空格分開。
  • 依賴關係後面的<Tab>縮排行是實現依賴關係進行的操作,即正常的UNIX命令。一個依賴關係可以附屬有多個操作。

用直白的話說,就是:

  • 想要helloworld嗎?那你必須有test.o,並執行附屬的操作。
  • 如果沒有test.o,那你必須搜尋其他依賴關係,並建立test.o。

 

我們執行

$make helloworld

來建立helloworld。

 

make是一個遞迴建立的過程:

  • Base Case 1: 如果當前依賴關係中沒有說明前提檔案,那麼直接執行操作。
  • Base Case 2: 如果當前依賴關係說明了目標檔案,而目標檔案所需的前提檔案已經存在,而且前提檔案與上次make時沒有發生改變(根據最近寫入時間判斷),也直接執行該依賴關係的操作。
  • 如果當前目標檔案依賴關係所需的前提檔案不存在,或者前提檔案發生改變,那麼以前提檔案為新的目標檔案,尋找依賴關係,建立目標檔案。

虛線: 依賴關係檢索

 

上面是make的核心功能。有了上面的功能,我們可以記錄項目中所有的依賴關係和相關操作,並使用make進行編譯。下面的內容都是在此核心內容上的拓展。

 宏

make中可以使用宏(MACRO)。宏類似於文本類型的變數。比如下面的CC:

CC = gcc

# helloworld is a binary filehelloworld: test.o
  echo "good"  $(CC) -o helloworld test.otest.o: test.c  $(CC) -c -o test.o test.c

 

我們用CC來代表"gcc"。在makefile中,使用$(CC)的方式來調用宏的值。make會在運行時,使用宏的值(gcc)來替代$(CC)。

shell的環境變數可以直接作為宏調用。如果同一個自訂的宏同時也有同名環境環境變數,make將優先使用自訂宏。

(可以使用$make -e helloworld來優先使用環境變數)

 

類似於C語言的宏,makefile中的宏可以方便的管理一些固定出現的文本,並方便替換操作。比如我們未來使用ifort編譯器時,只需要更改宏定義為:

CC = ifort

就可以了

 

內部宏

make中有內部定義的宏,可以直接使用。$@中包含有當前依賴關係的目標檔案名,而$^包含當前目標的前提檔案:

CC = gcc# helloworld is a binary filehelloworld: test.o  echo $@  $(CC) -o $@ $^test.o: test.c  $(CC) -c -o $@ $^

 

內部宏       功能

$*          當前依賴關係中的目標檔案名,不包括尾碼。

$*          當前依賴關係中,發生改變的前提檔案

$$          字元"$"

 

如果目標或者前提檔案是一個完整路徑,我們可以附加D和F來提取檔案夾部分和檔案名稱部分,比如$(@F)表示目標檔案的檔案名稱部分。

 

尾碼依賴

在makefile中使用

.SUFFIXES: .c .o

來說明.c和.o是尾碼。

 

我們可以使用尾碼依賴的方式,比如:

CC = gcc.SUFFIXES: .c .o.c.o:        $(CC) -c -o $@ $^#--------------------------# helloworld is a binary filehelloworld: test.o        echo $@        $(CC) -o $@ $^test.o: test.c

我們定義.c和.o為尾碼。並有尾碼依賴關係.c.o:。前者為前提,後者為目標。(注意,與一般的依賴關係順序不同)

上面的test.o和test.c有依賴關係,但沒有操作。make會發現該依賴關係符合.c.o的尾碼依賴,並執行該尾碼依賴後面的操作。

 

如果項目很大型的時候,尾碼依賴非常有用。符合尾碼依賴的檔案往往有類似的操作,我們可以將這些操作用尾碼依賴表示,而避免重複輸入。

 

其他

makefile的續行符為\

 

makefile中經常會定義下面依賴關係:

all:

如果make後沒有跟隨檔案名稱,那麼將執行該依賴關係。

clean:

常用於清理曆史檔案。

 

比如:

CC = gcc.SUFFIXES: .c .o.c.o:        $(CC) -c -o $@ $^#--------------------------all: helloworld        @echo "ALL"# helloworld is a binary filehelloworld: test.o        @echo $@        $(CC) -o $@ $^test.o: test.cclean:        -rm helloworld *.o

注意: echo前面的@和rm前面的-。@後的命令將不顯示命令本身。-後面的命令將忽略錯誤(比如刪除不存在的檔案)。

 總結

make的核心功能是根據依賴關係來實現編譯管理。

make的其他功能是讓使用者可以更加便捷的寫出makefile。

 

參考

http://oreilly.com/linux/excerpts/9780596100292/gnu-make-utility.html

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.