2

I have problem compiling a project under MacOS with clang.

I did "pinpoint" the problem inside 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';
}

Here is how I am compiling it.

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$ 

Any help will be appreciated.

update

I tried clang++, but it gives me same error message.

Community
  • 1
  • 1
Nick
  • 9,962
  • 4
  • 42
  • 80

2 Answers2

3

The <charconv> header contains declarations and uses of std::__1::__itoa::__u32toa, a function which is not defined in that header. The function is defined in libc++.dylib. However, Apple does not ship libc++.dylib with the same frequency as it ships headers; and, possibly more important, 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. So there was a period of about 53 days where (this aspect of) libc++ just didn't work on OSX. Maybe Apple picked it up and shipped it during that period.

One way to make your code work is to build libc++ yourself. 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

Some commenters on your question are suggesting that you could make your code work by using GNU libstdc++ instead of LLVM libc++. That's vaguely true, but I suspect that building libstdc++ for OSX will be even harder than building libc++ for OSX. (And the latter is not simple!) I am not aware of any way to install libstdc++ on OSX. There is brew install gcc@8, but I bet GCC 8 didn't have <charconv> either.

As of early 2020, no vendor (except just recently Microsoft) provides a full implementation of <charconv> — the floating-point to_chars and from_chars turn out to be difficult, so most vendors don't provide them. ("Why didn't they just copy an existing implementation?" Well, it turns out that <charconv> was standardized as part of C++17 before any implementation existed. Nobody guessed that it would be difficult!)

Quuxplusone
  • 23,928
  • 8
  • 94
  • 159
  • Do you know when is expected Apple to provide library with correct implementation for integers only? I mean when we might expect it? – Nick Jan 11 '20 at 09:36
  • I had the same issue with clang-7, upgrade to clang-8 solved it. – Pavel K. Apr 20 '21 at 07:19
0

I wrote a nice long answer to this, to then check and see that it works for me (clang 9.0.0 on linux). You compile with clang and not clang++. The long answer below:

Clang's libc++ has not fully implemented the "Elementary string conversions, revision 5 " (as in to_chars and from_chars) for a long time and some parts are still outstanding, see here. But I think yours should work, so maybe you should update your library.

For usage of to_chars please consider, that it explicitly adds no \0 at the end of the string. Therefore you cannot just use std::cout << (const char *) buffer.data();. You have to use the pointer (named p in your code) to mark the end of your string. Either by inserting a \0, by generating a std::string_view sv(buffer.data(), static_cast<size_t>(p-buffer.data());, using std::copy(buffer.begin(), p, std::ostream_iterator<char>(std::cout, "")); or another of far too many ways.

n314159
  • 4,990
  • 1
  • 5
  • 20
  • I know about \0, but example worked on gcc. Any easy way to update the library on MacOS ? – Nick Nov 18 '19 at 23:44
  • You did not read my answer: You use the wrong compiler. Type `clang++` not `clang`. – n314159 Nov 18 '19 at 23:45
  • clang++ have absolutely the same output. – Nick Nov 18 '19 at 23:48
  • I use not apple system and it would be also just googling for me to find out what to do. Is there are reason to not use g++ if it works there? Why are you specifying the standard library and not using the default? – n314159 Nov 18 '19 at 23:53
  • `clang++ -std=c++17 x.cc -lstdc++` isn't this correct way for compiling c++17 on unix, linux and macos? without `-lstdc++` iostream will not work. – Nick Nov 18 '19 at 23:55
  • On my system I call `clang++ -std=c++17 x.cc`. Looking at the manpage the intended way to specify the stdlib is `-stdlib=`, where possible values for library are `libc++` and `libstdc++`. For me only the later works since it seems i dont have libc++ installed. But if it works with gcc, it should also work with clang since they can use the same standardlibrary (it's only code). Maybe you want to find out which one gcc uses. – n314159 Nov 19 '19 at 00:00