MinGW 使用 msvcr90.dll
MinGW 编译出来的程序总是使用 VC6 的 msvcrt.dll ,VC8,9,10有很多新的API(仅限于c runtime),想使用怎么办?
比如:boost 对 MinGW 最低要求就是 msvcrt 7.0
1.MinGW 系统默认情况
MinGW 根据宏 MSVCRT_VERSION 来选择 msvcr 版本,如果用户未指定则默认使用 VC7 的 API(bug, MinGW 默认链接的是 msvcrt.dll, 虽然与 msvcr70.dll 差别不是太大)
MinGW 4.8 (w32api-4.0.3-1) 中有如下定义,根据目标操作系统的版本来确定运行时(链接时候依然需要手动指定特定版本 msvcrt)
文件 /MinGW/include/_mingw.h
/* * We need to set a default MSVCRT_VERSION which describes the MSVCRT.DLL on * the users system. We are defaulting to XP but we recommend the user define * this in his config.h or Makefile file based on the minimum supported version * of OS for his program. * ME = 600 * XP = 710 * VISTA = 800 * WIN7 = 900 * WIN8 = 1010 */ #ifndef MSVCRT_VERSION #if _WIN32_WINNT >= _WIN32_WINNT_WIN8 #define MSVCRT_VERSION 1010 #elif _WIN32_WINNT >= _WIN32_WINNT_WIN7 #define MSVCRT_VERSION 900 #elif _WIN32_WINNT >= _WIN32_WINNT_VISTA #define MSVCRT_VERSION 800 #elif _WIN32_WINNT >= _WIN32_WINNT_WINXP #define MSVCRT_VERSION 710 #elif _WIN32_WINNT >= _WIN32_WINNT_WIN2K #define MSVCRT_VERSION 700 #elif _WIN32_WINNT >= _WIN32_WINNT_WINME #define MSVCRT_VERSION 600 #else #define MSVCRT_VERSION 700 #endif /* _WIN32_WINNT >= _WIN32_WINNT_WINME */ #endif /* ndef MSVCRT_VERSION */
MinGW 4.7 及之前是通过宏 __MSVCRT_VERSION__ 来选择 msvcr 的版本的。
2. MinGW 使用高版本 VC runtime
编辑 spec 文件(参考 http://www.mingw.org/wiki/HOWTO_Use_the_GCC_specs_file)
生成默认的 GCC spec 文件
gcc -dumpspecs > <mingw-root>/lib/gcc/mingw32/<gcc-version>/specs
修改 specs 文件中的 cpp 和 libgcc (标红部分)
*cpp:-DMSVCRT_VERSION=0x0710 %{posix:-D_POSIX_SOURCE} %{mthreads:-D_MT} %{pthread:-D_REENTRANT} %{!no-pthread: }*libgcc:%{mthreads:-lmingwthrd} -lmingw32 %{shared-libgcc:-lgcc_s} %{!shared-libgcc:-lgcc_eh} -lgcc -lmoldname71 -lmingwex -lmsvcr71
注意:此方法只能支持从 msvcrt.dll 改为 msvcr70.dll 或者 msvcr71.dll
链接更高版本的 msvcr 动态库时候,如 msvcr90.dll,会提示无法定位 _findfirst 于 msvcr90.dll 上。
此问题的原因在于:MinGW 在链接阶段会链接 libmingwex.a 库,而此库是以 VC6 为环境编译的,其依赖 msvcrt.dll。 所以也需要以 VC8,9,10 的环境编译多份 mingwex ——这里可以取巧仅以 VC8 为环境编译一个版本即可,因为 VC8 相比 VC71 API 改变很多,但跟后续的 VC9,10 差别不大。
3. 重新编译 libmingwex.a
修改 w32api-4.0.3-1.mingw32-src/Makefine.in 指定 VC 运行时的版本(这里指定 vc8 ,同时附带将操作系统版本最低要求改为xp)
ALL_CFLAGS=$(CFLAGS) $(INCLUDES) -DNTDDI_VERSION=0x05010000 -DMSVCRT_VERSION=800
MinGW win32api 4.0.3-1 的头文件中关于 findfirst findnext 的定义不正确,需要修改替换 wchar.h 和 io.h,点此下载
然后重新编译
./configuremake
将编译后的 ligmingex.a 拷贝至 MinGW/lib 目录,记得加个后缀,这里依赖 vc8 所以改名为 libmingex80.a 。
修改 spec 文件,将 -lmingwex 改为上面的新文件。
*libgcc:%{mthreads:-lmingwthrd} -lmingw32 %{shared-libgcc:-lgcc_s} %{!shared-libgcc:-lgcc_eh} -lgcc -lmoldname80 -lmingwex80 -lmsvcr80
然后随便编译一个文件,运行程序则会报如下问题,找不到 msvcr90.dll
强制拷贝一个 msvcr90.dll 到程序目录,但运行时候则报 R6034 的问题,见下图
对此问题,在生成的目标 exe 目录下手动创建一个 manifest 文件即可解决。
文件名: 程序名.后缀.manifest
内容(version 需要根据你系统的 msvcr 版本修改):
<?xml version='1.0' encoding='UTF-8' standalone='yes'?><assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'><trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"><security><requestedPrivileges><requestedExecutionLevel level='asInvoker' uiAccess='false' /> <!-- VC2008 新增,程序是否需要以管理员运行 --></requestedPrivileges></security></trustInfo><dependency><dependentAssembly><assemblyIdentity type='win32' name='Microsoft.VC90.CRT' version='9.0.21022.8' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' /></dependentAssembly></dependency></assembly>
备注:网上有说想链接高版本 msvcr,只需编译时候 不链接任何 MinGW 的标准库,只链接 msvcr 和 gcc (细节见http://stackoverflow.com/questions/3402252/how-to-link-against-msvcr90-dll-with-mingw-gcc),但实际结果如下:
$ gcc a.c -nostdlib -lmsvcr80 -lgccd:/msys/mingw/bin/../lib/gcc/mingw32/4.8.1/libgcc.a(__main.o):(.text+0x5a): undefined reference to `atexit'collect2.exe: error: ld returned 1 exit status
4. 嵌入manifest
1.
发布程序时为了简单,可以用 mt.exe (VC中的工具) 嵌入manifest
对于exe
mt.exe –manifest MyApp.exe.manifest -outputresource:MyApp.exe;1
对于dll
mt.exe –manifest MyLibrary.dll.manifest -outputresource:MyLibrary.dll;2
2.
每次编译都得手动拷贝一个 manifest,确实非常烦人,这里使用更方便的方法。将manifest文件编译为资源,然后让MinGW链接
创建文件 msvcr.rc
#include "winuser.h" CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST msvcrt.manifest
创建 msvcrt.manifest ,内容同前面的manifest即可
<?xml version='1.0' encoding='UTF-8' standalone='yes'?> <assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> <security> <requestedPrivileges> <requestedExecutionLevel level='asInvoker' uiAccess='false' /> </requestedPrivileges> </security> </trustInfo> <dependency> <dependentAssembly> <assemblyIdentity type='win32' name='Microsoft.VC90.CRT' version='9.0.21022.8' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' /> </dependentAssembly> </dependency> </assembly>
使用 MinGW 的 windres 将前面的 manifest 编译为资源
windres --input msvcr.rc --output msvcr90_manifest.o
将生成的 msvcr90_manifest.o 放到 MinGW 的 lib 目录,
修改 MinGW 的 spec 文件,startfile 部分增加
*startfile:
%{shared|mdll:dllcrt2%O%s} %{!shared:%{!mdll:crt2%O%s}} %{pg:gcrt2%O%s} crtbegin.o%s msvcr90_manifest.o%s
posted on 2014-09-25 00:10 JesseFang 阅读(1308) 评论(0) 编辑 收藏 举报