Same version of clang giving different results on different OS's - c++

I have clang 15.0.7 installed with brew in MacOS and the same version installed with MSYS2 in Windows 10.
When I compile the following program:
#include <filesystem>
int main()
{
std::filesystem::path p("/some/path");
std::string s(p);
}
using clang++ -std=c++20 test.cpp I get no compilation errors on MacOS, but in windows it gives:
test.cpp:6:15 error: no matching constructor for initialization of 'std::string' (aka 'basic_string<char>')
std::string s(p);
^ ~
[more errors]
What is going on?

std::filesystem::path::value_type is wchar_t on Windows and char elsewhere.
Hence, std::filesystem::path has a conversion operator to std::wstring on Windows and to std::string elsewhere (who even thought this was a good idea?!).
Call .string() to get std::string in a "portable" manner.
On Windows, make sure to test UTF-8 support on all standard library flavors you're interested in (MSVC STL, GCC's libstdc++, Clang's libc++). I remember that at least on MSVC you had to enable UTF-8 support with a locale, or use std::u8string.

Related

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.

std::to_chars compile but not linking on MacOS / clang

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.

C++ Use of wstring_convert on Linux

I would like to be able to convert text read from a file into multibyte characters.
I have the following C++ code on Windows that is working for me.
When I try to compile the code on Linux though it is failing.
#include <locale>
....
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> utfconv;
std::string line;
while (std::getline(infile, line))
{
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> utfconv;
std::wstring widestr = utfconv.from_bytes(line);
This throws the following errors:
wstring_convert is not a member of std
codecvt_utf8_utf16 is not a member of std
expected primary-expression before wchar_t
I'm using GCC Red Hat 4.4.7-4.
Based on what I read, I've imported 'locale', but it still can't find it.
If wstring_convert is not available, is there something equivalent that I can do?
Most likely your standard is not set properly. std::wstring_convert was first introduced in C++11 and deprecated in C++17, so you need to add the compiler flag -std=c++11 or -std=c++14.
EDIT:
Just saw the GCC version you're using. It's way out of date. Everything should work fine if you download GCC 4.9.x or above
You will have to use a newer GCC version. Precompiled versions are part of Developer Toolset (available as part of most Red Hat Enterprise Linux subscriptions) or as part of Software Collections for CentOS:
devtoolset-7

How should I build a C++ app for distribution to different versions of OS X/macOS?

I know that certain versions of the compiler will break the C++ ABI, but I don't know which versions.
Would I need to use a different version of Xcode for each OS version that I want to support? If so, which versions of Xcode should I use?
You seem to be expecting the kinds of C++ compiler/ABI compatibility issues that are common on Linux. OS X/macOS largely doesn't have issues like these--you can build a binary against the latest SDK (10.13), and set the deployment target to the oldest OS version you want to support (i.e. 10.10). The resulting binary will work on 10.10 and up, there's no need to build multiple binaries for different OS versions.
On the command line, the deployment target can be set using -mmacosx-min-version=. The compiler will even error out if you try to use a library/language feature that is not available on the target version (like std::shared_timed_mutex, a new C++14 feature). Note that some new language features (like std::make_unique here) are implemented in the compiler/headers, so the older library is not a problem:
$ cat test5.cpp
#include <memory>
#include <shared_mutex>
int main()
{
auto x = std::make_unique<int>(3);
printf("%d\n", *x);
std::shared_timed_mutex y;
return 0;
}
$ clang++ -std=c++14 -o test5 test5.cpp -mmacosx-version-min=10.9
test5.cpp:8:7: error: 'shared_timed_mutex' is unavailable: introduced in macOS 10.12
std::shared_timed_mutex y;
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/shared_mutex:204:58: note: 'shared_timed_mutex' has been
explicitly marked unavailable here
class _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_timed_mutex
^
1 error generated.
I believe Qt answers the question with their table of "Supported configurations for Qt 5.10"
https://doc.qt.io/qt-5.10/supported-platforms.html
The three builds would use:
Xcode 8.2 (macOS 10.11)
Xcode 8.3.3 (macOS 10.12)
Xcode 9 (macOS 10.13)

clang++ and u16string

I'm having a hell of a time with this simple line of code and the latest clang++
#include <stdio.h>
#include <string>
using std::u16string;
int main ( int argc, char** argv )
{
u16string s16 = u"鵝滿是快烙滴好耳痛";
return EXIT_SUCCESS;
}
Ben-iMac:Desktop Ben$ clang++ -std=c++0x -stdlib=libc++ main.cpp -o main
main.cpp:15:21: error: use of undeclared identifier 'u'
u16string s16 = u"鵝滿是快烙滴好耳痛"
The latest released versions of clang, v2.9 from llvm.org or Apple's clang 3.0, do not support Unicode string literals. The latest available version, built from top of trunk source does support Unicode string literals.
The next llvm.org release of clang (i.e., 3.0) will support the Unicode string literal syntax, but does not have support for any source file encoding beyond ASCII. So even with that llvm.org release you won't be able to type in those characters literally in your source and have them converted to a UTF-16 encoded string value. Instead you'll have to use the \u escapes. Again, top of trunk does support UTF-8 source code, but it didn't get put in in time for the llvm.org 3.0 release that is currently under testing. The next release after that (in 6 months or so) should have better support for UTF-8 source code (but not other source encodings).
Edit: The Xcode 4.3 version of clang does have these features.
Edit: And now the 3.1 release from LLVM.org has them
So clang now fully supports the following:
#include <string>
int main() {
std::u16string a = u"鵝"; // UTF-8 source is transformed into UTF-16 literal
std::u32string b = U"滿"; // UTF-8 source is transformed into UTF-32 literal
}
It turns out the standard does not actually require much support for char16_t and char32_t in the iostreams library, so you'll probably have to convert to another string type to get much use out of this. At least the ability to convert between these and the more useful std::string is required (though not exactly convenient to set up...).
You can test clang for individual C++11 features, e.g.:
http://clang.llvm.org/docs/LanguageExtensions.html#cxx_unicode_literals
and here's a status page:
http://clang.llvm.org/cxx_status.html