MicroPython 外部 C 模块¶
在开发用于 MicroPython 的模块时,您可能会发现您遇到 Python 环境的限制,通常是由于无法访问某些硬件资源或 Python 速度限制。
如果通过最大化 MicroPython 速度中, 的建议无法解决您的限制,则用C(和/或 C++,如果为您的端口实现)编写部分或全部模块是一个可行的选择。
如果您的模块旨在访问或使用常用硬件或库,请考虑在 MicroPython 源代码树中与类似模块一起实现它,并将其作为拉取请求提交。但是,如果您的目标是晦涩的或专有的系统,则将其保留在主 MicroPython 存储库的外部可能更有意义。
本章介绍如何将此类外部模块编译为 MicroPython 可执行文件或固件映像。Make 和 CMake 构建工具都受支持,在编写外部模块时,最好为这两个工具添加构建文件,以便该模块可以在所有端口上使用。但是在编译特定端口时,您只需要使用一种构建方法,Make 或 CMake。
另一种方法是 在 .mpy 文件中 使用本机机器代码,它允许编写放置在 .mpy 文件中的自定义 C 代码,该代码可以动态导入到正在运行的 MicroPython 系统中,而无需重新编译主固件。
外部 C 模块的结构¶
MicroPython 用户 C 模块是一个包含以下文件的目录:
*.c
/*.cpp
/*.h
的源代码文件的模块。这些通常包括正在实现的低级功能和用于公开函数和模块的 MicroPython 绑定函数。
目前编写这些函数/模块的最佳参考是在 MicroPython 树中找到类似的模块并将它们用作示例。
micropython.mk
包含此模块的 Makefile 片段。$(USERMOD_DIR)
可用作micropython.mk
模块目录的路径。因为它是为每个 c 模块重新定义的,所以应该在您micropython.mk
的本地 make 变量中扩展,例如EXAMPLE_MOD_DIR := $(USERMOD_DIR)
你的
micropython.mk
必须将模块源文件添加到$(USERMOD_DIR)
到SRC_USERMOD
的扩展副本中,例如SRC_USERMOD += $(EXAMPLE_MOD_DIR)/example.c
如果您有自定义编译器选项(例如
-I
添加目录以搜索头文件),则应将这些选项添加到C代码的CFLAGS_USERMOD
和C++代码的CXXFLAGS_USERMOD
。micropython.cmake
包含此模块的 CMake 配置。micropython.cmake
,您可以${CMAKE_CURRENT_LIST_DIR}
用作当前模块的路径。您
micropython.cmake
应该定义一个INTERFACE
库并将源文件关联起来,编译定义并包含目录。然后应该将库链接到usermod
目标。add_library(usermod_cexample INTERFACE) target_sources(usermod_cexample INTERFACE ${CMAKE_CURRENT_LIST_DIR}/examplemodule.c ) target_include_directories(usermod_cexample INTERFACE ${CMAKE_CURRENT_LIST_DIR} ) target_link_libraries(usermod INTERFACE usermod_cexample)
请参阅下面的完整使用示例。
基本示例¶
这个名为的简单模块cexample
提供了一个函数cexample.add_ints(a, b)
,它将两个整数参数相加并返回结果。它可以
在示例目录
的 MicroPython 源代码树中找到, 并且有一个源文件和一个包含上述内容的 Makefile 片段:
micropython/
└──examples/
└──usercmodule/
└──cexample/
├── examplemodule.c
├── micropython.mk
└── micropython.cmake
有关其他说明,请参阅这些文件中的注释。在cexample
模块旁边还有cppexample
以相同方式工作的模块,但显示了在 MicroPython 中混合 C 和 C++ 代码的一种方式。
将 cmodule 编译成 MicroPython¶
要构建这样的模块,请编译 MicroPython(请参阅 入门),应用 2 处修改:
将构建时标志设置
USER_C_MODULES
为指向要包含的模块。对于使用 Make 这个变量的端口应该是一个自动搜索模块的目录。对于使用 CMake 的端口,这个变量应该是一个包含要构建的模块的文件。详情请见下文。通过将相应的 C 预处理器宏设置为 1 来启用模块。仅当您正在构建的模块未自动启用时才需要这样做。
为了构建MicroPython附带的示例模块,Make将USER_C_MODULES
设置为 examples/usercmodule
目录,
CMake将USER_C_MODULES
设置为 examples/usercmodule/micropython.cmake
目录。
例如,以下是使用示例模块构建 unix 端口的方法:
cd micropython/ports/unix
make USER_C_MODULES=../../examples/usercmodule
在构建中包含新用户模块时,您可能需要在开始时运行一次。构建输出将显示找到的模块: make clean
...
Including User C Module from ../../examples/usercmodule/cexample
Including User C Module from ../../examples/usercmodule/cppexample
...
对于基于 CMake 的端口,例如 rp2,这看起来会有些不同(注意 CMake 实际上是由 调用的make
):
cd micropython/ports/rp2
make USER_C_MODULES=../../examples/usercmodule/micropython.cmake
同样,您可能需要先运行CMake 才能获取用户模块。CMake 构建输出按名称列出模块: make clean
...
Including User C Module(s) from ../../examples/usercmodule/micropython.cmake
Found User C Module(s): usermod_cexample, usermod_cppexample
...
顶层的内容 micropython.cmake
可用于控制启用哪些模块。
对于您自己的项目,将自定义代码保留在 MicroPython 主源代码树之外会更方便,因此典型的项目目录结构如下所示:
my_project/
├── modules/
│ ├── example1/
│ │ ├── example1.c
│ │ ├── micropython.mk
│ │ └── micropython.cmake
│ ├── example2/
│ │ ├── example2.c
│ │ ├── micropython.mk
│ │ └── micropython.cmake
│ └── micropython.cmake
└── micropython/
├──ports/
... ├──stm32/
...
在将 Make 设置USER_C_MODULES
为my_project/modules
目录的情况下构建时。例如,构建 stm32 端口:
cd my_project/micropython/ports/stm32
make USER_C_MODULES=../../../modules
当使用 CMake 构建顶层时micropython.cmake
——直接在my_project/modules
目录中找到—— include
你想要的所有模块都应该可用:
include(${CMAKE_CURRENT_LIST_DIR}/example1/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/example2/micropython.cmake)
然后构建:
cd my_project/micropython/ports/esp32
make USER_C_MODULES=../../../../modules/micropython.cmake
请注意, ..
由于其主CMakeLists.txt
文件的位置,esp32 端口需要额外的相对路径。您还可以指定USER_C_MODULES
.
USER_C_MODULES
变量指定的所有模块(使用 Make 时在此目录中找到,或include
使用 CMake 时通过添加)将被编译,但只有那些启用的模块可用于导入。用户模块通常是默认启用的(这由模块的开发人员决定),在这种情况下,除了USER_C_MODULES
如上所述设置之外别无他法。
如果默认情况下未启用模块,则必须启用相应的 C 预处理器宏。可以通过搜索 MP_REGISTER_MODULE
模块源代码中的行(它通常出现在主源文件的末尾)来找到该宏名称。to 的第三个参数MP_REGISTER_MODULE
是宏名称,必须将其设置为 1CFLAGS_EXTRA
才能使模块可用。如果第三个参数只是数字 1,则默认情况下启用该模块。
例如,该examples/usercmodule/cexample
模块默认启用,因此其源代码中有以下行:
MP_REGISTER_MODULE(MP_QSTR_cexample, example_user_cmodule, 1);
或者,要在默认情况下禁用此模块但可以通过预处理器配置选项进行选择,它将是:
MP_REGISTER_MODULE(MP_QSTR_cexample, example_user_cmodule, MODULE_CEXAMPLE_ENABLED);
在这种情况下,模块是通过将启用CFLAGS_EXTRA=-DMODULE_CEXAMPLE_ENABLED=1
的make
命令,或编辑 mpconfigport.h
或 mpconfigboard.h
添加
#define MODULE_CEXAMPLE_ENABLED (1)
请注意,确切的方法取决于端口,因为它们具有不同的结构。如果没有正确完成,它将编译但导入将无法找到模块。
MicroPython 中的模块使用¶
一旦内置到您的 MicroPython 副本中,该模块现在可以像任何其他内置模块一样在 Python 中访问,例如
import cexample
print(cexample.add_ints(1, 3))
# should display 4