• 关于MFC库和CRT库冲突的分析


    当MFC库和CRT库冲突时,会出现一个LNK2005的错误。具体的错误如下:

    nafxcwd.lib(dllmodul.obj): error LNK2005: _DllMain@12 already defined in LIBCMTD.lib(dllmain.obj)

    nafxcwd.lib(afxmem.obj): error LNK2005: "void * __cdecl operator new(unsigned int)"(??2@YAPAXI@Z) already defined in LIBCMTD.lib(new.obj)

    nafxcwd.lib(afxmem.obj): error LNK2005: "void __cdecl operator delete(void *)"(??3@YAXPAX@Z) already defined in LIBCMTD.lib(dbgdel.obj)

    nafxcwd.lib(afxmem.obj): error LNK2005: "void __cdecl operator delete[](void *)"(??_V@YAXPAX@Z) already defined in LIBCMTD.lib(delete2.obj)

    首先我们来认识下这些错误中提示的信息:

    nafxcwd.lib,MFC静态链接库,调试版。(发布版是nafxcw.lib)

    LIBCMTD.lib,多线程版的CRT库。

    DLLMain函数,在dllmodul.cpp和dllmain.cpp中都有定义。

    new、delete、delete[],CRT库中有一套标准实现,但是MFC中均重新实现了一遍。

    那么上面的错误的意思即是,已经链接过LIBCMTD.lib,再链接nafxcwd.lib即会报重复定义的错误。

    对于MFC工程中的DllMain,new, delete函数要求先链接MFC库。而通过上面的错误信息显示,工程是先链接的LIBCMTD.lib,才会出错。

    版 本

    类 型

    使用的library

    被忽略的library

    备注

    R  Release

    单线程

    libc.lib

    libcmt.lib, msvcrt.lib, libcd.lib, libcmtd.lib, msvcrtd.lib

    多线程

    libcmt.lib

    libc.lib, msvcrt.lib, libcd.lib, libcmtd.lib, msvcrtd.lib

    MTd

    使用DLL的多线程

    msvcrt.lib

    libc.lib, libcmt.lib, libcd.lib, libcmtd.lib, msvcrtd.lib

    MDd

    D   Debug

    单线程

    libcd.lib

    libc.lib, libcmt.lib, msvcrt.lib, libcmtd.lib, msvcrtd.lib

    多线程

    libcmtd.lib

    libc.lib, libcmt.lib, msvcrt.lib, libcmtd.lib, msvcrtd.lib

    MT

    使用DLL的多线程

    msvcrtd.lib

    libc.lib, libcmt.lib, msvcrt.lib, libcd.lib, libcmtd.lib

    MD

    然后,我们来看一下工程的链接顺序。

    在工程Properties->Liker->General->Show Progress->For Libraries Searched (如果想看更详细的信息可选Displayall progress messages)。

    会显示如下信息:

    Searching libraries

    Searching C:ProgramFiles (x86)Microsoft Visual Studio 10.0VClibLIBCMTD.lib:

    Searching C:ProgramFiles (x86)Microsoft Visual Studio 10.0VClibOLDNAMES.lib:

    Searching C:ProgramFiles (x86)Microsoft Visual Studio 10.0VCatlmfclib afxcwd.lib:

    nafxcwd.lib(dllmodul.obj): error LNK2005: _DllMain@12 already defined in LIBCMTD.lib(dllmain.obj)

    nafxcwd.lib(afxmem.obj): error LNK2005: "void * __cdecl operator new(unsigned int)"(??2@YAPAXI@Z) already defined in LIBCMTD.lib(new.obj)

    nafxcwd.lib(afxmem.obj): error LNK2005: "void __cdecl operator delete(void *)"(??3@YAXPAX@Z) already defined in LIBCMTD.lib(dbgdel.obj)

    nafxcwd.lib(afxmem.obj): error LNK2005: "void __cdecl operator delete[](void *)"(??_V@YAXPAX@Z) already defined in LIBCMTD.lib(delete2.obj)

    Searching C:ProgramFiles (x86)Microsoft SDKsWindowsv7.0Alibkernel32.lib:

    Searching C:ProgramFiles (x86)Microsoft SDKsWindowsv7.0Alibuser32.lib:

    Searching C:ProgramFiles (x86)Microsoft SDKsWindowsv7.0Alibgdi32.lib:

    Searching C:ProgramFiles (x86)Microsoft SDKsWindowsv7.0Alibmsimg32.lib:

    从上面搜索链接库的顺序,就可以看出是先链接LIBCMTD.lib的,然后再链接nafxcwd.lib时就报错。

    再次,我们打开*.vcproj工程文件,找到类似下面的信息

    <ItemGroup>

        <ClCompile Include="CSI.c"/>

        <ClCompileInclude="Log.cpp" />

        <ClCompileInclude="SourcecodeFTLFlashDrv_IF.c" />

        <ClCompileInclude="SourcecodePTLUsbDriver.c" />

        <ClCompileInclude="stdafx.cpp">

          <PrecompiledHeaderCondition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>

          <PrecompiledHeaderCondition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>

        </ClCompile>

        <ClCompileInclude="U3_MLC.cpp" />

      </ItemGroup>

    通过上面文件的顺序,我们可以看出,这个顺序是由文件夹及文件名按字段排序得到的。

    CSI.c文件依据规则排在最前,那么链接的顺序也是最新的。因为是.c文件,必须是以C编译器来编程,必定是链接标准C库,也即LIBCMTD.lib.

    如果我们手动将上面的工程信息调整如下:

    <ItemGroup>

        <ClCompileInclude="Log.cpp" />

        <ClCompile Include="CSI.c"/>

        <ClCompileInclude="SourcecodeFTLFlashDrv_IF.c" />

        <ClCompileInclude="SourcecodePTLUsbDriver.c" />

        <ClCompileInclude="stdafx.cpp">

          <PrecompiledHeaderCondition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>

          <PrecompiledHeaderCondition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>

        </ClCompile>

        <ClCompileInclude="U3_MLC.cpp" />

      </ItemGroup>

    我们再来看工程的搜索链接顺序:

    Searching libraries

    Searching C:ProgramFiles (x86)Microsoft Visual Studio 10.0VCatlmfclib afxcwd.lib:

    Searching C:ProgramFiles (x86)Microsoft Visual Studio 10.0VClibLIBCMTD.lib:

    Searching C:ProgramFiles (x86)Microsoft Visual Studio 10.0VClibOLDNAMES.lib:

    Searching C:ProgramFiles (x86)Microsoft SDKsWindowsv7.0Alibkernel32.lib:

    Searching C:ProgramFiles (x86)Microsoft SDKsWindowsv7.0Alibuser32.lib:

    Searching C:ProgramFiles (x86)Microsoft SDKsWindowsv7.0Alibgdi32.lib:

    Searching C:ProgramFiles (x86)Microsoft SDKsWindowsv7.0Alibmsimg32.lib:

    我们可以看到nafxcwd.lib最先被搜索链接,并且错误也消失了。

    由此看来,通过调整.vcproj文件中的文件编译顺序,是可以影响到链接顺序的,是可以解决MFC库和CRT库链接顺序影响的错误的。

    但是这种方法有个弊端,即如果下次再添加.c文件或是没有包信预编译头文件的.cpp非MFC类,并且文件名排序在最前,依然可能再次引起上述问题。

    微软提供一个针对上述问题的解决方法,建一个Aa.cpp的文件,然后写个如下函数:

    int test(){new int; return 1;}

    因为这个文件名,这个文件自然会被最先链接到,并链接到nafxcwd.lib.即可以解决上述手动调节文件顺序的问题。

    算是个取巧的,感觉却怪怪的。

    另外,网上还有人提供这样的方法:

    Properties->Liker->Command Line->Additional Options: /FORCE:MULTIPLE

    针对这个设置,MSDN介绍是

    Use/FORCE:MULTIPLE to create an output file whether or not LINK finds more thanone definition for a symbol.

    A file created withthis option may not run as expected

    其实这种方法,相当于强制链接而忽略重复定义。而且上面的英文也说了,文件虽然创建了,但是未必按预期执行。

    所以这种方法是不应该被使用的。

    很多时候,有库冲突,很快就会想到忽略冲突库。可是在这里却并不行。因为这两个冲突的库是都要使用的。

    所有网上有人提出了这种方法,即开始把两个库Nafxcwd.lib;Libcmtd.lib都忽略掉,然后重新附加这两个库Nafxcwd.lib;Libcmtd.lib。

    然后通过查看链接顺序,确实能够正确的链接。

    但,事实上没必要这么复杂。我们只需要保证Nafxcwd.lib这个库优先链接即可。事实上,额外附加的库都会优先链接的。

    即在Properties->Liner->Input->Additional Dependencies后的编辑框中添加Nafxcwd.lib。这样就使得Nafxcwd.lib最先链接了。

    参考资料:

    https://msdn.microsoft.com/en-us/library/72zdcz6f.aspx?f=255&MSPPError=-2147217396

    https://support.microsoft.com/en-us/kb/148652

    https://msdn.microsoft.com/zh-cn/library/70abkas3.aspx?f=255&MSPPError=-2147217396

  • 相关阅读:
    皇帝的用人之道,这一点古今皆同
    sharepoint打包
    powershellbegin
    taxonomy
    powershelluninstall webapplication
    面试题
    字符串处理
    在页面中插入视频时的文件夹命名问题
    process object
    扩展名显示与隐藏
  • 原文地址:https://www.cnblogs.com/feihe0755/p/4655508.html
Copyright © 2020-2023  润新知