本文目录
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
3.2.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"
- 启动MinGW环境,运行msys_vs2010_win32.bat或msys_vs2010_win64.bat。
3.2.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 $@
%.o:%asm
$(ASM) $(SFLAGS) $< -o $@
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 $@ $(LIBXXX) $(OBJS) > out
%.o:%.c:
$(CC) $(CLFAGS) -c -Fo $@ $<
$(LIBXXX):
make -C ../lib -f Makfile_lib
clean:
rm -rf $(C_OBJS) $(TARGET)
make -C ../liib -f Makfile_lib clean
3.2.3 编译方法
cd build/demo
make -f Makefile_demo
cd build/lib
make -f Makefile_lib
3.2.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!
本博文只能阅读,谢绝转载,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 2963033731@qq.com