zoukankan      html  css  js  c++  java
  • 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

    生成默认的 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,点此下载

     
    然后重新编译
    ./configure
    make
     
    将编译后的 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 -lgcc
    d:/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

  • 相关阅读:
    CrawlSpider
    如何提升scrapy爬取数据的效率
    scrapy中的selenium
    scrapy五大核心组件和中间件以及UA池和代理池
    scrapy处理post请求的传参和日志等级
    移动端数据爬取
    python网络爬虫之图片链家在技术.seleninum和PhantonJS
    [典型漏洞分享]从一个手动分析的反射型XSS漏洞看待一个安全设计原则【中危】
    [典型漏洞分享]YS VTM模块存在格式化字符串漏洞,可导致VTM进程异常退出【高危】
    Android Logcat Security(转)
  • 原文地址:https://www.cnblogs.com/JesseFang/p/3991832.html
Copyright © 2011-2022 走看看