diff options
| author | Antonin Godard <antonin.godard@bootlin.com> | 2025-02-17 15:50:25 +0100 |
|---|---|---|
| committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2025-02-26 14:49:28 +0000 |
| commit | dcfbb14ad38aa31eab9f51c4af21b6f85667963c (patch) | |
| tree | 806b3c45782deb3a6f708b5123f7657cf1117db6 /documentation | |
| parent | 705966c54623b85775ba540acbd6941c91e23e40 (diff) | |
| download | poky-dcfbb14ad38aa31eab9f51c4af21b6f85667963c.tar.gz | |
dev-manual/multiconfig: add suggested best practices and baremetal sections
After the suggestions from Mark Hatle on the list
(https://lists.yoctoproject.org/g/docs/topic/110487932), add two
sections to the multiconfig doc:
- Suggested best practices: suggestion for better design of multiconfig
builds.
- Common use case: baremetal build.
This section applies the guidelines from the first sections and apply
it to a real-life example of how to use multiconfig. This one to build
some baremetal firmware alongside a regular Linux build.
Suggested-by: Mark Hatle <mark.hatle@kernel.crashing.org>
Reviewed-by: Quentin Schulz <quentin.schulz@cherry.de>
(From yocto-docs rev: 36fb1e9e5099aa0d858d5478530143e9bac39588)
Signed-off-by: Antonin Godard <antonin.godard@bootlin.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'documentation')
| -rw-r--r-- | documentation/dev-manual/multiconfig.rst | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/documentation/dev-manual/multiconfig.rst b/documentation/dev-manual/multiconfig.rst index 8371cf0e46..71fe542efb 100644 --- a/documentation/dev-manual/multiconfig.rst +++ b/documentation/dev-manual/multiconfig.rst | |||
| @@ -174,3 +174,139 @@ and have separate configuration files, BitBake places the artifacts for | |||
| 174 | each build in the respective temporary build directories (i.e. | 174 | each build in the respective temporary build directories (i.e. |
| 175 | :term:`TMPDIR`). | 175 | :term:`TMPDIR`). |
| 176 | 176 | ||
| 177 | Suggested best practices | ||
| 178 | ======================== | ||
| 179 | |||
| 180 | - :term:`TMPDIR` (other than the default set in bitbake.conf) is only set in | ||
| 181 | ``local.conf`` by the user. This means that we should **not** manipulate | ||
| 182 | :term:`TMPDIR` in any way within the Machine or Distro :term:`configuration | ||
| 183 | file`. | ||
| 184 | |||
| 185 | - A multiconfig should specify a :term:`TMPDIR`, and should specify it by | ||
| 186 | appending the multiconfig name with :term:`BB_CURRENT_MC`. | ||
| 187 | |||
| 188 | - Recipes that are used to transfer the output from a multiconfig build to | ||
| 189 | another should use ``do_task[mcdepends]`` to trigger the build of the | ||
| 190 | component, and then transfer the item to the current configuration in | ||
| 191 | :ref:`ref-tasks-install` and :ref:`ref-tasks-deploy`, assuming the value of | ||
| 192 | the deployed item based on :term:`TMPDIR`. | ||
| 193 | |||
| 194 | The :ref:`ref-tasks-install` and :ref:`ref-tasks-deploy` tasks should look | ||
| 195 | like this:: | ||
| 196 | |||
| 197 | do_install() { | ||
| 198 | install -m 0644 ${TMPDIR}-<multiconfig>/tmp/deploy/images/<machine>/somefile ${D}/some/path | ||
| 199 | } | ||
| 200 | |||
| 201 | do_deploy() { | ||
| 202 | install -m 0644 ${TMPDIR}-<multiconfig>/tmp/deploy/images/<machine>/somefile ${DEPLOYDIR}/somefile | ||
| 203 | } | ||
| 204 | |||
| 205 | In the example above: | ||
| 206 | |||
| 207 | - ``<multiconfig>`` is the multiconfig name as set by the multiconfig | ||
| 208 | :term:`configuration file` (see the :ref:`dev-manual/multiconfig:Setting | ||
| 209 | Up and Running a Multiple Configuration Build` section above). | ||
| 210 | |||
| 211 | - ``<machine>`` must be the :term:`MACHINE` for which ``somefile`` was built | ||
| 212 | and deployed. This value may differ from the current :term:`MACHINE` if | ||
| 213 | the multiconfig :term:`configuration file` overrides it. | ||
| 214 | |||
| 215 | - Firmware recipes can set the :term:`INHIBIT_DEFAULT_DEPS` variable to ``1`` | ||
| 216 | if they don't rely on default dependencies such as the standard C library. | ||
| 217 | |||
| 218 | Common use case: building baremetal firmware alongside a Linux build | ||
| 219 | ==================================================================== | ||
| 220 | |||
| 221 | A common use case for multiconfig is to use the default configuration as the | ||
| 222 | regular Linux build, while one or more multiconfigs can be used to build special | ||
| 223 | components, such as baremetal firmware. It would also apply to a scenario where | ||
| 224 | a microcontroller, for example, is companion to a main processor where Linux is | ||
| 225 | running. This section details how one can achieve these kinds of scenarios with | ||
| 226 | a multiconfig build. | ||
| 227 | |||
| 228 | Adding a multiconfig configuration file and recipe for a baremetal firmware | ||
| 229 | --------------------------------------------------------------------------- | ||
| 230 | |||
| 231 | As described in :ref:`dev-manual/multiconfig:Setting Up and Running a Multiple | ||
| 232 | Configuration Build`, each multiconfig will require a separate | ||
| 233 | :term:`Configuration File`. In addition, we will define a separate | ||
| 234 | :term:`TMPDIR` for our baremetal firmware build configuration. | ||
| 235 | |||
| 236 | For example, we will define a new ``conf/multiconfig/baremetal-firmware.conf`` | ||
| 237 | as follows:: | ||
| 238 | |||
| 239 | TMPDIR .= "-${BB_CURRENT_MC}" | ||
| 240 | TCLIBC = "newlib" | ||
| 241 | |||
| 242 | The ``baremetal-firmware.conf`` file configures a separate :term:`TMPDIR` for | ||
| 243 | holding binaries compiled with the `newlib <https://sourceware.org/newlib/>`__ | ||
| 244 | toolchain (see :term:`TCLIBC`). | ||
| 245 | |||
| 246 | .. note:: | ||
| 247 | |||
| 248 | Here, the default :term:`MACHINE` is not overridden by the multiconfig | ||
| 249 | configuration file. As a consequence, the architecture of the built baremetal | ||
| 250 | binaries will be the same. In other cases, where the firmware runs on a | ||
| 251 | completely different architecture, the :term:`MACHINE` must be overridden. | ||
| 252 | |||
| 253 | We then create a recipe ``my-firmware.bb`` that defines how the baremetal | ||
| 254 | firmware is built. The recipe should contain enough information for the | ||
| 255 | :term:`OpenEmbedded build system` to properly compile the firmware with our | ||
| 256 | toolchain. The building tasks may vary depending on the nature of the firmware. | ||
| 257 | However, the recipe should define a :ref:`ref-classes-deploy` task that deploys | ||
| 258 | the output into the :term:`DEPLOYDIR` directory. We will consider in the | ||
| 259 | following that the file is named ``my-firmware.elf``. | ||
| 260 | |||
| 261 | Building the firmware | ||
| 262 | --------------------- | ||
| 263 | |||
| 264 | The firmware can be built with BitBake with the following command:: | ||
| 265 | |||
| 266 | $ bitbake mc:baremetal-firmware:my-firmware | ||
| 267 | |||
| 268 | However, we would prefer for ``my-firmware`` to be automatically built when | ||
| 269 | triggering a normal Linux build. | ||
| 270 | |||
| 271 | Using a ``mcdepend``, a recipe belonging to the Linux build can trigger the | ||
| 272 | build of ``my-firmware``. For example, let's consider that our Linux build needs | ||
| 273 | to assemble a "special" firmware that uses the output of our ``my-firmware`` | ||
| 274 | recipe - let's call it ``my-parent-firmware.bb``. Then, we should specify this | ||
| 275 | dependency in ``my-parent-firmware.bb`` with:: | ||
| 276 | |||
| 277 | do_compile[mcdepends] = "mc::baremetal-firmware:my-firmware:do_deploy" | ||
| 278 | |||
| 279 | The above will ensure that when the :ref:`ref-tasks-compile` task of | ||
| 280 | ``my-parent-firmware`` is triggered, the :ref:`ref-tasks-deploy` task of | ||
| 281 | ``my-firmware`` will already have run successfully. | ||
| 282 | |||
| 283 | Using the output of ``my-firmware`` | ||
| 284 | ----------------------------------- | ||
| 285 | |||
| 286 | After ``my-firmware`` recipe has deployed ``my-firmware.elf``, we need to use | ||
| 287 | the output in some way. We can make a series of assumptions, based on the | ||
| 288 | default Yocto Project variables in order to get the binary for packaging. | ||
| 289 | |||
| 290 | First, we can set the following in ``my-parent-firmware.bb``:: | ||
| 291 | |||
| 292 | FIRMWARE_FILE ??= "${TMPDIR}-baremetal-firmware/deploy/images/<machine>/my-firmware.elf" | ||
| 293 | FIRMWARE_FILE[vardepsexclude] += "TMPDIR" | ||
| 294 | |||
| 295 | The first assignment stores the value of the path to the firmware built and | ||
| 296 | deployed by the ``my-firmware.bb`` recipe. The second assignment excludes the | ||
| 297 | :term:`TMPDIR` variable from being part of ``FIRMWARE_FILE``'s dependencies --- | ||
| 298 | meaning that changing the value of :term:`TMPDIR` (for example, changing the | ||
| 299 | host on which the firmware is built) will not invalidate the :ref:`shared state | ||
| 300 | cache <overview-manual/concepts:shared state cache>`. | ||
| 301 | |||
| 302 | Additionally, ``<machine>`` should be replaced by the :term:`MACHINE` for which | ||
| 303 | we are building in the baremetal-firmware context. | ||
| 304 | |||
| 305 | We can then add a :ref:`ref-tasks-install` task to ``my-parent-firmware``:: | ||
| 306 | |||
| 307 | do_install() { | ||
| 308 | install -Dm 0644 ${FIRMWARE_FILE} ${D}/lib/firmware/my-firmware.elf | ||
| 309 | } | ||
| 310 | |||
| 311 | Doing the above will allow the firmware binary to be transferred and packaged | ||
| 312 | into the Linux context and rootfs. | ||
