WS63 SDK 添加 C++ 编译支持完整指南
概述
本文档记录了在海思 WS63 SDK 中添加 C++ 编译支持的完整过程,包括遇到的问题、解决方案和最终配置。适用于需要在 WS63 芯片上使用 TensorFlow Lite Micro (TFLM) 或其他 C++ 库的开发者。
开发环境
-
芯片: WS63 (RISC-V 架构,riscv31)
-
工具链: riscv32-musl-105-fp (支持浮点)
-
SDK 路径:
G:\HiSpark_SDK\fbb_ws63 -
TFLite Micro:
G:\HiSpark_SDK\fbb_ws63\tflite-micro
背景与目标
初始状态
WS63 SDK 原生只支持 C 语言编译,缺少 C++ 支持:
-
没有
cxxflags配置 -
构建系统未配置 C++ 编译器选项
-
CMake 构建脚本未区分 C/C++ 编译选项
目标
-
添加基本的 C++ 编译支持
-
支持浮点运算(与 C 代码 ABI 兼容)
-
能够编译和运行 C++ 测试程序
-
为集成 TFLite Micro 做准备
配置步骤
步骤 1: 添加架构级别的 CXXFLAGS
文件: src/build/config/target_config/common_config.py
问题: arch_config 中所有架构只定义了 ccflags,缺少 cxxflags
解决方案: 为每个架构添加 cxxflags 字段
# ===== CUSTOM BEGIN: 添加 common_cxxflags =====
common_cxxflags = [
'-std=gnu++17', # C++17 标准
'-Wall',
'-Werror',
'-Wextra',
'-Winit-self',
'-Wpointer-arith',
# '-Wstrict-prototypes', # C++ 不支持此选项,已移除
'-Wno-type-limits',
'-Wno-unused-parameter', # TFLM 头文件中有未使用参数
'-fno-strict-aliasing',
'-Os',
'-fno-unwind-tables',
]
# ===== CUSTOM END =====
为每个架构添加 cxxflags(以 riscv31 为例,WS63 使用此架构):
'riscv31': {
'ccflags': [...],
# ===== CUSTOM BEGIN: 为 riscv31 架构添加 C++ 编译标志 =====
'cxxflags': [
'-ffreestanding',
'-fdata-sections',
'-Wno-implicit-fallthrough',
'-ffunction-sections',
'-nostdlib',
'-pipe',
'-mabi=ilp32',
'-march=rv32imc',
'-fno-tree-scev-cprop',
'-fno-common',
'-mpush-pop',
'-msmall-data-limit=0',
'-fno-ipa-ra',
'-Wtrampolines',
'-Wlogical-op',
# '-Wjump-misses-init', # C only, 已移除
"-Wa,-enable-c-lbu-sb",
"-Wa,-enable-c-lhu-sh",
"-fimm-compare",
"-femit-muliadd",
"-fmerge-immshf",
"-femit-uxtb-uxth",
"-femit-lli",
"-femit-clz",
"-fldm-stm-optimize",
'-g',
],
# ===== CUSTOM END =====
'linkflags': [...],
...
}
关键点:
-
C++ 移除了
-Wjump-misses-init(仅 C 支持) -
C++ 移除了
-Wstrict-prototypes(C++ 不支持)
步骤 2: 配置 CMake 区分 C/C++ 编译选项
文件: src/build/cmake/build_component.cmake
问题: CMake 使用相同的编译选项编译 C 和 C++ 文件
解决方案: 使用 CMake 生成器表达式区分语言
# 原代码:
target_compile_options(${COMPONENT_NAME}
PRIVATE
${COMPILE_CCFLAGS}
$<$<BOOL:${USE_KCONFIG}>:-include${PROJECT_BINARY_DIR}/mconfig.h>
)
# 修改为:
target_compile_options(${COMPONENT_NAME}
PRIVATE
# ===== CUSTOM BEGIN: 为 C++ 语言添加单独的编译选项 =====
# 原代码:${COMPILE_CCFLAGS} (适用于所有语言)
# 修改原因:C++ 需要使用不同的编译标志(如 -std=gnu++17 而非 -std=gnu99)
$<$<COMPILE_LANGUAGE:C>:${COMPILE_CCFLAGS}>
$<$<COMPILE_LANGUAGE:CXX>:${CXXFLAGS}>
# ===== CUSTOM END: 原代码 ${COMPILE_CCFLAGS} 已被上面的生成器表达式替换 =====
$<$<BOOL:${USE_KCONFIG}>:-include${PROJECT_BINARY_DIR}/mconfig.h>
)
步骤 3: 初始化 CXXFLAGS 变量
文件: src/build/cmake/global_variable.cmake
问题: CXXFLAGS 变量未初始化
解决方案:
# ===== CUSTOM BEGIN: 添加 CXXFLAGS 默认值 =====
# 如果从 Python 构建脚本传入了 CXXFLAGS,则使用该值;否则使用 CCFLAGS 作为默认值
if(NOT DEFINED CXXFLAGS)
set(CXXFLAGS "${CCFLAGS}")
endif()
# ===== CUSTOM END =====
步骤 4: 为 WS63 添加浮点支持(关键)
文件: src/build/config/target_config/ws63/target_config.py
问题: C++ 代码使用软浮点 ABI (-mabi=ilp32),而 C 代码使用单精度浮点 ABI (-mabi=ilp32f),导致链接时 ABI 不兼容
错误信息:
can't link soft-float modules with single-float modules
failed to merge target specific data of file
解决方案:
4.1 为 C++ 添加浮点和优化选项
'cxxflags': [
*fp_flags, # 应用浮点 ABI 替换
*codesize_flags['ccflags'],
# 禁用异常和 RTTI 以减少运行时依赖
'-fno-exceptions',
'-fno-rtti',
# 解决未定义引用问题
'-fno-threadsafe-statics',
],
4.2 修改 Python 构建脚本使用 pretend
文件: src/build/script/enviroment.py
def merge_common_config(self, com_config):
""" 将公共配置项合并到config中 """
self.pretend('ccflags', com_config.get_ram_ccflags())
# ===== CUSTOM BEGIN: 为 cxxflags 也使用 pretend =====
# 原代码:self.extend('cxxflags', com_config.get_ram_cxxflags())
# 修改原因:确保 target_config 中定义的 cxxflags(包括 fp_flags)能够替换 common_cxxflags 中的选项
self.pretend('cxxflags', com_config.get_ram_cxxflags())
# ===== CUSTOM END =====
self.extend('rom_ccflags', com_config.get_rom_ccflags())
...
4.3 添加 C++ 标准库
# 原代码:'std_libs': ['m', 'c', 'gcc'],
# ===== CUSTOM BEGIN: 添加 C++ 标准库支持 =====
# 原代码:'std_libs': ['m', 'c', 'gcc'],
'std_libs': ['m', 'c', 'gcc', 'stdc++'],
# ===== CUSTOM END =====
4.4 添加链接器选项
'linkflags': [
*codesize_flags['linkflags'],
# ===== CUSTOM BEGIN: 添加 C++ 链接器选项 =====
# 允许未定义引用(TFLM 的某些函数可能不需要)
'-Wl,--allow-shlib-undefined',
# '-Wl,--unresolved-symbols=ignore-in-link-files', # 此选项不支持,已移除
# ===== CUSTOM END =====
],
步骤 6: 创建 C++ 测试程序
文件: src/application/samples/tflm_hello_world/test_cpp.cc
目的: 验证基本的 C++ 编译和运行
/**
* Simple C++ test file for WS63
* Tests basic C++ compilation support
*/
// 在包含 C 头文件之前,为 C++ 定义正确的 NULL
#ifdef NULL
#undef NULL
#endif
#define NULL 0
#include "common_def.h"
#include "soc_osal.h"
#include "app_init.h"
// 简单的 C++ 类测试
class CppTest {
private:
int value;
public:
constexpr CppTest(int v) : value(v) {}
~CppTest() = default;
int getValue() const { return value; }
void setValue(int v) { value = v; }
CppTest& operator+(const CppTest& other) {
value += other.value;
return *this;
}
};
// 模板函数测试
template<typename T>
constexpr T add(T a, T b) {
return a + b;
}
static constexpr CppTest global_test(42);
extern "C" void tflm_cpp_test_entry(void)
{
CppTest test1(10);
CppTest test2(20);
test1 + test2;
int result = add(5, 3);
osal_printk("C++ Test: global_test = %d, result = %d\r\n",
global_test.getValue(), result);
osal_printk("C++ Test: test1.getValue() = %d, test2.getValue() = %d\r\n",
test1.getValue(), test2.getValue());
}
app_run(tflm_cpp_test_entry);
遇到的问题与解决方案
问题 1: C++ 特有编译选项导致错误
错误:
cc1plus.exe: error: command line option '-Wjump-misses-init' is valid for C/ObjC but not for C++
解决: 从 cxxflags 中移除 C 特有选项
-
移除
-Wjump-misses-init -
移除
-Wstrict-prototypes
问题 2: 浮点 ABI 不兼容
错误:
can't link soft-float modules with single-float modules
failed to merge target specific data of file
解决:
-
为
cxxflags应用fp_flags(浮点选项替换) -
使用
pretend()方法合并配置,确保替换生效
问题 3: 函数签名不匹配
错误:
error: invalid conversion from 'int (*)()' to 'init_call_t {aka void (*)()}'
解决: 将 tflm_cpp_test_entry 返回类型从 int 改为 void
问题 4: 未使用参数警告
错误:
error: unused parameter 'size' [-Werror=unused-parameter]
解决: 在 common_cxxflags 中添加 -Wno-unused-parameter
问题 5: 头文件找不到
错误:
fatal error: flatbuffers/flatbuffers.h: No such file or directory
fatal error: fixedpoint/fixedpoint.h: No such file or directory
解决: 添加 TFLM 及其依赖的头文件路径
最终配置总结
关键修改文件列表
-
src/build/config/target_config/common_config.py
- 添加
common_cxxflags - 为所有架构添加
cxxflags
- 添加
-
src/build/cmake/build_component.cmake
- 使用生成器表达式区分 C/C++ 编译
-
src/build/cmake/global_variable.cmake
- 初始化
CXXFLAGS变量
- 初始化
-
src/build/config/target_config/ws63/target_config.py
- 添加
cxxflags并应用浮点和优化选项 - 添加 C++ 标准库
- 添加链接器选项
- 添加
-
src/build/script/enviroment.py
- 修改
cxxflags使用pretend而非extend
- 修改
-
src/application/samples/CMakeLists.txt
- 添加 TFLM 头文件路径
-
src/application/samples/tflm_hello_world/CMakeLists.txt
- 添加测试源文件
验证结果
测试的 C++ 特性
✅ 类和对象
✅ 构造函数/析构函数
✅ 成员函数
✅ 运算符重载
✅ 模板函数
✅ constexpr 变量
✅ extern “C” 链接
总结
通过以上配置,WS63 SDK 现在完全支持 C++ 编译。主要成果:
-
✅ 实现了 C/C++ 混合编译
-
✅ 解决了浮点 ABI 兼容性问题
-
✅ 成功编译并运行 C++ 测试程序
-
✅ 为集成 TFLM 或其他 C++ 库奠定了基础
文档版本: 1.0
最后更新: 2025-02-08
作者: Claude (协助配置)
适用 SDK 版本: WS63 SDK 1.10.106
参考链接: WS63添加C++经验总结及讨论