2015-12-15 13:04:16 +01:00
|
|
|
Creating modules {#creating-modules}
|
|
|
|
================
|
|
|
|
Modules in RIOT are well-defined units of code that provide a set of features
|
|
|
|
to your application. This includes also drivers and to a certain extent ports
|
|
|
|
for CPUs and boards (with some exceptions, see <!-- @ref porting-guide --> the
|
|
|
|
porting guide for further information).
|
|
|
|
|
|
|
|
The general structure {#the-general-structure}
|
|
|
|
=====================
|
|
|
|
Like @ref creating-an-application "applications", modules are directories
|
|
|
|
containing source files and a Makefile. Additionally their API can be defined
|
|
|
|
in one or more header files, residing in the include path of their
|
|
|
|
super-module.
|
|
|
|
|
|
|
|
E.g. the @ref sys_shell module is implemented in `sys/shell` and defines its
|
|
|
|
API in `sys/include/shell.h` and the @ref drivers_isl29020 driver is
|
|
|
|
implemented in `drivers/isl29020` and defines its API in
|
|
|
|
`drivers/include/isl29020.h`.
|
|
|
|
|
|
|
|
A module's Makefile just needs to include `Makefile.base` in the RIOT
|
|
|
|
repository:
|
|
|
|
|
|
|
|
~~~~~~~~~~~~~~~~~~~ {.mk}
|
2017-05-30 16:20:52 +02:00
|
|
|
include $(RIOTBASE)/Makefile.base
|
2015-12-15 13:04:16 +01:00
|
|
|
~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
If your module's name differs from the name of the directory it resides in you
|
|
|
|
need to set the `MODULE` macro in addition.
|
|
|
|
|
|
|
|
When compiled a module always provides a `MODULE_<MODULENAME>` macro to the
|
|
|
|
system. This way, other modules can check if the module is available in the
|
|
|
|
current configuration or not.
|
|
|
|
|
|
|
|
Modules can be used by adding their name to the `USEMODULE` macro of your
|
|
|
|
application's Makefile.
|
|
|
|
|
2018-03-01 14:06:28 +01:00
|
|
|
### Pitfalls ###
|
|
|
|
|
|
|
|
The `MODULE` name should be unique or build breaks as modules overwrite the
|
2019-01-07 15:29:25 +01:00
|
|
|
same output file. This might for example lead to `undefined reference to` errors
|
|
|
|
in the linker which can be hard to track down.
|
2018-03-01 14:06:28 +01:00
|
|
|
|
|
|
|
This problem happened in the past for:
|
|
|
|
|
|
|
|
* Packages root directory (libfixmath/u8g2)
|
|
|
|
* boards/cpu/periph and their common boards/cpu/periph
|
|
|
|
|
|
|
|
Note: even if all boards and cpus implement the `board` and `cpu` modules, only
|
|
|
|
one is used in an application so there is no conflict.
|
|
|
|
|
|
|
|
|
2015-12-15 13:04:16 +01:00
|
|
|
Module dependencies
|
|
|
|
===================
|
|
|
|
Your module may depend on other modules to minimize code duplication. These
|
|
|
|
dependencies are defined in `Makefile.dep` with the following syntax:
|
|
|
|
|
|
|
|
~~~~~~~~~~~~~~~~~~~ {.mk}
|
|
|
|
ifneq (,$(filter your_module,$(USEMODULE))) # if module in USEMODULE
|
|
|
|
USEMODULE += dep1 # add dependencies to USEMODULE
|
|
|
|
USEMODULE += dep2
|
|
|
|
endif
|
|
|
|
~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
Note, that `Makefile.dep` is processed only once so you have to take care to
|
|
|
|
add the dependency block for your module *before* your dependencies pull in
|
|
|
|
their dependencies.
|
|
|
|
|
|
|
|
Modules outside of RIOTBASE {#modules-outside-of-riotbase}
|
|
|
|
===========================
|
|
|
|
Modules can be defined outside `RIOTBASE`. In addition to add it to `USEMODULE`
|
2018-04-19 16:05:43 +02:00
|
|
|
the user needs to add the module path to `EXTERNAL_MODULE_DIRS`.
|
|
|
|
|
|
|
|
The external module can optionally define the following files:
|
|
|
|
* `Makefile.include` file to set global build configuration like `CFLAGS` or add
|
|
|
|
API headers include paths to the `USEMODULE_INCLUDES` variable.
|
|
|
|
* `Makefile.dep` file to set module dependencies
|
2015-12-15 13:04:16 +01:00
|
|
|
|
2018-04-19 17:10:51 +02:00
|
|
|
An example can be found in
|
|
|
|
[`tests/external_module_dirs`](https://github.com/RIOT-OS/RIOT/tree/master/tests/external_module_dirs)
|
|
|
|
|
2015-12-15 13:04:16 +01:00
|
|
|
Pseudomodules {#pseudomodules}
|
|
|
|
=============
|
2020-04-15 10:25:31 +02:00
|
|
|
Pseudomodules are modules that are not static libraries, i.e. do not generate a
|
|
|
|
`<module name>.a` file.
|
|
|
|
|
|
|
|
To create a pseudomodule just add its name to `makefiles/pseudomodules.inc.mk`
|
|
|
|
with `PSEUDOMODULES += <modulename>` in alphabetical order.
|
|
|
|
|
|
|
|
A Pseudomodule may or may not have a source file associated with it. To make the
|
|
|
|
distinction between them we will refer to those that don't as true-Pseudomodules.
|
|
|
|
|
|
|
|
The main use case for true-Pseudomodules is to provide base information for
|
|
|
|
dependencies to other modules or information to the code base via the
|
|
|
|
`MODULE_<MODULENAME>` macro.
|
|
|
|
|
|
|
|
Pseudomodules with source code exist under a "real" `MODULE` since they will
|
|
|
|
generate a `<pseudomodule_name>.o` file grouped under that `MODULE`s
|
|
|
|
`<module_name>.a` file.
|
|
|
|
|
|
|
|
These modules appear in RIOT under two forms:
|
|
|
|
|
|
|
|
1. Conditionally included source files:
|
|
|
|
|
|
|
|
```
|
|
|
|
foo/
|
|
|
|
|----foo_bar.c
|
|
|
|
|----foo.c
|
|
|
|
|----Makefile
|
|
|
|
```
|
|
|
|
|
|
|
|
In `foo/Makefile` you add the source file to the `SRC` variable, conditioned on
|
|
|
|
the Pseudomodule inclusion
|
|
|
|
|
|
|
|
```mk
|
|
|
|
ifneq (,$(filter foo_bar,$(USEMODULE)))
|
|
|
|
SRC += foo_bar.c
|
|
|
|
endif
|
|
|
|
```
|
|
|
|
|
|
|
|
See `sys/net/ble/skald` for an example in code.
|
|
|
|
|
|
|
|
2. Using the `SUBMODULES` mechanism:
|
|
|
|
|
|
|
|
```
|
|
|
|
foo/
|
|
|
|
|----spam.c
|
|
|
|
|----ham.c
|
|
|
|
|----eggs.c
|
|
|
|
|----Makefile
|
|
|
|
```
|
|
|
|
|
|
|
|
```mk
|
|
|
|
# make all code end up in "foo_bar.a", this can be any name
|
|
|
|
MODULE := foo_bar
|
|
|
|
|
|
|
|
# ensure that "foo_ham" or "bar_foo_ham" builds "foo_ham.c".
|
|
|
|
BASE_MODULE := foo
|
|
|
|
|
|
|
|
# list of source files that are not SUBMODULES
|
|
|
|
SRC := spam.c
|
|
|
|
|
|
|
|
# enable submodules by setting SUBMODULES = 1
|
|
|
|
SUBMODULES = 1
|
|
|
|
```
|
|
|
|
|
|
|
|
When using `SUBMODULES` in a `MODULE` all `SRC` file excluded from `foo/Makefile`
|
|
|
|
will be considered `SUBMODULES`. In the example above `ham.c` and `eggs.c`.
|
|
|
|
These source files will be conditionally included depending if the modules have
|
|
|
|
been added, i.e. `USEMODULE += foo_ham foo_eggs` (it's the same as case 1 but
|
|
|
|
handled automatically in `Makefile.base`).
|
|
|
|
|
|
|
|
The `SUBMODULES` mechanism is more flexible since `BASE_MODULE` allows matching
|
|
|
|
the only parts of compounded module names and only match against part of that name.
|
|
|
|
|
|
|
|
See `sys/ztimer/Makefile` for an example in code.
|
|
|
|
|
2020-05-19 17:49:42 +02:00
|
|
|
`SUBMODULES` can also be true-pseudomodules.
|
|
|
|
|
|
|
|
# Helper tools
|
|
|
|
|
|
|
|
To help you start writing a module, the RIOT build system provides the
|
|
|
|
`generate-module` make target. It is a wrapper around the
|
|
|
|
[riotgen](https://pypi.org/project/riotgen/) command line tool that is helpful
|
|
|
|
when starting to implement a module: all required files are generated with
|
|
|
|
copyright headers, doxygen groups, etc, so you can concentrate on the module
|
|
|
|
implementation.
|
|
|
|
The module source files are created in the `sys` directory.
|
|
|
|
|
|
|
|
**Usage:**
|
|
|
|
|
|
|
|
From the RIOT base directory, run:
|
|
|
|
```
|
|
|
|
make generate-module
|
|
|
|
```
|
|
|
|
Then answer a few questions about the driver:
|
|
|
|
- Module name: enter a name for your module. It will be used as both the name
|
|
|
|
of the module directory under sys, where the source files are created, and
|
|
|
|
the build system module (used with `USEMODULE`).
|
|
|
|
- Module doxygen name: Enter the name of module, as displayed in the
|
|
|
|
Doxygen documentation.
|
|
|
|
- Brief doxygen description: Describe in one line what is this module about.
|
|
|
|
|
|
|
|
Other global information (author name, email, organization) should be retrieved
|
|
|
|
automatically from your git configuration.
|
|
|
|
|
|
|
|
Once completed, the module files are located in
|
|
|
|
`sys/<module name>/<module name>.c` and `sys/include/<module name>.h`.
|