VxWorks 6.9 内核编程指导之读书笔记 -- C++开发

时间:2024-06-27 18:35:56
  • 5.1 介绍
  • 针对C++的VxWorks配置
  • C++头文件
  • 使用C++启动任务
  • C和C++之前调用代码
  • C++编译器说明
  • 在信号处理和ISR中使用C++
  • 下载C++编写的内核模块
  • C++编译器的不同
  • 命名空间
  • C++异常处理
  • C++示例

介绍

注意:风河C++编译器与GNU C++二进制文件不兼容。

针对C++的VxWorks配置

默认情况下,VxWorks只包含了最小的C++支持。可以通过包含所有或部分组件来支持C++的全部或部分功能,

INCLUDE_CTORS_DTORS

默认包含了该组件。确保编译器产生初始化函数,包括C++静态对象的初始化,在内核启动时调用。

INCLUDE_CPLUS

包含C++应用程序的基本支持。通常与INCLUDE_CPLUS_LANG一起使用。

INCLUDE_CPLUS_LANG

包含C++语言特性的支持,如new,delete和异常处理

INCLUDE_CPLUS_IOSTREAM

包含所有类库功能。

INCLUDE_CPLUS_DEMANGLER

该组件在使用INCLUDE_CPLUS和INCLUDE_SYM_TBL组件时被自动增加。

C++头文件

每个编译器都有自己的头文件和类库,不必用户指定所在的文件夹,编译器将在特定目录查找。

使用C++启动任务

任何使用C++启动的任务都必须使用VX_FP_TASK选项。默认,从主机工具发起的任务自动带有该选项(如Wind Shell)。

注意:没有使用该选项,将在运行时导致很难调试的、不可预期的浮点寄存器的损坏。C++的异常处理器将使用浮点寄存器。该选项确保产生异常时,浮点寄存器将被保存和恢复。

C和C++代码之间的调用

如果在C中调用C++的代码,则必须使用extern “C”来导出原型。使用下面的方式可以使代码能被C和C++都调用。

#ifdef _cplusplus

extern "C" void myEntryPoint();

#else

void myEntryPoint();

#endif

C++编译器的说明

Small data area (SDA)重新分配,只被PowerPC和MIPS支持,C++代码并不工作。别使用风河Diab编译器的-Xsmall-const=8 -Xsmall-data=8选项,或GUN编译器的-G8 -msdata=eabi选项

在信号处理器和ISR中使用C++

在信号处理器和ISR中使用C++代码必须特别小心。更多信息看信号处理和编写ISR章节。

下载C++编写的内核模块

要下载到VxWorks内核的C++代码应该被链接成单一的可下载对象模块。它必须被munched,任何COMDAT和linkonce的section必须被填充。

使用单一的C++模块

VxWorks的加载器只支持自包含的C++模块。自包含C++模块就是不使用其它模块中的类的模块,它的类也不被其它模块使用。特别,模块要么包含标准类库的一份拷贝,要不根本不使用C++标准类库。

为了产生自包含模块,所有可下载的C++对象必须被链接成单一的可下载对象模块。

卸载不是自包含的C++模块,可能导致其它模块中创建的对象或数据结构的引用的损坏。如果iostream的标准库的部分从一个稍后被卸载的模块中初始化,这是可能发生的。这种情况下,iostream的任何的进一步使用都将导致内核异常(访问非法地址)。

Munching一个应用程序模块

在C++模块被下载到VxWorks内核之前,由于历史原因,它必须经历一个额外的步骤,称为munching。Munching执行以下任务

  1. 对静态对象的初始化支持
  2. 确保对所有的静态对象按顺序调用正确的构造和析构函数。
  3. 对应风河的编译器,自动填充COMDAT段;对应GNU编译器,自动填充linkonce段。

Munching必须在下载之前,编译之后执行。

Munching的例子

对于每一个工具链,下面的例子编译了一个C++应用程序源码hello.cpp,在.o上运行munch,编译产生ctdt.c文件,并连接应用程序和ctdt.o产生可可下载的模块,hello.out。

