Closed candrews closed 3 years ago
See https://github.com/gabime/spdlog/issues/1955#issuecomment-860676872 for a fix.
For me libfmt 8.0.0 causes a test failure:
# /usr/bin/ctest --output-on-failure --force-new-ctest-process
Test project /builddir/build/BUILD/spdlog-1.8.5/build
Start 1: spdlog-utests
1/1 Test #1: spdlog-utests ....................***Failed 4.73 sec
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
spdlog-utests is a Catch v2.8.0 host application.
Run with -? for options
-------------------------------------------------------------------------------
to_hex_different_size_per_line
-------------------------------------------------------------------------------
../tests/test_misc.cpp:202
...............................................................................
../tests/test_misc.cpp:217: FAILED:
REQUIRE( ends_with(oss.str(), "0000: 090A0B410C4B ...A.K" + std::string(spdlog::details::os::default_eol) + "0006: FFFF .." + std::string(spdlog::details::os::default_eol)) )
with expansion:
false
[2021-06-22 17:46:38.459] [test] [trace] Test stdout_st
[2021-06-22 17:46:38.459] [test] [debug] Test stdout_mt
[2021-06-22 17:46:38.459] [test] [info] Test stderr_st
[2021-06-22 17:46:38.459] [test] [info] Test stderr_mt
[2021-06-22 17:46:38.459] [test] [warning] Test stderr_mt
[2021-06-22 17:46:38.459] [test] [error] Test stderr_mt
[2021-06-22 17:46:38.459] [test] [critical] Test stderr_mt
[2021-06-22 17:46:38.460] [test] [info] Test stdout_color_st
[2021-06-22 17:46:38.460] [test] [trace] Test stdout_color_mt
[2021-06-22 17:46:38.460] [test] [debug] Test stderr_color_st
[2021-06-22 17:46:38.460] [test] [info] Test stderr_color_mt
[2021-06-22 17:46:38.460] [test] [warning] Test stderr_color_mt
[2021-06-22 17:46:38.460] [test] [error] Test stderr_color_mt
[2021-06-22 17:46:38.460] [test] [critical] Test stderr_color_mt
[*** LOG ERROR #0001 ***] [2021-06-22 17:46:39] [test-error] {argument not found}
===============================================================================
test cases: 145 | 144 passed | 1 failed
assertions: 492 | 491 passed | 1 failed
0% tests passed, 1 tests failed out of 1
Total Test time (real) = 4.74 sec
The following tests FAILED:
1 - spdlog-utests (Failed)
Errors while running CTest
Is this a duplicate of https://github.com/gabime/spdlog/issues/1941?
Compile time format string checking also causes errors around fmt::format_to
in spdlog::logger::log_
. The error can be "fixed" by converting it to a runtime format checking with fmt::runtime
. This only occurs when there's a format specifier in the string, if you just have string constants, then there is no error. This also occurs if you wrap your format string with FMT_STRING
, or convert to a compile string with the _cf
literal.
/extern/spdlog/include/spdlog/logger.h: In instantiation of ‘void spdlog::logger::log_(spdlog::source_loc, spdlog::level::level_enum, const FormatString&, const Args& ...) [with FormatString = fmt::v8::basic_string_view<char>; Args = {std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >}]’:
/extern/spdlog/include/spdlog/logger.h:87:13: required from ‘void spdlog::logger::log(spdlog::source_loc, spdlog::level::level_enum, spdlog::string_view_t, const Args& ...) [with Args = {std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >}; spdlog::string_view_t = fmt::v8::basic_string_view<char>]’
/extern/spdlog/include/spdlog/logger.h:340:27: error: ‘fmt’ is not a constant expression
316 | fmt::format_to(buf, fmt, std::forward<Args>(args)...);
| ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
If you use FMT_COMPILE
, you get an error that looks like
/extern/spdlog/include/spdlog/spdlog.h:241:137: error: no matching function for call to ‘spdlog::logger::log(spdlog::source_loc, spdlog::level::level_enum, some_fn(const std::filesystem::__cxx11::path&)::<lambda()>::FMT_COMPILE_STRING, std::string)’
I made #1976 which fixes some of the build errors, but not everything so I closed it. At the minimum some things with fmt::pad and memory writers also need to be changed.
Is this a duplicate of #1941?
Yes, same issue.
Fixed in latest commit. But I get lots of warning C4996: 'fmt::v8::format_to': was declared deprecated
@vitaut What's the recommended replacement to format_to
?
Currently spdlog use it as follows:
memory_buf_t buf;
fmt::format_to(buf, fmt, std::forward<Args>(args)...);
details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
Only format_to
that takes a buffer is deprecated, you can still pass an iterator:
fmt::format_to(std::back_inserter(buf), fmt, std::forward<Args>(args)...);
Fixed. Thanks @vitaut
Now spdlog ships with fmt v8.0 by default!
Now spdlog ships with fmt v8.0 by default!
:partying_face: I'm looking forward to a new release version!
I applied https://github.com/gabime/spdlog/commit/8bf718671a9eac5517c27a5ffe72089b7f426d8c in part (only the patch to src/fmt.cpp) and v7 headers seem to leak even with -DSPDLOG_FMT_EXTERNAL=ON
.
Perhaps I misunderstand how that switch is supposed to work, but I was under the impression the bundled fmt headers would be completely ignored in favour of the system ones.
You need to take latest fmt commit, since it was fixed by fmt after the v8 release.
@gabime can you please make a new release of spdlog?
It is not ready yet. There are compilation problems with cpp 17/20 and with utf support in windows.
need to fix #1978
There's already a fmt v8.0.1 out...
Any progress on this? I cannot build spdlog for Fedora Rawhide.
@xvitaly for what is worth, these patches fix the problem on openSUSE Tumbleweed.
@lgbaldoni It works. Many thanks.
@vitaut Could you advice on how to use FMT_COMPILE in spdlog? I am having trouble enabling it. For example, the following (with clang 13, c++20)
spdlog::info(FMT_COMPILE("should not compile ? {:d}"), "SDFSDF");
gives me:
/home/gabi/spdlog/include/spdlog/logger.h:95:9: error: no matching member function for call to 'log'
log(source_loc{}, lvl, fmt, std::forward<Args>(args)...);
^~~
/home/gabi/spdlog/include/spdlog/logger.h:113:9: note: in instantiation of function template specialization 'spdlog::logger::log<FMT_COMPILE_STRING, char const (&)[7]>' requested here
log(level::info, fmt, std::forward<Args>(args)...);
^
/home/gabi/spdlog/include/spdlog/spdlog.h:157:27: note: in instantiation of function template specialization 'spdlog::logger::info<FMT_COMPILE_STRING, char const (&)[7]>' requested here
default_logger_raw()->info(fmt, std::forward<Args>(args)...);
^
/home/gabi/spdlog/example/example.cpp:34:13: note: in instantiation of function template specialization 'spdlog::info<FMT_COMPILE_STRING, char const (&)[7]>' requested here
spdlog::info(FMT_COMPILE("should not compile ? {:d}"), "SDFSDF");
^
/home/gabi/spdlog/include/spdlog/logger.h:87:10: note: candidate function template not viable: no known conversion from 'const FMT_COMPILE_STRING' to 'spdlog::string_view_t' (aka 'basic_string_view<char>') for 3rd argument
void log(source_loc loc, level::level_enum lvl, string_view_t fmt, Args &&...args)
^
/home/gabi/spdlog/include/spdlog/logger.h:148:10: note: candidate function not viable: no known conversion from 'spdlog::source_loc' to 'log_clock::time_point' (aka 'time_point<std::chrono::system_clock, duration<long, ratio<1, 1000000000>>>') for 1st argument
void log(log_clock::time_point log_time, source_loc loc, level::level_enum lvl, string_view_t msg)
^
/home/gabi/spdlog/include/spdlog/logger.h:80:10: note: candidate template ignored: requirement 'fmt::is_compile_string<FMT_COMPILE_STRING>::value' was not satisfied [with FormatString = FMT_COMPILE_STRING]
void log(source_loc loc, level::level_enum lvl, const FormatString &fmt, Args &&...args)
^
/home/gabi/spdlog/include/spdlog/logger.h:183:10: note: candidate function template not viable: requires 3 arguments, but 4 were provided
void log(source_loc loc, level::level_enum lvl, const T &msg)
^
/home/gabi/spdlog/include/spdlog/logger.h:161:10: note: candidate function not viable: requires 3 arguments, but 4 were provided
void log(source_loc loc, level::level_enum lvl, string_view_t msg)
^
/home/gabi/spdlog/include/spdlog/logger.h:143:10: note: candidate function template not viable: requires 3 arguments, but 4 were provided
void log(source_loc loc, level::level_enum lvl, const T &msg)
^
/home/gabi/spdlog/include/spdlog/logger.h:93:10: note: candidate function template not viable: no known conversion from 'spdlog::source_loc' to 'level::level_enum' for 1st argument
void log(level::level_enum lvl, const FormatString &fmt, Args &&...args)
^
/home/gabi/spdlog/include/spdlog/logger.h:174:10: note: candidate function not viable: requires 2 arguments, but 4 were provided
void log(level::level_enum lvl, string_view_t msg)
^
/home/gabi/spdlog/include/spdlog/logger.h:135:10: note: candidate function template not viable: requires 2 arguments, but 4 were provided
void log(level::level_enum lvl, const T &msg)
and If I remove typename std::enable_if<fmt::is_compile_string<FormatString>::value, int>::type = 0
from logger.h it compiles fine but no compile time format error is raised by fmt.
AFAICS removing enable_if
works and gives you compile-time checks provided that you call a formatting function in info
: https://godbolt.org/z/qEPv1zexz.
Unfortunately it doesn't work in spdlog context. I created a branch to reproduce: https://github.com/gabime/spdlog/blob/issue_1975/example/example.cpp
@vitaul Any help would be very appreciated.
Is the repro supposed to give an error? It compiles with clang:
% clang++ --version
Apple clang version 12.0.5 (clang-1205.0.22.11)
Target: x86_64-apple-darwin20.5.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
% clang++ example/example.cpp -I include -std=c++20
Which compiler and options do you use?
I see you mention clang 13 and c++20 in one of the previous comment which is kinda close to my setup.
Is the repro supposed to give an error? It compiles with clang:
I expected the line
spdlog::info(FMT_COMPILE("Should not compile {:d}"), "hello");
to fail in compile time but it passed. I tried both gcc11 and clang, and got same result.
AFAICS the problem is in method log_
, which converts the compile-time string to plain string_view:
memory_buf_t buf;
// faster than fmt::format_to(std::back_inserter(buf), fmt, std::forward<Args>(args)...);
fmt::detail::vformat_to(buf, fmt::string_view(fmt), fmt::make_format_args(args...), {});
I don't outright see which overload of which function to use, though.
which converts the compile-time string to plain string_view
I already tried to remove the conversion. Didn’t help. Got compiler errors.
@mjerabek is correct, the reason why you don't get compile-time checks (or rather format string compilation because that's what FMT_COMPILE
does) is conversion into string_view
. If you want compile-time format string handling you should use fmt::format_to
:
fmt::format_to(std::back_inserter(buf), fmt, std::forward<Args>(args)...);
You get compile errors because fmt/compile.h
include is missing. Here's a simplified example: https://godbolt.org/z/3KvWoqW17 that uses format_to
and has the correct include.
But then it won't compile (in c++20) without always wrapping with FMT_COMPILE: https://godbolt.org/z/35bvsq3cW
What I am trying to achieve it to provide the user the option to call info with or without FMT_COMPILE.
I tried here https://godbolt.org/z/1xhvrbexn to overload using typename std::enable_if<fmt::is_compile_string<S>::value, int>::type = 0,..
But that doesn't seem to work either. seems the format string is never marked as fmt::is_compile_string
As a side note,I thought that fmt enables compile-time format check by default in c++20, but it seems one need to wrap with FMT_COMPILE
for the check to actually happen.
What I am trying to achieve it to provide the user the option to call info with or without FMT_COMPILE.
In that case you'll need two overloads, one with format string compilation and one without (https://godbolt.org/z/Msc1cx3jq):
#include <fmt/compile.h>
template <
typename S, typename... T,
std::enable_if_t<!std::is_convertible_v<const S&, fmt::format_string<T...>>, int> = 0>
void info(const S& fmt, T&&... args) {
auto buf = fmt::memory_buffer();
fmt::format_to(std::back_inserter(buf), fmt, std::forward<T>(args)...);
}
template <typename... T>
void info(fmt::format_string<T...> fmt, T&&... args) {
auto buf = fmt::memory_buffer();
fmt::format_to(std::back_inserter(buf), fmt, std::forward<T>(args)...);
}
I might be missing something.. It doesn't compile if wrapped with FMT_COMPILE
: https://godbolt.org/z/9qncEvhMc
I messed up SFINAE in the example, should be fixed now (I updated the comment).
Great. Thanks @vitaut. Anyway, seems that under c++20 the format string get compiled anyway (even without wrapping with FMT_COMPILE). Probably by design?
It will be validated at compile-time but still processed at runtime unless you wrap it in FMT_COMPILE
. In the future some forms of compilation that don't result in code bloat might be enabled by default.
I'm getting error C4996: 'fmt::v9::detail::arg_mapper<context>::map': was declared deprecated
after upgrading fmt to v 9.0.0 is this related?
I'm getting
error C4996: 'fmt::v9::detail::arg_mapper<context>::map': was declared deprecated
after upgrading fmt to v 9.0.0 is this related?
I also ran into this issue. This problem is often encountered because it does not know how to convert to the target type. So, if you are trying to format a user-defined type, you need to refer to this. Or, just convert it to a common type.
Trying to build spdlog 1.8.5 with libfmt 8.0.0 fails with this error:
build.log