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?
I'm running into an issue with my clang-cl based DLL build:
Which I finally tracked down to this definition in os.h:
Since
ostreamhasFMT_APIin it, MSVC ABI considers the inline functions indetail::buffer<char>to bedllimportwhen used inprintf-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. Howeverfmt.dlldoes not have this symbol.Just including
fmt/os.hin format.cc fixes the error (which can be behind a#ifdef FMT_OS), or adding an explicit template instantiation:I see a similar PR was merged previously to make
ostreamnot inherit fromdetail::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?