使用风河工具链 
1. Compile the source code:
$ dcc -tPPC604FH:vxworks61 -Xlocal-data-area-static-only -XO \
-IinstallDir/vxworks-6.x/target/h -DCPU=PPC32 -DTOOL_FAMILY=diab -DTOOL=diab \
-D_WRS_KERNEL -c hello.cpp
2. Munch the object file:
$ ddump -Ng hello.o | tclsh \
installDir/vxworks-6.x/host/resource/hutils/tcl/munch.tcl -c ppc > ctdt.c
3. Compile the munch output:
$ dcc -tPPC604FH:vxworks61 -Xlocal-data-area-static-only -XO \
-IinstallDir/vxworks-6.x/target/h -DCPU=PPC32 -DTOOL_FAMILY=diab -DTOOL=diab \
-D_WRS_KERNEL -c ctdt.c
4. Link the original object file with the munched object file to create a
downloadable module:
$ dld -tPPC604FH:vxworks61 -X -r4 -o hello.out hello.o ctdt.o 注意:-r4选项填充输入文件中包含的任何COMDAT段。
使用GNU工具链
1. Compile the source code:
ccppc -mcpu=604 -mstrict-align -O2 -fno-builtin \
-IinstallDir/vxworks-6.x/target/h \
-DCPU=PPC604 -DTOOL_FAMILY=gnu -DTOOL=gnu -c hello.cpp
2. Munch the object file:
nmppc hello.o | wtxtcl installDir/vxworks-6.x/host/src/hutils/munch.tcl \
-c ppc > ctdt.c
3. Compile the munch output:
ccppc -mcpu=604 -mstrict-align -fdollars-in-identifiers -O2 \
-fno-builtin -IinstallDir/vxworks-6.x/target/h \
-DCPU=PPC604 -DTOOL_FAMILY=gnu -DTOOL=gnu -c ctdt.c
4. Link the original object file with the munched object file to create a
downloadable module:
ccppc -r -nostdlib -Wl,-X \
-T installDir/vxworks-6.x/target/h/tool/gnu/ldscripts/link.OUT \
-o hello.out hello.o ctdt.o 注意:VxWorks内核对象加载器并不直接支持linkonce段。相反,在加载之前,linkonce段必须被合并和填充到标准的text和data段。-T选项用来填充任何包含的linkonce段。

使用通用的Makefile规则  

如果使用makefile,则可以编写简单的munch规则(定义适当的CPU和TOOL),可以在支持GUN和风河工具链。

CPU     = PPC604
TOOL = gnu
TGT_DIR = $(WIND_BASE)/target
include $(TGT_DIR)/h/make/defs.bsp
default : hello.out
%.o : %.cpp
$(CXX) $(C++FLAGS) -c $<
%.out : %.o
$(NM) $*.o | $(MUNCH) > ctdt.c
$(CC) $(CFLAGS) $(OPTION_DOLLAR_SYMBOLS) -c ctdt.c
$(LD_PARTIAL) $(LD_PARTIAL_LAST_FLAGS) -o $@ $*.o ctdt.o

munching、下载和连接之后,静态构造和析构将被调用。

调用静态构造和析构

内核加载器提供了自动和手动选项去调用静态构造和析构。

自动调用是默认策略。静态构造仅在模块被下载之后且模块加载器返回给调用者之前被执行。静态析构在模块被卸载之前执行。

手动调用意味着用户必须在模块加载之后,显式调用静态构造,但是必须在运行应用程序之前。也需要用户在任务完成之后且在模块卸载之前,显式调用析构。

静态构造可以通过调研cplusCtors来调用。静态析构通过cplusDtors来调用。这些函数带有单独的模块名称作为参数。然而,你也可以通过调用这些函数而不带参数来调用所有的被加载到当前系统的对象的静态构造和析构。

注意:当使用手动方法时,每个模块的构造必须只能被调用一次。

可以在运行时,调用cplusXtorSet函数来改变调用策略。可以使用cplusStratShow来得到当前的调用策略。

C++编译器的不同

风河公司的C++编译器使用EDG风格(Edison Design Group),完全遵循ANSI C++标准。GUN编译器支持大部分ANSI C++标准的语言特性。二者的二进制文件并不兼容。因此,编译VxWorks映像的工具链和编译可下载的内核应用程序必须使用相同的工具链。

模板实例化

运行时类型信息

命名空间

无特别之处

C++异常处理

C++异常处理是通过INCLUDE_CPLUS_LANG组件提供的。为了禁用C++异常处理,必须

  1. 在创建VIP项目之前,定义CXX_STL_VARIANT=abridged环境变量。这确保正确的库被链接(异常禁用)。
  2. 为GNU添加-mc++-abr;为Diab添加-Xc++-abr选项。

C++演示

factory例子演示了C++的各种特性,包括STL,用户定义模板,运行时类型信息RTII及异常处理。代码位于/target/src/demo/cplusplus/factory。

使用该实例程序,内核必须包含下列组件

  • INCLUDE_CPLUS
  • INCLUDE_CPLUS_LANG
  • INCLUDE_CPLUS_IOSTREAM

另外对于GNU编译器,还需包含以下组件

  • INCLUDE_CPLUS_STRING
  • INCLUDE_CPLUS_STRING_IO

编译代码作为可下载内核模块,下载到目标板上,并且调用testFactory来启动。举个例子,在shell中使用如下命令

ld <factory.out

testFactory