1

I am currently using libfmt for C++, and I am getting an error that I don't think I should be getting. The code works sometimes, but it doesn't at other times.

When I am linking libfmt from the homebrew installed location(I am on MacOS), it works completely. When I am linking statically from the one I build, using cd $(PATH_FMT) && mkdir -p build && cd build && cmake .. && make. I then link with LDFLAGS += $(PATH_FMT)/build/libfmt.a. The difference between the two is whether or not the following line is commented out in my makefile: CCFLAGS += -I/opt/homebrew/include. The code is as follows:

#define FMT_HEADER_ONLY
#include <fmt/core.h>
#include <fmt/format.h>

.
.
.

template<typename... Ts> static inline std::string format(const std::string &s, Ts &&...ts) {
    return fmt::vformat(std::string_view(s), fmt::make_format_args(ts...));
}

Again, the error only occurs when I use the version I built rather than the one Homebrew provides. The error is as follows:

src/util/log.cpp:13:43: error: no matching function for call to 'make_format_args'
                                          fmt::make_format_args(level_name, f, line, func, msg,
                                          ^~~~~~~~~~~~~~~~~~~~~
lib/fmt/include/fmt/core.h:1804:16: note: candidate function [with Context = fmt::basic_format_context<fmt::appender, char>, T = <const std::string, std::string, unsigned long, const std::string, const std::string, const char *>] not viable: expects an lvalue for 6th argument
constexpr auto make_format_args(T&... args)

I understand the error relates to this question: candidate function not viable: expects an l-value for 3rd argument, but it doesn't make sense to me in this context. It also doesn't make sense because the libfmt API shows this as an example: argument lists. In this example, they are doing the same thing I am.

It doesn't make sense to me that there is an error when I build it myself but not when I use the brew-installed version. It also doesn't make sense that I am getting an error at all, even though I am doing what seems like the same thing as the example in the API. Both the Homebrew version and the manually built version are 10.0.0. Does anyone know what might be wrong?

coopikoop
  • 15
  • 4
  • The error has nothing to do with linking, either static or dynamic. This is a compilation error and the build doesn't go to the linking stage. Check the version of libfmt you have built and the version of libfmt you have installed via homebrew, are they the same? – n. m. could be an AI Jun 01 '23 at 06:13
  • As I said at the end of the post, they are both version 10.0.0. – coopikoop Jun 01 '23 at 13:43
  • Compare `lib/fmt/include/fmt/core.h` (or better all headers under lib/fmt/include) in both locations, are they identical? Add `-H` to the compiler arguments, do the header files come from the place you expect them to be? – n. m. could be an AI Jun 01 '23 at 13:48
  • They are either included from `lib/fmt/include/fmt/core.h` or `/opt/homebrew/include/fmt/core.h`. There was a difference, the Homebrew version was `#define FMT_VERSION 100000`, compared to mine being `#define FMT_VERSION 100001`. So I guess I updated the submodule at some point or something. Thank you! – coopikoop Jun 01 '23 at 14:00

1 Answers1

1

The error suggests that you are passing an rvalue as the 6th argument (which is cut off in the error message). You don't need fmt::vformat or fmt::make_format_args at all and should be using fmt::format and wrapping the format string in fmt::runtime to mark the format string as only known at runtime:

return fmt::format(fmt::runtime(format_str),
                   level_name, f, line, func, msg, /* 6th argument */);

This will fix the error and make the intent clear.

vitaut
  • 49,672
  • 25
  • 199
  • 336