尝试使用 ostream<< 运算符对象时与 fmt 6.2.1-3 + clang 10.0.0 的链接问题

Posted

技术标签:

【中文标题】尝试使用 ostream<< 运算符对象时与 fmt 6.2.1-3 + clang 10.0.0 的链接问题【英文标题】:Linking issues with fmt 6.2.1-3 + clang 10.0.0 when trying to use ostream<< operator objects尝试使用 ostream<< 运算符对象时与 fmt 6.2.1-3 + clang 10.0.0 的链接问题 【发布时间】:2020-08-12 14:43:00 【问题描述】:

在遇到 std::thread 的 get_id() 问题并通过 fmt 打印(即使我包含 fmt/ostream.h)后,我想我会将这个简单的 fmt_test.cpp 文件放在一起(基于 this ):

#include <fmt/core.h>
#include <fmt/ostream.h>
#include <iostream>

class date 
   int  m_year, m_month, m_day;
public:
   date( int year, int month, int day ):
      m_year  (  year ),
      m_month ( month ),
      m_day   (   day )
   

   friend std::ostream & operator<<( std::ostream &out, date const &d ) 
      return out << d.m_year << '-' << d.m_month << '-' << d.m_day;
   
;

int main() 
   auto s = fmt::format( "The date is ", date(2012, 12, 9) ); // s == "The date is 2012-12-9"
   fmt::print( "", s );
   return 0;

pacman 中可用的 fmt 版本是 6.2.1-3,这是我正在使用的版本。我正在使用带有以下参数的 clang 10.0.0 进行编译:

clang++ fmt_test.cpp -std=c++20 -stdlib=libc++ -O0 -g -o testbin -lfmt -v

我得到的输出是:

clang version 10.0.0 
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /sbin
Found candidate GCC installation: /sbin/../lib/gcc/x86_64-pc-linux-gnu/10.1.0
Found candidate GCC installation: /sbin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0
Found candidate GCC installation: /usr/lib/gcc/x86_64-pc-linux-gnu/10.1.0
Found candidate GCC installation: /usr/lib64/gcc/x86_64-pc-linux-gnu/10.1.0
Selected GCC installation: /sbin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0
Candidate multilib: .;@m64
Candidate multilib: 32;@m32
Selected multilib: .;@m64
 "/usr/bin/clang-10" -cc1 -triple x86_64-pc-linux-gnu -emit-obj -mrelax-all -disable-free -disable-llvm-verifier -discard-value-names -main-file-name fmt_test.cpp -mrelocation-model pic -pic-level 2 -pic-is-pie -mthread-model posix -mframe-pointer=all -fmath-errno -fno-rounding-math -masm-verbose -mconstructor-aliases -munwind-tables -target-cpu x86-64 -dwarf-column-info -fno-split-dwarf-inlining -debug-info-kind=limited -dwarf-version=4 -debugger-tuning=gdb -v -resource-dir /usr/lib/clang/10.0.0 -internal-isystem /usr/bin/../include/c++/v1 -internal-isystem /usr/local/include -internal-isystem /usr/lib/clang/10.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -std=c++20 -fdeprecated-macro -fdebug-compilation-dir /home/falk/Code/Sandbox -ferror-limit 19 -fmessage-length 0 -stack-protector 2 -fgnuc-version=4.2.1 -fobjc-runtime=gcc -fcxx-exceptions -fexceptions -fdiagnostics-show-option -faddrsig -o /tmp/fmt_test-befb6c.o -x c++ fmt_test.cpp
clang -cc1 version 10.0.0 based upon LLVM 10.0.0 default target x86_64-pc-linux-gnu
ignoring nonexistent directory "/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/bin/../include/c++/v1
 /usr/local/include
 /usr/lib/clang/10.0.0/include
 /usr/include
End of search list.
 "/sbin/ld" -pie --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o testbin /sbin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../lib64/Scrt1.o /sbin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../lib64/crti.o /sbin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/crtbeginS.o -L/sbin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0 -L/sbin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../lib64 -L/usr/bin/../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/sbin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../.. -L/usr/bin/../lib -L/lib -L/usr/lib /tmp/fmt_test-befb6c.o -lfmt -lc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /sbin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/crtendS.o /sbin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../lib64/crtn.o
