新手如何有效避免Pybind11使用的各种坑【undefine symbol xxx, dynamic module does not define xxx等】

从 Python 调用 C++ 基本上有两种方法:一是使用 PyBind11 C++ 库生成 Python 模块,二使用 cytpes Python 包访问已编译的共享库。 使用cytpes还需要额外对c++代码进行处理,而使用 Pybind11能够直接对c++代码进行导出,并且支持c++的许多数据类型如vector的自动转换,十分方便。

安装的教程很多,在此不再赘述。然而,对一个新手来说, 难免在使用的时候会遇到很多坑,而有些坑比较玄学,本教程也只是记录遇到过的一些坑的解决办法,便于自己回顾类似的问题,如果能顺便帮助到其他人,不上荣幸。

注意:本文只适用于ubuntu系统

Example:

将c++代码导出为python接口至少需要两个文件,源文件和cmakelists.txt文件,假设都在example文件下:

1. 源文件,需要包含c++代码和pybind11的接口绑定:

pybind_test.cpp

#include <pybind11/pybind11.h>
#include <string>
#include <iostream>

using namespace std;
namespace py = pybind11;
 
 
class Pybindtest
{
public:
    virtual ~Pybindtest();
    Pybindtest(std::string &inputs)
    {
        info = inputs;
    }
    void printInfo()
    {
        std::cout << "Your input is " << info << std::endl;
        
    }
private:
    std::string info;
};
 
PYBIND11_MODULE(libmy_module, m) 
{
    m.doc() = "pybind11 Hierarchical Localization cpp backend";
 
    py::class_<Pybindtest>(m, "Pybindtest")
    .def(py::init<std::string &>())
    .def("printInfo", &Pybindtest::printInfo);
}

2.CMakeLists.txt

