筆者的程式教學常用VC的命令列工具來編譯程式,寫一篇用法介紹。
筆者寫只有一個檔案的小程式時還是用命令列來build,寫小程式就要開IDE未免太費工,寫規模大一點的程式才用IDE。
不論Visual Studio、Code::Blocks或Eclipse,IDE實際上也是用這些命令列工具在build程式,IDE會把哪個原始碼檔案有更新、選項、還有依存的header與library整理好,產生命令列,然後執行命令列工具。
VC可以用免費的Express或Community版,先下載並安裝好再照本篇寫的操作。
寫這篇時去看了一下Visual Studio官網……,這裡可以下載最新版,但想下載舊版不是很容易。
https://visualstudio.microsoft.com/zh-hant/vs/community/
VC的命令列編譯器是cl.exe,但是直接打cl.exe會找不到這個檔案,即使找到檔案位置,用完整路徑執行它也會跳「找不到header或library」之類的錯誤,要動一些手續。
首先在Visual Studio的資料夾找到vcvars64.bat這個檔案。
如筆者的電腦上Visual Studio 2013的在這裡
其他版本的話把12.0換成不同的數字。
amd64代表產生的exe檔是x86_64架構,在bin資料夾翻一下可以看到其他架構的,如果想build x86 32bit的程式要用這個。
把vcvars64.bat複製到一個比較好找的地方,例如直接放在D:\下面。
在檔案總管「不要選取任何檔案或資料夾」,按「Shift+滑鼠右鍵」,Windows 7會出現「在此處開啟命令視窗」,Windows 8以後會出現「在這裡開啟 PowerShell 視窗」,如下圖。
選這一項。Windows 8以後由於開啟的是PowerShell,要打cmd、按Enter切換成傳統命令列。Windows 7不用做這一步。
打命令列執行剛剛的vcvars64.bat,看起來什麼都沒發生,實際上會設定必要的環境變數。
執行cl,如果出現「Microsoft (R) ...」的訊息就成功了,現在在任何資料夾下都可以執行VC的工具。
在Windows 10上操作的樣子:
用滑鼠直接點vcvars64.bat執行是無效的。而且vcvars64.bat只在這個命令列視窗有效,每次開新的命令列視窗都要重新執行一次vcvars64.bat。
附帶一提,Visual Studio產品名稱、內部版本號、還有VC版本號這三個是不一樣的
_MSC_VER是Visual C自動產生的macro,如果要根據VC版本做不同處理,或是檢查目前編譯器是不是VC要用到它。
詳細說明看微軟官方的文件
Predefined macros
介紹筆者常用的工具:
cl.exe
nmake.exe
dumpbin.exe
執行vcvars64.bat也會把Windows SDK的工具加入PATH環境變數,變成各處都可以執行,例如VS2013的放在這裡
以下兩個是筆者比較常用的。
rc.exe
fxc.exe
筆者寫只有一個檔案的小程式時還是用命令列來build,寫小程式就要開IDE未免太費工,寫規模大一點的程式才用IDE。
不論Visual Studio、Code::Blocks或Eclipse,IDE實際上也是用這些命令列工具在build程式,IDE會把哪個原始碼檔案有更新、選項、還有依存的header與library整理好,產生命令列,然後執行命令列工具。
VC可以用免費的Express或Community版,先下載並安裝好再照本篇寫的操作。
寫這篇時去看了一下Visual Studio官網……,這裡可以下載最新版,但想下載舊版不是很容易。
https://visualstudio.microsoft.com/zh-hant/vs/community/
VC的命令列編譯器是cl.exe,但是直接打cl.exe會找不到這個檔案,即使找到檔案位置,用完整路徑執行它也會跳「找不到header或library」之類的錯誤,要動一些手續。
首先在Visual Studio的資料夾找到vcvars64.bat這個檔案。
如筆者的電腦上Visual Studio 2013的在這裡
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\amd64\vcvars64.bat |
amd64代表產生的exe檔是x86_64架構,在bin資料夾翻一下可以看到其他架構的,如果想build x86 32bit的程式要用這個。
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\vcvars32.bat |
把vcvars64.bat複製到一個比較好找的地方,例如直接放在D:\下面。
在檔案總管「不要選取任何檔案或資料夾」,按「Shift+滑鼠右鍵」,Windows 7會出現「在此處開啟命令視窗」,Windows 8以後會出現「在這裡開啟 PowerShell 視窗」,如下圖。
選這一項。Windows 8以後由於開啟的是PowerShell,要打cmd、按Enter切換成傳統命令列。Windows 7不用做這一步。
打命令列執行剛剛的vcvars64.bat,看起來什麼都沒發生,實際上會設定必要的環境變數。
執行cl,如果出現「Microsoft (R) ...」的訊息就成功了,現在在任何資料夾下都可以執行VC的工具。
在Windows 10上操作的樣子:
用滑鼠直接點vcvars64.bat執行是無效的。而且vcvars64.bat只在這個命令列視窗有效,每次開新的命令列視窗都要重新執行一次vcvars64.bat。
附帶一提,Visual Studio產品名稱、內部版本號、還有VC版本號這三個是不一樣的
產品名稱 | VS版本號 | _MSC_VER |
Visual Studio 2012 | 11.0 | 1700 |
Visual Studio 2013 | 12.0 | 1800 |
Visual Studio 2015 | 14.0 | 1900 |
Visual Studio 2017 | 15.0 | 1910~1916 |
Visual Studio 2019 | 16.0 | 1920~1928 |
_MSC_VER是Visual C自動產生的macro,如果要根據VC版本做不同處理,或是檢查目前編譯器是不是VC要用到它。
#ifdef _MSC_VER //Visual C #if _MSC_VER<=1800 //VS2013以前 #else //VS2015以後 #endif #else //Visual C以外的compiler #endif |
Predefined macros
介紹筆者常用的工具:
cl.exe
主要的編譯器,基本用法:/MD:連結C/C++標準函式庫時(如printf、malloc這些C語言教學書會介紹的函式),連結至DLL,不要靜態連結。建議寫任何程式都加上/MD,因為靜態連結會發生很多鳥事。
cl 程式碼檔名 /Fe輸出檔名 優化選項 /MD /link 要連結的函式庫
/link:之後的參數會原封不動傳給linker,一般是填要連結的函式庫,有需要也可以填其他參數。
/link之前的參數順序可互換。
例如「如何建一個視窗—Windows API篇」,程式碼是window.c,想要的輸出檔名是window.exe,要連結user32.lib,就這樣打除了exe以外還會同時產生window.obj,在這裡沒用處,可以刪除,但好像沒有方法叫它不產生。
cl window.c /Fewindow.exe /O2 /MD /link user32.lib
C/C++編譯過程是「preprocessor做字串代換 → 產生組合語言 → 產生目的檔(obj) → linker產生可執行檔」,在「C/C++的static保留字」有寫到把途中的組合語言輸出的方法,如下,研究效能優化有時候需要看組合語言。/c:只做到編譯成obj這一步,不要產生exe檔。因此不需要/link的參數。
cl /c function_static.c /Fafunction_static.asm /O2 /MD
/Fa:指定組合語言檔名。
這是官方的命令列參數說明,想看其他VC版本可按左邊的Version切換。
Compiler options listed by category
Linker options
nmake.exe
一個很古老的工具:make的VC版。如果覺得每次都重新打命令列很麻煩,可以把命令列存在一個檔案裡,以後用nmake自動執行。
開一個純文字檔寫以下內容,其中cl前面的空白是Tab字元(巴哈姆特不能顯示Tab字元,所以不要複製貼上,請自己按Tab鍵輸入),檔名存成makefile (不加附檔名),放在跟window.c同一資料夾。然後在命令列打nmake就會執行這一行指令。它會檢查程式碼有沒有變更過,方法是比較window.c和window.exe的修改時間,如果window.exe比較新就不重新編譯。
window.exe: window.c
cl window.c /Fewindow.exe /O2 /MD /link user32.lib
如果資料夾裡有很多.c或.cpp檔,一個一個打指令有點費事,有個方法自動化:把makefile寫成這樣打「nmake exe檔名稱」就會把同名的.c或.cpp檔編譯成exe檔。
.c.exe :
cl $< /Foa.obj /Fe$(@) /O2 /MD /link user32.lib
.cpp.exe :
cl $< /Foa.obj /Fe$(@) /O2 /MD /link user32.lib
/Foa.obj是把產生的obj檔命名為a.obj,這樣obj檔只會有一個,沒有這個的話每個exe都會產生一個同名的obj檔,多出一堆無用的檔案。
這個語法是VC特有,GCC的make要用另一種寫法。
也可以像一般程式語言一樣用變數和判斷式,更詳細的用法請自己查makefile的語法,網路上GCC版的也可以參考,有些語法可以用在VC。
官方的nmake說明
自動化的用法是參考這兩篇
Predefined Rules
Filename Macros
dumpbin.exe
看obj、lib、exe或dll的資訊,「C/C++的static保留字」有用它看obj檔含有的符號。
dumpbin /symbols static_global2.obj
也可以看DLL有哪些exported function,下面是隨便找一個Windows內建DLL來看。
dumpbin /exports c:\windows\System32\user32.dll
執行vcvars64.bat也會把Windows SDK的工具加入PATH環境變數,變成各處都可以執行,例如VS2013的放在這裡
C:\Program Files (x86)\Windows Kits\8.1\bin\x64\ |
rc.exe
名稱是resource compiler的縮寫,跟Windows exe檔的特殊功能:資源(resource)有關。可以把icon、圖像、對話框配置、或任意資料嵌入exe或dll檔,之後可用LoadImage之類的函式讀取。
目前寫的文章還沒有用到資源的功能,以後寫到相關教學時再補上。
fxc.exe
寫Direct3D程式時用來編譯shader。一樣等寫到Direct3D教學時再補上。