std::to_chars 在 MacOS / clang 上编译但不链接
std::to_chars compile but not linking on MacOS / clang
我在 MacOS 下使用 clang 编译项目时遇到问题。
我确实“查明”了里面的问题 charconv
header:
#include <charconv>
#include <array>
#include <iostream>
int main(){
std::array<char, 64> buffer;
auto[p, ec] = std::to_chars(buffer.begin(), buffer.end(), 123);
if (ec != std::errc() )
std::cout << "error" << '\n';
std::cout << (const char *) buffer.data() << '\n';
}
这是我编译它的方式。
Nikolays-MacBook-Air:~ nmmm$ clang --version
Apple LLVM version 10.0.1 (clang-1001.0.46.4)
Target: x86_64-apple-darwin18.5.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
Nikolays-MacBook-Air:~ nmmm$ clang -std=c++17 x.cc -lstdc++
Undefined symbols for architecture x86_64:
"std::__1::__itoa::__u32toa(unsigned int, char*)", referenced from:
std::__1::__itoa::__traits_base<unsigned int, void>::__convert(unsigned int, char*) in x-9b1746.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Nikolays-MacBook-Air:~ nmmm$
我们将不胜感激。
更新
我试过 clang++,但它给了我同样的错误信息。
我为此写了一个很好的长答案,然后检查它是否适合我(linux 上的 clang 9.0.0)。您使用 clang
而不是 clang++
进行编译。下面是长答案:
Clang 的 libc++ 已经很长时间没有完全实现 "Elementary string conversions, revision 5 "(如 to_chars
和 from_chars
),有些部分仍然很出色,请参阅 here。但我认为你的应该工作,所以也许你应该更新你的图书馆。
对于 to_chars
的用法请考虑,它在字符串末尾明确添加 no [=15=]
。因此你不能只使用 std::cout << (const char *) buffer.data();
。您必须使用指针(在您的代码中命名为 p
)来标记字符串的结尾。通过插入 [=15=]
、生成 std::string_view sv(buffer.data(), static_cast<size_t>(p-buffer.data());
、使用 std::copy(buffer.begin(), p, std::ostream_iterator<char>(std::cout, ""));
或其他太多方法。
<charconv>
header 包含 std::__1::__itoa::__u32toa
的声明和使用,一个未在 header 中定义的函数。该函数在 libc++.dylib
中定义。 但是,Apple 发货libc++.dylib
的频率与它发货header 的频率不同;而且,可能更重要的是,libc++ failed to include the new symbol in its "abilist" for Apple until 2018-09-23, even though the header change landed on 2018-08-01。因此,有大约 53 天的时间,libc++(的这方面)在 OSX 上无法正常工作。也许苹果在那段时间拿起它并发货了。
使代码工作的一种方法是自己构建 libc++。 Instructions here, as of late 2019.
$ clang++ -std=c++17 test.cc $ROOT/llvm-project/build/lib/libc++.dylib \
-Wl,-rpath,$ROOT/llvm-project/build/lib
$ ./a.out
123
一些针对您问题的评论者建议您可以使用 GNU libstdc++ 而不是 LLVM libc++ 来使您的代码正常工作。这有点对,但我怀疑为 OSX 构建 libstdc++ 会比为 OSX 构建 libc++ 更难。 (后者并不 简单!)我不知道有什么方法可以在 OSX 上安装 libstdc++。有 brew install gcc@8
,但我敢打赌 GCC 8 也没有 <charconv>
。
截至 2020 年初,没有 供应商 (except just recently Microsoft) 提供了 <charconv>
的完整实现 — floating-point to_chars
和 from_chars
结果证明很难,所以大多数供应商不提供它们。 ("Why didn't they just copy an existing implementation?" 好吧,事实证明 <charconv>
在任何实现存在之前就被标准化为 C++17 的一部分。没有人猜到它会 困难!)
我在 MacOS 下使用 clang 编译项目时遇到问题。
我确实“查明”了里面的问题 charconv
header:
#include <charconv>
#include <array>
#include <iostream>
int main(){
std::array<char, 64> buffer;
auto[p, ec] = std::to_chars(buffer.begin(), buffer.end(), 123);
if (ec != std::errc() )
std::cout << "error" << '\n';
std::cout << (const char *) buffer.data() << '\n';
}
这是我编译它的方式。
Nikolays-MacBook-Air:~ nmmm$ clang --version
Apple LLVM version 10.0.1 (clang-1001.0.46.4)
Target: x86_64-apple-darwin18.5.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
Nikolays-MacBook-Air:~ nmmm$ clang -std=c++17 x.cc -lstdc++
Undefined symbols for architecture x86_64:
"std::__1::__itoa::__u32toa(unsigned int, char*)", referenced from:
std::__1::__itoa::__traits_base<unsigned int, void>::__convert(unsigned int, char*) in x-9b1746.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Nikolays-MacBook-Air:~ nmmm$
我们将不胜感激。
更新
我试过 clang++,但它给了我同样的错误信息。
我为此写了一个很好的长答案,然后检查它是否适合我(linux 上的 clang 9.0.0)。您使用 clang
而不是 clang++
进行编译。下面是长答案:
Clang 的 libc++ 已经很长时间没有完全实现 "Elementary string conversions, revision 5 "(如 to_chars
和 from_chars
),有些部分仍然很出色,请参阅 here。但我认为你的应该工作,所以也许你应该更新你的图书馆。
对于 to_chars
的用法请考虑,它在字符串末尾明确添加 no [=15=]
。因此你不能只使用 std::cout << (const char *) buffer.data();
。您必须使用指针(在您的代码中命名为 p
)来标记字符串的结尾。通过插入 [=15=]
、生成 std::string_view sv(buffer.data(), static_cast<size_t>(p-buffer.data());
、使用 std::copy(buffer.begin(), p, std::ostream_iterator<char>(std::cout, ""));
或其他太多方法。
<charconv>
header 包含 std::__1::__itoa::__u32toa
的声明和使用,一个未在 header 中定义的函数。该函数在 libc++.dylib
中定义。 但是,Apple 发货libc++.dylib
的频率与它发货header 的频率不同;而且,可能更重要的是,libc++ failed to include the new symbol in its "abilist" for Apple until 2018-09-23, even though the header change landed on 2018-08-01。因此,有大约 53 天的时间,libc++(的这方面)在 OSX 上无法正常工作。也许苹果在那段时间拿起它并发货了。
使代码工作的一种方法是自己构建 libc++。 Instructions here, as of late 2019.
$ clang++ -std=c++17 test.cc $ROOT/llvm-project/build/lib/libc++.dylib \
-Wl,-rpath,$ROOT/llvm-project/build/lib
$ ./a.out
123
一些针对您问题的评论者建议您可以使用 GNU libstdc++ 而不是 LLVM libc++ 来使您的代码正常工作。这有点对,但我怀疑为 OSX 构建 libstdc++ 会比为 OSX 构建 libc++ 更难。 (后者并不 简单!)我不知道有什么方法可以在 OSX 上安装 libstdc++。有 brew install gcc@8
,但我敢打赌 GCC 8 也没有 <charconv>
。
截至 2020 年初,没有 供应商 (except just recently Microsoft) 提供了 <charconv>
的完整实现 — floating-point to_chars
和 from_chars
结果证明很难,所以大多数供应商不提供它们。 ("Why didn't they just copy an existing implementation?" 好吧,事实证明 <charconv>
在任何实现存在之前就被标准化为 C++17 的一部分。没有人猜到它会 困难!)