为基本的 clang cpp windows 程序构建 fmt - 链接器问题?

Building fmt for basic clang cpp windows program - Linker issue?

我是 C++ 的初学者,正在尝试在基本程序中编译和使用 fmt library,但我在运行时遇到了问题。程序,Tester.cpp,简单如下:

// #define FMT_HEADER_ONLY
// #include <C:\Program Files (x86)\FMT\include\fmt\format.h>
#include <fmt/format.h> 
#include <iostream>
    
int main() {
  std::cout << "C++ Code Executing!" << std::endl;
  int num = 7;
    
 std::cout << fmt::format("The answer is {}.", num) << std::endl;  
}

我以前从未真正使用过cmake,但到目前为止已按照以下步骤下载和编译库:

git clone https://github.com/fmtlib/fmt.git
cd fmt
mkdir build
cd build
cmake ..
cmake --build . --config Release
cmake --install .

这会将一系列 header 文件存储到此目录中:

C:\Program Files (x86)\FMT\include\fmt

根据我程序中的注释行,如果我指示它仅使用 header 并包含一个直接指向 header 文件的路径,它似乎确实有效,但我相信我应该能够以我可以 link 的方式编译 fmt 库,而无需仅使用 header ,理想情况下作为静态库,(尽管作为初学者我可能在这方面是错误的)。如果我通过以下方式使用 clang++ 进行编译,则采用当前格式:

clang++ -isystem "C:\Program Files (x86)\FMT\include" Tester.cpp -o Tester.exe

我收到以下错误:

Tester-333c8c.o : error LNK2019: unresolved external symbol "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl fmt::v8::vformat(class fmt::v8::basic_string_view<char>,class fmt::v8::basic_format_args<class fmt::v8::basic_format_context<class fmt::v8::appender,char> >)" (?vformat@v8@fmt@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$basic_string_view@D@12@V?$basic_format_args@V?$basic_format_context@Vappender@v8@fmt@@D@v8@fmt@@@12@@Z) referenced in function main
Tester.exe : fatal error LNK1120: 1 unresolved externals
clang++: error: linker command failed with exit code 1120 (use -v to see invocation)

我相信这是因为编译器可以找到 header 文件进行编译,但是 linker 没有 definition/object 文件来 link 成可执行文件?这是我试图修复的部分,但一直无法修复。

根据 fmt 8.1.1 的说明,我尝试使用带有 -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE 的 cmake 创建静态库,生成 fmt.lib 文件,但试图 link 这似乎也无助于解决我的问题。我也试过在编译时向不同的目录添加一个 -L 标志,但仍然出现错误。

问题

有人能指出我在尝试为我的程序编译和使用这个库时哪里出错了吗?

我在 Windows 系统上。我一直在使用 clang 和 Neovim 进行代码编辑,尽管我确实安装了 Visual Studio,因为我相信 clang 依赖于部分灌输。如果可能的话,我希望纯粹通过命令行工具来做到这一点。作为初学者,如果相关,我对 cpp 的某些部分(例如 header 文件)应该如何工作也有点不稳定。

编辑 根据 HolyBlackCat 对 linking 的评论,我还尝试了以下操作:

clang++ -isystem "C:\Program Files (x86)\FMT\include" -LC:/FMT -lfmt Tester.cpp -o Tester.exe

with fmt.lib located in C:\FMT and get and error that starts like so:

fmt.lib(format.obj) : error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MD_DynamicRelease' doesn't match value 'MT_StaticRelease' in Tester-6086ae.o
msvcprt.lib(MSVCP140.dll) : error LNK2005: "public: __cdecl std::_Lockit::_Lockit(int)" (??0_Lockit@std@@QEAA@H@Z) already defined in libcpmt.lib(xlock.obj)
...
...
Many lines...
...
LINK : warning LNK4217: symbol '_isatty' defined in 'libucrt.lib(isatty.obj)' is imported by 'fmt.lib(format.obj)' in function '"void __cdecl fmt::v8::detail::print(struct _iobuf *,class fmt::v8::basic_string_view<char>)" (?print@detail@v8@fmt@@YAXPEAU_iobuf@@V?$basic_string_view@D@23@@Z)'
Tester.exe : fatal error LNK1169: one or more multiply defined symbols found
clang++: error: linker command failed with exit code 1169 (use -v to see invocation)

您应该喜欢 https://fmt.dev/latest/usage.html 中记录的 {fmt} 库。例如,如果您使用的是 CMake,则可以按如下方式完成:

target_link_libraries(<your-target> fmt::fmt)

发布我最终的 solution/workaround,

在与 HolyBlackCat 进行评论对话后,我决定删除 MSVC 并安装 MinGW-w64 环境(通过 Choclatey winlibs)。然后我通过 cmake 构建了 FMT,如下所示:

mkdir build
cd build
cmake .. -G "MinGW Makefiles"
cmake --build .

然后我可以通过以下方式编译我的程序:

clang++ Tester.cpp -o Tester.exe -isystem "C:\Codingrd_Party\C++\fmt\include" -L "C:\Codingrd_Party\C++\fmt\build" -l:libfmt.a

编译成功并生成可运行的可执行文件。

我怀疑问题是 cmake 正在使用 MSVC 进行构建,然后尝试 link 使用 clang 导致某处不兼容。