欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
編寫(xiě)高質(zhì)量的Makefile

一、前言

回想自己的第一個(gè)Makefile,是這個(gè)樣子的


代碼
hello:hello.c
    gcc hello.c -o hello



后來(lái)有所進(jìn)步,陸續地寫(xiě)了一些大都是這個(gè)樣子的Makefile:

代碼
foobar:foo.o bar.o
    gcc -o foo.o bar.o
foo.o:foo.c
    gcc -c foo.c
bar.o:foo.c
    gcc -c bar.c

.PHONY:clean
clean:
    rm -rf *.o foobar



看上去還行,用起來(lái)也不錯,但是隨著(zhù)程序規模的擴大,每次添加一個(gè)新文件,都要手動(dòng)修改Makefile,實(shí)在是不厭其煩。

后來(lái)閱讀了一些開(kāi)源程序的Makefile源代碼,當然,不是automake生成的那種,有了一些心得,幾番進(jìn)化,一段時(shí)間后,感覺(jué)對GNU make算是有了些初步的了解,在此總結一下,也算是溫故而知新了。而且我記性比較差 (IMG:http://acm.hrbeu.edu.cn/forums/style_emoticons/default/F5CC4.gif) ,放在這里算是記錄一下,免得以后忘記。同時(shí)也免得大家再去翻那些繁復的手冊,浪費不必要的時(shí)間。 (IMG:http://acm.hrbeu.edu.cn/forums/style_emoticons/default/D3F5F.gif)

下文中makefile操作的對象有三個(gè)文件: foo.c , bar.c 和bar.h,內容分別如下:

foo.c

代碼
#include "bar.h"

int main(){

    print("Hello, makefile!");
              
    return 0;
}




bar.c

代碼

#include <stdio.h>

int print(char * msg){

    printf("%s/n",msg);

    return 0;
}




bar.h

代碼
int print(char * msg);




OK,該交代的都交代了,進(jìn)入正題。


二、我的makefile模板

把上個(gè)項目的makefile整理了一下,感覺(jué)結構比較清晰,可以作為模板供以后使用。

文件內容大體是這個(gè)樣子的:

代碼
CC = gcc
CFLAGS = -Wall -O
INCLUDE = -I/usr/include/mysql                             #其實(shí)在這里用不著(zhù)這幾個(gè)選項
LFLAGS = -L/usr/lib/mysql -lmysqlclient -lpthread   #僅做示意之用

TARGET = foobar

SOUCE_FILES = $(wildcard *.c)
OBJS = $(patsubst %.c,%.o,$(SOUCE_FILES))

%.o : %.c %.h
    $(CC) -c $(CFLAGS) $< -o $@

%.o : %.c
    $(CC) -c $(CFLAGS) $< -o $@

$(TARGET): $(OBJS)
    $(CC) $^ -o $@ $(INCLUDE) $(LFLAGS)

.PHONY:clean
clean:
    $(RM) $(TARGET) $(OBJS)




解釋?zhuān)?br>
前幾行都是變量的定義,至于為什么要定義這些變量,理由和編程中使用宏定義是一樣的,那就是改一個(gè)就可以使很多地方同時(shí)生效,避免了重復的工作。

按照慣例:

CC變量指定了使用的編譯器
CFLAGS變量包含了所需的編譯選項
INCLUDE是尋找頭文件的路徑
LFLAGS是加載外部庫時(shí)的指定選項。
TARGET變量代表最終要生成的可執行程序

下面的內容就是關(guān)鍵了,我們將利用一些GNU make內置的函數與推導規則來(lái)完成我們的目標。

首先的任務(wù)是自動(dòng)獲得當前目錄下所有的源文件,好讓我們新添文件后不必再修改Makefile。
完成這個(gè)功能的是這行代碼

SOUCE_FILES = $(wildcard *.c)

wildcard是GNU make程序預定義的一個(gè)函數,作用便是獲取匹配模式文件名,原型為$(wildcardPATTERN)。它的詳細說(shuō)明可以看這里。簡(jiǎn)單來(lái)說(shuō)wildcard函數的參數只有一個(gè),就是函數名之后的文件名模式,這里的模式使用shell可識別的通配符,包括“?”(單字符)、“*”(多字符)等?,F在我們的需求是獲取當前目錄下的所有.c文件,模式自然是*.c。

按照最基本的依賴(lài)規則,生成TARGET文件依賴(lài)于一系列的.o文件,那么如何獲得這些.o文件的列表呢?答案是使用patsubst模式替換函數函數:

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

