乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

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

       bira 2013-11-12

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

       

             本文主要分為三部分:第一部分講述namke工具使用makefile的用法;第二部分講述makefile的主要語法;第三部分講述自己動手實踐學(xué)習(xí)寫makefile文件。第四部分是編寫一個工具將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錯誤存儲到文件stderrfile。

       

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

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


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

       

      macro name =  macro value

       

      直譯就是宏名 =  宏的值

       

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

       

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

           THIRD_PARTY  =  $(OPEN_SOURCE)

       

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

       

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

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

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

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

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

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

       

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

      目標(biāo):依賴項

           命令

        

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

       

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

       

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

       

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

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

      # 宏定義

      ……


      # 描述塊

       

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

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



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

      [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鏈接器的命令行用法,這里只簡單敘述cl和link的用法。

      cl的一些常用選項:

      -c: 編譯但不鏈接

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

      -I:包含的頭文件

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

       

      link的一些常用選項:

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

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

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

      /out: 指定輸出的文件。

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

       

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

       

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

      OUTDIR = .\Debug

       

      #這里增加了一個輸出:$(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工具增加了兩個選項

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

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

       

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

       

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

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

      Stop.

       

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

       

      我們繼續(xù)完善這個makefile。我們想增加一個清理輸出文件的指令,就是常用的clean指令。我們可以在描述塊all后面加一個描述塊: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這個描述塊,而你運(yùn)行下面的命令:

      nmake /f makefile.vc clean

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

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

      Stop.

       

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

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


      其中macrodefs就是允許我們定義一些自定義宏來控制編譯輸出的。這次我們可以定義兩個宏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. #這里增加了一個輸出:$(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,范文慶、周彬彬、安靖編著

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

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多