Skip to content

1.15.0: linker errors with MSVC link-time-code-generation #5200

@dgrunwald

Description

@dgrunwald

Describe the bug
When building our application, I am getting this linker error after upgrading to 1.15.0:

13:10:13  zstd_streambuf.obj : error LNK2005: "public: virtual int __cdecl Poco::BasicBufferedStreamBuf<char,struct std::char_traits<char>,class Poco::BufferAllocator<char> >::overflow(int)" (?overflow@?$BasicBufferedStreamBuf@DU?$char_traits@D@std@@V?$BufferAllocator@D@Poco@@@Poco@@UEAAHH@Z) already defined in libPocoFoundation.dll.if.lib(libPocoFoundation.dll)
13:10:13  zstd_streambuf.obj : error LNK2005: "public: virtual int __cdecl Poco::BasicBufferedStreamBuf<char,struct std::char_traits<char>,class Poco::BufferAllocator<char> >::underflow(void)" (?underflow@?$BasicBufferedStreamBuf@DU?$char_traits@D@std@@V?$BufferAllocator@D@Poco@@@Poco@@UEAAHXZ) already defined in libPocoFoundation.dll.if.lib(libPocoFoundation.dll)
13:10:13  bazel-out\x64_windows-opt\bin\projects\libs\shared\libShared.dll : fatal error LNK1169: one or more multiply defined symbols found

Weirdly enough, this only happens for release builds and only if LTCG is enabled.
We are using MSVC 14.44.35207 (VS2022.14).

I believe the root cause is that daf19e5 removed the dllimport annotation on the extern template class declarations.
Note that MSVC's dllexport is not valid on such declarations, so omitting the Foundation_API macro is correct for MSVC when building Poco itself. (the dllexport annotation instead belongs on the template instance definition in the .cpp file)
But when the header is included into an application where Foundation_API expands to dllimport instead, this annotation is still necessary.

I believe the correct code for such an extern template should be:

-#if defined(POCO_OS_FAMILY_WINDOWS)
+#if defined(POCO_OS_FAMILY_WINDOWS) && defined(Foundation_EXPORTS)
 extern template class BasicBufferedStreamBuf<char, std::char_traits<char>>;
 #else
 extern template class Foundation_API BasicBufferedStreamBuf<char, std::char_traits<char>>;
 #endif

Applying this patch locally allows our build to succeed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions