LOADING

加载过慢请开启缓存 浏览器默认开启

毕业设计 (1) - WS63 (Hi3863) 完成 C++ 支持过程

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++ 编译选项

目标

  1. 添加基本的 C++ 编译支持

  2. 支持浮点运算(与 C 代码 ABI 兼容)

  3. 能够编译和运行 C++ 测试程序

  4. 为集成 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

解决:

  1. cxxflags 应用 fp_flags(浮点选项替换)

  2. 使用 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 及其依赖的头文件路径


最终配置总结

关键修改文件列表

  1. src/build/config/target_config/common_config.py

    • 添加 common_cxxflags
    • 为所有架构添加 cxxflags
  2. src/build/cmake/build_component.cmake

    • 使用生成器表达式区分 C/C++ 编译
  3. src/build/cmake/global_variable.cmake

    • 初始化 CXXFLAGS 变量
  4. src/build/config/target_config/ws63/target_config.py

    • 添加 cxxflags 并应用浮点和优化选项
    • 添加 C++ 标准库
    • 添加链接器选项
  5. src/build/script/enviroment.py

    • 修改 cxxflags 使用 pretend 而非 extend
  6. src/application/samples/CMakeLists.txt

    • 添加 TFLM 头文件路径
  7. src/application/samples/tflm_hello_world/CMakeLists.txt

    • 添加测试源文件

验证结果

测试的 C++ 特性

✅ 类和对象
✅ 构造函数/析构函数
✅ 成员函数
✅ 运算符重载
✅ 模板函数
✅ constexpr 变量
✅ extern “C” 链接


总结

通过以上配置,WS63 SDK 现在完全支持 C++ 编译。主要成果:

  1. ✅ 实现了 C/C++ 混合编译

  2. ✅ 解决了浮点 ABI 兼容性问题

  3. ✅ 成功编译并运行 C++ 测试程序

  4. ✅ 为集成 TFLM 或其他 C++ 库奠定了基础


文档版本: 1.0
最后更新: 2025-02-08
作者: Claude (协助配置)
适用 SDK 版本: WS63 SDK 1.10.106
参考链接: WS63添加C++经验总结及讨论

问答