Windowsプラットフォームの下でMakefile学習ノート(一)

11248 ワード

本論文は、http://blog.csdn.net/clever101/article/details/8147352から回転する.
Makefileを勉強する決心をしました.ソースコードをコンパイルする時、コンパイルプラットフォームにまたがる問題を解決するためです.一方、ソースはサーバー側でコンパイルするとIDEでコンパイルするのは不便です.
 
       本文は主に三つの部分に分けられています.第一部分はnamkeツールのmakefileの使い方を説明します.第二部分はmakefileの主要文法を述べます.第三部分は自分で実践してmakefileファイルを書くことを述べます.第四部分はツールを作成して、vcプロジェクトファイルをMakefileファイルに変換します.
 
       まず、VS環境でMakefileを使うツールがnmakeであることを明らかにします.そこで私たちはnmakeのMakefileファイルを使ってよく名前を付ける行の使い方を知る必要があります.nmakeはMakefileファイルを使用しています.
 
namke /f  makefile /x stderrfile  [macrodefs] [targets]
makefileはmakefileファイルであり、x stderfileはオプションパラメータであり、namkeエラーをファイルstderfileに格納する.
続いてmakefileの主な文法を紹介します.makefileのコメントは〓で始まる.
# this is my first makefile
Makefileの重要な構成部分はマクロです.MakefileのマクロはC言語のマクロと似ています.その本質は文字列の置換です.その文法は簡単です.
 
macro name=  macro value
 
直訳するとマクロ名=  マクロの値
 
      VSプリミッションは、OUTIRなど多くのマクロを定義しています.これらのマクロは、元の値をカバーするために、あなたのMakefileで再定義できます.
 
       マクロは環境変数を使うことができます.OPEN_.SOURCEの環境変数は、マクロをこのように定義することができます.
     THIRD.パーティー  =  $(OPEN_USOURCE)
 
      マクロの参照の使い方は$(マクロ名)です.
 
続いてMakefileの第二の重要な構成部分の前処理命令を紹介します.Makefileの前処理コマンドとC言語の前処理コマンドは類似しています.
!ERRORストリングス      ——    エラー「string」を表示してから実行を停止します.エラーコードはU 1050です.
!MESSAGE string  ——   文字列を表示します.これは一般的にC言語を情報表示するために使われます.
!INCLUDE[*]filename[]——makefileを含む.
!IF const ——  成立すれば(非ゼロ)処理!Fと次ELESEかENDIF間の語句
例えばIFDEFマクロム、IFNDEFマクロム、ELESE、ESEIF、ESEIFDEF、ESEIFNDEF、ENDIFとC言語の钻ifなどの指令の意味は一致していますが、ここではいちいち詳しく述べません.
 
   Makefileの第三の主要な構成部分は説明ブロックである.ブロックの構造を説明するには、以下の通りである.
ターゲット:依存項
     コマンド
  
ここでは目標、依存項、命令というものを少し説明します.目標とは、ユーザーが最終的に望んだ結果、つまりnmakeが生成しなければならない結果である.目標は一つのファイル、カタログでもいいし、何でもなくてもいいです.ターゲットが存在しない場合、またはターゲットのタイムスタンプ(ファイルの最後の修正時間)が依存項よりも早い場合、またはターゲットタイプがファイルではない場合、nmakeは説明ブロックの「コマンド」を実行します.
 
依存項とは、生成対象に必要なオブジェクトのことです.一つの目標は一つ以上の依存項を持ってもいいし、依存項がなくてもいいです.複数の依存項をスペースで区切ります.指定された依存項が存在しない場合は、他の説明ブロックのターゲットから探すが、まずこの目標を生成する必要がある.
 
コマンドはnmakeがターゲットを生成する際に呼び出すコマンドです.ユーザ自身がコマンドラインで実行する効果と同じです.
 
namkeを使ってプログラム構築を行う場合、nmakeはタイムスタンプ判定機構を採用しています.ターゲットを生成すると、ターゲットファイルが存在するかどうかを判断します.または、最後の変更時間は依存項の最終修正時間より遅いですか?すべての依存項の最終修正時間が目標の最終修正時間よりも遅い場合、現在の目標ファイルは既存の依存項を用いて生成されており、最新のものであり、再生成する必要はないと説明している.
   ここに紹介します.Mdakefileの文法の詳細については大体知っているかもしれませんが、Makefileの常用文書構造についてはまだ分かりません.このレベルに対する理解が足りないと、Makefileファイルの作成方法が分かりません.よく使われるMakefileのファイル構造を紹介します.Makefileファイル構造は、以下のような構成であってもよい.
xiマクロ定義
……
 
湖南省にある地名
 
        こんなにたくさん勉強しました.実践してみます.まず簡単なコンソール工程であるConsoreTestをください.すべてはプロジェクトガイドによってデフォルトで設定すればいいです.メール関数に簡単なコードを追加します.具体的には次のようになります.
