日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

开发工具(三)

發(fā)布時間:2024/10/8 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 开发工具(三) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

內(nèi)建規(guī)則

到目前為止,我們已經(jīng)在makefile文件中確切的指定了如何執(zhí)行過程的每一步。事實上,makefile有大量的內(nèi)建規(guī)則從而可以很大程度的簡化makefile文件,特別是當(dāng)我們有大量源文件的時候。下面我們創(chuàng)建foo.c,這是一個傳統(tǒng)的Hello World程序。

#include <stdlib.h>
#include <stdio.h>
int main()
{
??? printf(“Hello World/n”);
??? exit(EXIT_SUCCESS);
}

不指定makefile文件,我們嘗試使用make來編譯。

$ make foo
cc???? foo.c -o foo
$

正如我們所看到的,make知道如何調(diào)用編譯器,盡管在這種情況下,他選擇cc而不是gcc(在Linux下這可以正常工作,因為通常cc鏈接到gcc)。有時,這些內(nèi)建規(guī)則是推斷規(guī)則(inference rules)。默認(rèn)的規(guī)則使用宏,所以通過為這些宏指定一個新值,我們可以改變默認(rèn)的行為。

$ rm foo
$ make CC=gcc CFLAGS=”-Wall -g” foo
gcc -Wall -g??? foo.c?? -o foo
$

我們可以使用-p選項使得make打印出其內(nèi)建規(guī)則。內(nèi)建規(guī)則太多而不能在這里全部列出,但是下面是GNU版本的make的make -p的簡短輸出,演示了其中的部分規(guī)則:

OUTPUT_OPTION = -o $@
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
%.o: %.c
# commands to execute (built-in):
??????? $(COMPILE.c) $(OUTPUT_OPTION) $<

我們現(xiàn)在可以通過指定構(gòu)建目標(biāo)文件的規(guī)則使用這些內(nèi)建規(guī)則來簡化我們的makefile文件,所以makefile文件的相關(guān)部分簡化為:

main.o: main.c a.h
2.o: 2.c a.h b.h
3.o: 3.c b.h c.h

后綴與模式規(guī)則

我們所看到的內(nèi)建規(guī)則使用后綴進(jìn)行工作(與Windows和MS-DOS的文件名擴(kuò)展相類似),所以當(dāng)指定一個帶有擴(kuò)展名的文件時,make知道應(yīng)使用哪條規(guī)則來創(chuàng)建帶有不同擴(kuò)展名的文件。在這里最通常的規(guī)則就是由以.c為結(jié)尾的文件創(chuàng)建以.o為結(jié)尾的文件。這個規(guī)則就是使用編譯器編譯文件,但是并不鏈接源文件。

有時我們需要能夠創(chuàng)建新規(guī)則。程序開發(fā)作者過去在一些源文件上需要使用不同的編譯器進(jìn)行編譯:兩個在MS-DOS下,以及Linux下的gcc。要滿足MS-DOS編譯器的要求,C++源文件而不是C源文件,需要以.cpp為后綴進(jìn)行命名。不幸的是,現(xiàn)在Linux下使用的make版本并沒有編譯.cpp文件的內(nèi)建規(guī)則。(他確實具有一個在Unix下更為常見的.cc的規(guī)則)

所以或者是為每一個單獨的文件指定一個規(guī)則,或者是我們需要教給make一個新的規(guī)則來由以.cpp為擴(kuò)展名的文件創(chuàng)建目標(biāo)文件。假如我們在這個工程中有大量的源文件,指定一個新規(guī)則節(jié)省了大量的輸入工作,并且使得在工程中添加一個新源文件更為容易。

要添加一個新的后綴規(guī)則,我們首先在makefile文件中添加一行,告訴make新的后綴;然后我們就可以使用這個新的后綴來編寫一條規(guī)則。make使用下面的語法樣式來定義一條通用的規(guī)則來由具有舊后綴的文件創(chuàng)建具有新后綴的文件:

.<old_suffix>.<new_suffix>:

下面是我們的makefile文件中一條新的通用規(guī)則的代碼片段,用于將.cpp文件轉(zhuǎn)換為.o文件:

.SUFFIXES:????? .cpp
.cpp.o:
?? $(CC) -xc++ $(CFLAGS) -I$(INCLUDE) -c $<

特殊依賴.cpp.o:告訴make接下來的規(guī)則用于將以.cpp為后綴的文件轉(zhuǎn)換為以.o為后綴的文件。當(dāng)我們編寫這個依賴時,我們使用特殊的宏名,因為我們并不知道我們將要轉(zhuǎn)換的實際文件名。要理解這條規(guī)則,我們只需要簡單的回憶起$<會擴(kuò)展為起始文件名(帶有舊后綴)即可。注意,我們只是告訴make如何由.cpp文件得到.o文件;make已經(jīng)知道如何由一個目標(biāo)文件獲得二進(jìn)制可執(zhí)行文件。

