spdlog icon indicating copy to clipboard operation
spdlog copied to clipboard

Problem building spdlog with external fmt

Open askraskr opened this issue 1 year ago • 3 comments

Just installed and test fmt library (development version) with the following instructions:

cmake -S fmt -B fmtb -DBUILD_SHARED_LIBS=TRUE -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE -DCMAKE_CXX_STANDARD=20 -DCMAKE_CXX_COMPILER=/usr/bin/g++-13
cmake --build fmtb
sudo cmake --install fmtb

It's working perfectly fine.

But I wanted my spdlog library to not use the bundled fmt, so I used SPDLOG_FMT_EXTERNAL option with the following command:

cmake -S spdlog -B spdlogb -DSPDLOG_FMT_EXTERNAL=ON -DCMAKE_CXX_STANDARD=20 -DCMAKE_CXX_COMPILER=/usr/bin/g++-13 -DSPDLOG_BUILD_SHARED=ON -DSPDLOG_BUILD_PIC=ON

But when I tried to build it, I got this error.

cmake --build spdlogb
/usr/local/include/fmt/base.h: In instantiation of ‘static void fmt::v10::detail::value<Context>::format_custom_arg(void*, typename Context::parse_context_type&, Context&) [with T = my_type; Formatter = fmt::v10::formatter<my_type>; Context = fmt::v10::context; typename Context::parse_context_type = fmt::v10::basic_format_parse_context<char>]’:
/usr/local/include/fmt/base.h:1374:19:   required from ‘constexpr fmt::v10::detail::value<Context>::value(T&) [with T = my_type; Context = fmt::v10::context]’
/usr/local/include/fmt/base.h:1632:41:   required from ‘constexpr fmt::v10::detail::value<Context> fmt::v10::detail::make_arg(T&) [with bool PACKED = true; Context = fmt::v10::context; T = my_type; typename std::enable_if<PACKED, int>::type <anonymous> = 0]’
/usr/local/include/fmt/base.h:2003:74:   required from ‘constexpr fmt::v10::detail::format_arg_store<Context, NUM_ARGS, 0, DESC> fmt::v10::make_format_args(T& ...) [with Context = context; T = {my_type}; long unsigned int NUM_ARGS = 1; long unsigned int NUM_NAMED_ARGS = 0; long long unsigned int DESC = 15; typename std::enable_if<(NUM_NAMED_ARGS == 0), int>::type <anonymous> = 0]’
/home/linuxuser/spdlog/include/spdlog/logger.h:328:75:   required from ‘void spdlog::logger::log_(spdlog::source_loc, spdlog::level::level_enum, spdlog::string_view_t, Args&& ...) [with Args = {my_type}; spdlog::string_view_t = fmt::v10::basic_string_view<char>]’
/home/linuxuser/spdlog/include/spdlog/logger.h:80:13:   required from ‘void spdlog::logger::log(spdlog::source_loc, spdlog::level::level_enum, fmt::v10::format_string<T ...>, Args&& ...) [with Args = {my_type}; fmt::v10::format_string<T ...> = fmt::v10::basic_format_string<char, my_type>]’
/home/linuxuser/spdlog/include/spdlog/logger.h:85:12:   required from ‘void spdlog::logger::log(spdlog::level::level_enum, fmt::v10::format_string<T ...>, Args&& ...) [with Args = {my_type}; fmt::v10::format_string<T ...> = fmt::v10::basic_format_string<char, my_type>]’
/home/linuxuser/spdlog/include/spdlog/logger.h:140:12:   required from ‘void spdlog::logger::info(fmt::v10::format_string<T ...>, Args&& ...) [with Args = {my_type}; fmt::v10::format_string<T ...> = fmt::v10::basic_format_string<char, my_type>]’
/home/linuxuser/spdlog/include/spdlog/spdlog.h:168:31:   required from ‘void spdlog::info(fmt::v10::format_string<T ...>, Args&& ...) [with Args = {my_type}; fmt::v10::format_string<T ...> = fmt::v10::basic_format_string<char, my_type>]’
/home/linuxuser/spdlog/example/example.cpp:289:43:   required from here
/usr/local/include/fmt/base.h:1393:29: error: passing ‘const fmt::v10::formatter<my_type>’ as ‘this’ argument discards qualifiers [-fpermissive]
 1393 |     ctx.advance_to(cf.format(*static_cast<qualified_type*>(arg), ctx));
      |                    ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/linuxuser/spdlog/example/example.cpp:275:10: note:   in call to ‘fmt::v10::context::iterator fmt::v10::formatter<my_type>::format(my_type, fmt::v10::format_context&)’
  275 |     auto format(my_type my, format_context &ctx) -> decltype(ctx.out()) {
      |          ^~~~~~
gmake[2]: *** [example/CMakeFiles/example.dir/build.make:76: example/CMakeFiles/example.dir/example.cpp.o] Error 1
gmake[1]: *** [CMakeFiles/Makefile2:126: example/CMakeFiles/example.dir/all] Error 2
gmake: *** [Makefile:156: all] Error 2

No matter what compiler (gcc) version or C++ standard I use, I get the same error. What is the problem?

askraskr avatar Jun 20 '24 11:06 askraskr

It may be that the definition of the fmt custom formatter refers to an older document (https://fmt.dev/8.0.0/api.html#formatting-user-defined-types). The fmt 10 documentation gives auto as the return type, but example.cpp gives decltype(ctx.out()). The two types are probably incompatible.

In fmt 10 document (https://fmt.dev/10.2.0/api.html#formatting-user-defined-types):

#include <fmt/core.h>

enum class color {red, green, blue};

template <> struct fmt::formatter<color>: formatter<string_view> {
  // parse is inherited from formatter<string_view>.

  auto format(color c, format_context& ctx) const;
};

Since it is example that is failing to build, you can work around the problem with -DSPDLOG_BUILD_EXAMPLE=OFF.

tt4g avatar Jun 20 '24 14:06 tt4g

starting from 11.0.0, fmt requires formatter::format to be const.

In the release note,

Started enforcing that formatter::format is const for compatibility with std::format

we should sync with this change.

ziyao233 avatar Jul 08 '24 10:07 ziyao233

FYI: This is preventing the use of clang 20 if you want to compile both this and fmtlib with the same cc since fmtlib needs an update to 11.2 to be compilable with clang-20 but spdlog can't build against that version of fmtlib.

allight avatar Jun 27 '25 15:06 allight