makefile檔案及VC++自帶的Nmake

333111444發表於2008-12-01

:轉載時請以超連結形式標明文章原始出處和作者資訊及本宣告http://cyinger-smiling.blogbus.com/logs/16826664.html

1.Dos下執行VC++自帶的Nmake,設定路徑

●C/C++ 編譯器需要的環境變數設定

古早以來,PC 上的 C 編譯器,就需要兩個環境變數:

LIB:這個環境變數告訴編譯器說,必要的 libraries 在哪裡(哪個磁碟目錄下)
INCLUDE
:告訴編譯器說,必要的 header files 在哪裡(哪個磁碟目錄下)

另外,為了讓我們能夠在任何 working directory 都叫得到編譯器,當然我們必須設定 PATH

從古早以來,一直到現在,C/C++ 編譯器都需要這三個環境變數。


Visual C++ 為例

Visual C++ 為例,如果安裝後的檔案佈局如下:

C:MSDEVVC98BIN : 這裡放有編譯器 CL.EXE
C:MSDEVVC98INCLUDE :
這裡放有 C/C++ header files
C:MSDEVVC98LIB :
這裡放有 C/C++ standard libraries

[@more@]

那麼你可以寫一個批次檔如下:

set PATH=C:MSDEVVC98BIN;C:MSDEVCOMMONMSDEV98BIN
set INCLUDE=C:MSDEVVC98INCLUDE
set LIB=C:MSDEVVC98LIB

之所以需要另外設定 PATH=C:MSDEVCOMMONMSDEV98BIN,是因為編譯器 CL.EXE 執行時需要 MSPDB60.DLL,而它被安裝於 C:MSDEVCOMMONMSDEV98BIN 之中。

如果你寫的程式不只是單純的 C/C++ 程式,還用到了 MFC,一樣可以在 console mode 下編譯,這時候你的環境變數應該如此設定:

set PATH=C:MSDEVVC98BIN;C:MSDEVCOMMONMSDEV98BIN
set INCLUDE=C:MSDEVVC98INCLUDE;C:MSDEVVC98MFCINCLUDE
set LIB=C:MSDEVVC98LIB;C:MSDEVVC98MFCLIB

多指定了 MFCINCLUDE MFCLIB,就可以讓編譯器和聯結器找到 MFC header files libraries。如果你還需要用到 ATL,就得在 INCLUDE 環境變數中再加上 C:MSDEVVC98ATLINCLUDE

=========================================

我的VC++安裝在D:Program FilesMicrosoft Visual Studio下,所以改寫批次檔如下:

set PATH=D:Program FilesMicrosoft Visual StudioVC98Bin;D:Program FilesMicrosoft Visual StudioCommonMSDev98Bin
set INCLUDE=D:Program FilesMicrosoft Visual StudioVC98Include;D:Program FilesMicrosoft Visual StudioVC98MFCInclude
set LIB=D:Program FilesMicrosoft Visual StudioVC98Lib;D:Program FilesMicrosoft Visual StudioVC98MFCLib

然後執行cmd,將以上設定複製貼上到滑鼠閃爍處。如果想要確認路徑更改正確,可以鍵入set命令檢視。

注:這樣的環境變數修改,僅對本次命令列視窗有效,因為它是一個虛擬裝置。如果想要每次進入時,不做這個工作。可以執行VCVARS32.BAT然後設定你的環境變數。為了不影響VC++的原本設定方便整合環境的使用,我並沒有實際操作,一個簡單的複製貼上也不見得麻煩。另外還可以在我的電腦-屬性-高階-環境變數裡直接修改,這個修改也是永久性的。到這裡,路徑就設定好了。下面試操作一下:

我在F:盤儲存了一個test.cpp檔案作為測試檔案。檔案內容如下:

=======================================
#include
void main()
{
cout<}
=========================================

使用cd命令把當前命令列視窗路徑切換到F:>,然後執行cl test.cpp命令,在F:盤路徑下生成了兩個檔案,test.objtest.exe。然後再執行test.exe,就可以看到結果了(輸出hello)。

下面再舉一個例子,也就是下面要學習的makefile檔案。測試檔名為mypath.mak(你可以任意取名),依舊儲存在當前路徑下。

===========================
all:
@echo $(PATH)
==========================

執行命令nmake mypath.mak,你可以看到輸出結果為你剛才設定過的路徑(我的結果是D:Program FilesMicrosoft Visual StudioVC98Bin;D:Program FilesMicrosoft Visual StudioCommonMSDev98Bin)。

2.產生自己的makefile檔案