模式替換函數patsubst函數原型為$(patsubstPATTERN,REPLACEMENT,TEXT),相比wildcard,它要復雜一些,顧名思義,三個(gè)參數依次代表了匹配模式,替換規則,替換目標字符串。在這里,我們需要把所有.c替換成.o,所以寫(xiě)成上面的樣子就可以了。

現在c源文件列表和obj文件列表都有了,下一步就該為每個(gè)源文件編寫(xiě)規則了。

其實(shí)很多源文件的編譯規則都是一樣的,就像最開(kāi)始那個(gè)Makefile中那樣

代碼
foo.o:foo.c
    gcc -c foo.c
bar.o:foo.c
    gcc -c bar.c



僅僅是文件名不同而已,因此就給了我們提取模式的某種可能性。我在一個(gè)關(guān)于winsock的makefile中找到了答案:

代碼
.SUFFIXES: .c .o
.c.o:
        $(CC) -c $(CFLAGS) $< -o $@



這個(gè)規則利用了GNU make的后綴規則。
在這里,當定義了一個(gè)目標是“.c.o”的規則時(shí)。它的含義是所有“.o”文件的依賴(lài)文件是對應的“.c”文件。因此在這條規則下,foo.c將被自動(dòng)編譯成foo,bar.c被編譯成bar。
而特殊目標.SUFFIXES這句的作用是: 在默認后綴的基礎上,增加了可以作為后綴的關(guān)鍵字符串。
其實(shí).c.o是肯定在默認識別的規則中的,不過(guò)為了保險起見(jiàn),還是顯式地聲明一下比較好。

可以看到,這個(gè)規則十分的晦澀,反正我第一眼真是沒(méi)看明白。因此,新版本的GNU make已經(jīng)使用模式規則替代了后綴規則。

同樣的功能,利用模式規則實(shí)現如下:

代碼
%.o : %.c
        $(CC) -c $(CFLAGS) $< -o $@



這樣看起來(lái)便清晰多了。如果考慮到頭文件,完美的寫(xiě)法應該是這樣的:

代碼
%.o : %.c %.h
        $(CC) -c $(CFLAGS) $< -o $@



在上面的規則中,還使用了一些GNU make的自動(dòng)化變量,他們的含義分別如下:

$@ --- 目標文件
$< --- 第一個(gè)依賴(lài)文件
$^ --- 所有的依賴(lài)文件

更多的自動(dòng)化變量可以參見(jiàn)這里

最后的規則就是生成可執行文件了,很普通,不再贅述。

