1 RTT配置
IDE:RT-Thread Studio
RT-Thread版本:4.1.0
MCU:CH32V103C8T6
1.1 配置步骤
- 点亮
c++
组件
- 链接脚本配置
在.text
段中加入:
PROVIDE(__ctors_start__ = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
PROVIDE(__ctors_end__ = .);
. = ALIGN(4);
因为在../rt-thread/components/cxx_crt_init.c
中对C++全局构造函数进行了初始化,链接脚本文件 link.lds
为 C++
全局构造函数的代码分配了段,链接时将其所产生的目标文件链接至 __ctors_start__
和 __ctors_end__
组成的段中。
在链接脚本加入下面段,增加对C++异常的支持:
/* .ARM.exidx is sorted, so has to go in its own output section. */
__exidx_start = .;
ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
/* This is used by the startup in order to initialize the .data secion */
_sidata = .;
} >FLASH AT>FLASH
__exidx_end = .;
__exidx_start
分配了 C++
异常的起始地址, __exidx_end
分配了 C++
异常的结束地址,当异常产生的时候,就会被分配到指定的段地址中。
最后,在.data
加入:
PROVIDE(__dtors_start__ = .);
KEEP(*(SORT(.dtors.*)))
KEEP(*(.dtors))
PROVIDE(__dtors_end__ = .);
. = ALIGN(4);
-
C++编译/链接器配置
注:以下配置内容ARM开发板创建工程时会自动配置,无需手动配置。
将C Complier的Preprocessor
和includes
内容复制到C++ Complier中:
添加C++ Linker中链接脚本的路径:
然后在C++ Linker中勾选:
- 将
main.c
改为main.cpp
(后面的应用程序应都采用cpp
格式)
1.2 使用注意事项
由于RT-Thread RTOS多用于嵌入式系统,对于c++应用程序有一些规则:
- 不使用异常。(实际测试异常捕获失败,导致相关线程卡死,或与因为内核的缘故?)
- 不使用运行时类型信息(RTTI)。
- 不鼓励使用模板,它很容易导致代码文本变大。
- 不鼓励使用静态类变量。调用它们的构造函数的时间和地点无法精确控制,这使多线程编程成为一场噩梦。
- 强烈反对多重继承,因为它会导致不可容忍的混乱。
2 MRS配置
IDE:MounRiver Studio
MCU:CH32V103C8T6
2.1 配置步骤
将创建的C工程转换为C++工程:
修改工程配置:
- 将GNU C中的目录复制到GNU C++中
如:
- 选用C++11标准
- 将
main.c
改为main.cpp
(后面的应用程序应都采用cpp
格式),对于所有.h文件加入:
#ifdef __cplusplus
extern "C" {
#endif
// original code
// ...
#ifdef __cplusplus
}
#endif
2.2 问题与优化
- 引用未定义函数 _read _write _sbrk
使用 printf ,scanf ,malloc 等函数需要实现
_read _lseek _isatty _fstat _write _sbrk
函数。可以重新实现_write() 和 _read() ,实现printf串口重定向。
-
C++支持函数重载,所以生成的目标代码的名字和C会有些不同,对于中断服务函数改名后,就与中断向量表中命名不一致,导致程序无法正常跳转到中断。因此存放诸如
TIM1_UP_IRQHandler
ISR函数的文件不能改为CPP格式,只能用C文件。若需要调用CPP函数,则需要用extern "C"
强制成C语言的名字规则,详见STM32 C/C++ (二)混合编程 函数相互调用 -
在C++中,全局变量和静态变量的构造函数需要在main函数执行前执行,这些构造函数的地址会放在
init_array
表中,因此需要调用这些函数的代码对变量进行初始化,否则构造函数中全局变量默认初始化为0
。(未初始化的变量放在BSS段被清零)
- 方法一
需勾选
--specs=nano.specs
参考RTT的配置(在gcc中ctor_list
里存放的即为全局对象的构造函数的指针):
__attribute__((weak)) int cplusplus_system_init(void)
{
typedef void(*pfunc)();
extern pfunc __ctors_start__[];
extern pfunc __ctors_end__[];
pfunc *p;
for (p = __ctors_start__; p < __ctors_end__; p++)
(*p)();
return 0;
}
并在.h文件中进行声明extern void cplusplus_system_init(void);
最后在startup中时钟初始化前调用:
jal cplusplus_system_init
jal SystemInit
la t0, main
csrw mepc, t0
mret
- 方法二
注意:需要删除startup文件中
.global _start
语句,因为编译器已经为我们定义了程序总入口。
__libc_init_array
函数的底层实现,不同的编译器有不同实现方式:
使用libc
自带的__libc_init_array
初始化函数,使用前需去掉makefile中的编译选项-nostartfiles
:
同样在startup中时钟初始化前调用:
jal __libc_init_array
jal SystemInit
...
However,「方法二」最终测试并没有成功调用构造函数的初始化列表,具体原因暂时不知…
rt-thread实现(rt-thread\components\libc\cplusplus\cxx_crt.cpp
):
void *operator new(size_t size)
{
return rt_malloc(size);
}
void *operator new[](size_t size)
{
return rt_malloc(size);
}
void operator delete(void *ptr)
{
rt_free(ptr);
}
void operator delete[](void *ptr)
{
return rt_free(ptr);
}
void __cxa_pure_virtual(void)
{
rt_kprintf("Illegal to call a pure virtual function.\n");
}
「IDE优化」
-
显示FLASH及RAM的使用占比情况(实际上是为
arm-none-eabi-ld.exe
工具添加--print-memory-usage
命令):
References
- 在 STM32 上使用 C++ 指南
- RT-Thread Studio添加c++及标准异常(std::exception)支持
- ld链接脚本 No such file or directory
- RT-Thread 怎样支持 C++ 的
- RISC-V MCU开发 (四):编译配置
- riscv gnu tool chain Compile error
- 程序员的自我修养—链接、装载与库11.4「C++全局构造与析构.」pdf
- .init, .ctors, and .init_array
- RISC-V MCU IDE MRS(MounRiver Studio)开发之: 编译后打印FLASH及RAM使用占比信息
Appendixes
RISC-V Embedded GCC/bin 所有编译工具帮助命令查看:
riscv-none-embed-addr2line.exe --help
riscv-none-embed-ar.exe --help
riscv-none-embed-as.exe --help
riscv-none-embed-c++.exe --help
riscv-none-embed-c++filt.exe --help
riscv-none-embed-cpp.exe --help
riscv-none-embed-elfedit.exe --help
riscv-none-embed-g++.exe --help
riscv-none-embed-gcc.exe --help
riscv-none-embed-gcc-8.2.0.exe --help
riscv-none-embed-gcc-ar.exe --help
riscv-none-embed-gcc-nm.exe --help
riscv-none-embed-gcc-ranlib.exe --help
riscv-none-embed-gcov.exe --help
riscv-none-embed-gcov-dump.exe --help
riscv-none-embed-gcov-tool.exe --help
riscv-none-embed-gdb.exe --help
riscv-none-embed-gdb-py.exe --help
riscv-none-embed-gprof.exe --help
riscv-none-embed-ld.bfd.exe --help
riscv-none-embed-ld.exe --help
riscv-none-embed-nm.exe --help
riscv-none-embed-objcopy.exe --help
riscv-none-embed-objdump.exe --help
riscv-none-embed-ranlib.exe --help
riscv-none-embed-readelf.exe --help
riscv-none-embed-size.exe --help
riscv-none-embed-strings.exe --help
riscv-none-embed-strip.exe --help
END