下面是我在網上找到的一個簡單的例子及其解說(

==================================下面來看一個簡單的例子(以下內容均以Win32平臺為例):
檔名:makefile
1. # makefile
2. # this is a example of make file
3. all:a1 a2
4. @echo this is all!
5. a1:
6. @echo this is a1!
7. a2:
8. @echo this is a2!

執行make後,結果如下:
this is a1!
this is a2!
this is all!

現在讓我們來分析一下這個簡單的規則檔案。

12行不用說,一眼就可以看出是註釋。在Make規則檔案中,註釋是以“#”開始,是行註釋,和C++中的“//”功能一樣。不過你可不能把它放到其它的語句之後,否則就錯了。第3行就是規則開始了!all:a1 a2一行中,規則的名字就是all,它通常是目標名(target)。一條規則可以有不止一個名字,像這一行,你也可以把它寫成all all2:a1 a2。這時,規則就有了兩個名稱—allall2。當然,還可以有更多,都看你自己。後面的57兩行也分別是兩條規則的起始。在“:”之後的,就是依賴項。在這一行裡,依賴項有兩個,分別是a1a2。這些依賴項可以是其它的規則名(目標名),也可以是檔名。依賴和目標之間的關係就是依賴關係。一條規則中,可以有零個(像後面的兩條規則)、一個或多個依賴。第4@echo this is all!是命令列。它是執行all規則時要執行的命令。要注意的是,一條規則內的命令要以tab為一行的起始,以表示命令是屬於一個規則。一條規則也可以有多條命令,每條命令佔一行(要以tab開頭)。至於可以使用哪些命令,這完全取決於你使用的OSSHELL

當執行make時,它會找到第一條規則。然後,make就會檢查依賴和目標之間的關係。如果目標比依賴舊,就執行規則,以更新目標。執行完規則就結束。如何判定目標和依賴的新舊呢?如果目標(檔案)不存在,目標的時間就為0;如果目標(檔案存在),目標的時間就為檔案的修改時間。如果依賴項是一條規則,就執行依賴的規則(這裡是一個遞迴),然後依賴的時間就是當前最新時間;如果是一個存在的檔案,就為檔案的修改時間,否則就報錯。之後,就可以比較目標和依賴之間的關係。不過,有一點特殊的是,在沒有依賴項時,依賴的時間為1

在這個例子中,make先找到規則“all”,發現目標不存在,所以目標的時間為0;然後在查詢依賴“a1”,結果“a1”不存在;於是,執行規則“a1”“a1”不存在,所以它的時間為0,而“a1”沒有依賴,它的依賴時間為11>0,所以,執行規則“a1”。然後返回規則“all”,再檢查依賴“a2”“a2”執行過程同“a1”。這時,“all”的目標時間為0,依賴時間為最新時間。於是,執行規則“all”的命令。

當然,大家也可以指定一條規則讓make執行,比如:make a1這個命令就是告訴make程式不去找第一條規則,而是規則“a1”來執行。並且我們還可以一次執行多條規則,比如:執行make a1 a2就會連續執行“a1”“a2”兩條規則。

OK,雖然講得很混亂,但也費了我半天的力氣。大家應該有一點了解make規則的執行過程了吧。
==============================================

依賴的基本寫法如下:
Target
Dependence
Command

==============================================
Target
可以是檔名。Dependence可以是其它的target名或檔名。Command就是作業系統所執行的命令列。
變數
一個make規則檔案有這些內容就已經基本可以工作了。可是,當我們在編譯一個程式時,如果有些內容要反覆用到,每次都要寫一長串的話,是很麻煩的。於是,make就引入了宏這個概念(其實也可以看成簡單的指令碼語言)。
宏變數的定義如下:
var1 = this is a macro demo!
var1
就是變數名,它的值就是“this is a macro demo!”
如果我們要使用這個變數的值,那只有透過$這個運算子才行—$var1)代表的就是“this is a macro demo!”
如下makefile
1. var1 = this is a macro demo!
2. all:
3. @echo $(var1)
結果輸出:
this is a macro demo!
使用者在執行命令列時也可以定義宏變數。其形式如下:
make all var1=”this is a test”
執行結果為:
this is a test
我們不僅可以使用自定義變數,還可以透過這種方式使用系統環境變數。這樣可以大大方便我們建議靈活的規則。如下makefile
1. all:
2. @echo $(WINDIR)
執行結果為:
C:WINDOWS
(注意:makefile中的變數是大小寫敏感的)
==========================================

下面介紹makefile檔案的一些內建變數:

==========================================
$@
代表規則中的目標名(也就是規則名)。
$<
代表規則中的依賴專案。注意,它只代表規則所有依賴專案中的第一項!
其它還有:
$^
代表規則中所有的依賴專案。
$?
代表規則中時間新於目標的依賴專案。
不僅如此,還可以給這些特殊的變數加一些限制。
如:
在規則
debug/out.exe : out.obj
中,$@代表debug/out.exe,而$(@D)代表目錄名debug$(@F)代表檔名out.exe。其它如$($($(^D)$(^F)$(?D)$(?F)與此類似。
=============================================

舉個例子說明,下面是原始makefile檔案內容:

==============================================
myprog : foo.o bar.o
gcc foo.o bar.o -o myprog

foo.o : foo.c foo.h bar.h
gcc -c foo.c -o foo.o

bar.o : bar.c bar.h
gcc -c bar.c -o bar.o
==============================================

用變數代替後的檔案內容:

==============================================
OBJS = foo.o bar.o
CC = gcc
CFLAGS = -Wall -O -g

myprog : $(OBJS)
$(CC) $^ -o $@

foo.o : foo.c foo.h bar.h
$(CC) $(CFLAGS) -c $
bar.o : bar.c bar.h
$(CC) $(CFLAGS) -c $

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12058779/viewspace-1014089/,如需轉載,請註明出處,否則將追究法律責任。

相關文章