為了方便調試,可以在makefile中定義一些偽目標。(偽目標的解釋和意義可以看這里
一般調試用的makefile中都會(huì )有兩個(gè)偽目標,一個(gè)clean,一個(gè)debug

對于clean,手冊里說(shuō):“make存在一個(gè)內嵌隱含變量“RM”,它被定義為:“RM = rm–f”。因此在書(shū)寫(xiě)“clean”規則的命令行時(shí)可以使用變量“$(RM)”來(lái)代替“rm”,這樣可以免出現一些不必要的麻煩!”雖然不知道“必要的麻煩”是什么,但是小心不為過(guò),照著(zhù)手冊做比較好。

對于debug,和正常模式不同的就是添加了一些編譯選項,修改CFLAGS的內容就可以了。但目前還沒(méi)搞明白怎么動(dòng)態(tài)地在makefile里修改變量的內容。這個(gè)問(wèn)題以后再說(shuō)。

三、在多文件夾情況使用makefile組織代碼

上一段中給出的makefile,對于一般的小程序已經(jīng)足矣,但是如果代碼文件越來(lái)越多,最后不得不放到幾個(gè)文件夾中,這時(shí)又該怎么辦?
比如說(shuō)我們準備把bar.c中的函數整理成了一個(gè)函數庫libbar放在主程序文件夾中的子文件夾libbar中,這時(shí)該如何利用makefile來(lái)組織這些文件?
比較好的辦法是在libbar文件夾中放置一個(gè)獨立的子makefile,然后在主makefile里調用它。

libbar/Makefile:

代碼
CC = gcc
CFLAGS = -Wall -O
AR = ar
AFLAGS = -r
INCLUDE = -I/usr/include/mysql
LFLAGS = -L/usr/lib/mysql -lmysqlclient -lpthread

TARGET = libbar.a

SOUCE_FILES = $(wildcard *.c)
OBJS = $(patsubst %.c,%.o,$(SOUCE_FILES))

%.o : %.c %.h
    $(CC) -c $(CFLAGS) $< -o $@

%.o : %.c
    $(CC) -c $(CFLAGS) $< -o $@

$(TARGET): $(OBJS)
    $(AR) $(AFLAGS) $(TARGET) $(OBJS)

.PHONY:clean
clean:
    $(RM) $(TARGET) $(OBJS)




Makefile:

代碼
CC = gcc
CFLAGS = -Wall -O
INCLUDE = -I./libbar
LFLAGS = -L./libbar -lbar

SHELL = /bin/bash
SUBDIRS = libbar

TARGET = foobar

SOUCE_FILES = $(wildcard *.c)
OBJS = $(patsubst %.c,%.o,$(SOUCE_FILES))

%.o : %.c %.h
    $(CC) -c $(CFLAGS) $(INCLUDE) $< -o $@

$(TARGET): $(OBJS) libs
    $(CC) $(OBJS) -o $@ $(INCLUDE) $(LFLAGS)

libs:
    @ for subdir in $(SUBDIRS); do /
        (cd $$subdir && $(MAKE)); /
    done

.PHONY:clean
clean:
    $(RM) $(TARGET) $(OBJS)
    @ for subdir in $(SUBDIRS); do /
        (cd $$subdir && $(MAKE) clean); /
    done




在主makefile中使用了shell的for語(yǔ)句,循環(huán)取出SUBDIRS中的子文件夾名,然后進(jìn)入子文件夾執行make,然后返回。如果在子makefile中出錯,編譯過(guò)程將終止。

四、編譯多個(gè)目標

不知你有沒(méi)有遇到過(guò)這樣的情況,那就是需要從很多的代碼,生成很多的可執行文件。

例如編寫(xiě)了一堆小工具,而每個(gè)工具只有一個(gè)源文件,用foo.c生成foo,用bar.c生成bar。

一個(gè)一個(gè)編譯肯定不現實(shí),這時(shí)該怎么做?讓我們用GNU make來(lái)解決吧!

仔細閱讀手冊,發(fā)現GNU make中的靜態(tài)模式,正好可以滿(mǎn)足這個(gè)要求。

方便閱讀,直接將手冊中關(guān)于靜態(tài)模式的解釋粘貼如下:

引用
靜態(tài)模式規則是這樣一個(gè)規則:規則存在多個(gè)目標,并且不同的目標可以根據目標文件的名字來(lái)自動(dòng)構造出依賴(lài)文件。靜態(tài)模式規則比多目標規則更通用,它不需要多個(gè)目標具有相同的依賴(lài)。但是靜態(tài)模式規則中的依賴(lài)文件必須是相類(lèi)似的而不是完全相同的。

靜態(tài)模式規則的基本語(yǔ)法:

TARGETS ...: TARGET-PATTERN: PREREQ-PATTERNS ...

COMMANDS

...

“TAGETS”列出了此規則的一系列目標文件。像普通規則的目標一樣可以包含通配符。

“TAGET-PATTERN”和“PREREQ-PATTERNS”說(shuō)明了如何為每一個(gè)目標文件生成依賴(lài)文件。從目標模式(TAGET-PATTERN)的目標名字中抽取一部分字符串(稱(chēng)為“莖”)。使用“莖”替代依賴(lài)模式(PREREQ-PATTERNS)中的相應部分來(lái)產(chǎn)生對應目標的依賴(lài)文件。




對應我們的需求,應該是用符合%.c模式的文件,生成文件名為%的可執行文件,同時(shí)利用自動(dòng)化變量,構造規則如下:

代碼
$(TARGET_FILES): % : %.cpp
    g++ $(CFLAGS) $< -o $@



其中$(TARGET_FILES)為最終的可執行文件名,可以用wildcard配合patsubs函數獲得。

因為$(TARGET_FILES)不止一個(gè),所以直接寫(xiě)這個(gè)命令的結果是只會(huì )編譯出一個(gè)可執行文件,即第目標文件列表中的一個(gè)文件,要想成功編譯出所有的,還需要偽目標的幫忙。

完整的makefile如下:

代碼
CC = gcc
CFLAGS = -Wall -O

SOUCE_FILES=$(wildcard *.c)
TARGET_FILES=$(patsubst %.c,%,$(SOUCE_FILES))

.PHONY:all

all:$(TARGET_FILES)

$(TARGET_FILES): % : %.c
    g++ $(CFLAGS) $< -o $@

clean:
    $(RM) $(TARGET_FILES)



五:收工

如果發(fā)現有什么錯誤的話(huà),歡迎指出~~~ (IMG:http://acm.hrbeu.edu.cn/forums/style_emoticons/default/C72B3.gif)                

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
GUN make 工具
一個(gè)通用的Makefile模板
Makefile的簡(jiǎn)要介紹
多文件工程的編譯-Makefile的簡(jiǎn)便寫(xiě)法
GNU make 指南 GCC、GDB & Makefile Qt中文論壇
GNU make中文手冊-第九章:執行make
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久