0

Background:

While setting up YouCompleteMe compile arguments for a standalone GCC + sysroot for aarch64, I went spelunking in the standard C++ system includes and found this little gem:

[sysroot]/usr/include/c++/11.2.0/cstdarg

#include <stdarg.h>

Which points at

[sysroot]/usr/include/c++/11.2.0/tr1/stdarg.h

#include <tr1/cstdarg>

Which, itself, points at

[sysroot]/usr/include/c++/11.2.0/tr1/cstdarg

#include <cstdarg>

Thereby looping us back to the beginning. The loop is ultimately broken by some #ifdef's but, ultimately, none of these files really defines anything substantial.

Since these three files all really just include other files, this is causing clangd (YCM's back-end compile server) to eventually parse

namespace std
{
  using ::va_list;
} // namespace std

from [sysroot]/usr/include/c++/11.2.0/cstdarg and then emit:

No member named 'va_list' in the global namespace

I double checked my standard system headers and they are essentially identical so this isn't just limited to my cross toolchain.

Questions:

  1. Where is va_list ultimately defined for C++?
  2. What arguments would I need to feed to clangd to resolve this?
  3. What is the purpose of defining system headers like this?

Reference:

The relevant compile arguments are:

'-xc++',
'-std=gnu++17',
'-stdlib=libc++',
'-nostdinc',
'-isystem', SYSROOT_AARCH64 + '/usr/include',
'-isystem', SYSROOT_AARCH64 + '/usr/include/linux',
'-isystem', SYSROOT_AARCH64 + '/usr/include/c++/11.2.0',
'-isystem', SYSROOT_AARCH64 + '/usr/include/c++/11.2.0/tr1',
'-isystem', SYSROOT_AARCH64 + '/usr/include/c++/11.2.0/aarch64-poky-linux',

Comment Responses:

@PasserBy: Where are you seeing that? The only stdarg.h I have is under c++/11.2.0/tr1 (see comment response to teapot418 below) and this does not have any typedefs in it. The total content of this file (minus comments) is:

#ifndef _TR1_STDARG_H
#define _TR1_STDARG_H 1

#include <tr1/cstdarg>

#endif

This matches my host system's stdarg.h so I don't think this is a failing of the toolchain.

@Lundin: I am not using this but it looks like <string> eventually includes <cstdarg> which causes clangd errors.

@teapot418: I had considered this when I noticed that other headers were included as <tr1/foo>. The problem, though, is that removing tr1 as an include directory causes stdarg.h to not be found at all. A simple find reveals:

$ find /path/to/sysroot/ -name stdarg.h
/path/to/sysroot/usr/include/c++/11.2.0/tr1/stdarg.h

This is strange to me as I would have expected to find the C version of stdarg.h somewhere like [sysroot]/usr/include. I would be wrong, though, as comparing to my host system yields the same result:

$ find /usr/include/ -name stdarg.h
/usr/include/c++/12/tr1/stdarg.h

Is there some other shenanigans going on here that I am missing?

@KamilCuk: See below. One thing I notice is that the pats are being included from .../sysroots/x86_64-pokysdk-linux/... while I was primarily using paths from .../sysroots/aarch64-poky-linux/.... Yocto generates both of these as part of the SDK and, I admit, I don't fully appreciate the difference between the two. I would have expected all relevant headers to be in the aarch64-poky-linux but, clearly, this assumption is false.

aarch64-poky-linux-gcc -E -xc - <<<'#include <stdarg.h>'
# 0 "<stdin>"
# 0 "<built-in>"
# 0 "<command-line>"
# 1 "<stdin>"
# 1 "/opt/lmc/sdk/remus/0.31.7/sysroots/x86_64-pokysdk-linux/usr/lib/aarch64-poky-linux/gcc/aarch64-poky-linux/11.2.0/include/stdarg.h" 1 3 4
# 40 "/opt/lmc/sdk/remus/0.31.7/sysroots/x86_64-pokysdk-linux/usr/lib/aarch64-poky-linux/gcc/aarch64-poky-linux/11.2.0/include/stdarg.h" 3 4

# 40 "/opt/lmc/sdk/remus/0.31.7/sysroots/x86_64-pokysdk-linux/usr/lib/aarch64-poky-linux/gcc/aarch64-poky-linux/11.2.0/include/stdarg.h" 3 4
typedef __builtin_va_list __gnuc_va_list;
# 99 "/opt/lmc/sdk/remus/0.31.7/sysroots/x86_64-pokysdk-linux/usr/lib/aarch64-poky-linux/gcc/aarch64-poky-linux/11.2.0/include/stdarg.h" 3 4
typedef __gnuc_va_list va_list;
# 2 "<stdin>" 2
MysteryMoose
  • 2,211
  • 4
  • 23
  • 47
  • I believe `va_list` is a typedef for `__gnuc_va_list` which is a typedef for `__builtin_va_list` which is a compiler builtin. This can be found in stdarg.h. – Passer By Apr 19 '23 at 01:26
  • Why would you ever use stdarg.h in C++ to begin with? Even in C the rule is to avoid this one like the plague. – Lundin Apr 19 '23 at 14:22
  • Search the bowels of the C compiler, for a normal non-cross env the file is in `/usr/lib/gcc/x86_64-linux-gnu/11/include/stdarg.h` (so not /usr/include) – teapot418 Apr 19 '23 at 15:03
  • And I don't think you should have the `tr1` dir as an include path, that's probably what eclipsed the real file and confused the compiler. `tr1/stdarg.h != stdarg.h` – teapot418 Apr 19 '23 at 15:06
  • Please post the output of `gcc -E -xc - <<<'#include '` – KamilCuk Apr 19 '23 at 18:26
  • @Lundin one common case would be that you're trying to compile some code that uses it, and you don't want to have to rewrite that code. – Jeremy Friesner Apr 19 '23 at 18:42

0 Answers0