Skip to content

本文是F7LY开发中遇到的一个问题,裸机环境本来都是freestanding的,记录一下解决过程。

当我发现一个for循环语法用不了时,我想把cpp的标准从17提升到20进行编译,但是一提升报了一万个错出来 提示的都是各种重定义:

sh
                 from kernel/boot/riscv/main.cc:12:
kernel/libs/klib.hh:56:16: error: conflicting declaration of ‘int vsnprintf(char*, size_t, const char*, va_list) with ‘C++’ linkage
   56 |         int    vsnprintf( char *str, size_t size, const char *format, va_list ap );
      |                ^~~~~~~~~
In file included from /usr/riscv64-linux-gnu/include/features.h:502,
                 from /usr/riscv64-linux-gnu/include/sys/types.h:25,
                 from kernel/devs/../types.hh:4,
                 from kernel/devs/spinlock.hh:5,
                 from kernel/devs/uart.hh:3,
                 from kernel/boot/riscv/main.cc:1:
/usr/riscv64-linux-gnu/include/bits/stdio2.h:65:1: note: previous declaration with ‘C’ linkage
   65 | __NTH (vsnprintf (char *__restrict __s, size_t __n,
      | ^~~~~
In file included from /usr/riscv64-linux-gnu/include/time.h:33,
                 from /usr/riscv64-linux-gnu/include/pthread.h:23,
                 from /usr/riscv64-linux-gnu/include/c++/11/riscv64-linux-gnu/bits/gthr-default.h:35,
                 from /usr/riscv64-linux-gnu/include/c++/11/riscv64-linux-gnu/bits/gthr.h:148,
                 from /usr/riscv64-linux-gnu/include/c++/11/bits/atomic_wait.h:38,
                 from /usr/riscv64-linux-gnu/include/c++/11/bits/atomic_base.h:41,
                 from /usr/riscv64-linux-gnu/include/c++/11/atomic:41,
                 from kernel/devs/spinlock.hh:7,
                 from kernel/devs/uart.hh:3,
                 from kernel/boot/riscv/main.cc:1:
kernel/tm/time.hh:28:17: error: expected identifier before numeric constant
   28 |                 CLOCK_REALTIME = 0,
      |                 ^~~~~~~~~~~~~~

fuck 不管加多少个-ffreestanding,-nostdlib这种标志都没用。 仔细一看unistd.h,这是怎么包含进来的,我怎么都不会用到这个库吧? 于是陷入深深的崩溃之中。 经高人指点,告诉我可以搜索什么地方可能会包含unistd。所以对所有的包含了的标准库都开始检索。 下面是<atomic>里面<atomic_base>的代码

c
#if __cplusplus > 201703L && _GLIBCXX_HOSTED
#include <bits/atomic_wait.h>
#endif

那很明显就是17一改就多包含了 然后在atomic_wait里就看到了那几个报错的源头:

c

#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
# include <cerrno>
# include <climits>
# include <unistd.h>
# include <syscall.h>
# include <bits/functexcept.h>
#endif

好的,那么这个宏我怎么取消呢?这个宏(包括 _GLIBCXX_HOSTED)定义在c++config里面

c
/* Define to 1 if you have the <link.h> header file. */
#define _GLIBCXX_HAVE_LINK_H 1

/* Define if futex syscall is available. */
#define _GLIBCXX_HAVE_LINUX_FUTEX 1

/* Define to 1 if you have the <linux/random.h> header file. */
#define _GLIBCXX_HAVE_LINUX_RANDOM_H 1

然后根本无法被重覆盖定义,如果改这个文件,以后用cpp的时候有你好看的。 怎么办呢? 那么,为什么学长他们的代码没有爆呢?我们重读一下代码

c

#include <atomic>

namespace hsai
{
...

确实是包含了atomic,当我看了下别人修改学长的时候,发现别人的突然变成了

c
#include <EASTL/atomic.h>

欸怎么就没有了。 然后我满心欢喜地去改我的,然后发现EASTL没有atomic,噢原来是.h啊,那没事.


不过蒙老师又告诉我是可以修的,_GLIBCXX_HOSTED这个宏应该是主机环境生效

c
/* Define to 1 if a full hosted library is built, or 0 if freestanding. */

#define _GLIBCXX_HOSTED __STDC_HOSTED__

但是,我加了-ffreestanding依然没有生效,为什么呢?

高人又让我看看编译参数的顺序 ,有时候顺序也会出问题

makefile
CFLAGS := -Wall -Werror -ffreestanding -O2 -fno-builtin -g -fno-stack-protector $(ARCH_CFLAGS)
CXXFLAGS := $(CFLAGS) -std=c++23 -nostdlib \
			-DEA_PLATFORM_LINUX -DEA_PLATFORM_POSIX \
            -DEA_PROCESSOR_RISCV -DEA_ENDIAN_LITTLE=1 \
            -Wno-deprecated-declarations -Wno-strict-aliasing \
            -fno-exceptions -fno-rtti -Wno-maybe-uninitialized

但是这里确实使用了-ffreestanding 网上似乎有信息。 103626 – _GLIBCXX_HOSTED should respect -ffreestanding_

txt
Jonathan Wakely 2021-12-09 11:05:34 UTC
Libstdc++ should not define _GLIBCXX_HOSTED to 1 when __STD_HOSTED__ == 0 i.e. when -ffreestanding is used.

但是我发现这个是21年的bug,已经被修复了,修复的方法就是#define _GLIBCXX_HOSTED __STDC_HOSTED__,那为什么还有bug?注意这一句评论:

txt
Jonathan Wakely 2022-09-17 22:19:14 UTC
I don't think we need to add the #error to every header. For a start, users never include the bits/* headers directly, and if they do, it's their problem. So we only need to mark the standard headers as hosted-only. And if we add it to <iosfwd>, that already covers a large number of them, because they include that.

所以这个b说我们不应该直接包含bits文件夹下的文件,那不然是我们的问题。但是我包含了<atomic>也会包含你们bit目录下的文件,也没有被控制到。 他们的意见是:

  • 不需要特别处理内部头文件(比如 bits/*),因为它们在 freestanding 下不会被安装。
    • 这部分标记和处理是冗余的,他说他会清理掉这部分。 呃,所以好像这就是bug。不过我没有发现bug的原因,这里应该是__STD_HOSTED__ 这个宏就出错了。

我尝试直接打印出那个宏来

c
    printfBlue("_GLIBCXX_HOSTED:%d\n",_GLIBCXX_HOSTED);

_GLIBCXX_HOSTED:1

那我就很费解,于是加了一行

c
    printfBlue("__STDC_HOSTED__:%d\n", __STDC_HOSTED__);

STDC_HOSTED:0 好的,关键信息来了。我们查资料知道了旧版本中它是硬编码 1 的,无论是否 freestanding。 这个问题在 GCC 11 被记录,在 GCC 13 中被修复(取决于你使用的具体发行版或交叉工具链版本)。

所以,可能是我工具链的版本问题

sh
$ riscv64-linux-gnu-g++ --version
riscv64-linux-gnu-g++ (Ubuntu 11.4.0-9ubuntu1) 11.4.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

好的,意味着我要换版本,最新版13已经没有问题。

上次更新于: