1. 程式人生 > >【PE】搭建支援C99原始碼編譯的vs2010工程的方法(附MinGW下Windows GNU makefile的編寫)

【PE】搭建支援C99原始碼編譯的vs2010工程的方法(附MinGW下Windows GNU makefile的編寫)

DATE: 2018.12.10


1、前言

    最近在編譯一份開原始碼時,由於VS對最新標準C實現C99的支援性差,在搭建編譯環境過程中遇到了一些問題,特記錄於此。
    現在很多開原始碼(比如x264,ffmpeg)中的C程式碼都採用c99規範,Linux gcc編譯器對c99目前也不是完全支援,但可以通過指定引數-std=c99或-std=gnu99來使用c99規範;VS對c99的支援性就更差了,目前vs2010,vs2012都不支援c99規範,從vs2013開始才部分支援c99規範。因此,問題來了:
如果我們需要vs2010版本編譯的可執行檔案或庫怎麼辦呢?
目前主要有一種解決方案:
採用c99toc89轉換工具進行預處理然後送入編譯器進行編譯。

具體方法在3小節中講述 。

2、參考

C99與C89區別以及轉換方法
C編譯標準-std=的設定方法以及工程標頭檔案包含設定
C99中stdint.h和inttype.h標頭檔案的使用方法及獲取路徑

3、搭建支援C99原始碼編譯的vs2010工程的方法

採用c99toc89工具:Tool to convert C99 code to MSVC-compatible C89

Usage: c99wrap $CC $CFLAGS source
3.1、vs2010工程中使用自定義生成工具搭建(這種方式便於除錯分析)

將工程中所有c檔案和cpp檔案設定自定義生成工具如下:

c99wrap cl /
c /Fo "Debug\%(Filename).obj" %(FullPath)

輸出設定為:

Debug\%(Filename).obj;%(Outputs)

注意: 當前測試發現,在純VS環境下,使用c99wrap轉換工具後編譯c99程式碼仍然會報錯!
原因: c99wrap.exe工具引數配置有問題導致(c99wrap工具引數解析採用’-c’的形式!),
正確的引數配置如下:

c99wrap cl -c -Fo "Debug\%(Filename).obj" %(FullPath)
Debug\%(Filename).obj;%(Outputs)

舉個栗子:

c99toc89_test.project//demo.c:

#include <stdio.h>
int add(int a, int b)
{
   int sum = 0;
   for(int i = 0; i< 10; i++)
   {
      sum += a + b;
   }
   return sum;
}
int main(int argc, char* argv[])
{
  int ret;
  ret = sum(5,  5);
  return ret;
}

上述程式碼中for語句採用了c99語法中的for語句內進行變數宣告。

編譯結果如下圖所示:
vs2010下需要使用c99toc89工具先轉換一下:
**我是圖片**

vs2013下可以直接編譯通過:
==/* 待補充*/==

3.2、MinGW環境中利用C99wrap採用編譯指令碼生成vs2010版本的可執行檔案(指令碼編譯)

強烈建議採用最新版本的c99wrap(V1.0.3),對C99基本完全支援。

下載地址:https://github.com/libav/c99-to-c89/releases/tag/release-1.0.3
(1)編譯環境:

  1. 首先在啟動MinGW環境之前,修改以下指令碼(路徑:MinGW/msys/1.0/msys.bat),並更名為msys_vs2010_win32/64.bat;
    在該指令碼的最開始新增下面的語句,啟動VS執行環境。
rem 對於win32:
call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\vcvars32.bat" 
rem 對於x64:
call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\amd64\vcvars64.bat" 
  1. 啟動MinGW環境,執行msys_vs2010_win32.bat或msys_vs2010_win64.bat。

(2)編譯指令碼:
platform.rules:

OS = $(shell uname)
CFLAGS += $(EXTRA_CFLAGS)
ifeq($(findstring MINGW, $(OS)),MINGW)
CC= c99wrap cl
CPP= c99wrap cl
AR= lib
LD= c99wrap link
ASM= yasm
ifeq($(PLATFORM), x86_32)
	CFLAGS += -DWIN32 -DARCH_X86_32 -O2
	SFLAGS += -f win32 -DPREFIX
	RC = RC -DWIN32
endif
ifeq($(PLATFORM), x86_64)
	CFLAGS += -DWIN64 -DARCH_X86_64 -O2
	SFLAGS += -f x64 -DPREFIX
	RC = RC -DWIN64
endif
endif

Makefile_lib:

include platform.rules
SRC_DIR = ./src
SRCS := $(wildcard $(SRC_IDR)/*c)
OBJS := $(subst .c,.o, $(SRCS))
TARGET= libxxx.lib dllxxx.dll
DEFS = xxxx.def   #模組定義檔案def
IMPLIB= dllxxx.lib  #引導庫
VER = xxx.ver
PDB_NAME = libxxx.pdb

OUT = -out
LIBRARY_STATIC = $(OUT):$(filter %.lib, $TARGET))
LIBRARY_SHARD = $(OUT):$(filter %.dll, $TARGET))

all: $(TARGET)
$(filter %.lib, $(TARGET)) : $(OBJS)
	$(AR) $(LIBRARY_STATIC) $(OBJS)
$(filter %.dll, $(TARGET)) : $(OBJS)	
	makedef $(VER) $(OBJS) > $(DEFS)
	$(RC) -fo enc_dll.res enc_dll.rc
	$(LD) -dll -def:$(DEFS) -implib: $(IMPLIB) $(LIBRARY_SHARD) $(OBJS) enc_dll.res $(OUTPDB)
%.o:%.c
	$(CC)  -I.  -I$(SRC_DIR)  $(CFLAGS) $< -o [email protected]
%.o:%asm
	$(ASM) $(SFLAGS) $< -o [email protected]
clean:
	rm -f $(OBJS) $(TARGET) $(IMPLIB) $(PDB_NAME) 

Makefile_demo:

include platform.rules
SRC_DEMO_DIR = ../../../demo
vpath %.c $(SRC_DEMO_DIR)
vpath %.h $(SRC_DEMO_DIR)
SRCS := $(wildcard $(SRC_DEMO_DIR )/*c)
C_OBJS := $(subst .c,.o, $(SRCS))
OBJS := $(filter-out ../../demo/osal.o, $(C_OBJS))
TARGET= $(BIN_DIR)/xxx.exe
LIBXXX := $(LIB_DIR)/libxxx.lib
OUT = -out
CFLAGS += -I $(SRC_DEMO_DIR ) -I../../../include _DWIN32
LDFLAGS := -libpath:$(LIB_DIR)

all: clean $(LIBXXX) $(TARGET)
 $(TARGET):$(OBJS)
 	$(LD) $(LDFLAGS) -PDB:$(BIN_DIR)/demo.pdb -debug -out [email protected] $(LIBXXX) $(OBJS) > out
%.o:%.c:
	$(CC) $(CLFAGS) -c -Fo [email protected] $<
$(LIBXXX):
	make -C ../lib -f Makfile_lib
clean:
	rm -rf $(C_OBJS) $(TARGET) 
	make -C ../liib -f Makfile_lib clean

(3)編譯方法

cd build/demo
make -f Makefile_demo
cd build/lib
make -f Makefile_lib

(4)擴充套件知識

  • makedef:庫符號匯出利用了MinGW bin中自帶的makedef工具,使用方法很簡單,VER檔案格式如下:
LIBXXX {
	global: XX_MPEG_*
	local: *;
};
  • filter與filter-out
$(filter ^lib, $(OBJS))   #從$(OBJS)中找到以lib開頭的檔案
$(filter-out test.o, $(OBJS))   #從$(OBJS)中濾除掉test.o檔案
4、採用GnuWin32工具進行windows下gnu makefile編寫

參考:
GnuWin32使用以及windows下gnu makefile編寫


THE END!