libcxx error: template with C linkage

Hi Everyone,

I'm compiling the LLVM libcxx for NuttX RTOS (compiling on Linux to
integrate it on NuttX).

But it is failing with tons of these "error: template with C linkage" :

make[1]: Entering directory '/home/alan/nuttxspace/nuttx/libxx'
CXX: libcxx/algorithm.cxx
arm-none-eabi-g++ -c -Wall -Wshadow -Wundef -g -mcpu=cortex-m4
-mthumb -mfloat-abi=soft -I. -isystem
/home/alan/nuttxspace/nuttx/include -isystem
/home/alan/nuttxspace/nuttx/include/cxx -isystem
/home/alan/nuttxspace/nuttx/include/libcxx -pipe -std=c++11
-DCLOCK_MONOTONIC -D__NuttX__ -pedantic -D_DEBUG
-D_LIBCPP_BUILD_STATIC libcxx/algorithm.cxx -o algorithm.o
In file included from
/home/alan/nuttxspace/nuttx/include/libcxx/algorithm:639:0,
                 from libcxx/algorithm.cxx:10:
/home/alan/nuttxspace/nuttx/include/libcxx/type_traits:397:1: error:
template with C linkage
template <class _T1, class _T2> struct _LIBCPP_TYPE_VIS_ONLY pair;
^
/home/alan/nuttxspace/nuttx/include/libcxx/type_traits:398:1: error:
template with C linkage
template <class _Tp> class _LIBCPP_TYPE_VIS_ONLY reference_wrapper;
^
/home/alan/nuttxspace/nuttx/include/libcxx/type_traits:399:1: error:
template with C linkage
template <class _Tp> struct _LIBCPP_TYPE_VIS_ONLY hash;
^
/home/alan/nuttxspace/nuttx/include/libcxx/type_traits:401:1: error:
template with C linkage
template <class>
^
/home/alan/nuttxspace/nuttx/include/libcxx/type_traits:404:1: error:
template with C linkage
template <class _Tp>
^
/home/alan/nuttxspace/nuttx/include/libcxx/type_traits:407:1: error:
template with C linkage
template <class _Tp, bool>
^
/home/alan/nuttxspace/nuttx/include/libcxx/type_traits:410:1: error:
template with C linkage
template <bool _Bp, class _If, class _Then>
^
/home/alan/nuttxspace/nuttx/include/libcxx/type_traits:412:1: error:
template with C linkage
template <class _If, class _Then>
^
/home/alan/nuttxspace/nuttx/include/libcxx/type_traits:419:1: error:
template with C linkage
template <bool, class _Tp> struct _LIBCPP_TYPE_VIS_ONLY __lazy_enable_if {};
^
/home/alan/nuttxspace/nuttx/include/libcxx/type_traits:420:1: error:
template with C linkage
template <class _Tp> struct _LIBCPP_TYPE_VIS_ONLY
__lazy_enable_if<true, _Tp> {typedef typename _Tp::type type;};
^
/home/alan/nuttxspace/nuttx/include/libcxx/type_traits:422:1: error:
template with C linkage
template <bool, class _Tp = void> struct _LIBCPP_TYPE_VIS_ONLY enable_if {};

I searched on Internet and discovered that this error happens when
there is some 'extern "C" { ' without the closing ' }' and then it
wrap some C++ code.

I saw this comment inside ctype.h :

#ifdef __cplusplus
#if defined(_LIBCPP_MSVCRT)
// We support including .h headers inside 'extern "C"' contexts, so switch
// back to C++ linkage before including these C++ headers.
extern "C++" {
  #include "support/win32/support.h"
  #include "support/win32/locale_win32.h"
}
#endif // _LIBCPP_MSVCRT

Although I'm not on MSVCRT, the comment explains why this error could happen.

But I used -save-temps to create the algorithm.ii and searched for all
occurrences of 'extern "C" {' inside it and I can confirm there is not
C++ header inside any 'extern C' block.

After many tests I noted that if I modify include/algorithm to include
'extern "C++" {' :
@@ -634,7 +634,10 @@ template <class BidirectionalIterator, class Compare>

#include <__config>
#include <initializer_list>
+extern "C++"
+{
#include <type_traits>
+}
#include <cstring>
#include <utility> // needed to provide swap_ranges.
#include <memory>

The issue disappear, but I want to discover the root caused instead of
use an ugly hack.

How I can discover where the error is happening, since -save-temps
didn't show nothing wrong ?

BR,

Alan

But I used -save-temps to create the algorithm.ii and searched for all

