亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 操作系統 > 正文

一個工程實例來學習 Makefile

2024-06-28 13:21:43
字體:
來源:轉載
供稿:網友
一個工程實例來學習 Makefile

March 3, 2015 8:19 PM

Makefile 文件的編寫學習前的準備

需要準備的工程目錄結構如下:

.├── add│?? ├── add_float.c│?? ├── add.h│?? └── add_int.c├── main.c└── sub    ├── sub_float.c    ├── sub.h    └── sub_int.c

文件編譯為可執行文件cacuNOTE:需要的源代碼:MakefileExample.tar

Makefile的介紹

使用 GCC 的命令行進行程序編譯在單個文件下是比較方便的,當工程中的文件逐漸增多,甚至變得十分龐大的時候,使用 GCC 命令編譯就會變得力不從心。linux 中的 make 工具提供了一種管理工程的功能,可以方便的進行程序的編譯,對更新的文件進行重編譯。

Makefile的基本格式為:

TARGET... : DEPENDEDS...COMMAND    ...    ...
  • TARGET:規則所定義的目標,通常是最后生成的文件,也可以是一個“動作”,稱之為“偽目標”。
  • DEPENDEDS:執行此規則所必須的依賴條件。
  • COMMAND:規則所執行的命令。命令可以是多個,每個命令占一行,以 Tab 開頭。
動手編寫多文件工程的Makefile1.命令行編譯程序

如果在命令行下手動編譯該程序比較麻煩,需要先編譯每個文件,生成目標文件,最后再將5個目標文件編譯成可執行文件。

#get add_int.o targetgcc -c add/add_int.c -o add/add_int.o -ggdb#get add_float.o targetgcc -c add/add_float.c -o add/add_float.o -ggdb#get sub_float.o targetgcc -c sub/sub_float.c -o sub/sub_float.o -ggdb#get sub_int.o targetgcc -c sub/sub_int.c -o sub/sub_int.o -ggdb#get main.o targetgcc -c main.c -o main.o -Iadd -Isub -ggdb#get cacu bin filegcc -o cacu add/add_int.o add/add_float.o sub/sub_int.o sub/sub_float.o main.o -ggdb#get main.S targetgcc -S add/add_int.o add/add_float.o sub/sub_int.o sub/sub_float.o main.o
2.多文件的Makefile

使用make進行項目管理,需要編寫Makefile。在編譯時,make程序按照順序從Makefile文件中讀取指令,依次執行!

#get cacu bin filecacu:add_int.o add_float.o sub_int.o sub_float.o main.ogcc -o cacu add/add_int.o add/add_float.o /sub/sub_int.o sub/sub_float.o main.o -ggdb#get add_int.o targetadd_int.o:add/add_int.c add/add.hgcc -c -o add/add_int.o add/add_int.c -ggdb#get add_float.o targetadd_float.o:add/add_float.c add/add.hgcc -c -o add/add_float.o add/add_float.c -ggdb#get sub_int.o targetsub_int.o:sub/sub_int.c sub/sub.hgcc -c -o sub/sub_int.o sub/sub_int.c -ggdb#get sub_float.o targetsub_float.o:sub/sub_float.c sub/sub.hgcc -c -o sub/sub_float.o sub/sub_float.c -ggdb#get main.o targetmain.o:main.c add/add.h sub/sub.hgcc -c -o main.o main.c -Iadd -Isub -ggdb#clean PRojectclean:rm -f cacu add/add_int.o add/add_float.o /sub/sub_int.o sub/sub_float.o main.o

當需要編譯工程時,直接在工程目錄中執行make即可。如果想清除編譯過程中生成的目標文件和cacu,執行make clean即可。

3.使用用戶自定義變量的Makefile

在Makefile文件中,用戶可以自定義變量,方便用戶修改參數。使用變量后,原本冗長的文件可以化簡為:

CC = gccCFLAGS = -Iadd -Isub -O2OBJS = add/add_int.o add/add_float.o sub/sub_float.o sub/sub_int.o main.oTARGET = cacuRM = rm -f$(TARGET):$(OBJS)$(CC) -o $(TARGET) $(OBJS) $(CFLAGS)$(OBJS):%o:%c$(CC) -c $(CFLAGS) $< -o $@clean:$(RM) $(TARGET) $(OBJS)

