搭建支持C99源代码编译的vs2010工程的方法(附MinGW下Windows GNU makefile的编写)

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 编译环境

  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"
  2. 启动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

文章标题:搭建支持C99源代码编译的vs2010工程的方法(附MinGW下Windows GNU makefile的编写)

字数:1.2k

本文作者:Soaring Lee

发布时间:2018-12-10, 15:13:47

最后更新:2021-06-14, 12:13:44

原始链接:https://soaringleefighting.github.io/2018/12/10/【PE系列】搭建支持C99源代码编译的vs2010工程的方法/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

×

喜欢就点赞,疼爱就打赏

相册