9

I'm trying to use the fmt (https://github.com/fmtlib/fmt) formatting header library in my c++ project.

I've added the path to the core header file at the top of my main file like so:

#include "../third_party/fmt/core.h"

but when I try to call any function like:

string message = fmt::format("The answer is {}", 42);

I get the following error:

Undefined symbols for architecture x86_64:
  "std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > fmt::v5::internal::vformat<char>(fmt::v5::basic_string_view<char>, fmt::v5::basic_format_args<fmt::v5::buffer_context<char>::type>)", referenced from:
      std::__1::basic_string<std::__1::enable_if<internal::is_string<char [17]>::value, fmt::v5::internal::char_t<char [17]>::type>::type, std::__1::char_traits<std::__1::enable_if<internal::is_string<char [17]>::value, fmt::v5::internal::char_t<char [17]>::type>::type>, std::__1::allocator<std::__1::enable_if<internal::is_string<char [17]>::value, fmt::v5::internal::char_t<char [17]>::type>::type> > fmt::v5::format<char [17], int>(char const (&) [17], int const&) in main.cpp.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [main] Error 1
make[1]: *** [CMakeFiles/main.dir/all] Error 2
make: *** [all] Error 2

I'm not sure how to use this as this is how I have used other header libraries in the past such as cxxopts. Any help would be appreciated!

vitaut
  • 49,672
  • 25
  • 199
  • 336
CoderCal
  • 149
  • 1
  • 1
  • 9
  • 2
    not to ask the obvious but did you define `FMT_HEADER_ONLY`? – PeterT Jun 15 '19 at 08:23
  • asking the obvious is always a good idea – john Jun 15 '19 at 08:27
  • Please produce a [mcve]. Not just one line of code. A (very) short but complete program, along with your compiler flags, is a must. – StoryTeller - Unslander Monica Jun 15 '19 at 08:29
  • @PeterT Nope I didn't. Rookie with this stuff. I didn't actually see that needed to be defined in the documentation. I see there's a line in the github readme about it though. Is this common for header libraries? Thanks for the help! – CoderCal Jun 15 '19 at 08:44
  • @CoderCal yes, header-only libraries commonly use preprocessor definitions for configuration or to basically even compile. Either for all translation-units or sometimes they require the definition to be only done inside one translation unit (where the implementation will reside). – PeterT Jun 15 '19 at 08:51

3 Answers3

4

You should link with the fmt library or use the optional header-only mode.

For example, if you have the file test.cc:

#include <fmt/core.h>

int main() {
  fmt::print("The answer is {}.", 42);
}

You can compile and link it with gcc:

g++ -std=c++11 test.cc -lfmt
vitaut
  • 49,672
  • 25
  • 199
  • 336
  • 2
    Could you mind giving some snippets on how to use optional header-only mode? I want to use ```fmt::format("The answer is {}", 42);``` Following the link you provide I still do not have much idea on how to use header-only mode.. Do you mean that we can do ```gcc -I[the directory to header files] src/format.cc my-test.cpp``` for the "optional header-only mode" ? where ```my-test.cpp``` includes ```fmt/core.h, fmt/format.h, fmt/format-inl.h```. – Ethanabc Apr 02 '21 at 06:54
  • 1
    Usage is almost identical, the only difference is that you should include `fmt/format.h` instead of `fmt/core.h`. – vitaut Apr 02 '21 at 16:38
1

From a comment in @vitaut's answer, if you change your #include line from this:

#include "../third_party/fmt/core.h"

to this:

#include "../third_party/fmt/format.h"

it will cause the code to be compiled in "header-only mode", and you won't need to change your build process to compile and link in the {fmt} library.

Clare Macrae
  • 3,670
  • 2
  • 31
  • 45
1

I'm working on Mac, and I did not realize that you can install the library using brew. It appears at the end of the page. I have been dealing with symbol errors all evening, and I'm not sure that all my problems were related to the build process. The compiling process was also not working properly.

The paths where the library is installed are: /usr/local/include and /usr/local/lib.

I'm using g++-11 to build my project and this instruction works for me:

g++-11 -std=c++20 -I/usr/local/include -L/usr/local/lib -lfmt main.cpp -o main

The only problem is that it works partially. It works fine with print:

fmt::print("Don't {}!\n", "panic");

But it breaks using format:

fmt::format("Don't {}!\n", "panic");

I'm missing something, but I'm not sure what.

By the way, if you are using VSCode, you can create a c_cpp_properties.json into your .vscode folder and add the include path for the headers.

{
  "includePath": [
    [...],
    "/usr/local/include/"
  ],
}

Not sure if this is related to your case, but I hope it helps.

Timbergus
  • 3,167
  • 2
  • 36
  • 35