occurrences of ‘extern “C” {’ inside it and I can confirm there is not
C++ header inside any ‘extern C’ block.

Are you sure about that? libc++ provides its own version of each C library header as well (ex. <math.h>).
My best guess is that the system C library is included a libc++ C library wrapper inside an ‘extern C’ block.

/Eric

Don’t libc++'s .h headers all have an extern “C++” block to avoid that possibility?

There also doesn’t seem to be any evidence of this in the #include stack reported by the compiler. It looks like maybe a system header ended with an extern “C” still open, or somehow libc++'s headers are being implicitly treated as “extern C” system headers (which get an explicit extern “C” wrapped around them).

Alan, can you provide the preprocessed file produced by -save-temps?

> But I used -save-temps to create the algorithm.ii and searched for all
> occurrences of 'extern "C" {' inside it and I can confirm there is not
> C++ header inside any 'extern C' block.

Are you sure about that? libc++ provides its own version of each C library
header as well (ex. <math.h>).
My best guess is that the system C library is included a libc++ C library
wrapper inside an 'extern C' block.

Don't libc++'s .h headers all have an extern "C++" block to avoid that
possibility?

It seems some headers do, including <math.h>, but there are still others
without it.

Thank you Eric and Richard,

Yes, I think there is some 'export "C" { ' without the closing brace
'}' in some NuttX header.

I got libcxx working on NuttX. Basically all I needed to do was to add
'extern "C++" {' inside all headers files:

https://bitbucket.org/acassis/libcxx/commits/all

Should these modification be included on libcxx? I can submit my patches!

BR,

Alan

Hi Richard,

Right, please find it attached.

Just to recall, these are the errors:

make[1]: Entering directory '/tmp/LIBCXX/nuttx_libcxx/libxx'
CXX: libcxx/algorithm.cxx
arm-none-eabi-g++ -c -Wall -Wshadow -Wundef -Os -fno-strict-aliasing
-fno-strength-reduce -fomit-frame-pointer -mcpu=cortex-m4 -mthumb
-mfloat-abi=soft -I. -isystem /tmp/LIBCXX/nuttx_libcxx/include
-isystem /tmp/LIBCXX/nuttx_libcxx/include/cxx -isystem
/tmp/LIBCXX/nuttx_libcxx/include/libcxx -pipe -std=c++11
-DCLOCK_MONOTONIC -D__NuttX__ -fno-builtin -fno-exceptions -fcheck-new
-fno-rtti -pedantic -D_DEBUG -D_LIBCPP_BUILD_STATIC
-D_LIBCPP_NO_EXCEPTIONS libcxx/algorithm.cxx -o algorithm.o
In file included from /tmp/LIBCXX/nuttx_libcxx/include/libcxx/algorithm:636:0,
                 from libcxx/algorithm.cxx:10:
/tmp/LIBCXX/nuttx_libcxx/include/libcxx/initializer_list:58:1: error:
template with C linkage
template<class _Ep>
^
/tmp/LIBCXX/nuttx_libcxx/include/libcxx/initializer_list:96:1: error:
template with C linkage
template<class _Ep>
^
/tmp/LIBCXX/nuttx_libcxx/include/libcxx/initializer_list:105:1: error:
template with C linkage
template<class _Ep>
^
In file included from /tmp/LIBCXX/nuttx_libcxx/include/libcxx/algorithm:637:0,
                 from libcxx/algorithm.cxx:10:
/tmp/LIBCXX/nuttx_libcxx/include/libcxx/type_traits:395:1: error:
template with C linkage
template <class _T1, class _T2> struct _LIBCPP_TYPE_VIS_ONLY pair;
^
/tmp/LIBCXX/nuttx_libcxx/include/libcxx/type_traits:396:1: error:
template with C linkage
template <class _Tp> class _LIBCPP_TYPE_VIS_ONLY reference_wrapper;
^
/tmp/LIBCXX/nuttx_libcxx/include/libcxx/type_traits:397:1: error:
template with C linkage
template <class _Tp> struct _LIBCPP_TYPE_VIS_ONLY hash;
^
/tmp/LIBCXX/nuttx_libcxx/include/libcxx/type_traits:399:1: error:
template with C linkage
template <class>
^
/tmp/LIBCXX/nuttx_libcxx/include/libcxx/type_traits:402:1: error:
template with C linkage
template <class _Tp>
^
/tmp/LIBCXX/nuttx_libcxx/include/libcxx/type_traits:405:1: error:
template with C linkage
template <class _Tp, bool>
^
/tmp/LIBCXX/nuttx_libcxx/include/libcxx/type_traits:408:1: error:
template with C linkage

BR,

Alan

algorithm.ii (1.55 MB)

Today (almost two years later) I received an email from Anthony
Merlino, he discovered the source of the issue:

"The arm-gcc toolchain automatically wraps extern C around all headers
included using the -isystem path.

See: Bug #1698539 “-isystem leads to code wrapped in extern “C"" : Bugs : GNU Arm Embedded Toolchain
Another discussion: Ian Lance Taylor - Re: error: template with C linkage

This default behavior can be changed by setting NO_IMPLICIT_EXTERN_C
and rebuilding the toolchain. Working on that now so I can test and
make sure it works."

I decided to send it here because other people could face similar
issues and could to spend much time trying to find an unbalanced
"extern C" that in fact doesn't exist.

BR,

Alan