Newlib v2.5.0 and LibC++ locale support BROKEN

I have a partial fix for these issues.

The first is a group of errors that are due to Newlib v2.5.0 providing a richer Locale support than previous releases (Newlib’s ‘locale.h’), and this is turn results in conflicts for all the definitions contained in LibC++’s source ‘include/support/newlib/xlocale.h’ I have changed:

#include <support/xlocale/__nop_locale_mgmt.h>

to:

#if defined(NEWLIB) && (NEWLIB == 2) \

&& defined(NEWLIB_MINOR) && (NEWLIB_MINOR >= 5) \

&& (!defined(__POSIX_VISIBLE) || (__POSIX_VISIBLE < 200809))

#include <support/xlocale/__nop_locale_mgmt.h>

#endif

I think that this is a reasonably portable resolution, though I will have to examine intermediate versions of Newlib after v2.2.0-20150423 and before v2.5.0 to see when the relevant changes occurred, so the exclusion check may need to be refined.

However, I am not sure what to do about ‘vasprintf’. I tried excluding the function ‘__libcpp_asprintf_l’ if ‘STRICT_ANSI’ is defined, but this had knock-on consequences because this function is used elsewhere in the C++ headers, so it is a more complex issue to resolve.

Thanks,

MartinO

You should define _GNU_SOURCE, in order to get the vasprintf definition (newlib will set __GNU_VISIBLE based on it)

While _GNU_SOURCE is “theoretically” supposed to be for end-users to define, to request extra nonstandard functions from standard headers, in practice, it’s set effectively always for C++ code, because the C++ standard libraries need it. (see how clang sets it by default for a number of targets in clang/lib/Basic/Targets.cpp).

Thanks James, I will try that.

MartinO

Following up on my message yesterday, I tried building with ‘_GNU_SOURCE’ defined, and this fixes the ‘vasprintf’ issue. But it threw up a different problem.

When compiling ‘llvm/projects/libcxx/src/system_error.cpp’ I got the following error message:

/home/martino/llvm/projects/libcxx/src/system_error.cpp:79:14: error: assigning to ‘int’ from incompatible type ‘char *’

if ((ret = ::strerror_r(ev, buffer, strerror_buff_size)) != 0) {

^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

and this is because Newlib’s implementation of ‘<string.h>’ is as follows (this is unchanged in v2.5.0 from v2.2.0):

/* There are two common strerror_r variants. If you request

_GNU_SOURCE, you get the GNU version; otherwise you get the POSIX

version. POSIX requires that #undef strerror_r will still let you

invoke the underlying function, but that requires gcc support. */

#if __GNU_VISIBLE

char *_EXFUN(strerror_r,(int, char *, size_t));

#else

ifdef GNUC

int _EXFUN(strerror_r,(int, char *, size_t))

#ifdef __ASMNAME

asm (__ASMNAME (“__xpg_strerror_r”))

#endif

;

else

int _EXFUN(__xpg_strerror_r,(int, char *, size_t));

define strerror_r __xpg_strerror_r

endif

#endif

So I edited ‘system_error.cpp’ and this with the other changes I mentioned appears to make it all compile perfectly J Of course, now I have to run the test-suite to see if it breaks anything. My edit to ‘system_error.cpp’ is as follows:

#if defined(linux) && !defined(_LIBCPP_HAS_MUSL_LIBC) \

&& (!defined(ANDROID) || ANDROID_API >= 23) \

(defined(_NEWLIB_VERSION) && defined(_GNU_SOURCE))

// GNU Extended version

string do_strerror_r(int ev) {

char buffer[strerror_buff_size];

char* ret = ::strerror_r(ev, buffer, strerror_buff_size);

return string(ret);

}

#else

// POSIX version

string do_strerror_r(int ev) {

Because my target is for an embedded system, ‘linux’ is not defined.

All the best,

MartinO