RIOT/doc/doxygen/src/build-system-basics.md
2020-05-08 11:29:39 +02:00

218 lines
9.0 KiB
Markdown

# Build System Basics {#build-system-basics}
# BOARD, CPU & FEATURES {#board-cpu-features}
## FEATURES {#features}
### What is a FEATURE?
A `FEATURE` is a mean of specifying valid/invalid dependencies and configurations.
Whenever a `FEATURE` is used there should be at some level a hardware requirement,
whether this is a _radio_, a _bus_ of a specific core architecture.
This is not a hard line, in some cases the line can be harder to establish than
others. There are complicated cases like `netif` since a network interface could
be fully implemented in software as a loop-back.
It's also important to note that a `FEATURE` does not mean there is a `MODULE`
with the same name. There could be many implementations for the same `FEATURE`.
The fact that many `FEATURES` translate directly into a `MODULE` is only by
convenience.
e.g.
# all periph features correspond to a periph submodule
USEMODULE += $(filter periph_%,$(FEATURES_USED))
### Providing a FEATURE
For a `FEATURE` to be provided by a `board` it must meet 2 criteria, and for
`periph_%` and other _hw_ (hardware) related `FEATURES` it must follow a 3rd criteria.
- Needs the "hardware" or BSP support (toolchain, build system, flasher, etc.)
- e.g.: `stm32l152re` has an SPI peripheral
`riotboot` needs to be able to link and flash at an offset
- Needs support in RIOT, an implementation of an api to interact with the _hw_
- e.g.: `cpu/stm32_common/periph/spi.c` is implemented for `stm32l1`
`riotboot` needs an implementation of `cpu_jump_to_image`
- Wiring between the _cpu/soc_(system on a chip) a _bus_ and other _cpu_/_hw_ components.
- e.g.: `nucleo-l152re/include/periph_conf.h` specified wiring between `PORT_Ax`
and `SPI1`
### All the FEATURES_%
- `FEATURES_PROVIDED` are available hardware (including BSP) features
(e.g.:`periph_hwrng`, `periph_uart`) or characteristics (e.g:`arch_32bits`) of
a board.
- `FEATURES_CONFLICT` are a series of `FEATURES` that can't be used at the same
time for a particular `BOARD`.
- `FEATURES_REQUIRED` are `FEATURES` that are needed by a `MODULE` or `APPLICATION`
to work.
- `FEATURES_OPTIONAL` are "nice to have" `FEATURES`, not needed but useful. If
available they are always included.
- `FEATURES_REQUIRED_ANY` are `FEATURES` of which (at least) one of
is needed by a `MODULE` or `APPLICATION`. Alternatives are separated by
a pipe (`|`) in order of preference, e.g.:
`FEATURES_REQUIRED_ANY += arch_avr8|arch_native` if both are provide then
`arch_avr8` will be used.
- `FEATURES_BLACKLIST` are `FEATURES` that can't be used by a `MODULE` or `APPLICATION`.
They are usually used for _hw_ characteristics like `arch_` to easily resolve
unsupported configurations for a group.
- `FEATURES_USED` are the final list of `FEATURES` that will be used by an `APPLICATION`
### Where to define FEATURES_%
- `FEATURES_PROVIDED`, `FEATURES_CONFLICT` and `FEATURES_CONFLICT_MSG ` are
defined in `Makefile.features`
- `FEATURES_REQUIRED`, `FEATURES_OPTIONAL`, `FEATURES_REQUIRED_ANY`,
and `FEATURES_BLACKLIST` are defined by the application `Makefile`
(`examples/%/Makefile`, `tests/%/Makefile`, etc.) or in `Makefile.dep`
## CPU/CPU_MODEL {#cpu}
`CPU` and `CPU_MODEL` refer to the _soc_ or _mcu_ (microcontroller)
present in a `BOARD`. The variables `CPU`, `CPU_FAM`, etc. are just arbitrary groupings
to avoid code duplication. How this grouping is done depends on every implementation
and the way each manufacturer groups there products.
These variables allows declaring the `FEATURES` that the _mcu/soc_ provides as well
as resolving dependencies.
`FEATURES` provided by a `CPU/CPU_MODEL` should not depend on the wiring of a
specific `BOARD` but be intrinsic to the _soc/mcu_.
A `CPU/CPU_MODEL` might support `FEATURES` that will depend on the `BOARD` wiring,
e.g.: bus (`uart`, `spi`) mappings. In this cases the `FEATURE` should be provided
by the `BOARD.`
## BOARD {#board}
In RIOTs build-system, a `BOARD` is a grouping of:
- _soc/mcu_ (`CPU/CPU_MODEL`)
- e.g.: `b-l072z-lrwan1` `stm32l072cz`
- _sensor/actuators_ (buttons and leds included) (`drivers`)
- e.g.: `b-l072z-lrwan1` leds and buttons
- _radios_, _ethernet_, etc. devices (`drivers`)
- e.g.: `b-l072z-lrwan1` `sx1276`
- _programming/debugging_ tools
- e.g.: `b-l072z-lrwan1` `stlink`
- configuration mapping cpu support capabilities to availability
- e.g.: `b-l072z-lrwan1` `periph_conf.h`, `gpio_params`
A `board` can have all the required `FEATURES` to interact with a radio or
sensor/actuator, but it doesn't necessarily provide that `FEATURE`.
e.g.:
- `samr21-xpro` provides a `at86rf233` radio as well as the necessary
`periph_*` features.
- `nucleo-*` provide all `periph_*` features to use `sx1272`, and
even a default configuration for the `SX1272MB2xA` shield, but not
doesn't provide the radio.
If a `board` in `$(RIOTBASE)/boards` is connected to a radio shield, sensors,
actuators, etc. then it is a different `board` than the one provided by default.
Whenever you need to have a device mapping (in linux-arm, it would require
a different device tree), then it is a different board and would need a
different `board/periph_conf`.
A `nucleo-*` with a `SX1272MB2xA` is a different board in RIOT sense.
_note_: if `devicetree` is implemented this concept will change.
# Variables declaration guidelines {#variable-declaration-guidelines}
This page contains basic guidelines about `make` variable declaration, it
summarizes some of the pros and cons as well as specifies good and bad patterns
in our build system. You might want to refer to `gnu make` documentation
regarding these subjects.
## Avoid unnecessary export
```
export OUTPUT = $(shell some-command)
```
Exporting a variable means it will be evaluated on every `target` call, which
slows down the build system. Always avoid exporting a variable if unneeded.
If an export is actually needed by a `sub-make` then export the variable only for
the needed targets using `target-export-variables` (more in
`makefiles/utils/variables.mk`).
Exported variables ("global variable") are hard to remove, specially when badly
documented. If no one knows why it's there and no one knows where it can be used
then no one knows if it's safe to remove since it's present for every target.
This is why global variables need clear documentation.
[gnumake doc](https://www.gnu.org/software/make/manual/html_node/Variables_002fRecursion.html)
## Use memoized for variables referencing a function or command
### recursively expanded variable:
~~~~~~~~~~~~~~~~
OUTPUT = $(shell some-command $(ANOTHER_VARIABLE))
~~~~~~~~~~~~~~~~
- When using `=` the value of the variable is only declared, but not set,
therefore the variable will only be evaluated when expanded (used) somewhere
in the makefile. If `$(OUTPUT)` is never expanded, `some-command`
is never executed and `ANOTHER_VARIABLE` not expanded.
- All variables or functions referenced by the declared variable will will be
evaluated every time the variable is expanded.
In the example `some-command` is executed every time `OUTPUT` is expanded, same for
`ANOTHER_VARIABLE`. If `some-command` is slow this introduced unneeded overhead.
- If the variable expansion doesn't involve evaluating a function the overhead
is none.
### simply expanded variable:
~~~~~~~~~~~~~~~~
OUTPUT := $(shell some-command $(ANOTHER_VARIABLE))
~~~~~~~~~~~~~~~~
- When using `:=` the value is only expanded once, expanding any reference to
other variables or functions. If `OUTPUT` is always used at least once and
evaluates a costly function (`some command`) then use `:=`.
- When using `:=` the variable will be evaluated even if not needed, which
introduces unnecessary delay, in particular `some command` or functions
evaluated by `ANOTHER_VARIABLE` are slow.
It can also cause a failure in a worst-case scenario (think what happens if a
tool is defined with `:=` but you don't have the tool and you don't need it either).
- The values of variables declared with `:=` depend on the order of definition.
### memoized:
~~~~~~~~~~~~~~~~
OUTPUT = $(call memoized,OUTPUT,$(shell some-command))
~~~~~~~~~~~~~~~~
- `memoized` is a RIOT defined function that combines characteristics from
both `=` and `:=`.
The variable expansion will be deferred until its first usage, but further
usage will consider it as a simply expanded variable, so it will use the already
evaluated value. In the example `some-command` would be executed once or not
at all (more in `makefiles/utils/variables.mk`).
[gnumake doc](https://www.gnu.org/software/make/manual/html_node/Flavors.html)
## Additional documentation
- Deferred vs. simple expansion: http://make.mad-scientist.net/deferred-simple-variable-expansion/
- Tracking issue: [#10850](https://github.com/RIOT-OS/RIOT/issues/10850)