MicroPython清单文件¶
总结¶
MicroPython有一个功能,可以将Python代码”冻结”到固件中,作为从文件系统加载代码的替代方案。
这有以下好处:
代码被预编译为字节码,避免了在加载时编译Python源代码的需要。
字节码可以直接从ROM(即闪存)执行,而不是复制到RAM。类似地,任何常量对象(字符串、元组等)也可以从ROM加载。这可能会为您的应用程序提供更多的可用内存。
在没有文件系统的设备上,这是加载Python代码的唯一方法。
在开发过程中,通常不建议冻结,因为它会显著降低开发周期,因为每次更新都需要重新刷新整个固件。但是,有选择地冻结一些很少更改的依赖项(例如第三方库)仍然是有用的。
列出要冻结到固件中的Python文件的方法是通过”manifest”,这是一个Python文件,将由构建过程解释。通常,您将编写一个清单文件作为板定义的一部分,但您也可以编写一个独立的清单文件,并将其与现有的板定义一起使用。
清单文件可以定义对:term: micropython-lib
库的依赖,以及文件系统上的Python文件,也可以定义对其他清单文件的依赖。
编写清单文件¶
manifest文件是包含一系列函数调用的Python文件。请参阅下面定义的可用函数。
清单文件中使用的任何路径都可以包含以下变量。这些都解析为绝对路径。
$(MPY_DIR)
– 指向micropython的路径。$(MPY_LIB_DIR)
– micropython-lib子模块的路径。建议使用require()
。$(PORT_DIR)
– 当前移植版本的路径(例如:ports/stm32
)$(BOARD_DIR)
– 当前板的路径(例如:ports/stm32/boards/PYBV11
)
自定义清单文件不应该存在于主MicroPython存储库中。您应该将它们与项目的其余部分一起放在版本控制中。
通常用于编译固件的清单将需要包括移植清单,其中可能包括板运行所需的冻结模块。如果您只是想向现有的板添加额外的模块,那么包括板清单(这将依次包括移植清单)。
使用自定义清单构建¶
你的manifest可以在 make
命令行中指定:
$ make BOARD=MYBOARD FROZEN_MANIFEST=/path/to/my/project/manifest.py
这适用于所有移植版本,包括基于CMake的移植版本(例如esp32, rp2),因为Makefile包装器会将其传递到CMake构建中。
向板定义添加清单¶
如果您有一个自定义板定义,您可以使它自动包含您的自定义清单。在基于make的移植版本(大多数移植版本)上,在您的 mpconfigboard.mk
中设置 FROZEN_MANIFEST
变量。
FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py
在基于CMake的移植版本(例如esp32, rp2)上,请使用 mpconfigboard.cmake
set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
高级功能¶
注意:opt
关键字参数可以在各种函数上设置,这控制了交叉编译器使用的优化级别。请参见:func:micropython.opt_level
。
- package(package_path, files=None, base_path='.', opt=None)¶
这相当于将 “package_path” 目录复制到设备(冻结代码除外)。
在最简单的情况下,冻结当前目录中的包 “foo”:
package("foo")
将递归包含foo中的所有 .py 文件,并将冻结为
foo/**/*.py
。如果包不在与manifest文件相同的目录中,请使用
base_path
:package("foo", base_path="path/to/libraries")
您可以使用上面的变量,例如
base_path
中的$(PORT_DIR)
。要限制包中的某些文件,请使用
files
(注意:路径应该是相对于包的):package("foo", files=["bar/baz.py"])
。
- module(module_path, base_path='.', opt=None)¶
包括一个Python文件作为模块。
如果文件在当前目录中:
module("foo.py")
否则,请使用base_path定位文件:
module("foo.py", base_path="src/drivers")
您可以使用上面的变量,例如
base_path
中的$(PORT_DIR)
。
- require(name, unix_ffi=False)¶
从 micropython-lib 中按名称(及其依赖项)要求一个包。
可选地指定unix_ffi=True以使用来自unix-ffi目录的模块。
- include(manifest_path)¶
包括另一个清单。
通常用于编译固件的清单将需要包括移植清单,其中可能包括板运行所需的冻结模块。
*manifest*参数可以是字符串(filename)或字符串可迭代对象。
相对路径是根据当前清单文件解析的。
如果路径指向一个目录,那么它隐式地包含该目录中的manifest.py文件。
您可以使用上面的变量,例如
manifest_path
中的$(PORT_DIR)
。
- metadata(description=None, version=None, license=None, author=None)¶
定义此清单文件的元数据。这对于micropython-lib包的清单很有用。
低级功能¶
为了完整起见,对这些函数进行了文档记录,但除了 freeze_as_str
之外,所有功能都可以通过高级函数访问。
- freeze(path, script=None, opt=0)¶
冻结由*path*指定的输入,自动确定其类型。
.py
脚本将首先被编译为.mpy
后冻结,然后一个.mpy
文件将被直接冻结。*path*必须是一个目录,它是开始搜索文件的基目录。当导入结果冻结的模块时,模块的名称将以*path*开头,即*path*从模块名称中排除。
如果*path*是相对的,它被解析为当前的
manifest.py
。如果*script*为None,*path*中的所有文件将被冻结。
如果*script*是一个可迭代对象,那么对可迭代对象的所有项调用
freeze()
(传递相同的*path*和*opt*)。如果*script*是一个字符串,那么它指定要冻结的文件或目录,并且可以在文件或最后一个目录之前包含额外的目录。文件或目录将在*path*中搜索。如果*script*是一个目录,那么该目录下的所有文件将被冻结。
*opt*是在编译
.py
到.mpy
时传递给mpy-cross的优化级别。这些级别在micropython.opt_level()
中描述。
- freeze_as_str(path)¶
冻结给定的*path*和其中的所有
.py
脚本作为字符串,该字符串将在导入时编译。
- freeze_as_mpy(path, script=None, opt=0)¶
先将
.py
脚本编译为.mpy
文件,然后冻结生成的.mpy
文件。有关参数的更多详细信息,请参阅freeze()
。
- freeze_mpy(path, script=None, opt=0)¶
冻结输入,必须是直接冻结的
.mpy
文件。有关参数的更多详细信息,请参阅freeze()
。
示例¶
要冻结当前目录中的单个文件,该文件将以 import mydriver
的形式可用,使用:
module("mydriver.py")
要冻结当前目录的子目录”mydriver”中的文件目录,该目录将以 import mydriver
的形式可用,使用:
package("mydriver")
要冻结 micropython-lib 中的”hmac”库,使用:
require("hmac")
PYBD_SF2
板的自定义 manifest.py
文件的一个更完整的例子是:
# Include the board's default manifest.
include("$(BOARD_DIR)/manifest.py")
# Add a custom driver
module("mydriver.py")
# Add aiorepl from micropython-lib
require("aiorepl")
然后用板进行编译
$ cd ports/stm32
$ make BOARD=PYBD_SF2 FROZEN_MANIFEST=~/src/myproject/manifest.py
请注意,大多数板没有自己的 manifest.py
,而是直接使用一个移植版本,在这种情况下,你的清单应该只需 include("$(PORT_DIR)/boards/manifest.py")
。