小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Windows平臺(tái)下Makefile學(xué)習(xí)筆記(一)

 bira 2013-11-12

 決心學(xué)習(xí)Makefile,一方面是為了解決編譯開源代碼時(shí)需要跨編譯平臺(tái)的問題(發(fā)現(xiàn)一些開源代碼已經(jīng)在使用VS2010開發(fā),但我還沒安裝VS2010,我想在VS2008下編譯這些代碼);另一方面源碼在服務(wù)器端編譯的話,使用IDE的方式編譯還是不太方便。

 

       本文主要分為三部分:第一部分講述namke工具使用makefile的用法;第二部分講述makefile的主要語法;第三部分講述自己動(dòng)手實(shí)踐學(xué)習(xí)寫makefile文件。第四部分是編寫一個(gè)工具將vc工程文件轉(zhuǎn)化為Makefile文件。

 

       首先要清楚的是在VS環(huán)境下使用Makefile的工具是nmake。因此我們需要弄明白nmake的使用Makefile文件常用命名行用法。nmake使用Makefile文件常用命名行用法是:


     

[plain] view plaincopy
  1. namke /f  makefile /x stderrfile  [macrodefs] [targets]  
 


其中makefile為makefile文件,/x stderrfile為可選參數(shù),即把namke錯(cuò)誤存儲(chǔ)到文件stderrfile。

 

      接著介紹makefile的主要語法。makefile的注釋以#開頭,如:

[plain] view plaincopy
  1. # this is my first makefile  


Makefile的一個(gè)重要組成部分是宏。Makefile中的宏和C語言的中宏類似,其實(shí)質(zhì)就是字符串替換。其語法很簡(jiǎn)單,如下:

 

macro name =  macro value

 

直譯就是宏名 =  宏的值

 

      VS預(yù)定義了很多宏,如OUTDIR,你可以在你的Makefile重新定義這些宏以覆蓋原來的值。

 

       宏可以使用環(huán)境變量,如你的系統(tǒng)有一個(gè)OPEN_SOURCE的環(huán)境變量,然后你可以這樣定義宏:

     THIRD_PARTY  =  $(OPEN_SOURCE)

 

      宏的引用用法是 $(宏名)。

 

接著介紹Makefile的第二個(gè)重要組成部分預(yù)處理指令。Makefile的預(yù)處理指令和C語言的預(yù)處理指令類似,其常用指令如下:

!ERROR string      ——    顯示錯(cuò)誤“string”, 然后停止執(zhí)行,錯(cuò)誤代碼為U1050

!MESSAGE string  ——   顯示字符串,這個(gè)一般用于信息顯示C語言的#pragma message

!INCLUDE [<]filename[>] —— 包含makefile。

!IF const ——  如果成立(非零),則處理!F和下一個(gè)!ELSE或!ENDIF之間的語句

還有諸如!IFDEF macroname、!IFNDEF macroname、!ELSE、!ELSEIF、!ELSEIFDEF、!ELSEIFNDEF、!ENDIF和C語言的#if之類的指令的意義是一致的,這里就不一一詳述了。

 

   Makefile的第三個(gè)主要組成部分是描述塊。描述塊的結(jié)構(gòu)如下:

目標(biāo):依賴項(xiàng)

     命令

  

這里略微解釋下什么叫目標(biāo)、依賴項(xiàng)和命令。所謂目標(biāo)就是用戶最終希望得到的結(jié)果,也就是nmake需要生成的結(jié)果。目標(biāo)可以是一個(gè)文件、目錄,也可以什么都不是。如果目標(biāo)不存在或者目標(biāo)的時(shí)間戳(文件的最后修改時(shí)間)比依賴項(xiàng)早,或者目標(biāo)類型不是文件,nmake將運(yùn)行描述塊中的“命令”。

 

依賴項(xiàng)是指在生成目標(biāo)所需要使用到的對(duì)象。一個(gè)目標(biāo)可以有一個(gè)或多個(gè)依賴項(xiàng),也可以沒有依賴項(xiàng)。多個(gè)依賴項(xiàng)以空格分隔。如果指定的依賴項(xiàng)不存在,則在其他描述塊的目標(biāo)中尋找,但首先需要生成這個(gè)目標(biāo)。

 

命令是nmake在生成目標(biāo)時(shí)所調(diào)用的命令。與用戶自己在命令行中執(zhí)行效果是一樣的。

 