當(dāng)我們調(diào)用make時,他使用我們的新規(guī)則由bar.cpp獲得bar.o,然后使用其內(nèi)建規(guī)則由.o獲得一個可執(zhí)行文件。-xc++標(biāo)記用于告訴gcc這是一個C++源文件。

在近些時候,make知道如何處理帶有.cpp擴(kuò)展名的C++源文件,但是當(dāng)將一種文件類型轉(zhuǎn)換為另一種文件類型時,這個技術(shù)是十分有用的。

更為舊的make版本包含一個對應(yīng)的語法用來達(dá)到同樣的效果,而且更好。例如,匹配規(guī)則使用通配符語法來匹配文件,而不是僅依賴于文件擴(kuò)展名。

對于上面例子中與.cpp規(guī)則等同的模式規(guī)則如下:

%.cpp: %o
?? $(CC) -xc++ $(CFLAGS) -I$(INCLUDE) -c $<

使用make管理庫

當(dāng)我們正處理一個大型工程時,使用庫來管理多個編譯產(chǎn)品通常是比較方便的。庫是文件,通常以.a為擴(kuò)展名,包含一個目標(biāo)文件的集合。make命令有一個處理庫的特殊語法,從而使得他們更易于管理。

這個語法就是lib (file.o),這就意味著目標(biāo)文件file.o存儲在庫lib.a中。make具有一個內(nèi)建的規(guī)則用于管理庫,通常如下面的樣子:

.c.a:
?? $(CC) -c $(CFLAGS) $<
?? $(AR) $(ARFLAGS) $@ $*.o

宏$(AR)與$(ARFLAGS)通常分別默認(rèn)為命令ar與選項rv。這個簡短的語法告訴make由一個.c文件得到.a庫,他必須執(zhí)行兩條規(guī)則:

第一條規(guī)則是他必須編譯源文件并且生成一個目標(biāo)文件
第二條規(guī)則是使用ar命令來修改庫,添加新的目標(biāo)文件

所以,如果我們有一個庫fud,包含文件bas.o,在第一條規(guī)則中$<被替換為bas.c。在第二條規(guī)則中,$@被替換為庫fud.a,而$*被替換為bas。

試驗--管理庫

實際上,管理庫的規(guī)則的使用是相當(dāng)簡單的。下面我們修改我們的程序,從而文件2.o與3.o保存在一個名為mylib.a的庫中。我們的makefile文件需要一些小的修改,所以Makefile5如下所示:

all: myapp
# Which compiler
CC = gcc
# Where to install
INSTDIR = /usr/local/bin
# Where are include files kept
INCLUDE = .
# Options for development
CFLAGS = -g -Wall -ansi
# Options for release
# CFLAGS = -O -Wall -ansi
# Local Libraries
MYLIB = mylib.a
myapp: main.o $(MYLIB)
?? $(CC) -o myapp main.o $(MYLIB)
$(MYLIB): $(MYLIB)(2.o) $(MYLIB)(3.o)
main.o: main.c a.h
2.o: 2.c a.h b.h
3.o: 3.c b.h c.h
clean:
?? -rm main.o 2.o 3.o $(MYLIB)
install: myapp
?? @if [ -d $(INSTDIR) ]; /
??? then /
????? cp myapp $(INSTDIR);/
????? chmod a+x $(INSTDIR)/myapp;/
????? chmod og-w $(INSTDIR)/myapp;/
????? echo “Installed in $(INSTDIR)”;/
?? else /
????? echo “Sorry, $(INSTDIR) does not exist”;/
?? fi

在這里需要注意我們是如何使用默認(rèn)規(guī)則來完成大多數(shù)工作的。現(xiàn)在讓我們來測試我們的新版本makefile文件。

$ rm -f myapp *.o mylib.a
$ make -f Makefile5
gcc -g -Wall -ansi?? -c -o main.o main.c
gcc -g -Wall -ansi?? -c -o 2.o 2.c
ar rv mylib.a 2.o
a - 2.o
gcc -g -Wall -ansi?? -c -o 3.o 3.c
ar rv mylib.a 3.o
a - 3.o
gcc -o myapp main.o mylib.a
$ touch c.h
$ make -f Makefile5
gcc -g -Wall -ansi?? -c -o 3.o 3.c
ar rv mylib.a 3.o
r - 3.o
gcc -o myapp main.o mylib.a
$

工作原理

我們首先刪除所有的目標(biāo)文件以及庫,并且允許make構(gòu)建myapp,他通過編譯并且在使用庫鏈接main.o之前創(chuàng)建庫,從而創(chuàng)建myapp。然后我們測試3.o的測試規(guī)則,他會通知make,如果c.h發(fā)生變動,那么3.c必須進(jìn)行重新編譯。他會正確的完成這些工作,在重新鏈接之前會編譯3.c并且更新庫,從而創(chuàng)建一個新的可執(zhí)行文件myapp。

高級主題:Makefile與子目標(biāo)

