Issue compiling on arm-none-eabi (newlib) with GNU extensions off
CrustyAuklet opened this issue · 4 comments
I'm using experimental outcome in a bare metal ARM cortex-m project. The code is using C++20 and I wanted to change it to -std=c++20
instead of -std=gnu++20
but this causes Outcome to no longer compile.
Compiler: arm-none-eabi-11.3.1-rel1 (latest ARM provided toolchain)
arch: ARM-v8M-baseline (M23)
I traced the issue to the following snippet:
https://github.com/ned14/outcome/blob/94035926674a6db75152a98981a400f074c91534/single-header/outcome-experimental.hpp#L9066-L9081
The code in newlib looks like this:
/* 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 *strerror_r (int, char *, size_t);
#elif __POSIX_VISIBLE >= 200112
# ifdef __GNUC__
int strerror_r (int, char *, size_t)
#ifdef __ASMNAME
__asm__ (__ASMNAME ("__xpg_strerror_r"))
#endif
;
# else
int __xpg_strerror_r (int, char *, size_t);
# define strerror_r __xpg_strerror_r
# endif
#endif
/* Reentrant version of strerror. */
char * _strerror_r (struct _reent *, int, int, int *);
With GNU extensions on the function int strerror_r (int, char *, size_t);
is available, but with GNU extensions off
we are only left with char* _strerror_r (struct _reent *, int, int, int *);
I fixed this in my vendored copy by adding an additional macro branch based on __GNU_VISIBLE
...
#elif __GNU_VISIBLE
strerror_r(c, buffer, sizeof(buffer));
#else
char *s = strerror(c); // NOLINT
if(s != nullptr)
{
strncpy(buffer, s, sizeof(buffer)); // NOLINT
buffer[1023] = 0;
}
#endif
strerror_r
is not racy unlike strerror
so I can't replace as you suggest. Can you suggest an alternative fix?
providing a definition works with GNU extensions on and off.
// ensure definition of strerror_r exists when GNU extensions off
char *strerror_r (int, char *, size_t);
#include <outcome/outcome-experimental.hpp>
Other than that the only function available
in all cases is char * _strerror_r (struct _reent *, int, int, int *);
. This appears to be the functions that all the other
flavors of strerror
are implemented against.
char* strerror_r (int errnum, char *buffer, size_t n)
{
char *error = _strerror_r (_REENT, errnum, 1, NULL);
if (strlen (error) >= n)
return error;
return strcpy (buffer, error);
}
Works in my project, thanks!