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

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

4.3 Windows 7 SP1 64位版下的 GCC 4.6.1(TDM-GCC (MinGW-w64))
  打開命令提示符,使用cd命令進(jìn)入程序所在目錄,并執(zhí)行以下命令——
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
 
 
  運(yùn)行結(jié)果——

 
 
參考文獻(xiàn)——
《跟我一起寫 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()函數(shù)用法總結(jié)》. 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
源碼下載—— 
http://files.cnblogs.com/zyl910/gcc64_make.rar