如果我們編寫一個大工程,有時將組成庫的文件由主文件分離并且存儲在一個子目錄中是十分方便的。使用make可以兩種方法來完成這個任務(wù)。

首先,我們在此子目錄可以有第二個makefile文件來編譯文件,將其存儲在一個庫中,然后將庫拷貝到上一層主目錄。在高層目錄中的主makefile文件然后有一條規(guī)則用于構(gòu)建這個庫,其調(diào)用第二個makefile文件的語法如下:

mylib.a:
?? (cd mylibdirectory;$(MAKE))

這就是說我們必須總是嘗試構(gòu)建mylib.a。當(dāng)make調(diào)用這條規(guī)則用于構(gòu)建庫時,他會進(jìn)入子目錄mylibdirectory,然后調(diào)用一個新的make命令來管理庫。因為這會調(diào)用一個新的shell,使用makefile的程序并不會執(zhí)行cd命令。然而,所調(diào)用的用于執(zhí)行規(guī)則構(gòu)建庫的shell是在一個不同的目錄中。括號可以保證他們都會在一個單獨的shell中進(jìn)行處理。

第二個方法是在一個單獨的makefile文件中使用一些額外的宏。這些額外的宏是通過在我們已經(jīng)討論過的這些宏的基礎(chǔ)上添加D(對目錄而言)或是F(就文件而言)來生成的。然后我們可以用下面的規(guī)則來覆蓋內(nèi)建的.c.o前綴規(guī)則:

.c.o:
???? $(CC) $(CFLAGS) -c $(@D)/$(<F) -o $(@D)/$(@F)

來在子目錄中編譯文件并且將目標(biāo)文件留下子目錄中。然后我們可以用如下的依賴與規(guī)則來更新當(dāng)前目錄中的庫:

mylib.a:?? mydir/2.o mydir/3.o
???? ar -rv mylib.a $?

我們需要決定在我們自己的工程中我們更喜歡哪種方法。許多工程只是簡單的避免具有子目錄,但是這樣會導(dǎo)致在源碼目錄中有大量的文件。正如我們在前面的概覽中所看到的,我們在子目錄中使用make只是簡單的增加了復(fù)雜性。

GNU make與gcc

如果我們正使用GNU make與GNU gcc編譯器,還有兩個有趣的選項:

第一個就是make的-jN("jobs")選項。這會使用make同時執(zhí)行N條命令。此時make可以同時調(diào)用多條規(guī)則,獨立的編譯工程的不同部分。依據(jù)于我們的系統(tǒng)配置,這對于我們重新編譯的時候是一個巨大的改進(jìn)。如果我們有多個源文件,嘗試這個選項是很有價值的。通常而言,小的數(shù)字,例如-j3,是一個好的起點。如果我們與其他用戶共享我們的機(jī)器,那么要小心使用這個選項。其他用戶也許不會喜歡每次編譯時我們啟動大量的進(jìn)程數(shù)。

另一個有用的選項就是gcc的-MM選項。這會產(chǎn)生一個適合于make的依賴列表。在一個具有大量源碼文件的工程中,每一個文件都會包含不同的頭文件組合,要正確的獲得依賴關(guān)系是非常困難的,但是卻是十分重要的。如果我們使用每一個源文件依賴于每一個頭文件,有時我們就會編譯不必須的文件。另一方面,如果我們忽略一些依賴,問題就會更為嚴(yán)重,因為我們會沒有編譯那些需要重新編譯的文件。

試驗--gcc -MM

下面我們使用gcc的-MM選項來為我們的例子工程生成一個依賴列表:

$ gcc -MM main.c 2.c 3.c
main.o: main.c a.h
2.o: 2.c a.h b.h
3.o: 3.c b.h c.h
$

工作原理

gcc編譯只是簡單的以適于插入一個makefile文件中的形式輸出所需要依賴行。我們所需要做的就是將輸出保存到一個臨時文件中,然后將其插入makefile文件中,從而得到一個完美的依賴規(guī)則集。如果我們有一個gcc的輸出拷貝,我們的依賴就沒有出錯的理由。

如果我們對于makefile文件十分自信,我們可以嘗試使用makedepend工具,這些執(zhí)行與-MM選項類似的功能,但是會將依賴實際添加到指定的makefile文件的尾部。

在我們離開makefile話題之前,也許很值得指出我們并不是只能限制自己使用makefile來編譯代碼或是創(chuàng)建庫。我們可以使用他們來自動化任何任務(wù),例如,有一個序列命令可以使得我們由一些輸入文件得到一個輸出文件。通常"非編譯器"用戶也許適用于調(diào)用awk或是sed來處理一些文件,或是生成手冊頁。我們可以自動化任何文件處理,只要是make由文件的日期與時間信息的修改可以處理的。

轉(zhuǎn)載于:https://www.cnblogs.com/dyllove98/archive/2009/03/14/2461963.html

總結(jié)

以上是生活随笔為你收集整理的开发工具(三)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。