NOTE:$(OBJS):%.o:%.c中 %.o:%.c 是將 $(OBJS) 中以 .o 結尾的文件替換成以 .c 結尾的文件。

其中 $< 和 $@ 是自動化變量,下一節會介紹。

4.使用預定義變量的Makefile

在Makefile中還有一些變量是系統預定義的,用戶可以直接使用。

Makefile中經常使用的變量及含義

變量名含 義默 認 值
AR生成靜態庫庫文件的程序名稱ar
AS匯編編譯器的名稱as
CCC語言編譯器的名稱cc
CPPC語言預編譯器的名稱/$(CC) -E
CXXC++語言編譯器的名稱g++
FCFORTRAN語言編譯器的名稱f77
RM刪除文件程序的名稱rm -f
ARFLAGS生成靜態庫庫文件程序的選項無默認值
ASFLAGS匯編語言編譯器的編譯選項無默認值
CFLAGSC語言編譯器的編譯選項無默認值
CPPFLAGSC語言預編譯器的編譯選項無默認值
CXXFLAGSC++語言編譯器的編譯選項無默認值
FFLAGSFORTRAN語言編譯器的編譯選項無默認值

因此,前面的Makefile文件可以改寫成:

CFLAGS = -Iadd -Isub -O2OBJS = add/add_int.o add/add_float.o /   sub/sub_int.o sub/sub_float.o main.oTARGET = cacu$(TARGET):$(OBJS)$(CC) -o $(TARGET) $(OBJS) $(CFLAGS)clean:-$(RM) $(TARGET) $(OBJS)

其中變量$(CC) $(RM)可以直接使用,默認值分別是ccrm -f。另外CFLAGS等變量是調用編譯器時的默認選項配置,在生成main.o時沒有指定編譯選項,make程序自動調用了文件中定義的CFLAGS選項來增加頭文件的搜索路徑。

5.使用自動變量的Makefile

還記得上面出現的 /$< 和 /$@ 嗎?它們是Makefile中的自動變量,分別代表依賴項和目標項。下面是一些常見的自動變量及其含義:

Makefile 中常見的自動變量和含義

變量含義
*表示目標文件的名稱,不包含目標文件的擴展名
+表示所有的依賴文件,這些依賴文件之間以空格分開,按照出現的先后為順序,其中可能包含重復的依賴文件
<表示依賴項中第一個依賴文件的名稱
?依賴項中,所有目標文件時間戳晚的依賴文件,依賴文件之間以空格分開
@目標項中目標文件的名稱
^依賴項中,所有不重復的依賴文件,這些文件之間以空格分開

由此,對上面的Makefile文件進行重寫,代碼如下:

CFLAGS = -Iadd -Isub -O2OBJS = add/add_int.o add/add_float.o /   sub/sub_int.o sub/sub_float.o main.oTARGET = cacu$(TARGET):$(OBJS)$(CC) $^ -o $@ $(CFLAGS)$(OBJS):%o:%c$(CC) -c $< -o $@ $(CFLAGS)clean:-$(RM) $(TARGET) $(OBJS)
6.設置搜索路徑

在大的系統中,通常存在很多目錄,手動添加目錄的方法不僅十分笨拙而且容易造成錯誤。Make 的目錄搜索功能提供了一個解決此問題的方法,指定需要搜索的目錄, make 會自動找到指定文件的目錄并添加到文件上, VPATH 變量可以實現此目的。VPATH 變量的使用方法如下:

VPATH = path1:path2:...

VPATH 右邊是冒號(:)分割路徑名稱,例如下面的指令:

VPATH = add:subadd_int.o:%.o:%.c$(CC) -c -o $@ $<

Make 的搜索路徑包含 add 和 sub 目錄。add_int.o 規則自動擴展成如下代碼:

add_int.o:add/add_int.ccc -c -o add_int.o add/add_int.c

用添加路徑的方法改寫上面的 Makefile 文件,代碼如下:

CFLAGS = -Iadd -Isub -O2OBJDIR = objsVPATH = add:sub:.OBJS = add_int.o add_float.o sub_int.o sub_float.o main.oTARGET = cacu$(TARGET):$(OBJSDIR) $(OBJS)$(CC) -o $(TARGET) $(OBJDIR)/*.o $(CFLAGS)$(OBJDIR):mkdir -p ./$@$(OBJS):%.o:%.c $(CC) -c $(CFLAGS) $< -o $(OBJDIR)/$@clean:-$(RM) $(TARGET)-$(RM) $(OBJDIR)/*.o -r
7.自動推導規則

使用命令 make 編譯擴展名為 .c 的 C 語言文件的時候,源文件的編譯規則不用明確地給出。這是因為 make 進行編譯的時候會使用一個默認的編譯規則,按照默認規則完成對 .c 文件的編譯,生成對應的 .o 文件。它執行命令 cc -c 來編譯 .c 源文件。在 Makefile 中只需要給出需要重建的目標文件(一個 .o 文件),make 會自動為這個 .o 文件尋找合適的依賴文件(對應的 .c 文件),并且使用默認的命令來構建這個目標文件。

對于上邊的例子,默認規則是使用命令cc -c main.c -o main.o來創建文件 main.o 。對一個目標文件是“文件名.o“,依賴文件是”文件名.c“的規則,可以省略其編譯規則的命令行,由 make 命令決定如何使用編譯命令和選項。此默認規則稱為 make 的隱含規則。

這樣,在書寫 Makefile 時,就可以省略掉描述 .c 文件和 .o 依賴關系的規則,而只需要給出那些特定的規則描述(.o 目標所需要的 .h 文件)。因此上面的例子可以使用更加簡單的方式書寫, Makefile 文件的內容如下:

CFLAGS = -Iadd -Isub -O2VPATH = add:subOBJS = add_int.o add_float.o sub_int.o sub_float.o main.oTARGET = cacu$(TARGET):$(OBJS)$(CC) -o $(TARGET) $(OBJS) $(CFLAGS)clean:-$(RM) $(TARGET)-$(RM) $(OBJS)
8.遞歸 make

對于規模比較大的程序,需要多個人在多個目錄下進行開發。如果只用一個 Makefile 來維護就會比較麻煩,因此可以在每個目錄下建立自己的 Makefile ,然后在總控 Makefile 中調用子目錄的 Makefile 文件。

目錄結構如下:

.├── add│?? ├── add_float.c│?? ├── add.h│?? ├── add_int.c│?? └── Makefile├── main.c├── Makefile└── sub    ├── Makefile    ├── sub_float.c    ├── sub.h    └── sub_int.c

1.遞歸調用的方式

add:cd add && $(MAKE)

它等價于

add:$(MAKE) -C add

2.總控Makefile

CC = gccCFLAGS = -O2TARGET = cacuexport OBJSDIR = $(shell pwd)/objs$(TARGET):$(OBJSDIR) main.o$(MAKE) -C add$(MAKE) -C sub$(CC) -o $(TARGET) $(OBJSDIR)/*.o$(OBJSDIR):mkdir -p $@main.o:%.o:%.c$(CC) -c $< -o $(OBJSDIR)/$@ $(CFLAGS) -Iadd -Isubclean:-$(RM) $(TARGET)-$(RM) $(OBJSDIR)/*.o

如果總控 Makefile 中的一些變量需要傳遞給下層的 Makefile,可以使用 export 命令。如:export OBJSDIR = ./objs

3.子目錄Makefile的編寫

Add 目錄下的 Makefile 如下:

OBJS = add_int.o add_float.oall:$(OBJS)$(OBJS):%.o:%.c$(CC) -c $< -o $(OBJSDIR)/$@ $(CFLAGS)clean:$(RM) $(OBJS)

Sub 目錄下的 Makefile 如下:

OBJS = sub_int.o sub_float.oall:$(OBJS)$(OBJS):%.o:%.c$(CC) -c $< -o $(OBJSDIR)/$@ $(CFLAGS)clean:$(RM) $(OBJS)
Makefile 中的函數1.獲取匹配模式的文件名wildcard

這個函數的功能是查找當前目錄下所有符合模式 PATTERN 的文件名,其返回值是以空格分割的、當前目錄下的所有符合模式 PATTERN 的文件名列表。其原型如下:

$(wildcard PATTERN)

例如,如下模式返回當前目錄下所有擴展名位 .c 的文件列表。

$(wildcard *.c)

2.模式替換函數patsubst

這個函數的功能是查找字符串 text 中按照空格分開的單詞,將符合模式 pattern 的字符串替換成 replacement。 Pattern 中的模式可以使用通配符, % 代表 0 個到 n 個字符,當 pattern 和 replacement 中都有 % 時,符合條件的字符將被 replacement 中的替換。函數的返回值是替換后的新字符串。其原型如下:

$(patsubst pattern, replacement, text)

例如,需要將 C 文件替換為 .o 的目標文件可以使用如下模式:

$(patsubst %.c, %.o, add.c)

上面的模式將 add.c 字符串作為輸入,當擴展名為 .c 時符合模式 %.c ,其中 % 在這里代表 add,替換為 add.o,并作為輸出字符串。

$(patsubst %.c, %.o, $(wildcard *.c))

輸出的字符串將當前擴展名為 .c 的文件替換成 .o 的文件列表。

3.循環函數foreach

這個函數的原型為:

$(foreach VAR, LIST, TEXT)

函數的功能為 foreach 將 LIST 字符串中一個空格分割的單詞,先傳給臨時變量 VAR ,然后執行 TEXT 表達式, TEXT 表達式處理結束后輸出。其返回值是空格分割表達式 TEXT 的計算結果。

例如,對于存在 add 和 sub 的兩個目錄,設置 DIRS 為 "add sub ./" 包含目錄 add、sub 和當前目錄。表達式 $(wildcard $(dir)/*.c) ,可以取出目錄 add 和 sub 及當前目錄中的所有擴展名為 .c 的C語言源文件:

DIRS = sub add ./FILES = $(foreach dir, $(DIRS), $(wildcard $(dir)/*.c))

利用上面幾個函數對原有的 Makefile 文件進行重新編寫,使新的 Makefile 可以自動更新各個目錄下的C語言源文件:

CC = gccCFLAGS = -O2 -Iadd -IsubTARGET = cacuDIRS = sub add .FILES = $(foreach dir, $(DIRS), $(wildcard $(dir)/*.c))OBJS = $(patsubst %.c, %.o, $(FILES))$(TARGET):$(OBJS)$(CC) -o $(TARGET) $(OBJS)clean:-$(RM) $(TARGET)-$(RM) $(OBJS)
總結

至此,已經可以閱讀大部分軟件的 Makefile 了~~~


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品99久久久久久白浆小说| 国产精品99免视看9| 欧美性猛交xxxxx免费看| 欧美日韩亚洲视频一区| 欧美国产高跟鞋裸体秀xxxhd| 成人精品视频在线| 午夜精品一区二区三区在线| 日本欧美在线视频| 91精品中国老女人| 亚洲精品乱码久久久久久金桔影视| 国产精品视频大全| 国产精品视频网址| xxxxx91麻豆| 日韩电影大片中文字幕| 亚洲精品suv精品一区二区| 成人xvideos免费视频| 欧美激情久久久久| 国产小视频91| 精品国内亚洲在观看18黄| 国产精品精品国产| 亚洲第一av网站| 色悠悠久久88| 欧美午夜宅男影院在线观看| 国产一区二区在线免费| 在线观看欧美www| 亚洲欧美国产精品专区久久| 欧美成人激情在线| 亚洲天堂av高清| 久久久久久久激情视频| 国产精品一香蕉国产线看观看| 91在线观看免费观看| 久久精品国产精品亚洲| 亚洲影视九九影院在线观看| 欧美日韩国产一区在线| 最近2019中文字幕第三页视频| 欧美亚洲视频一区二区| 国产精品h片在线播放| 欧美裸体男粗大视频在线观看| 性色av一区二区三区红粉影视| 欧美在线观看www| 欧美日韩在线观看视频| 97视频免费观看| 久久久精品国产网站| 日韩视频在线免费观看| 中文字幕久久久av一区| 国产在线视频一区| 欧美伊久线香蕉线新在线| 中文字幕亚洲欧美一区二区三区| 97国产成人精品视频| 91社区国产高清| 日韩精品在线观看网站| 国产精品免费视频久久久| 午夜精品久久久久久久99热浪潮| 成人福利在线视频| 97精品久久久| 一区二区三区黄色| 中文字幕亚洲一区在线观看| 中文字幕日韩视频| 欧美性猛交xxxx乱大交极品| 亚洲第一av网| 欧美日韩亚洲天堂| 欧美中文在线字幕| 亚洲美女精品久久| 国产色综合天天综合网| 欧美成人精品不卡视频在线观看| 欧美又大粗又爽又黄大片视频| 九九热r在线视频精品| 日韩中文字幕在线视频播放| 亚洲缚视频在线观看| 欧美在线视频一区| 亚洲精品自在久久| 久久久久女教师免费一区| 一本色道久久88亚洲综合88| 久久久久国产精品免费网站| 日韩男女性生活视频| 日韩av片电影专区| 九九热这里只有精品免费看| 成人免费淫片视频软件| 欧美国产日产韩国视频| 日韩av在线看| 日日噜噜噜夜夜爽亚洲精品| 日韩av电影免费观看高清| 97精品欧美一区二区三区| 亚洲欧美国产va在线影院| 亚洲国产成人爱av在线播放| 中文字幕av一区| 国产精品欧美激情在线播放| 欧美俄罗斯乱妇| 欧美日韩国产成人| 国产精品久久久久久av| 精品国产精品三级精品av网址| 91精品国产91久久久久久| 91精品国产高清久久久久久91| 欧美裸体xxxx极品少妇| 91精品国产91久久久久久最新| 欧美人在线视频| 欧美午夜性色大片在线观看| 国产精品成人aaaaa网站| 欧美大片大片在线播放| 日韩视频在线免费观看| 国产男女猛烈无遮挡91| 中文字幕久久久| 中文综合在线观看| 97福利一区二区| 川上优av一区二区线观看| 欧美亚洲国产成人精品| 自拍偷拍亚洲欧美| 亚洲成人国产精品| 亚洲国产精品女人久久久| 亚洲成人动漫在线播放| 成人免费视频a| 久久99视频精品| 国产成人91久久精品| 久久久人成影片一区二区三区观看| 欧美插天视频在线播放| 久久精品精品电影网| 久久久国产精品视频| 成人国产亚洲精品a区天堂华泰| 日本sm极度另类视频| 中文字幕欧美日韩精品| 精品久久香蕉国产线看观看亚洲| 麻豆成人在线看| 91久久久久久久| 国产亚洲精品一区二555| 精品丝袜一区二区三区| 亚洲iv一区二区三区| 狠狠久久五月精品中文字幕| 欧美电影在线观看完整版| 亚洲а∨天堂久久精品9966| 日本精品一区二区三区在线播放视频| 日韩一区二区三区xxxx| 欧美日韩国产二区| 欧美视频免费在线| 欧美怡春院一区二区三区| 久久91精品国产91久久跳| 精品国产欧美一区二区三区成人| 日韩欧美福利视频| 成人有码在线播放| 岛国视频午夜一区免费在线观看| 亚洲最新av在线| 日韩亚洲国产中文字幕| 成人黄色影片在线| 久久av中文字幕| 热99精品只有里视频精品| 亚洲美女视频网站| 日韩欧美在线字幕| 欧美激情按摩在线| 久热精品视频在线观看| 国产精品久久久av久久久| 成人字幕网zmw| 国产91露脸中文字幕在线| 国产成人亚洲综合91精品| 国产精品第一第二| 久久精品国亚洲| 欧美麻豆久久久久久中文| 富二代精品短视频| 国产精品久久久久久亚洲调教| 色青青草原桃花久久综合| 国产99久久精品一区二区| 欧美性xxxx| 日韩电影免费在线观看| 欧美一区二区三区免费观看| 国产精品爱久久久久久久| 久久精品国产视频|