SCons, Boost::ASIO, предварительно скомпилированные заголовки Windows и ошибки компоновщика
-
14-09-2019 - |
Вопрос
Я изучаю возможность использования SCons в процессе сборки, поскольку мы разрабатываем C++ для нескольких платформ.Я уже на 99 % завершил конфигурацию сборки, но столкнулся с ОЧЕНЬ странная ошибка в Windows, связанная с предварительно скомпилированным заголовочным файлом.Еще более странно то, что это происходит только в одном проекте.
В файле SConscript для этого проекта у меня есть следующее для компиляции PCH в Windows:
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, хотя он включен в предварительно скомпилированный заголовочный файл и вверх по цепочке в некоторых #includes.
Еще более загадочным является то, что если я отключу компиляцию предварительно скомпилированного заголовочного файла, но при этом принудительно его включаю, все компилируется и линкуется нормально.Это просто занимает чертовски вечность.
Кто-нибудь знает, что может быть причиной этих ошибок компоновщика?
Заранее спасибо.
--- РЕДАКТИРОВАТЬ ---
Вот командная строка, которую SCons выдает для построения PCH (без включенных путей):
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
Вот командная строка для компилируемого файла (опять же без включаемых путей):
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 в каждый файл, скомпилированный в проекте.
Решение
Кажется, я решил свою проблему.При предварительной компиляции файла заголовка cl.exe создает файл .obj.Поскольку мы используем внутреннюю магию boost для автоматического связывания с необходимыми библиотеками в Windows, а наш заголовок #includes также находится в предварительно скомпилированном заголовке, эти ссылки также включаются в файл .obj.К сожалению, этот файл .obj не добавляется в список файлов .obj, которые необходимо связать (в данном случае для создания .dll).
Это помогло вручную добавить файл .obj, созданный во время компиляции PCH, к аргументу LINKFLAGS.Это на 100% полностью решает мою проблему.Возможно, пришло время обновить инструмент msvc.py и отправить патч в SCons!
Другие советы
При компиляции есть два определения, которые используются при создании предварительно скомпилированных заголовков:
/D_USRDLL
/D_WINDLL
Насколько я знаю, это реликвии MFC.Я на самом деле ничего о них не знаю, но не удивлюсь, если wxWidgets будет от них зависеть.Я сомневаюсь, что Boost это делает (но я тоже не смотрел).