在使用namke進(jìn)行程序構(gòu)建時(shí),nmake采用了時(shí)間戳判斷機(jī)制。在生成一個(gè)目標(biāo)時(shí),會(huì)判斷目標(biāo)文件是否存在或目標(biāo)的最后修改時(shí)間是否晚于所有依賴項(xiàng)的最后修改時(shí)間。如果所有依賴項(xiàng)的最后修改時(shí)間都比目標(biāo)的最后修改時(shí)間晚,則說明當(dāng)前的目標(biāo)文件是使用現(xiàn)有的依賴項(xiàng)生成,是最新的,沒有必要再進(jìn)行生成。

   介紹到這里,可能你對(duì)Mdakefile的語法細(xì)節(jié)有了大致的了解,但估計(jì)你對(duì)Makefile的常用文件結(jié)構(gòu)還不了解。如果缺少對(duì)這一層的理解,你還是對(duì)如何編寫Makefile文件一頭霧水。下面介紹一下常用的Makefile文件結(jié)構(gòu)。Makefile文件結(jié)構(gòu)可以是如下的結(jié)構(gòu):

# 宏定義

……


# 描述塊

 

        學(xué)了這么多,我們來實(shí)踐一下。首先我們來一個(gè)簡(jiǎn)單的控制臺(tái)工程——ConsoleTest。一切根據(jù)工程向?qū)Р捎媚J(rèn)設(shè)置即可。然后在main函數(shù)中添加幾句簡(jiǎn)單代碼(這個(gè)用于判斷我們生成的程序是否成功),具體如下:

[plain] view plaincopy
  1. int _tmain(int argc, _TCHAR* argv[])  
  2. {  
  3.     printf("Hello World! \n");  
  4.     getchar();  
  5.     return 0;  
  6. }  



       然后我們?cè)贑onsoleTest文件夾下新建一個(gè)makefile.vc。我們開始正式編寫一個(gè)makefile文件了。這時(shí)我們的大腦可能會(huì)一片空白,雖然你學(xué)了很多makefile語法,但邁出第一步依然是困難,這是正常的反應(yīng)。好吧,讓我們一步步來吧。首先要告訴你makefile的一個(gè)基本原則:以終為始,這個(gè)似乎和我們平時(shí)進(jìn)行的過程式編程的原則相悖。所謂以終為始,就是你通過makefile文件首先告訴編譯器這個(gè)工程是想生成一個(gè)exe還是一個(gè)dll還是一個(gè)靜態(tài)庫(kù)。然后告訴編譯器要生成這個(gè)exe之類需要生成哪些obj文件。在這個(gè)例子中,我們要生成一個(gè)exe,所以我們?cè)趍akefile文件的第一行就是:

[plain] view plaincopy
  1. all:ConsoleTest.exe  



接下來就是編譯器的一般生成過程:編譯加鏈接命令,具體是:

[plain] view plaincopy
  1. # compile  
  2. stdafx.obj: stdafx.cpp  
  3.     cl -c -D_X86=1 -DWIN32 -D_DEBUG -D_CONSOLE -Istdafx.h stdafx.cpp  
  4.      
  5. ConsoleTest.obj: ConsoleTest.cpp stdafx.obj  
  6.     cl -c -D_X86=1 -DWIN32 -D_DEBUG -D_CONSOLE -Istdafx.h ConsoleTest.cpp  
  7.   
  8. # link  
  9. ConsoleTest.exe: ConsoleTest.obj  
  10. link /INCREMENTAL:YES /NOLOGO /subsystem:console /out:ConsoleTest.exe ConsoleTest.obj kernel32.lib  


其中cl語句是VC編譯器的編譯器的命令行編譯,link語句是VC鏈接器的命令行用法,這里只簡(jiǎn)單敘述cl和link的用法。

cl的一些常用選項(xiàng):

-c: 編譯但不鏈接

-D: 定義預(yù)處理器,如-D_X86=1:指定在x86平臺(tái)上編譯,-D_DEBUG:定義預(yù)處理器_DEBUG,

-I:包含的頭文件

cl的最后一個(gè)參數(shù)是所編譯的文件。

 

link的一些常用選項(xiàng):

/INCREMENTAL:是否啟用增量鏈接,YES為啟用,NO為不啟用,

/NOLOGO: 取消顯示啟動(dòng)版權(quán)標(biāo)志

/SUBSYSTEM:指定子系統(tǒng),在PC桌面程序上一般是兩個(gè)選項(xiàng):console(控制臺(tái)程序)和WINDOWS(非控制臺(tái)程序)。

