docs/develop: Improve user C modules to properly describe how to build.
Make and CMake builds are slightly different and these changes help make it clear what to do in each case. Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
parent
d87f42b0e5
commit
f541b3673d
@ -18,7 +18,11 @@ If however you're targeting obscure or proprietary systems it may make
|
|||||||
more sense to keep this external to the main MicroPython repository.
|
more sense to keep this external to the main MicroPython repository.
|
||||||
|
|
||||||
This chapter describes how to compile such external modules into the
|
This chapter describes how to compile such external modules into the
|
||||||
MicroPython executable or firmware image.
|
MicroPython executable or firmware image. Both Make and CMake build
|
||||||
|
tools are supported, and when writing an external module it's a good idea to
|
||||||
|
add the build files for both of these tools so the module can be used on all
|
||||||
|
ports. But when compiling a particular port you will only need to use one
|
||||||
|
method of building, either Make or CMake.
|
||||||
|
|
||||||
An alternative approach is to use :ref:`natmod` which allows writing custom C
|
An alternative approach is to use :ref:`natmod` which allows writing custom C
|
||||||
code that is placed in a .mpy file, which can be imported dynamically in to
|
code that is placed in a .mpy file, which can be imported dynamically in to
|
||||||
@ -111,116 +115,140 @@ To build such a module, compile MicroPython (see `getting started
|
|||||||
<https://github.com/micropython/micropython/wiki/Getting-Started>`_),
|
<https://github.com/micropython/micropython/wiki/Getting-Started>`_),
|
||||||
applying 2 modifications:
|
applying 2 modifications:
|
||||||
|
|
||||||
- an extra ``make`` flag named ``USER_C_MODULES`` set to the directory
|
1. Set the build-time flag ``USER_C_MODULES`` to point to the modules
|
||||||
containing all modules you want included (not to the module itself).
|
you want to include. For ports that use Make this variable should be a
|
||||||
|
directory which is searched automatically for modules. For ports that
|
||||||
|
use CMake this variable should be a file which includes the modules to
|
||||||
|
build. See below for details.
|
||||||
|
|
||||||
|
2. Enable the modules by setting the corresponding C preprocessor macro to
|
||||||
|
1. This is only needed if the modules you are building are not
|
||||||
|
automatically enabled.
|
||||||
|
|
||||||
For building the example modules which come with MicroPython,
|
For building the example modules which come with MicroPython,
|
||||||
set ``USER_C_MODULES`` to the ``examples/usercmodule`` directory.
|
set ``USER_C_MODULES`` to the ``examples/usercmodule`` directory for Make,
|
||||||
For your own projects it's more convenient to keep custom code out of
|
or to ``examples/usercmodule/micropython.cmake`` for CMake.
|
||||||
the main source tree so a typical project directory structure will look
|
|
||||||
like this::
|
|
||||||
|
|
||||||
my_project/
|
For example, here's how the to build the unix port with the example modules:
|
||||||
├── modules/
|
|
||||||
│ └──example1/
|
|
||||||
│ ├──example1.c
|
|
||||||
│ ├──micropython.mk
|
|
||||||
│ └──micropython.cmake
|
|
||||||
│ └──example2/
|
|
||||||
│ ├──example2.c
|
|
||||||
│ ├──micropython.mk
|
|
||||||
│ └──micropython.cmake
|
|
||||||
│ └──micropython.cmake
|
|
||||||
└── micropython/
|
|
||||||
├──ports/
|
|
||||||
... ├──stm32/
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
with ``USER_C_MODULES`` set to the ``my_project/modules`` directory.
|
|
||||||
|
|
||||||
A top level ``micropython.cmake`` - found directly in the ``my_project/modules``
|
|
||||||
directory - should ``include`` all of your modules.
|
|
||||||
|
|
||||||
.. code-block:: cmake
|
|
||||||
|
|
||||||
include(${CMAKE_CURRENT_LIST_DIR}/example1/micropython.cmake)
|
|
||||||
include(${CMAKE_CURRENT_LIST_DIR}/example2/micropython.cmake)
|
|
||||||
|
|
||||||
|
|
||||||
- all modules found in this directory (or added via ``include`` in the top-level
|
|
||||||
``micropython.cmake`` when using CMake) will be compiled, but only those which are
|
|
||||||
enabled will be available for importing. If a module is to always be enabled,
|
|
||||||
which is usually the case for custom modules and custom builds, then it is
|
|
||||||
enough to supply "1" as the third parameter to the registration macro, like:
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
MP_REGISTER_MODULE(MP_QSTR_cexample, example_user_cmodule, 1);
|
|
||||||
|
|
||||||
Alternatively, to make the module disabled by default but selectable through
|
|
||||||
a preprocessor configuration option, use:
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
MP_REGISTER_MODULE(MP_QSTR_cexample, example_user_cmodule, MODULE_CEXAMPLE_ENABLED);
|
|
||||||
|
|
||||||
|
|
||||||
Then ``MODULE_CEXAMPLE_ENABLED`` has to be set to 1 to make the module available.
|
|
||||||
This can be done by adding ``CFLAGS_EXTRA=-DMODULE_CEXAMPLE_ENABLED=1`` to
|
|
||||||
the ``make`` command, or editing ``mpconfigport.h`` or ``mpconfigboard.h``
|
|
||||||
to add
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
#define MODULE_CEXAMPLE_ENABLED (1)
|
|
||||||
|
|
||||||
|
|
||||||
Note that the exact method depends on the port as they have different
|
|
||||||
structures. If not done correctly it will compile but importing will
|
|
||||||
fail to find the module.
|
|
||||||
|
|
||||||
To sum up, here's how the ``cexample`` module from the ``examples/usercmodule``
|
|
||||||
directory can be built for the unix port:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
cd micropython/ports/unix
|
cd micropython/ports/unix
|
||||||
make USER_C_MODULES=../../examples/usercmodule all
|
make USER_C_MODULES=../../examples/usercmodule
|
||||||
|
|
||||||
The build output will show the modules found::
|
You may need to run ``make clean`` once at the start when including new
|
||||||
|
user modules in the build. The build output will show the modules found::
|
||||||
|
|
||||||
...
|
...
|
||||||
Including User C Module from ../../examples/usercmodule/cexample
|
Including User C Module from ../../examples/usercmodule/cexample
|
||||||
Including User C Module from ../../examples/usercmodule/cppexample
|
Including User C Module from ../../examples/usercmodule/cppexample
|
||||||
...
|
...
|
||||||
|
|
||||||
|
For a CMake-based port such as rp2, this will look a little different (note
|
||||||
For a CMake-based port such as rp2, this will look a little different:
|
that CMake is actually invoked by ``make``):
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
cd micropython/ports/rp2
|
cd micropython/ports/rp2
|
||||||
make USER_C_MODULES=../../examples/usercmodule all
|
make USER_C_MODULES=../../examples/usercmodule/micropython.cmake
|
||||||
|
|
||||||
|
Again, you may need to run ``make clean`` first for CMake to pick up the
|
||||||
The CMake build output lists the modules by name::
|
user modules. The CMake build output lists the modules by name::
|
||||||
|
|
||||||
...
|
...
|
||||||
Including User C Module(s) from ../../examples/usercmodule/micropython.cmake
|
Including User C Module(s) from ../../examples/usercmodule/micropython.cmake
|
||||||
Found User C Module(s): usermod_cexample, usermod_cppexample
|
Found User C Module(s): usermod_cexample, usermod_cppexample
|
||||||
...
|
...
|
||||||
|
|
||||||
|
The contents of the top-level ``micropython.cmake`` can be used to control which
|
||||||
|
modules are enabled.
|
||||||
|
|
||||||
The top-level ``micropython.cmake`` can be used to control which modules are enabled.
|
For your own projects it's more convenient to keep custom code out of the main
|
||||||
|
MicroPython source tree, so a typical project directory structure will look
|
||||||
|
like this::
|
||||||
|
|
||||||
|
my_project/
|
||||||
|
├── modules/
|
||||||
|
│ ├── example1/
|
||||||
|
│ │ ├── example1.c
|
||||||
|
│ │ ├── micropython.mk
|
||||||
|
│ │ └── micropython.cmake
|
||||||
|
│ ├── example2/
|
||||||
|
│ │ ├── example2.c
|
||||||
|
│ │ ├── micropython.mk
|
||||||
|
│ │ └── micropython.cmake
|
||||||
|
│ └── micropython.cmake
|
||||||
|
└── micropython/
|
||||||
|
├──ports/
|
||||||
|
... ├──stm32/
|
||||||
|
...
|
||||||
|
|
||||||
Or for your own project with a directory structure as shown above,
|
When building with Make set ``USER_C_MODULES`` to the ``my_project/modules``
|
||||||
including both modules and building the stm32 port for example:
|
directory. For example, building the stm32 port:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
cd my_project/micropython/ports/stm32
|
cd my_project/micropython/ports/stm32
|
||||||
make USER_C_MODULES=../../../modules all
|
make USER_C_MODULES=../../../modules
|
||||||
|
|
||||||
|
When building with CMake the top level ``micropython.cmake`` -- found directly
|
||||||
|
in the ``my_project/modules`` directory -- should ``include`` all of the modules
|
||||||
|
you want to have available:
|
||||||
|
|
||||||
|
.. code-block:: cmake
|
||||||
|
|
||||||
|
include(${CMAKE_CURRENT_LIST_DIR}/example1/micropython.cmake)
|
||||||
|
include(${CMAKE_CURRENT_LIST_DIR}/example2/micropython.cmake)
|
||||||
|
|
||||||
|
Then build with:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
cd my_project/micropython/ports/esp32
|
||||||
|
make USER_C_MODULES=../../../../modules/micropython.cmake
|
||||||
|
|
||||||
|
Note that the esp32 port needs the extra ``..`` for relative paths due to the
|
||||||
|
location of its main ``CMakeLists.txt`` file. You can also specify absolute
|
||||||
|
paths to ``USER_C_MODULES``.
|
||||||
|
|
||||||
|
All modules specified by the ``USER_C_MODULES`` variable (either found in this
|
||||||
|
directory when using Make, or added via ``include`` when using CMake) will be
|
||||||
|
compiled, but only those which are enabled will be available for importing.
|
||||||
|
User modules are usually enabled by default (this is decided by the developer
|
||||||
|
of the module), in which case there is nothing more to do than set ``USER_C_MODULES``
|
||||||
|
as described above.
|
||||||
|
|
||||||
|
If a module is not enabled by default then the corresponding C preprocessor macro
|
||||||
|
must be enabled. This macro name can be found by searching for the ``MP_REGISTER_MODULE``
|
||||||
|
line in the module's source code (it usually appears at the end of the main source file).
|
||||||
|
The third argument to ``MP_REGISTER_MODULE`` is the macro name, and this must be set
|
||||||
|
to 1 using ``CFLAGS_EXTRA`` to make the module available. If the third argument is just
|
||||||
|
the number 1 then the module is enabled by default.
|
||||||
|
|
||||||
|
For example, the ``examples/usercmodule/cexample`` module is enabled by default so
|
||||||
|
has the following line in its source code:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
MP_REGISTER_MODULE(MP_QSTR_cexample, example_user_cmodule, 1);
|
||||||
|
|
||||||
|
Alternatively, to make this module disabled by default but selectable through
|
||||||
|
a preprocessor configuration option, it would be:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
MP_REGISTER_MODULE(MP_QSTR_cexample, example_user_cmodule, MODULE_CEXAMPLE_ENABLED);
|
||||||
|
|
||||||
|
In this case the module is enabled by adding ``CFLAGS_EXTRA=-DMODULE_CEXAMPLE_ENABLED=1``
|
||||||
|
to the ``make`` command, or editing ``mpconfigport.h`` or ``mpconfigboard.h`` to add
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
#define MODULE_CEXAMPLE_ENABLED (1)
|
||||||
|
|
||||||
|
Note that the exact method depends on the port as they have different
|
||||||
|
structures. If not done correctly it will compile but importing will
|
||||||
|
fail to find the module.
|
||||||
|
|
||||||
|
|
||||||
Module usage in MicroPython
|
Module usage in MicroPython
|
||||||
|
Loading…
Reference in New Issue
Block a user