summaryrefslogtreecommitdiff
path: root/docs/reference/manifest.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/reference/manifest.rst')
-rw-r--r--docs/reference/manifest.rst271
1 files changed, 194 insertions, 77 deletions
diff --git a/docs/reference/manifest.rst b/docs/reference/manifest.rst
index b756de47e..9bcafd583 100644
--- a/docs/reference/manifest.rst
+++ b/docs/reference/manifest.rst
@@ -1,35 +1,177 @@
+.. _manifest:
+
MicroPython manifest files
==========================
-When building firmware for a device the following components are included in
-the compilation process:
+Summary
+-------
+
+MicroPython has a feature that allows Python code to be "frozen" into the
+firmware, as an alternative to loading code from the filesystem.
+
+This has the following benefits:
+
+- the code is pre-compiled to bytecode, avoiding the need for the Python
+ source to be compiled at load-time.
+- the bytecode can be executed directly from ROM (i.e. flash memory) rather than
+ being copied into RAM. Similarly any constant objects (strings, tuples, etc)
+ are loaded from ROM also. This can lead to significantly more memory being
+ available for your application.
+- on devices that do not have a filesystem, this is the only way to
+ load Python code.
+
+During development, freezing is generally not recommended as it will
+significantly slow down your development cycle, as each update will require
+re-flashing the entire firmware. However, it can still be useful to
+selectively freeze some rarely-changing dependencies (such as third-party
+libraries).
+
+The way to list the Python files to be be frozen into the firmware is via
+a "manifest", which is a Python file that will be interpreted by the build
+process. Typically you would write a manifest file as part of a board
+definition, but you can also write a stand-alone manifest file and use it with
+an existing board definition.
+
+Manifest files can define dependencies on libraries from :term:`micropython-lib`
+as well as Python files on the filesystem, and also on other manifest files.
+
+Writing manifest files
+----------------------
+
+A manifest file is a Python file containing a series of function calls. See the
+available functions defined below.
+
+Any paths used in manifest files can include the following variables. These all
+resolve to absolute paths.
+
+- ``$(MPY_DIR)`` -- path to the micropython repo.
+- ``$(MPY_LIB_DIR)`` -- path to the micropython-lib submodule. Prefer to use
+ ``require()``.
+- ``$(PORT_DIR)`` -- path to the current port (e.g. ``ports/stm32``)
+- ``$(BOARD_DIR)`` -- path to the current board
+ (e.g. ``ports/stm32/boards/PYBV11``)
+
+Custom manifest files should not live in the main MicroPython repository. You
+should keep them in version control with the rest of your project.
+
+Typically a manifest used for compiling firmware will need to include the port
+manifest, which might include frozen modules that are required for the board to
+function. If you just want to add additional modules to an existing board, then
+include the board manifest (which will in turn include the port manifest).
+
+Building with a custom manifest
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Your manifest can be specified on the ``make`` command line with:
+
+.. code-block:: bash
+
+ $ make BOARD=MYBOARD FROZEN_MANIFEST=/path/to/my/project/manifest.py
+
+This applies to all ports, including CMake-based ones (e.g. esp32, rp2), as the
+Makefile wrapper that will pass this into the CMake build.
+
+Adding a manifest to a board definition
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you have a custom board definition, you can make it include your custom
+manifest automatically. On make-based ports (most ports), in your
+``mpconfigboard.mk`` set the ``FROZEN_MANIFEST`` variable.
+
+.. code-block:: makefile
+
+ FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py
+
+On CMake-based ports (e.g. esp32, rp2), instead use ``mpconfigboard.cmake``
+
+.. code-block:: cmake
+
+ set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
+
+High-level functions
+~~~~~~~~~~~~~~~~~~~~
+
+Note: The ``opt`` keyword argument can be set on the various functions, this controls
+the optimisation level used by the cross-compiler.
+See :func:`micropython.opt_level`.
+
+.. function:: package(package_path, files=None, base_path=".", opt=None)
+
+ This is equivalent to copying the "package_path" directory to the device
+ (except as frozen code).
+
+ In the simplest case, to freeze a package "foo" in the current directory:
+
+ .. code-block:: python3
+
+ package("foo")
+
+ will recursively include all .py files in foo, and will be frozen as
+ ``foo/**/*.py``.
+
+ If the package isn't in the same directory as the manifest file, use ``base_path``:
+
+ .. code-block:: python3
+
+ package("foo", base_path="path/to/libraries")
+
+ You can use the variables above, such as ``$(PORT_DIR)`` in ``base_path``.
+
+ To restrict to certain files in the package use ``files`` (note: paths
+ should be relative to the package): ``package("foo", files=["bar/baz.py"])``.
+
+.. function:: module(module_path, base_path=".", opt=None)
+
+ Include a single Python file as a module.
+
+ If the file is in the current directory:
+
+ .. code-block:: python3
+
+ module("foo.py")
+
+ Otherwise use base_path to locate the file:
+
+ .. code-block:: python3
+
+ module("foo.py", base_path="src/drivers")
+
+ You can use the variables above, such as ``$(PORT_DIR)`` in ``base_path``.
+
+.. function:: require(name, unix_ffi=False)
+
+ Require a package by name (and its dependencies) from :term:`micropython-lib`.
+
+ Optionally specify unix_ffi=True to use a module from the unix-ffi directory.
+
+.. function:: include(manifest_path)
-- the core MicroPython virtual machine and runtime
-- port-specific system code and drivers to interface with the
- microcontroller/device that the firmware is targeting
-- standard built-in modules, like ``sys``
-- extended built-in modules, like ``json`` and ``machine``
-- extra modules written in C/C++
-- extra modules written in Python
+ Include another manifest.
+
+ Typically a manifest used for compiling firmware will need to include the
+ port manifest, which might include frozen modules that are required for
+ the board to function.
+
+ The *manifest* argument can be a string (filename) or an iterable of
+ strings.
-All the modules included in the firmware are available via ``import`` from
-Python code. The extra modules written in Python that are included in a build
-(the last point above) are called *frozen modules*, and are specified by a
-``manifest.py`` file. Changing this manifest requires rebuilding the firmware.
+ Relative paths are resolved with respect to the current manifest file.
-It's also possible to add additional modules to the filesystem of the device
-once it is up and running. Adding and removing modules to/from the filesystem
-does not require rebuilding the firmware so is a simpler process than rebuilding
-firmware. The benefit of using a manifest is that frozen modules are more
-efficient: they are faster to import and take up less RAM once imported.
+ If the path is to a directory, then it implicitly includes the
+ manifest.py file inside that directory.
-MicroPython manifest files are Python files and can contain arbitrary Python
-code. There are also a set of commands (predefined functions) which are used
-to specify the Python source files to include. These commands are described
-below.
+ You can use the variables above, such as ``$(PORT_DIR)`` in ``manifest_path``.
-Freezing source code
---------------------
+.. function:: metadata(description=None, version=None, license=None, author=None)
+
+ Define metadata for this manifest file. This is useful for manifests for
+ micropython-lib packages.
+
+Low-level functions
+~~~~~~~~~~~~~~~~~~~
+
+These functions are documented for completeness, but with the exception of
+``freeze_as_str`` all functionality can be accessed via the high-level functions.
.. function:: freeze(path, script=None, opt=0)
@@ -42,9 +184,7 @@ Freezing source code
module will start after *path*, i.e. *path* is excluded from the module
name.
- If *path* is relative, it is resolved to the current ``manifest.py``. Use
- ``$(MPY_DIR)``, ``$(MPY_LIB_DIR)``, ``$(PORT_DIR)``, ``$(BOARD_DIR)`` if you
- need to access specific paths.
+ If *path* is relative, it is resolved to the current ``manifest.py``.
If *script* is None, all files in *path* will be frozen.
@@ -75,71 +215,48 @@ Freezing source code
Freeze the input, which must be ``.mpy`` files that are frozen directly.
See ``freeze()`` for further details on the arguments.
-
-Including other manifest files
-------------------------------
-
-.. function:: include(manifest, **kwargs)
-
- Include another manifest.
-
- The *manifest* argument can be a string (filename) or an iterable of
- strings.
-
- Relative paths are resolved with respect to the current manifest file.
-
- Optional *kwargs* can be provided which will be available to the included
- script via the *options* variable.
-
- For example:
-
- .. code-block:: python3
-
- include("path.py", extra_features=True)
-
- then in path.py:
-
- .. code-block:: python3
-
- options.defaults(standard_features=True)
- # freeze minimal modules.
- if options.standard_features:
- # freeze standard modules.
- if options.extra_features:
- # freeze extra modules.
-
-
Examples
--------
-To freeze a single file which is available as ``import mydriver``, use:
+To freeze a single file from the current directory which will be available as
+``import mydriver``, use:
.. code-block:: python3
- freeze(".", "mydriver.py")
+ module("mydriver.py")
-To freeze a set of files which are available as ``import test1`` and
-``import test2``, and which are compiled with optimisation level 3, use:
+To freeze a directory of files in a subdirectory "mydriver" of the current
+directory which will be available as ``import mydriver``, use:
.. code-block:: python3
- freeze("/path/to/tests", ("test1.py", "test2.py"), opt=3)
+ package("mydriver")
-To freeze a module which can be imported as ``import mymodule``, use:
+To freeze the "hmac" library from :term:`micropython-lib`, use:
.. code-block:: python3
- freeze(
- "../relative/path",
- (
- "mymodule/__init__.py",
- "mymodule/core.py",
- "mymodule/extra.py",
- ),
- )
+ require("hmac")
-To include a manifest from the MicroPython repository, use:
+A more complete example of a custom ``manifest.py`` file for the ``PYBD_SF2``
+board is:
.. code-block:: python3
- include("$(MPY_DIR)/extmod/uasyncio/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")
+
+Then the board can be compiled with
+
+.. code-block:: bash
+
+ $ cd ports/stm32
+ $ make BOARD=PYBD_SF2 FROZEN_MANIFEST=~/src/myproject/manifest.py
+
+Note that most boards do not have their own ``manifest.py``, rather they use the
+port one directly, in which case your manifest should just
+``include("$(PORT_DIR)/boards/manifest.py")`` instead.