/out: 指定輸出的文件。

link最后的參數(shù)是需要鏈接的obj文件和庫(kù)文件。

 

cl和link的詳細(xì)用法請(qǐng)參考MSDN和參考文獻(xiàn)2《VC命令行編譯C++》。

 

我們看到生成的obj文件和ConsoleTest.exe是放到當(dāng)前的源碼文件夾下。一般我們想把它放到debug文件夾下。那么我們?cè)撛趺醋瞿??這時(shí)就可以用到makefile中的一個(gè)常用部分——宏。我們可以這樣定義一個(gè)宏,然后創(chuàng)建debug文件夾,具體代碼是:

OUTDIR = .\Debug

 

#這里增加了一個(gè)輸出:$(OUTDIR)

[plain] view plaincopy
  1. all: $(OUTDIR) $(OUTDIR)\ConsoleTest.exe  



#假如不存在$(OUTDIR)文件夾,就創(chuàng)建它

[plain] view plaincopy
  1. $(OUTDIR) :  
  2. if not exist "$(OUTDIR)" mkdir $(OUTDIR)  


相應(yīng)地,生成的obj文件和exe文件都需要加上輸出文件的路徑,具體如下:

[plain] view plaincopy
  1. # compile  
  2. $(OUTDIR)\stdafx.obj: stdafx.cpp  
  3.     cl -c -D_X86=1 -DWIN32 -D_DEBUG -D_CONSOLE -Istdafx.h /Fo"$(OUTDIR)\\" /Fd"$(OUTDIR)\\" stdafx.cpp   
  4.      
  5. $(OUTDIR)/ConsoleTest.obj: ConsoleTest.cpp $(OUTDIR)\stdafx.obj  
  6.     cl -c -D_X86=1 -DWIN32 -D_DEBUG -D_CONSOLE -Istdafx.h /Fo"$(OUTDIR)\\" /Fd"$(OUTDIR)\\" ConsoleTest.cpp  
  7.   
  8. # link  
  9. $(OUTDIR)\ConsoleTest.exe: $(OUTDIR)\ConsoleTest.obj  
  10.     link /INCREMENTAL:YES /NOLOGO /subsystem:console /out:$(OUTDIR)\ConsoleTest.exe $(OUTDIR)\ConsoleTest.obj kernel32.lib  


這里cl工具增加了兩個(gè)選項(xiàng)

/Fo:指定obj文件的放置路徑

/Fd:指定pdb文件的放置路徑

 

這里需要值得注意的,Windows平臺(tái)下文件反斜杠應(yīng)該采用\,而不是跨平臺(tái)的/,因?yàn)槲以袿UTDIR = .\Debug寫成OUTDIR = ./Debug,結(jié)果造成if not exist不識(shí)別$(OUTDIR)而造成語法錯(cuò)誤。/在windows平臺(tái)下的makefile中大多地方可以識(shí)別,但在一些地方不能識(shí)別(例如if not exist語句),而\在任何地方都能識(shí)別的。

 

還有就是命令語句必須至少空出一格,而不能頂格寫。如果if not exist"$(OUTDIR)" mkdir $(OUTDIR)頂格,就會(huì)出現(xiàn)錯(cuò)誤:

makefile.vc(5) : fatal error U1034: 語法錯(cuò)誤 : 缺少分隔符

Stop.

 

    除開命令語句,其它語句都應(yīng)該頂格寫。

 

我們繼續(xù)完善這個(gè)makefile。我們想增加一個(gè)清理輸出文件的指令,就是常用的clean指令。我們可以在描述塊all后面加一個(gè)描述塊:clean,clean描述塊的代碼如下:

[plain] view plaincopy
  1. clean:  
  2.        if exist $(OUTDIR) del $(OUTDIR)\*.ilk  
  3.        if exist $(OUTDIR) del $(OUTDIR)\*.obj  
  4.     if exist $(OUTDIR) del $(OUTDIR)\*.exe    


        如果makefile文件中不存在clean這個(gè)描述塊,而你運(yùn)行下面的命令:

nmake /f makefile.vc clean

會(huì)出現(xiàn)下面的錯(cuò)誤提示:

NMAKE : fatal error U1052: 未找到文件“clean”