/sbin/ld: /tmp/fmt_test-befb6c.o: in function `std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > fmt::v6::internal::grouping<char>(fmt::v6::internal::locale_ref)':
/usr/include/fmt/format.h:855: undefined reference to `std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > fmt::v6::internal::grouping_impl<char>(fmt::v6::internal::locale_ref)'
/sbin/ld: /tmp/fmt_test-befb6c+.o: in function `void fmt::v6::internal::format_value<char, date>(fmt::v6::internal::buffer<char>&, date const&, fmt::v6::internal::locale_ref)':
/usr/include/fmt/ostream.h:102: undefined reference to `std::__1::locale fmt::v6::internal::locale_ref::get<std::__1::locale>() const'
clang-10: error: linker command failed with exit code 1 (use -v to see invocation)

知道可能出了什么问题吗?我尝试使用其他参数,如 std=c++17 并在 -lfmt 的参数位置附近移动,但无济于事。 :(

另一个例子,'fmt_test2.cpp`:

#include <fmt/core.h>
#include <fmt/ostream.h>
#include <iostream>
#include <thread>

void foo()  return; 

int main()

    std::thread t1( foo );
    std::thread t2( foo );

    // these two lines work without problems:
    // std::cout << "t1's id: " << t1.get_id() << '\n'
    //           << "t2's id: " << t2.get_id() << '\n';

    // these two lines result in linking errors:
    fmt::print( "t1's id: \n", t1.get_id() );
    fmt::print( "t2's id: \n", t2.get_id() );

    t1.join();
    t2.join();

clang++ -pthread -std=c++20 -stdlib=libc++ -lfmt -O0 -g fmt_test2.cpp -o testbin 的构建输出为:

/sbin/ld: /tmp/fmt_test-d2bca4.o: in function `void fmt::v6::internal::format_value<char, std::__1::__thread_id>(fmt::v6::internal::buffer<char>&, std::__1::__thread_id const&, fmt::v6::internal::locale_ref)':
/usr/include/fmt/ostream.h:102: undefined reference to `std::__1::locale fmt::v6::internal::locale_ref::get<std::__1::locale>() const'
/sbin/ld: /tmp/fmt_test-d2bca4.o: in function `std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > fmt::v6::internal::grouping<char>(fmt::v6::internal::locale_ref)':
/usr/include/fmt/format.h:855: undefined reference to `std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > fmt::v6::internal::grouping_impl<char>(fmt::v6::internal::locale_ref)'
clang-10: error: linker command failed with exit code 1 (use -v to see invocation)

【问题讨论】:

这能回答你的问题吗? error when trying to overload << operator and using friend function 所以基本上在类之外定义这个运算符。 嗯,但即使是 std 库定义的 fmt.dev/latest/api.html#ostream-api ???? @MarekR 无法重现您的问题godbolt.org/z/1dzf3Mgodbolt.org/z/esfcbT 【参考方案1】:

这看起来像是 pacman 包的问题,​​因为您的示例适用于 fmt 6.2.1 的库存版本:https://godbolt.org/z/14dEfx。我建议检查 pacman 版本的 libfmt 导出的符号。

【讨论】:

我明白了,谢谢!经过进一步调查,如果我删除“-stdlib=libc++”编译器参数,它似乎可以工作。奇数。 pacman包可能是用libstdc++编译的。

以上是关于尝试使用 ostream<< 运算符对象时与 fmt 6.2.1-3 + clang 10.0.0 的链接问题的主要内容,如果未能解决你的问题,请参考以下文章

命名空间中的ostream operator <<隐藏其他ostream :: operator [duplicate]

如何使用运算符在一个ostream中写入多少个字符?或者如何读取所写的内容?

流运算符的重载

为模板类重载友元运算符 <<

第四周:运算符重载

在cpp中重载<<运算符的正确方法是啥[重复]