std::to_chars compile but not linking on MacOS / clang - c++

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.

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!)

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.

Related

Compiling a C plus plus program using GCC compiler

I am trying to compile this little program in file demo.cpp by gcc demo.cpp,
#include <iostream>
using namespace std;
int main() {
cout << "Hello World!";
return 0;
}
It does not do so successfully. I get Undefined symbols for architecture arm64:,
This seems like pretty popular error but people are getting it on way more complicated programs. Note that it works if I comment the cout line. I am not sure exactly what am I doing wrong here. gcc -v returns,
Apple clang version 14.0.0 (clang-1400.0.29.202)
Target: arm64-apple-darwin22.2.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
This is probably because the GCC compiler, according to my experience, is supposed to compile C language codes only, not C++. G++ is used to compile C++. The specific problem with the cout line is that C uses printf(), not cout, to print to the terminal. Therefore, the C compiler outputs your line as undefined symbols.

cmath error on MacOS c++17: call to abs ambiguous

Having this error using c++17 on Mac OS.
As far as I can tell, code is correct and should work fine (compiles without issue w/ g++ and clang++ on linux).
Also, as far as I can tell, the current default mac version of clang [10.0.1] should support c++17 (full version info printout below).
So, my question is: is this actually a bug in my code, but it works by fluke on linux? Or is it an issue with MacOS clang e.g., not full c++17 implementation?
From cppref:
Defined in header (since C++17):
int abs( int n );
Other c++17 features seem to work completely fine.
#include <cmath>
// #include <cstdlib> //works if included
int main() {
int i = 1;
// return std::abs(1); // Works fine
return std::abs(i); // Fails
}
Compile with:
clang++ -std=c++17 test.cpp
Get this error:
test.cpp:7:10: error: call to 'abs' is ambiguous
return std::abs(i);
^~~~~~~~
/Library/Developer/CommandLineTools/usr/include/c++/v1/math.h:761:1: note:
candidate function
abs(float __lcpp_x) _NOEXCEPT {return ::fabsf(__lcpp_x);}
^
(... etc.)
1 error generated.
If you #include <cstdlib>, it works without error.
using -std=gnu++17 or -std=c++1z doesn't remove the problem either.
In the actual code (which is obviously more complex than the above, and actually uses c++17 features), the error happens depending on the order of my include files.
I can't replicate that in the simple example, but I assume it boils down to calling the cstdlib version instead of the cmath version.
Currently, my 'workaround' is to just put the header includes into the order that works..but this is hardly a long-term solution.
Does anyone know the cause?
Version info (error not specific to this MacOS version, also happens on my students' laptops):
Bens-iMac:test ben$ clang++ -v
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
See LWG Issue 2912
This has been fixed in libc++ trunk. I don't know if Apple has shipped this fix yet. As you found, including <cstdlib> is a workaround.

How to compile C++ on Mac OS using TR1

I have a preexisting product that builds on Linux, and I'm trying to port it to Mac OS.
msoulier#merlin:~$ xcode-select -v
xcode-select version 2343.
msoulier#merlin:~$ g++ -v
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 7.3.0 (clang-703.0.29)
Target: x86_64-apple-darwin15.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
The problem is that it uses the tr1/tuple library, and for some reason,
that is not in the default include path.
msoulier#merlin:~$ ls /usr/include/c++/4.2.1/tr1/tuple
/usr/include/c++/4.2.1/tr1/tuple
So it's there, which should be in the include path based on the
--with-gxx-include-dir option above,
And yet
msoulier#merlin:~$ cat hello.cpp
#include <iostream>
#include <tr1/tuple>
using namespace std;
int main(void) {
cout << "Hello, World!" << endl;
return 0;
}
msoulier#merlin:~$ g++ -o hello hello.cpp
hello.cpp:2:10: fatal error: 'tr1/tuple' file not found
#include <tr1/tuple>
^
1 error generated.
Why doesn't this just work?
Thanks.
Short answer: call clang++ with -stdlib=libstdc++, and the tr1 headers will be there.
Long answer:
The reason for your error and the 2 sets of C++ includes is that macOS/Xcode has two different C++ standard libraries you can build against: an old GNU libstdc++, and the new and modern LLVM libc++.
As of macOS 10.12 Sierra, the default is now libc++ and libstdc++ is deprecated. libstdc++ is quite old, v4.2.1, and predates C++11 (hence the tr1 headers). If you're going to be maintaining this code long-term, it'd be worth the time to make it C++11 compliant (i.e. #include <tuple>)
Update: Xcode 10 no longer allows building against libstdc++. Either update your codebase to use standard C++11 headers, or use Xcode 9 if that's really not an option.

g++ does not include files it says it includes for C++11?

Short version
When I compile even a simple code using a feature of the C++11 standard (the std::stod function), GCC 4.9.1 fails with the following error:
example.cpp: In function 'int main()':
example.cpp:10:18: error: 'stod' is not a member of 'std'
double earth = std::stod (orbits,&sz);
^
example.cpp:11:17: error: 'stod' is not a member of 'std'
double moon = std::stod (orbits.substr(sz));
^
What?
The command I use is g++ -std=c++11 example.cpp.
This is the test code (which compiles fine on other systems):
// stod example from http://www.cplusplus.com/reference/string/stod/
#include <iostream> // std::cout
#include <string> // std::string, std::stod
int main ()
{
std::string orbits ("365.24 29.53");
std::string::size_type sz; // alias of size_t
double earth = std::stod (orbits,&sz);
double moon = std::stod (orbits.substr(sz));
std::cout << "The moon completes " << (earth/moon) << " orbits per Earth year.\n";
return 0;
}
details
I am using a version of GCC 4.9.1 I compiled myself on two different clusters running CentOS 6.5 (I use the modules system on stuff in my home dir since I'm not an admin).
I will call them cluster 1 and cluster 2: cluster 1 is where the failure happens.
The GCCs were compiled in the same way and at the same time, and loaded using identical module files (save for a minor difference in the base path). The installations are, as far as I can easily check, identical (the same include files exist on both clusters, and have the same contents).
The output from g++ -v is the same on both clusters (again, except for the install path):
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/home/andyras/bin/gcc-4.9.1/libexec/gcc/x86_64-unknown-linux-gnu/4.9.1/lto-wrapper
Target: x86_64-unknown-linux-gnu
Configured with: ../gcc-4.9.1/configure --prefix=/home/andyras/bin/gcc-4.9.1 --enable-languages=c,c++,fortran
Thread model: posix
gcc version 4.9.1 (GCC)
g++ -v using the system GCC gives the same output on both clusters, except on cluster 1 it says it is gcc version 4.4.7 20120313 (Red Hat 4.4.7-3) (GCC) and on cluster 2 says gcc version 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC)
I am trying to debug using g++ -std=c++11 -save-temps -MD example.cpp for more info... this gives some clues, but I don't know where to go from here.
The intermediate (.ii) files on cluster 1 are missing some lines, for example (excerpt from diffing the .ii files):
< # 277 "/opt/gcc-4.9.1/include/c++/4.9.1/cwchar" 3
---
> # 277 "/home/andyras/bin/gcc-4.9.1/include/c++/4.9.1/cwchar" 3
961,963c934,936
< using std::wcstold;
< using std::wcstoll;
< using std::wcstoull;
---
>
>
>
As I interpret it, GCC on both clusters tries to include files like cwchar, but on cluster 1 there are blank lines instead of things being defined. On cluster 2 the stod function is in the intermediate file, but not on cluster 1.
Could it be a preprocessor error?
Now looking at the .d (dependency) files, I also see a concrete difference. There are some files listed on cluster 2 that are not listed on cluster 1. Here is the list (I processed the contents of the .d files to account for the different base paths; // stands in for the install path):
85a86,108
> //gcc-4.9.1/include/c++/4.9.1/ext/string_conversions.h
> //gcc-4.9.1/include/c++/4.9.1/cstdlib
> /usr/include/stdlib.h
> /usr/include/bits/waitflags.h
> /usr/include/bits/waitstatus.h
> /usr/include/sys/types.h
> /usr/include/sys/select.h
> /usr/include/bits/select.h
> /usr/include/bits/sigset.h
> /usr/include/sys/sysmacros.h
> /usr/include/alloca.h
> //gcc-4.9.1/include/c++/4.9.1/cstdio
> /usr/include/libio.h
> /usr/include/_G_config.h
> /usr/include/bits/stdio_lim.h
> /usr/include/bits/sys_errlist.h
> //gcc-4.9.1/include/c++/4.9.1/cerrno
> /usr/include/errno.h
> /usr/include/bits/errno.h
> /usr/include/linux/errno.h
> /usr/include/asm/errno.h
> /usr/include/asm-generic/errno.h
> /usr/include/asm-generic/errno-base.h
I was curious if cpp was looking for includes in all the wrong places, but this seems legit (cpp -v):
#include <...> search starts here:
/home/andyras/bin/gcc-4.9.1/include
/home/andyras/bin/gcc-4.9.1/include/c++/4.9.1/
/home/andyras/bin/gcc-4.9.1/include/c++/4.9.1/x86_64-unknown-linux-gnu/
/home/andyras/bin/gcc-4.9.1/lib/gcc/x86_64-unknown-linux-gnu/4.9.1/include
/usr/local/include
/home/andyras/bin/gcc-4.9.1/lib/gcc/x86_64-unknown-linux-gnu/4.9.1/include-fixed
/usr/include
End of search list.
This has been a very frustrating couple of hours trying to track down the source of the problem. I could, of course, use something like atof(myString.c_str()) instead of std::stod, but I am wondering if there is an underlying issue that will foul up future projects using other bits of C++11.
Any more clues or insight would be very much appreciated.
You have already done all the necessary footwork to determine the root cause. You already know the answer: you have posted clear differences between how custom gcc installs behave on your "cluster 1" and "cluster 2", a non-working and a working build.
So, something is obviously different between these two gcc installs; if one compiles, links, and runs some code, and the other one chokes on the exact same piece of code. Unfortunately, it's hard to pinpoint where things go off the rails. Having built gcc myself before, previously, I can say that gcc is a hellishly difficult, and very fickle package to install. For example, after several days chasing a mysterious failure when linking some C++ code, I ended up chasing it down to gcc picking up the wrong version of binutils, in gcc's configure script, and internally turning off some obscure feature, that eventually manifested itself as a link failure not of gcc, but of stuff that got built with gcc. gcc itself got built, and installed, with nary a complaint, but it was broken.
So, I find it completely unsurprising, and entirely plausible, the proposition that gcc itself got built and installed without an apparent issue, but it's broken, and will choke on valid code, in this fashion.
My guess would be that your busted gcc build is using a broken default include path -- it's looking for headers in /usr/include, instead of your own custom installation directory. That's the most likely answer, but it could really be anything.
Well, you obviously have (like you wrote yourself) two different versoins of gcc (one time 4.4.7-3 and the other 4.4.7-4), and It seems that they have (even though slightly) differences in compiling the code.
As I've read somewhere, the C++11-standard is not yet included completely in all compilers, so this seems to be the cause on the one Cluster. The other has (you might know why) a version where more of the new standard is included and since you want you use exactly this feature I'd recommend installing this version on the other Cluster too.

How to compile a C++ program in LLVM using clang++?

There is a tutorial - http://llvm.org/docs/GettingStartedVS.html Example done in pure C. I can compile and link it. Without problem, really. But I need C++, not pure C. And here the difficulties begin.
For clang++ I use string like
"C:\..> clang++ -c hello.cpp -emit-llvm -o hello.bc"
then:
"C:\..> llc -filetype=obj hello.bc"
and
"C:\..> link hello.obj -defaultlib:libcmt -out:hello.exe"
there I get 14 errors LNK2001: unresolved external symbol
So, I need some tips. What I do wrong?
//-----------------
hello.cpp:
#include < iostream >
int main()
{
std::cout << "TEST\n" << std::endl;
return 0;
}
//-----------------
OS: Windows7.
UPD: Main question: how from .bc get .exe? (LLVM, Windows7)
You can use my GCC and Clang packages:
Download and extract them to the same directory. Clang will use GCC 4.6.3's libstdc++ and MinGW-w64's CRT. Call it like you would gcc.
Clang/LLVM cannot currently work with MSVC's C++ library, due to ABI issues. GCC's libstdc++ works quite well, though it has holes in surprising places (like std::to_string, <regex>, and <thread>).
Clang's Windows support is OK, but far from complete. You cannot for example dllexport whole C++ classes, unfortunately. And Win64 code generation is also not good enough to have a working C++ install (even in combination with GCC, like for 32-bit).