代码之家  ›  专栏  ›  技术社区  ›  Grant Limberg

scons、boost::asio、Windows预编译头和链接器错误

  •  4
  • Grant Limberg  · 技术社区  · 16 年前

    我正在使用SCONS对我们的构建过程进行调查,因为我们为多个平台开发C++。我在构建配置中占了99%,但是我遇到了 非常 Windows上的奇怪错误与预编译头文件有关。更奇怪的是,它只发生在一个项目上。

    在该项目的sconscript文件中,我有以下内容在Windows上编译PCH:

    if env['PLATFORM'] == 'win32':
        env['PCH'] = env.PCH('MyPCH-LSCommon.pch', 'Common/src/MyPCH.h')[0]
        env['PCHSTOP'] = '"MyPCH.h"'
    

    我还将编译器标志设置为强制在项目中的所有文件上包括mypch.h:

    if env['PLATFORM'] == 'win32':
        cxxflags = [ '/FI"MyPCH.h"' ]
    

    一切都进行得很顺利。直到最后一个dll链接阶段,我才获得链接器错误的页面,如:

    error LNK2001: unresolved external symbol "private: static class
    boost::asio::detail::tss_ptr<class boost::asio::detail::call_stack<class 
    boost::asio::detail::win_iocp_io_service>::context> boost::asio::detail::call_stack<class 
    boost::asio::detail::win_iocp_io_service>::top_" 
    (?top_@?$call_stack@Vwin_iocp_io_service@detail@asio@boost@@@detail@asio@boost@@0V?$tss_ptr@
    Vcontext@?$call_stack@Vwin_iocp_io_service@detail@asio@boost@@@detail@asio@boost@@@234@A)
    

    还有:

         error LNK2001: unresolved external symbol "private: static class 
    boost::asio::detail::winsock_init<2,0> boost::asio::detail::winsock_init<2,0>::instance_" 
    (?instance_@?$winsock_init@$01$0A@@detail@asio@boost@@0V1234@A)
    

    这让人费解,因为我收到的链接警告中没有一个类甚至不使用boost::asio,尽管它包含在预编译头文件中,并且在某些include的链上。

    更令人费解的是,如果我禁用预编译头文件的编译,但仍然强制它包含,那么所有的编译和链接都很好。这需要永远的恐惧。

    有人知道是什么导致这些链接器错误吗?

    事先谢谢。

    ---编辑---

    下面是scons为构建pch而发出的命令行(减去include路径):

        cl /nologo /W4 /Od /RTC1 /MDd /TP /EHsc /FD /RTC1 /RTCc /Gy /openmp /TP 
    /Fd"\vc80.pdb" /nologo /Wp64 /wd4231 /wd4616 /errorReport:prompt /Zm256 /MDd /Od
    /FI"CedrusPCH.h" /DOS_WINDOWS=OS_WINDOWS /D_WIN32 /DWIN32 /D_WIN32_WINNT=0X500 /D_WINDOWS 
    /D_UNICODE /DBOOST_ALL_DYN_LINK /DBOOST_REGEX_DYN_LINK /DBOOST_LIB_DIAGNOSTIC 
    /D_VC80_UPGRADE=0x710 /DUNICODE /DWXUSINGDLL /DwxUSE_SERVICE_DISCOVERY=1 /D_DEBUG /D_DEBUG 
    /DSL_ENABLE_NETWORKING=1 /DWXMAKINGDLL_LSCOMMON /DSLSDK_USEDLL 
    /c C:\Projects\licenser\Common\src\CedrusPCH.h /Foscons-out\dbg\obj\CedrusPCH-LSCommon.obj
    /Yc"CedrusPCH.h" /Fpscons-out\dbg\obj\CedrusPCH-LSCommon.pch /ZI CedrusPCH.h
    

    下面是正在编译的文件的命令行(同样减去include路径):

    cl /Foscons-out\dbg\obj\Licenser\src\secure\windows_crypto
    \PlatformCryptoKeyProvider_wincrypt.obj /c C:\Projects\licenser\Licenser\src\secure
    \windows_crypto\PlatformCryptoKeyProvider_wincrypt.cpp /nologo /W4 /Od /RTC1 /MDd /TP 
    /EHsc /FD /RTC1 /RTCc /Gy /openmp /TP /Fd"\vc80.pdb" /nologo /Wp64 /wd4231 /wd4616 
    /errorReport:prompt /Zm256 /MDd /Od /FI"CedrusPCH.h" /nologo /W4 /Od /RTC1 /MDd 
    /DOS_WINDOWS=OS_WINDOWS /D_WIN32 /DWIN32 /D_WIN32_WINNT=0X500 /D_WINDOWS /D_UNICODE 
    /DBOOST_ALL_DYN_LINK /DBOOST_REGEX_DYN_LINK /DBOOST_LIB_DIAGNOSTIC /D_VC80_UPGRADE=0x710 
    /DUNICODE /DWXUSINGDLL /DwxUSE_SERVICE_DISCOVERY=1 /D_DEBUG /D_DEBUG 
    /DSL_ENABLE_NETWORKING=1 /DWXMAKINGDLL_LSCOMMON /DSLSDK_USEDLL /D_USRDLL /D_WINDLL 
     /Yu"CedrusPCH.h" /Fpscons-out\dbg\obj\CedrusPCH-LSCommon.pch /ZI
    PlatformCryptoKeyProvider_wincrypt.cpp
    

    最后,下面是链接命令行:

    link /nologo /MACHINE:X86 /DEBUG -manifest /dll /out:scons-out\dbg\obj\LSCommon.dll 
    /implib:scons-out\dbg\obj\LSCommon.lib /LIBPATH:scons-out\dbg\lib 
    /LIBPATH:C:\Projects\licenser\scons-out\dbg\lib /LIBPATH:scons-out\dbg\obj 
    /LIBPATH:. /LIBPATH:C:\Projects\licenser /LIBPATH:C:\Projects\licenser\scons-out\dbg\obj 
    /LIBPATH:C:\Projects\wxWidgets\lib\vc_dll_vc8 /LIBPATH:C:\Projects\boost\install\lib 
    "/LIBPATH:C:\Program Files\Microsoft Platform SDK for Windows Server 2003 R2\Lib" 
    "/LIBPATH:C:\Program Files\Bonjour SDK\lib\win32" unicows.lib winmm.lib comctl32.lib 
    rpcrt4.lib ws2_32.lib oleacc.lib kernel32.lib user32.lib gdi32.lib winspool.lib 
    comdlg32.lib advapi32.lib shell32.lib oleacc.lib ole32.lib oleaut32.lib uuid.lib 
    odbc32.lib odbccp32.lib boost_signals-vc80-mt-gd-1_39.lib boost_system-vc80-mt-gd-1_39.lib 
    boost_date_time-vc80-mt-gd-1_39.lib boost_regex-vc80-mt-gd-1_39.lib 
    boost_wserialization-vc80-mt-gd-1_39.lib boost_serialization-vc80-mt-gd-1_39.lib 
    boost_thread-vc80-mt-gd-1_39.lib wxbase28ud.lib wxbase28ud_net.lib wxbase28ud_xml.lib 
    wxmsw28ud_adv.lib wxmsw28ud_aui.lib wxmsw28ud_core.lib wxmsw28ud_html.lib wxmsw28ud_qa.lib 
    wxmsw28ud_richtext.lib wxmsw28ud_xrc.lib LSBase.lib disphelper.lib Crypt32.lib 
    /PDB:scons-out\dbg\obj\LSCommon.pdb /DEBUG 
    scons-out\dbg\obj\Licenser\src\dll_template_instantiation_export_LSCommon.obj 
    scons-out\dbg\obj\Licenser\src\secure\ConcreteMessageSigningAlgorithm_DSA_with_SHA1.obj 
    scons-out\dbg\obj\Licenser\src\secure\CryptoObjectFactory.obj 
    scons-out\dbg\obj\Licenser\src\secure\EntropyCalculation.obj 
    scons-out\dbg\obj\Licenser\src\data\LSAccount.obj 
    scons-out\dbg\obj\Licenser\src\data\LSAccountHistory.obj 
    scons-out\dbg\obj\Licenser\src\server_daemon\LSAccountHistoryRequestPacket.obj 
    scons-out\dbg\obj\Licenser\src\server_daemon\LSAccountRequestPacket.obj 
    scons-out\dbg\obj\Licenser\src\data\LSActivation.obj 
    scons-out\dbg\obj\Licenser\src\server_daemon\LSActivationRequestPacket.obj 
    scons-out\dbg\obj\Licenser\src\data\LSBlob.obj 
    scons-out\dbg\obj\Licenser\src\data\LSCompositePrimaryKey.obj 
    scons-out\dbg\obj\Licenser\src\data\LSDatabaseElementBase.obj 
    scons-out\dbg\obj\Licenser\src\server_daemon\LSDoActivateReplyPacket.obj 
    scons-out\dbg\obj\Licenser\src\server_daemon\LSDoActivateRequestPacket.obj 
    scons-out\dbg\obj\Licenser\src\server_daemon\LSDoManualActivateReplyPacket.obj 
    scons-out\dbg\obj\Licenser\src\server_daemon\LSDoManualActivateRequestPacket.obj 
    scons-out\dbg\obj\Licenser\src\data\LSLicense.obj 
    scons-out\dbg\obj\Licenser\src\data\LSLicenseHistory.obj 
    scons-out\dbg\obj\Licenser\src\server_daemon\LSLicenseHistoryRequestPacket.obj 
    scons-out\dbg\obj\Licenser\src\server_daemon\LSLicenseRequestPacket.obj 
    scons-out\dbg\obj\Licenser\src\server_daemon\LSLoginReplyPacket.obj 
    scons-out\dbg\obj\Licenser\src\server_daemon\LSLoginRequestPacket.obj 
    scons-out\dbg\obj\Licenser\src\data\LSMachine.obj 
    scons-out\dbg\obj\Licenser\src\server_daemon\LSMachineRequestPacket.obj 
    scons-out\dbg\obj\Licenser\src\server_daemon\LSNet.obj 
    scons-out\dbg\obj\Licenser\src\data\LSPhyActivation.obj 
    scons-out\dbg\obj\Licenser\src\data\deprecated_streamables\LSPhyActivation_LegacyStreamingHelper.obj 
    scons-out\dbg\obj\Licenser\src\data\LSPrimaryKey.obj 
    scons-out\dbg\obj\Licenser\src\data\LSPrimaryKeyDefinitions.obj 
    scons-out\dbg\obj\Licenser\src\data\LSProduct.obj 
    scons-out\dbg\obj\Licenser\src\data\LSProductHistory.obj 
    scons-out\dbg\obj\Licenser\src\server_daemon\LSProductHistoryRequestPacket.obj 
    scons-out\dbg\obj\Licenser\src\server_daemon\LSProductRequestPacket.obj 
    scons-out\dbg\obj\Licenser\src\data\LSSimplePrimaryKey.obj 
    scons-out\dbg\obj\Licenser\src\data\LSUser.obj 
    scons-out\dbg\obj\Licenser\src\data\LSUserHistory.obj 
    scons-out\dbg\obj\Licenser\src\server_daemon\LSUserHistoryRequestPacket.obj 
    scons-out\dbg\obj\Licenser\src\server_daemon\LSUserRequestPacket.obj 
    scons-out\dbg\obj\Licenser\src\server_daemon\streaming_versioning\StreamableClassInfoVersionTranslator.obj
    scons-out\dbg\obj\Licenser\src\data\deprecated_streamables\LSProduct_deprecated_v_2.obj 
    scons-out\dbg\obj\Licenser\src\secure\deprecated_streamables\DSA.obj 
    scons-out\dbg\obj\Licenser\src\secure\deprecated_streamables\DSAKeyPair.obj 
    scons-out\dbg\obj\Licenser\src\secure\deprecated_streamables\DSAPublicKey.obj 
    scons-out\dbg\obj\Licenser\src\secure\deprecated_streamables\Hash.obj 
    scons-out\dbg\obj\Licenser\src\secure\deprecated_streamables\SHA1.obj 
    scons-out\dbg\obj\Licenser\src\server_daemon\LSActivationApprovalStrategy.obj 
    scons-out\dbg\obj\Licenser\src\data\LSDatabaseElementT.obj 
    scons-out\dbg\obj\Licenser\src\data\LSPairPrimaryKeyT.obj 
    scons-out\dbg\obj\Licenser\src\data\LSSimplePrimaryKeyT.obj 
    scons-out\dbg\obj\Licenser\src\secure\windows_crypto\PlatformCryptoKeyProvider_wincrypt.obj
    scons-out\dbg\obj\Licenser\src\secure\windows_crypto\Scoped_RAII_AutoReleaseWincryptHandleFactory.obj
    

    另外,每个单独的文件都没有显式包含PCH头,但是在命令行选项中,我有/fi,它强制在项目中编译的每个文件中包含PCH。

    2 回复  |  直到 16 年前
        1
  •  2
  •   Grant Limberg    16 年前

    我似乎解决了我自己的问题。预编译头文件时,cl.exe生成.obj文件。因为我们使用Boost的内部魔力自动链接到Windows上所需的库,并且Boost头includes也在预编译头中,所以这些链接也包含在.obj文件中。不幸的是,这个.obj文件没有添加到需要链接的.obj文件列表中(在本例中是生成.dll)。

    它的工作原理是将编译PCH期间生成的.obj文件手动附加到linkflags参数。这样做完全解决了我一直遇到的问题。也许是时候更新msvc.py工具并向scons发送补丁了!

        2
  •  0
  •   Michael Burr    16 年前

    编译时有两个定义,而编译预编译头时有两个定义:

    /D_USRDLL
    /D_WINDLL
    

    据我所知,这些是MFC的遗迹。我对它们一无所知,但如果wxwidgets对它们有一些依赖性,我不会感到惊讶。我怀疑这是真的(但我也没看过)。