cmake_minimum_required(VERSI
<think>嗯,用户遇到了一个链接错误:“undefined symbol FLASH_PageErase (referred from stm32l0xx_hal_flash.o)”。首先,我需要理解这个错误的含义。这个错误意味着在链接阶段,编译器找不到FLASH_PageErase函数的定义。用户可能在使用STM32的HAL库,特别是L0系列,所以需要检查相关的库文件和配置。 首先,我应该回忆STM32的HAL库结构。FLASH操作相关的函数通常在特定型号的HAL库中定义,例如stm32l0xx_hal_flash_ex.c。FLASH_PageErase可能是一个扩展函数,需要在头文件中声明并在源文件中实现。用户可能没有包含正确的源文件或头文件,或者工程配置中缺少必要的文件。 接下来,考虑用户可能的问题来源。可能用户在使用STM32CubeMX生成代码时,没有正确配置FLASH模块,或者手动添加了HAL库文件但遗漏了某些部分。另一个可能性是芯片型号不匹配,例如使用的HAL库是针对不同系列的,比如L1而不是L0,导致函数未定义。 需要进一步分析FLASH_PageErase函数的定义位置。在STM32L0系列的HAL库中,这个函数应该存在于stm32l0xx_hal_flash_ex.c文件中,并且声明在stm32l0xx_hal_flash_ex.h头文件中。用户可能没有在工程中包含这个源文件,或者头文件路径没有正确设置。 另外,检查用户是否启用了FLASH扩展功能。有些HAL库函数需要在头文件(如stm32l0xx_hal_conf.h)中通过定义宏来启用,比如#define HAL_FLASH_MODULE_ENABLED。如果这个宏没有被定义,相关的函数就不会被编译进去,导致链接错误。 还要考虑链接器脚本是否正确,是否包含了必要的库文件。如果用户使用的是标准外设库而不是HAL库,函数名称和结构可能不同,导致符号未定义。需要确认用户使用的库类型是否与工程配置一致。 可能的解决方案包括:检查并包含缺失的源文件,确认头文件包含路径,启用必要的宏定义,以及验证芯片型号和库文件的匹配性。此外,建议用户使用STM32CubeMX重新生成代码,以确保配置的正确性,或者手动添加缺失的文件到工程中。 需要指导用户逐步排查,从检查文件包含开始,到确认宏定义,再到验证工程配置和库版本。同时,提醒用户注意函数名称的拼写和大小写是否正确,以及是否在代码中正确调用了HAL_FLASHEx_PageErase函数,因为有时候文档中的函数名称可能与实际实现略有不同。 总结来说,这个错误通常是由于缺少源文件、头文件配置错误或宏定义未启用导致的。需要系统性地检查这些方面,帮助用户一步步解决问题。</think>### 一、错误本质解释 当出现 **`undefined symbol FLASH_PageErase (referred from stm32l0xx_hal_flash.o)`** 错误时,表示: 1. **链接器无法找到函数定义**:编译器通过了语法检查,但链接阶段发现 `FLASH_PageErase` 函数未在工程中实现。 2. **常见于STM32 HAL库开发**:该函数属于STM32芯片的Flash操作底层驱动,需依赖特定文件或配置。 --- ### 二、核心原因分析 $$ \text{错误触发条件} = \text{缺失函数实现文件} + \text{工程配置错误} $$ - **直接原因**: - `FLASH_PageErase` 的实现未包含在工程中(缺少 `stm32l0xx_hal_flash_ex.c` 文件)。 - 工程未启用Flash扩展功能(未定义 `HAL_FLASH_MODULE_ENABLED` 宏)。 - **深层原因**: 1. 使用STM32CubeMX生成代码时未勾选Flash模块。 2. 手动移植HAL库时遗漏关键文件。 3. 芯片型号与HAL库版本不匹配(如使用L1系列的库编译L0芯片代码)。 --- ### 三、系统化解决方案 #### 1. **添加缺失的HAL库文件** - **关键文件**: - **`stm32l0xx_hal_flash_ex.c`**:包含 `FLASH_PageErase` 的实现。 - **`stm32l0xx_hal_flash_ex.h`**:包含函数声明。 - **操作步骤**: 1. 在工程中添加 `Drivers/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_flash_ex.c`。 2. 确保头文件路径包含 `Drivers/STM32L0xx_HAL_Driver/Inc`。 #### 2. **启用Flash模块宏定义** - 在 `stm32l0xx_hal_conf.h` 中启用宏: ```c #define HAL_FLASH_MODULE_ENABLED // 取消注释此行 ``` - ✅ **验证点**: - 确认其他必要宏(如 `HAL_FLASH_EX_MODULE_ENABLED`)是否启用。 #### 3. **检查CubeMX工程配置** ```mermaid graph TD A[错误出现] --> B{是否使用CubeMX生成代码?} B -->|是| C[检查SYS配置] C --> D[确认芯片型号为STM32L0xx] D --> E[重新生成代码并勾选Flash模块] B -->|否| F[手动添加HAL库文件] ``` #### 4. **验证函数命名与芯片兼容性** - **STM32L0系列特有函数**: - 正确函数名:`HAL_FLASHEx_PageErase`(注意大小写和前缀 `Ex`)。 - **常见错误**: ```c HAL_FLASH_PageErase(...); // 错误!L0系列需使用Ex扩展函数 HAL_FLASHEx_PageErase(...); // 正确 ``` --- ### 四、进阶排查步骤 #### 1. **查看函数定义位置** - 在 `stm32l0xx_hal_flash_ex.c` 中查找定义: ```c HAL_StatusTypeDef HAL_FLASHEx_PageErase(uint32_t Page, uint32_t Banks) { // 具体实现... } ``` - 若文件缺失,需从[ST官网](https://www.st.com)下载对应HAL库。 #### 2. **检查链接器脚本** - 确认链接脚本(如 `STM32L0xxxx_FLASH.ld`)包含Flash操作所需内存区域: ``` MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64K RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 8K } ``` #### 3. **预处理结果分析** - 使用GCC生成预处理文件(`-E`选项),搜索 `HAL_FLASHEx_PageErase`: ```bash arm-none-eabi-gcc -E main.c -o main.i grep "HAL_FLASHEx_PageErase" main.i ``` - 若无输出,说明宏未正确启用或头文件未包含。 --- ### 五、常见错误案例 #### 案例1:未包含`stm32l0xx_hal_flash_ex.c` ```c // 错误现象: // 工程中仅包含stm32l0xx_hal_flash.c,但未添加flash_ex.c ``` ✅ **修正方案**: - 在IDE(如Keil)中右键工程 → 添加 `stm32l0xx_hal_flash_ex.c`。 #### 案例2:芯片型号与库不匹配 ```c // 错误配置: // 使用STM32L1xx的HAL库编译L0芯片代码 ``` ✅ **解决方案**: - 在CubeMX中重新选择芯片型号(STM32L0xx),重新生成代码。 --- ### 六、特殊场景处理 #### 1. **自定义Flash操作函数** - 若需覆盖HAL库函数,使用弱符号定义: ```c __weak HAL_StatusTypeDef HAL_FLASHEx_PageErase(uint32_t Page) { // 自定义实现 } ``` #### 2. **低功耗模式下的Flash操作** - 在STOP模式下操作Flash前需唤醒: ```c HAL_PWR_EnterSTOPMode(...); // 唤醒后等待Flash就绪 __HAL_FLASH_WAIT_FOR_READY(); HAL_FLASHEx_PageErase(...); ``` --- ### 七、验证方法 #### 1. **最小代码测试** ```c int main(void) { HAL_Init(); HAL_FLASH_Unlock(); HAL_FLASHEx_PageErase(FLASH_PAGE_5, FLASH_BANK_1); // 测试擦除操作 HAL_FLASH_Lock(); while(1); } ``` - 编译通过且无错误即表示配置正确。 #### 2. **调试器验证** - 在 `HAL_FLASHEx_PageErase` 设置断点,观察Flash内容是否被擦除。 --- ### 八、总结 该错误的核心是 **函数实现缺失或配置错误**。通过以下步骤可彻底解决: 1. 添加 `stm32l0xx_hal_flash_ex.c` 文件到工程。 2. 启用 `HAL_FLASH_MODULE_ENABLED` 宏。 3. 检查CubeMX配置与芯片型号匹配性。 4. 确保函数调用符合STM32L0的命名规范(如 `Ex` 后缀)。 若仍存在问题,建议: - 使用STM32CubeMX重新生成代码。 - 对比ST官方例程(如STM32CubeL0的Flash例程)。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱哭的熊孩子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值