-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Description
I'm running into an issue with my clang-cl based DLL build:
LINK: command "lld-link /nologo test/CMakeFiles/printf-test.dir/printf-test.cc.obj /out:bin/printf-test.exe /implib:test/printf-test.lib /pdb:bin/printf-test.pdb /version:0.0 [...] c++.lib ws2_32.lib bcrypt.lib userenv.lib msvcrt.lib msvcprt.lib /machine:x64 /INCREMENTAL:NO /subsystem:console test/test-main.lib fmt.lib test/gtest/gtest.lib kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib /MANIFEST:EMBED,ID=1" failed (exit code 1) with the following output:
lld-link: error: undefined symbol: __declspec(dllimport) public: void __cdecl fmt::v12::detail::buffer<char>::try_resize(unsigned __int64)
>>> referenced by test/CMakeFiles/printf-test.dir/printf-test.cc.obj:(int __cdecl fmt::v12::detail::format_float<double>(double, int, struct fmt::v12::format_specs const &, bool, class fmt::v12::detail::buffer<char> &))
>>> referenced by test/CMakeFiles/printf-test.dir/printf-test.cc.obj:(int __cdecl fmt::v12::detail::format_float<double>(double, int, struct fmt::v12::format_specs const &, bool, class fmt::v12::detail::buffer<char> &))
>>> referenced by test/CMakeFiles/printf-test.dir/printf-test.cc.obj:(int __cdecl fmt::v12::detail::format_float<double>(double, int, struct fmt::v12::format_specs const &, bool, class fmt::v12::detail::buffer<char> &))
>>> referenced 9 more times
Which I finally tracked down to this definition in os.h:
class FMT_API ostream : private detail::buffer<char> {
Since ostream has FMT_API in it, MSVC ABI considers the inline functions in detail::buffer<char> to be dllimport when used in printf-test.cc, and even if the definition is available in the header, the compiler expects to find the function to be defined in the dll and just emits a relocation. However fmt.dll does not have this symbol.
Just including fmt/os.h in format.cc fixes the error (which can be behind a #ifdef FMT_OS), or adding an explicit template instantiation:
template FMT_API void buffer<char>::try_resize(size_t);
I see a similar PR was merged previously to make ostream not inherit from detail::buffer<char> and instead use it as a member, which would also solve this problem. However, looks like that change was somehow reverted as of latest master and the 12.0 release has the inheritance again.
I acknowledge it's odd that I'm running into this with clang-cl and the shared builds in CI pass with MSVC. It is possible this is a clang-cl bug, or difference in behavior with MSVC. Even if clang-cl is differing in behavior from MSVC, would we still want to incorporate one of the fixes?