作者:zyl910
為了適應現在越來越流行的64位系統,經常需要將代碼分別編譯為32位版和64位版。其次,除了需要生成debug版用於開發測試外,還需要生成release版用於發布。本文介紹了如何利用makefile條件編譯來生成這些版本,而且不僅兼容Linux下的GCC,還支持MinGW、TDM-GCC等Windows下的GCC編譯器。
一、C程序代碼
為了測試條件編譯的效果,以下面這個C語言程序為例(gcc64_make.c)——
#include <stdio.h> #include <assert.h> // 獲取程序位數(被編譯為多少位的代碼) int GetProgramBits() { return sizeof(int*) * 8; } int main(int argc, char* argv[]) { printf("bits:\t%d\n", GetProgramBits()); assert( argc>1 ); return 0; }
main函數中,前兩條語句的含義為——
第一條語句用於顯示當前程序的位數。如果編譯為32位版,將會顯示“bits: 32”;如果編譯為64位版,將會顯示“bits: 64”。
第二條語句是一條斷言,需要argc變量大於1。如果編譯為debug版,若運行時未加命令參數,該斷言失敗,於是輸出錯誤信息並終止程序;如果編譯為release版,所有斷言被屏蔽,不會有錯誤信息。
二、GCC命令行參數
復習一下GCC命令行參數,看看各個版本的區別——
32位版:加上 -m32 參數,生成32位的代碼。
64位版:加上 -m64 參數,生成64位的代碼。
debug版:加上 -g 參數,生成調試信息。
release版:加上 -static 參數,進行靜態鏈接,使程序不再依賴動態庫。加上 -O3 參數,進行最快速度優化。加上-DNDEBUG參數,定義NDEBUG宏,屏蔽斷言。
當沒有-m32或-m64參數時,一般情況下會生成跟操作系統位數一致的代碼,但某些編譯器存在例外,例如——
32位Linux下的GCC,默認是編譯為32位代碼。
64位Linux下的GCC,默認是編譯為64位代碼。
Window系統下的MinGW,總是編譯為32位代碼。因為MinGW只支持32位代碼。
Window系統下的MinGW-w64(例如安裝了TDM-GCC,選擇MinGW-w64),默認是編譯為64位代碼,包括在32位的Windows系統下。
三、makefile代碼
makefile的代碼為——
# flags CC = gcc CFLAGS = -Wall LFLAGS = # args RELEASE =0 BITS = # [args] 生成模式. 0代表debug模式, 1代表release模式. make RELEASE=1. ifeq ($(RELEASE),0) # debug CFLAGS += -g else # release CFLAGS += -static -O3 -DNDEBUG LFLAGS += -static endif # [args] 程序位數. 32代表32位程序, 64代表64位程序, 其他默認. make BITS=32. ifeq ($(BITS),32) CFLAGS += -m32 LFLAGS += -m32 else ifeq ($(BITS),64) CFLAGS += -m64 LFLAGS += -m64 else endif endif .PHONY : all clean # files TARGETS = gcc64_make OBJS = gcc64_make.o all : $(TARGETS) gcc64_make : $(OBJS) $(CC) $(LFLAGS) -o $@ $^ gcc64_make.o : gcc64_make.c $(CC) $(CFLAGS) -c $< clean : rm -f $(OBJS) $(TARGETS) $(addsuffix .exe,$(TARGETS))
為了控制條件編譯,定義了RELEASE、BITS這兩個變量,分別賦初值。然后用ifeq判斷RELEASE、BITS變量的值,分別加上不同的參數。
因賦有初值,直接執行“make”時,編譯得到的是默認位數的debug版。
若在執行make時給變量賦值,將會得到不同的版本——
make RELEASE=0:(默認位數的)debug版。
make RELEASE=1:(默認位數的)release版。
make BITS=32:32位(的debug)版。
make BITS=64:64位(的debug)版。
make RELEASE=0 BITS=32:32位的debug版。
make RELEASE=0 BITS=64:64位的debug版。
make RELEASE=1 BITS=32:32位的release版。
make RELEASE=1 BITS=64:64位的release版。
該makefile的代碼風格是精心設計的,可以很方便的擴展——
需要增加代碼文件或依賴關系時,修改“# files”之后的內容。
需要調整編譯參數時,修改前半部分的參數變量。
需要增加新的條件編譯參數時,在“# args”定義一個變量並賦初值,然后再在后面用“ifeq”判斷變量來調整編譯參數。
最后的“rm -f $(OBJS) $(TARGETS) $(addsuffix .exe,$(TARGETS))”是為了兼容MinGW、TDM-GCC等Windows下的GCC編譯器而設計的——
裝好MSYS,再配置一下PATH環境變量,Windows中也可以使用rm命令刪除文件。
因Windows下的可執行文件的擴展名是exe,所以使用了addsuffix函數增加“.exe”擴展名。
因Linux下不會生成.exe可執行文件,而Windows下不會生成無擴展名的可執行文件,導致rm會因找不到文件而報錯。這時可以加上-f參數忽略該錯誤。
四、測試結果
4.1 Fedora 17 64位版下的 GCC 4.7.0
打開終端,使用cd命令進入程序所在目錄,並執行以下命令——
make clean make ./gcc64_make make clean make RELEASE=1 ./gcc64_make make clean make BITS=32 ./gcc64_make make clean make RELEASE=1 BITS=32 ./gcc64_make gcc --version
運行結果——

4.2 Windows XP SP3 32位版下的 GCC 4.6.2(MinGW (20120426))
打開命令提示符,使用cd命令進入程序所在目錄,並執行以下命令——
make clean make gcc64_make make clean make RELEASE=1 gcc64_make make clean make BITS=64 gcc --version
運行結果——

4.3 Windows 7 SP1 64位版下的 GCC 4.6.1(TDM-GCC (MinGW-w64))
打開命令提示符,使用cd命令進入程序所在目錄,並執行以下命令——
make clean make gcc64_make make clean make RELEASE=1 gcc64_make make clean make BITS=32 gcc64_make make clean make RELEASE=1 BITS=32 gcc64_make gcc --version
運行結果——

參考文獻——
《跟我一起寫 Makefile》. 陳皓. http://blog.csdn.net/haoel/article/details/2886
《Makefile條件編譯debug版和release版》. 功夫Panda. http://www.cnblogs.com/caosiyang/archive/2012/06/13/2548051.html
《assert()函數用法總結》. Glroy. http://www.cnblogs.com/ggzss/archive/2011/08/18/2145017.html
《Windows版GCC之TDM-GCC 4.5.2》. 單魚游弋. http://www.cnblogs.com/wxxweb/archive/2011/05/30/2063434.html
