makefile簡明教程

2021-10-01 10:16:21 字數 4055 閱讀 7487

makefile  主要是編譯就是用來編譯原始檔的

makefile的檔案命名:makefile 或 makefile

makefile的規則或者說寫法就三個部分:目標、依賴、命令

具體怎麼寫呢 

目標:依賴

(tab縮排)命令

看乙個小例子

執行gcc命令

這就是乙個最簡單的makefile,但是它最大問題是,如果你修改了中乙個.c檔案,在gcc編譯的時候會把所有的c檔案都編譯一遍,這樣效率就很低,所以可以把他們分開寫,先編譯成.o二進位制檔案。這樣就是第二個例子

main.o :main.c

gcc main.c -c

add.o :add.c

gcc add.c -c

sub.o :sub.c

gcc sub.c -c

mul.o :mul.c

gcc mul.c -c

這樣當你更改某乙個.c檔案後,只會編譯你修改的那個c檔案,編譯成.o二進位制檔案,而不用把所有的都編譯一遍,節省很多時間。

那makefile是怎麼知道要重新編譯的是哪乙個檔案呢。

原理是

如果依賴存在就判斷是否需要更新也就是小目標是否要執行,

判斷的依據是目標和依賴的時間,如果目標的時間大於依賴的時間,不更新,反之需要更新。說白了就是它會根據檔案時間的變化檢測你有沒有更改原始檔,更改了就要更新。因為一定是現有依賴才有的目標,目標.o檔案時間要晚於依賴的時間也說成大於。也就是說一旦更改了依賴檔案,這個檔案最終時間就在目標之後了,依賴時間大於了目標時間,說明你修改了依賴檔案,這時就需要更新。

但是上面這個makefile寫的太冗餘了。下面看下面乙個例子改進一下:

前面說makefile就像乙個指令碼,那它就可以有變數和函式。所以先看一下變數,變數你可以自己定義,makefile本身也提供了幾個固定的變數。

自定義變數:makefile裡面自定義變數沒有型別 直接賦值就行,例如:obj = a.o b.o c.o 或者 obj  = 10 ,不講道理的使用,

但是變數不能直接使用要取出變數的值,用$符號,例如$(obj)

makfile提供的變數:cc 、cpplags、ldflags、libs等

cc=」gcc -march=k8 -o2 -s」                           

ldflags = -l/var/***/lib -l/opt/mysql/lib

libs = -lmysqlclient -liconv

cppflags='-i/usr/local/libjpeg/include -i/usr/local/libpng/include'

就是在gcc編譯的時候需要指定一下頭檔案和庫檔案目錄,寫起來太長了,你就講路徑賦值給相應的變數,這是一種規範,你隨便給別的變數也能用。甚至很多makefile檔案中編譯都沒有gcc的字樣就是把gcc賦值給了cc。當然也可以把這些值設定到環境變數中去export ldflags="-l/var/***/lib -l/opt/mysql/lib -wl,r/var/***/lib -wl,r/opt/mysql/lib" ;

自動變數:$@、$<、$^,makefile提供了幾個變數表示著固定的意思,不能對他們賦值且只能在規則命令中使用。

$@:規則中的目標

$<:規則中的第乙個依賴

$^:規則中的所有的依賴

改寫例二

obi = main.o add.o sub.o mul.o

$(target):$(obj)

gcc $(obj)  -o  $(target)      這一行就可以替換成 gcc $^ -o $@

%.o:%.c                               %模式匹配代表所有的.o檔案和所有的.c檔案

gcc -c $< -o $@

現在這個makefile的可移植性很差

這裡看一下makefile的函式

makefile中所有的函式都有返回值,下面介紹兩個makefile的函式

(1)wildcard查詢指定資料夾下指定型別的檔案

src = $(wildcard ./*.c)  當前目錄下所有的.c檔案並賦值給src

(2)patsubst匹配替換

obj = $(patsubst %.c, %.o,$(src))  把src變數中所有.c檔案替換為.o檔案

src = $(wildcard ./*.c)

obj = $(patsubst %.c,%.c,$(src))

$(target):$(obj)

gcc $^ -o $@

%.o:%.c

gcc -c $< -o $@

前面說的makefile最後生成的是只有第一目標,也就終極目標。其實makefile也可以生成不是終極目標的目標,

呼叫使用 :make 目標名   ,例如乙個makefile最後會執行make clean清理專案

src = $(wildcard ./*.c)

obj = $(patsubst %.c,%.c,$(src))

$(target):$(obj)

gcc $^ -o $@

%.o:%.c

gcc -c $< -o $@

hello:

echo "hello,makefile"

執行make hello 會列印hello,makefile

如果我們加乙個,清理專案的操作,表示如果執行失敗刪除前面生成的檔案。

clean:

-mkdir  /abc

-rm $(obj)&(target) -f       #-f表示強制執行 ,命令前的'-'號表示當前命令失敗向下執行

這裡有會有個問題就是,如果當前目錄下有同名的clean檔案,make clean就不會執行。前面例二就說了,makefile根據依賴的時間來判斷會不會更新,但是這裡clean沒有依賴。

解決這個問題的方法是寫乙個偽目標  .phony:clean ,注意phony前面有個'.'符號。

完整的就是

src = $(wildcard ./*.c)

obj = $(patsubst %.c,%.c,$(src))

$(target):$(obj)

gcc $^ -o $@

%.o:%.c

gcc -c $< -o $@

.phony:clean

clean:

-mkdir /abc

-rm $(obj)&(target) -f

好了makefile就是這麼簡單。

最後寫乙個小例子

在plus目錄下有兩個目錄include和src,現在在plus目錄下編寫makefile,編譯src下的原始檔,需要include中的標頭檔案。

cppflas = ./include

src = $(wildcard ./src/*.c)

obj = $(patsubst %.c,%.c,$(src))

$(target):$(obj)

gcc $^ -o $@

%.o:%.c

echo $<

gcc -c $< -i $(cppflags) -o $@

上面可以甚至讓 cppflas = '-i./include',這樣gcc中就不用再加引數 -i了

Visual Unit 簡明教程

visual unit,簡稱vu,是新一代單元測試工具,功能強大,使用簡單,完全視覺化,不需編寫測試 vu的測試結果使程式行為一目了然,有助於整理程式設計思路,提高程式設計效率和正確性,並能快速排錯 vu還增強偵錯程式功能 如自由後退 用例切換 提高除錯的效率 vu能達到空前的測試完整性,輕鬆完成語...

MYSQL簡明教程

dos進入mysql命令 c mysql h 127.0.0.1 u root p enter password mysql 進入完成 建立資料庫 create database databasename 使用指定資料庫進行操作 方法1 use database databasename 方法2 m...

Struts Hibernate簡明教程

jboss 資助的開源專案,當前比較流行的持久層框架,是一種先進的 jdbc 封裝框架。優點 提高了資料訪問層的開發效率,使我們不必直接呼叫 jdbc 來訪問關係型資料庫。hibernate 建立在物件導向的基礎之上,開發人員只需針對物件進行操作,不必再關心資料庫的連線關閉,sql的執行,以及 re...