Stop.

 

       我們繼續(xù)完善這個(gè)makefile。因?yàn)楝F(xiàn)在只能編譯debug版本,我們想用戶能指定編譯debug版本或release版本,用戶只需要輸入“debug”或“release”來指定。我們想到可以設(shè)定一個(gè)宏標(biāo)記來指定,當(dāng)用戶輸入正確時(shí)就編譯相應(yīng)的版本,錯(cuò)誤時(shí)就提示使用方法。同時(shí)我們想到前面提到nmake工具的命令行用法是:

[plain] view plaincopy
  1. namke /f  makefile /x stderrfile  [macrodefs] [targets]  


其中macrodefs就是允許我們定義一些自定義宏來控制編譯輸出的。這次我們可以定義兩個(gè)宏debug和release。具體不再詳述,下面列出代碼:

[plain] view plaincopy
  1. #設(shè)置編譯標(biāo)記,初始化為FALSE  
  2. CFGSET     =  FALSE  
  3.   
  4. #定義debug版本的預(yù)處理器  
  5. CCDEBUG    = -DWIN32 -D_DEBUG -D_CONSOLE  
  6.   
  7. #定義release版本的預(yù)處理器  
  8. CCNODBG    = -DWIN32 -D_NDEBUG -D_CONSOLE  
  9.   
  10. !IFDEF debug  
  11. CC         = $(CCDEBUG)  
  12. OUTDIR = .\Debug  
  13. CFGSET     =  TRUE  
  14. !ELSE IFDEF release  
  15. CC         = $(CCNODBG)  
  16. OUTDIR = .\Release  
  17. CFGSET     =  TRUE  
  18. !ENDIF  
  19.   
  20. # 提示用法  
  21. #  
  22. !IF "$(CFGSET)"== "FALSE"  
  23. !MESSAGE Usage: nmake /f Makefile.vc [<config>] [<target>]        
  24. !MESSAGE  
  25. !MESSAGE where <config> is one of:  
  26. !MESSAGE -  release=1               - build release version  
  27. !MESSAGE -  debug=1                 - build debug version  
  28. !MESSAGE  
  29. !MESSAGE <target> may be:  
  30. !MESSAGE -  clean                 - clear output file  
  31. !MESSAGE  
  32. !MESSAGE  
  33. !ERROR please choose a valid configuration instead"  
  34. !ENDIF  
  35.   
  36.   
  37. #這里增加了一個(gè)輸出:$(OUTDIR)  
  38. all: $(OUTDIR) $(OUTDIR)\ConsoleTest.exe  
  39.   
  40. #假如不存在$(OUTDIR)文件夾,就創(chuàng)建它  
  41. $(OUTDIR) :  
  42.  if not exist "$(OUTDIR)" mkdir $(OUTDIR)  
  43.    
  44. clean:  
  45.        if exist $(OUTDIR) del $(OUTDIR)\*.ilk  
  46.        if exist $(OUTDIR) del $(OUTDIR)\*.obj  
  47.        if exist $(OUTDIR) del $(OUTDIR)\*.exe       
  48.      
  49. # compile  
  50. $(OUTDIR)\stdafx.obj: stdafx.cpp  
  51.     cl -c  $(CC) -Istdafx.h /Fo"$(OUTDIR)\\" /Fd"$(OUTDIR)\\" stdafx.cpp   
  52.      
  53. $(OUTDIR)\ConsoleTest.obj: ConsoleTest.cpp $(OUTDIR)\stdafx.obj  
  54.     cl -c  $(CC) -Istdafx.h /Fo"$(OUTDIR)\\" /Fd"$(OUTDIR)\\" ConsoleTest.cpp  
  55.   
  56. # link  
  57. $(OUTDIR)\ConsoleTest.exe: $(OUTDIR)\ConsoleTest.obj  
  58.     link /machine:x86 /INCREMENTAL:YES /NOLOGO /subsystem:console /out:$(OUTDIR)\ConsoleTest.exe $(OUTDIR)\ConsoleTest.obj kernel32.lib  
  59.       


該makefile的用法是:

[plain] view plaincopy
  1. #編譯debug版本  
  2. nmake /f makefile.vc debug=1  
  3. #編譯release版本  
  4. nmake /f makefile.vc release=1  
  5. #清除debug版本  
  6. nmake /f makefile.vc debug=1 clean  
  7. #清除release版本  
  8. nmake /f makefile.vc release=1 clean  


參考文獻(xiàn):

 

1. MSDN 2008,Microsoft Corporation

2. VC命令行編譯C++

3. 精通Windows API,范文慶、周彬彬、安靖編著

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多