int _tmain(int argc, _TCHAR* argv[])
{
    printf("Hello World! 
"); getchar(); return 0; }
その後、ConsolieTestフォルダの下でmakefile.vcを新規作成します.私たちは本格的にmakefileファイルを作成し始めました.この時、私たちの脳は真っ白になるかもしれません.makefileの文法をたくさん勉強しましたが、第一歩を踏み出すのは依然として困難です.これは正常な反応です.はい、一歩ずつ来ましょう.まず、makefileの基本原則を教えます.終わりに始まります.これは私たちが普段行っているプロセスプログラミングの原則とは違っているようです.終わりを起点として、あなたがmakefileファイルを通じてまずこのプロジェクトをコンパイラに教えます.exeを生成したいですか?それともdllですか?それとも静的なライブラリですか?コンパイラにこのexeなどを生成するにはどのようなObjファイルが必要かを教えます.この例では、我々はexeを生成しますので、makefileファイルの最初の行は以下の通りです.
all:ConsoleTest.exe
次にコンパイラの一般的な生成プロセスです.コンパイルとリンクコマンドは、具体的には
# compile
stdafx.obj: stdafx.cpp
    cl -c -D_X86=1 -DWIN32 -D_DEBUG -D_CONSOLE -Istdafx.h stdafx.cpp
   
ConsoleTest.obj: ConsoleTest.cpp stdafx.obj
    cl -c -D_X86=1 -DWIN32 -D_DEBUG -D_CONSOLE -Istdafx.h ConsoleTest.cpp

# link
ConsoleTest.exe: ConsoleTest.obj
link /INCREMENTAL:YES /NOLOGO /subsystem:console /out:ConsoleTest.exe ConsoleTest.obj kernel32.lib
ここでは、cl文はVCコンパイラのコマンドラインコンパイルで、link文はVCリンク器のコマンドラインの使い方です.ここでは、clとlinkの使い方を簡単に述べるだけです.
clのいくつかの常用オプション:
-c:コンパイルしますが、リンクしません.
-D:プリプロセッサを定義します.例えば-D_X 86=1:指定はx 86プラットフォームにコンパイルして、-D_DEBUG:プリプロセッサを定義する_DEBUG、
-I:含まれるヘッダファイル
clの最後のパラメータはコンパイルされたファイルです.
 
linkのいくつかの一般的なオプション:
//INCREMENTAL:インクリメンタルリンクを有効にするかどうか、YESは有効にするか、NOは有効にしないか、
//NOLOGO:起動権マークの表示をキャンセルする
/SUBSYSTEM:サブシステムを指定して、PCデスクトッププログラムでは、一般的に2つのオプションがあります.
/out:出力するファイルを指定します.
linkの最後のパラメータは、リンクが必要なObjファイルとライブラリファイルです.
 
clとlinkの詳細な使い方はMSDNと参考文献2「VCコマンドラインコンパイルC+」を参照してください.
 
私たちは生成されたObjファイルとCosolieTest.exeが現在のソースフォルダの下に置かれているのを見ました.一般的に私たちはそれをdebugフォルダの下に置きたいです.どうすればいいですか?このときには、makefileの中の常用部分の一つであるマクロを使うことができます.マクロをこのように定義してdebugフォルダを作成できます.具体的なコードは:
OUTDDIR=\Debug
 
铅ここで出力を増加しました.
all: $(OUTDIR) $(OUTDIR)\ConsoleTest.exe
铅フォルダが存在しないなら、それを作成します.
 
$(OUTDIR) :
if not exist "$(OUTDIR)" mkdir $(OUTDIR)
したがって、生成されたObjファイルとexeファイルは、出力ファイルのパスを追加する必要があり、特に以下の通りである.
# compile
$(OUTDIR)\stdafx.obj: stdafx.cpp
    cl -c -D_X86=1 -DWIN32 -D_DEBUG -D_CONSOLE -Istdafx.h /Fo"$(OUTDIR)\\" /Fd"$(OUTDIR)\\" stdafx.cpp 
   
$(OUTDIR)/ConsoleTest.obj: ConsoleTest.cpp $(OUTDIR)\stdafx.obj
    cl -c -D_X86=1 -DWIN32 -D_DEBUG -D_CONSOLE -Istdafx.h /Fo"$(OUTDIR)\\" /Fd"$(OUTDIR)\\" ConsoleTest.cpp

# link
$(OUTDIR)\ConsoleTest.exe: $(OUTDIR)\ConsoleTest.obj
    link /INCREMENTAL:YES /NOLOGO /subsystem:console /out:$(OUTDIR)\ConsoleTest.exe $(OUTDIR)\ConsoleTest.obj kernel32.lib
ここでclツールは二つのオプションを追加しました.
//Fo:Objファイルの配置経路を指定する
/Fd:pdbファイルの配置経路を指定する
 
ここで注意しなければならないのは、Windowsプラットフォームの下でファイルのバックスラッシュを採用しなければなりません.プラットフォームをまたぐ/ではなく、OUTIR=.\DebugをOUTIRと書いたことがあります./Debug、結果としてif not existが認識されなくなりました.windowsプラットフォームの下のmakefileの多くは識別できますが、一部のところでは識別できません.
 
また、命令文は少なくとも一つのマスを空けて、上のマスを入れてはいけません.if not exist「$(OUTIR)」mkdirドル(OUTIR)のトップ格があると、エラーが発生します.
makefile.vc(5):fatal error U 1034:文法エラー:分離子が不足しています.
Stop.
 
    命令文を除いて、他の語句は上の格で書くべきです.
 
私たちはこのmakefileを引き続き改善します.私たちは出力ファイルを整理するためのコマンドを追加したいです.通常のcleanコマンドです.説明ブロックallの後に説明ブロックを追加できます.clean、cleanはブロックのコードを以下のように記述します.
clean:
       if exist $(OUTDIR) del $(OUTDIR)\*.ilk
       if exist $(OUTDIR) del $(OUTDIR)\*.obj
    if exist $(OUTDIR) del $(OUTDIR)\*.exe  
makefileファイルにcleanという説明ブロックが存在しない場合、以下のコマンドを実行します.
nmake/f makefile.vc clean
次のエラーメッセージが表示されます.
NMAKE:fatal error U 1052:ファイル「clean」が見つかりませんでした.
Stop.
 
       私たちはこのmakefileを引き続き改善します.今はdebugバージョンしかコンパイルできませんので、ユーザーがdebugバージョンまたはreleaseバージョンをコンパイルできるようにしたいです.ユーザーは「debug」または「release」を入力して指定してください.マクロタグを設定して指定してもいいと思いますが、ユーザーが正しい入力をするとバージョンがコンパイルされます.同時に、先に述べたnmakeツールのコマンドラインの使い方を思い出します.
namke /f  makefile /x stderrfile  [macrodefs] [targets]
その中でmacrodefsは私達がいくつかのカスタムマクロを定義してコンパイル出力を制御することを許可します.今回は二つのマクロデバッグとreleaseを定義できます.詳細はもう詳しく説明しません.以下にコードを書きます.
 
#      ,    FALSE
CFGSET     =  FALSE

#  debug       
CCDEBUG    = -DWIN32 -D_DEBUG -D_CONSOLE

#  release       
CCNODBG    = -DWIN32 -D_NDEBUG -D_CONSOLE

!IFDEF debug
CC         = $(CCDEBUG)
OUTDIR = .\Debug
CFGSET     =  TRUE
!ELSE IFDEF release
CC         = $(CCNODBG)
OUTDIR = .\Release
CFGSET     =  TRUE
!ENDIF

#     
#
!IF "$(CFGSET)"== "FALSE"
!MESSAGE Usage: nmake /f Makefile.vc [<config>] [<target>]      
!MESSAGE
!MESSAGE where <config> is one of:
!MESSAGE -  release=1               - build release version
!MESSAGE -  debug=1                 - build debug version
!MESSAGE
!MESSAGE <target> may be:
!MESSAGE -  clean                 - clear output file
!MESSAGE
!MESSAGE
!ERROR please choose a valid configuration instead"
!ENDIF


#         :$(OUTDIR)
all: $(OUTDIR) $(OUTDIR)\ConsoleTest.exe

#     $(OUTDIR)   ,    
$(OUTDIR) :
 if not exist "$(OUTDIR)" mkdir $(OUTDIR)
 
clean:
       if exist $(OUTDIR) del $(OUTDIR)\*.ilk
       if exist $(OUTDIR) del $(OUTDIR)\*.obj
       if exist $(OUTDIR) del $(OUTDIR)\*.exe     
   
# compile
$(OUTDIR)\stdafx.obj: stdafx.cpp
    cl -c  $(CC) -Istdafx.h /Fo"$(OUTDIR)\\" /Fd"$(OUTDIR)\\" stdafx.cpp 
   
$(OUTDIR)\ConsoleTest.obj: ConsoleTest.cpp $(OUTDIR)\stdafx.obj
    cl -c  $(CC) -Istdafx.h /Fo"$(OUTDIR)\\" /Fd"$(OUTDIR)\\" ConsoleTest.cpp

# link
$(OUTDIR)\ConsoleTest.exe: $(OUTDIR)\ConsoleTest.obj
    link /machine:x86 /INCREMENTAL:YES /NOLOGO /subsystem:console /out:$(OUTDIR)\ConsoleTest.exe $(OUTDIR)\ConsoleTest.obj kernel32.lib
    
次は使い方です.
#  debug  
nmake /f makefile.vc debug=1
#  release  
nmake /f makefile.vc release=1
#  debug  
nmake /f makefile.vc debug=1 clean
#  release  
nmake /f makefile.vc release=1 clean