Skip to content

dfetch-org/example-zephyr

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

26 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

example-zephyr

A complete Zephyr RTOS example application managed with dfetch instead of west submodules.

Why dfetch instead of west?

Zephyr's standard tooling relies on west, which uses git submodules under the hood. This approach has several drawbacks:

  • Submodule state is implicit and easy to break
  • Dependencies are not stored inside the repository — contributors must run west update after every clone
  • Merging and rebasing across submodule boundaries is error-prone

dfetch solves this by copying dependency sources directly into the repository. All code lives in one place, making the repository fully self-contained and reproducible without any extra fetch step after cloning.

This repo demonstrates the Zephyr example-application set up with dfetch and a Dockerfile to keep the build environment reproducible.


Table of Contents

  1. Prerequisites
  2. Install dfetch
  3. Create the basic manifest
  4. Fetch the core sources
  5. Register dfetch as a west command
  6. Add hardware abstraction modules
  7. Wire up the CMake module
  8. Take ownership of the application
  9. How west is configured
  10. Build
  11. Flash

Prerequisites

Before starting, make sure the following tools are installed on your system:

  • Python 3.8+ — required by dfetch and Zephyr's scripts
  • git — required by dfetch to fetch sources
  • CMake 3.13.1+ and Ninja — the Zephyr build system
  • Zephyr SDK — the cross-compilation toolchain; follow the official Zephyr Getting Started Guide

west (Zephyr's meta-tool) is installed automatically in the next step via pip.

Tip

The easiest way to get a fully configured environment is to open this repository in the provided Dev Container. It includes the Zephyr SDK, CMake, and all other build tools pre-installed.


Install dfetch

Create a Python virtual environment and install dfetch.

Unix/macOS
python -m venv venv
. venv/bin/activate
pip install dfetch
Windows (Command Prompt)
python -m venv venv
venv\Scripts\activate.bat
pip install dfetch
Windows (PowerShell)

If script execution is blocked, run Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser once first.

python -m venv venv
venv\Scripts\Activate.ps1
pip install dfetch

Create the basic manifest

dfetch is driven by a dfetch.yaml manifest that lists all external dependencies. Create the following file in the root of your workspace:

manifest:
  version: 0.0

  remotes:
  - name: zephyrproject-rtos
    url-base: https://github.com/zephyrproject-rtos

  projects:
  - name: zephyr
    repo-path: zephyr.git
    dst: zephyr
    branch: main
    ignore:
    - .github
    - samples
    - tests

  - name: application
    dst: application
    branch: main
    repo-path: example-application.git

This manifest defines two projects:

Project Source Destination
zephyr zephyrproject-rtos/zephyr zephyr/
application zephyrproject-rtos/example-application application/

Fetch the core sources

Run dfetch to clone the declared projects into the repository:

dfetch update

Then install Zephyr's Python tooling into the same virtual environment (this includes west):

pip install -r zephyr/scripts/requirements-base.txt

Note

All subsequent commands (dfetch, west) assume this virtual environment is active.


Register dfetch as a west command

At this point west is installed but knows nothing about dfetch. The next steps will add HAL modules via dfetch, and it is convenient to run them with west update so the workflow feels natural to anyone familiar with west.

This repository ships a west extension command — dfetch-update — that calls dfetch's own CLI. The command lives in dfetch/commands/:

Copy both files from this repository into the same paths in your workspace.

Next, register the command with west by adding the dfetch directory as a project in application/west.yml. West loads extension commands from the project's directory, so pointing the project path at dfetch/ is enough — no separate git repository is needed:

manifest:
  self:
    west-commands: scripts/west-commands.yml

  remotes:
    - name: zephyrproject-rtos
      url-base: https://github.com/zephyrproject-rtos
    - name: dfetch-org
      url-base: https://github.com/dfetch-org

  projects:
    - name: zephyr
      remote: zephyrproject-rtos
      revision: main
      west-commands: scripts/west-commands.yml

    - name: example-zephyr
      remote: dfetch-org
      revision: main
      path: dfetch
      west-commands: commands/west-commands.yml

Now initialise the west workspace and set the alias that maps west update to dfetch-update:

west init -l application
west config alias.update dfetch-update

Commit the resulting .west/config so that everyone who clones the repository gets a working workspace with the alias already set — no manual setup required:

git add .west/config application/west.yml dfetch/commands
git commit -m "Register dfetch-update as a west command, alias west update"

From this point on use west update wherever you would previously have run dfetch update. West resolves the alias and calls dfetch-update, which invokes dfetch internally.


Add hardware abstraction modules

The example application requires several hardware abstraction layer (HAL) modules. These are declared in application/west.yml under a name-allowlist:

projects:
  - name: zephyr
    remote: zephyrproject-rtos
    revision: main
    import:
      name-allowlist:
        - cmsis_6    # required by the ARM port for Cortex-M
        - hal_nordic # required by the custom_plank board (Nordic based)
        - hal_stm32  # required by the nucleo_f302r8 board (STM32 based)

The entries in name-allowlist refer to projects defined in zephyr/west.yml. Look each one up there to find its revision and path. For example:

# in zephyr/west.yml
- name: cmsis_6
  repo-path: CMSIS_6
  revision: 30a859f44ef8ab4dc8f84b03ed586fd16ccf9d74
  path: modules/hal/cmsis_6
  groups:
  - hal

- name: hal_nordic
  revision: 4dea410729da817a464f778533eb721473262e5b
  path: modules/hal/nordic
  groups:
  - hal

- name: hal_stm32
  revision: 57803da28e985e1cbc32a7ea993578f7267d0935
  path: modules/hal/stm32
  groups:
  - hal

Translate each entry into dfetch syntax and add them to your dfetch.yaml:

Note

The dfetch manifest syntax is similar to west.yml but has a few differences:

  • path: becomes dst:
  • groups: is not used and should be removed
  • repo-path: must be set explicitly (append .git to the name if the field is absent)
  - name: cmsis_6 # required by the ARM port for Cortex-M
    repo-path: CMSIS_6.git
    revision: 30a859f44ef8ab4dc8f84b03ed586fd16ccf9d74
    dst: modules/hal/cmsis_6

  - name: hal_nordic # required by the custom_plank board (Nordic based)
    repo-path: hal_nordic.git
    revision: 4dea410729da817a464f778533eb721473262e5b
    dst: modules/hal/nordic

  - name: hal_stm32 # required by the nucleo_f302r8 board (STM32 based)
    revision: 57803da28e985e1cbc32a7ea993578f7267d0935
    repo-path: hal_stm32.git
    dst: modules/hal/stm32

Run west update to fetch the new modules (the alias calls dfetch-update which in turn invokes dfetch):

west update

Wire up the CMake module

Zephyr needs to know about the fetched modules at CMake configure time. This repository provides a self-contained CMake module in dfetch/cmake/ that does this automatically by reading dfetch.yaml — no manual -DZEPHYR_MODULES flags required.

Create the directory and copy the two files from this repository:

Then add the following lines to application/app/CMakeLists.txt before find_package(Zephyr ...):

get_filename_component(WORKSPACE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../.." ABSOLUTE)
list(APPEND CMAKE_MODULE_PATH "${WORKSPACE_ROOT}/dfetch/cmake")
include(DfetchModules)

dfetch_discover_zephyr_modules("${WORKSPACE_ROOT}/dfetch.yaml" "${WORKSPACE_ROOT}")
dfetch_set_zephyr_build_version("${WORKSPACE_ROOT}/zephyr")

dfetch_discover_zephyr_modules scans every dst: path in dfetch.yaml and adds those that contain a zephyr/module.yml to ZEPHYR_MODULES.

dfetch_set_zephyr_build_version reads zephyr/VERSION and sets BUILD_VERSION, silencing the CMake warning that appears when Zephyr is present as a plain directory without its own .git.


Take ownership of the application

The application entry in dfetch.yaml was only there to bootstrap a starting point — a minimal Zephyr application structure to build from. Now that you have a local copy, the directory belongs to your repository. Keeping it under dfetch management would mean dfetch update can overwrite your edits at any time, so remove it from the manifest.

The fetched application/west.yml contains an import: block that tells west to pull HAL modules from Zephyr's own manifest. Because dfetch now manages those modules directly, delete the import: block from the zephyr project entry. The block looks like this — remove it entirely:

      # delete these lines from application/west.yml:
      import:
        name-allowlist:
          - cmsis_6
          - hal_nordic
          - hal_stm32

Then remove the application entry from dfetch.yaml and delete .dfetch_data.yaml (dfetch's tracking file) so dfetch no longer considers the directory its own:

rm application/.dfetch_data.yaml

Your final dfetch.yaml should look like this:

manifest:
  version: 0.0

  remotes:
  - name: zephyrproject-rtos
    url-base: https://github.com/zephyrproject-rtos

  projects:
  - name: zephyr
    repo-path: zephyr.git
    dst: zephyr
    branch: main

  - name: cmsis_6 # required by the ARM port for Cortex-M
    repo-path: CMSIS_6.git
    revision: 30a859f44ef8ab4dc8f84b03ed586fd16ccf9d74
    dst: modules/hal/cmsis_6

  - name: hal_nordic # required by the custom_plank board (Nordic based)
    repo-path: hal_nordic.git
    revision: 4dea410729da817a464f778533eb721473262e5b
    dst: modules/hal/nordic

  - name: hal_stm32 # required by STM32-based boards (e.g. nucleo_f302r8)
    repo-path: hal_stm32.git
    revision: 57803da28e985e1cbc32a7ea993578f7267d0935
    dst: modules/hal/stm32

The application/ directory is itself a Zephyr module — it contains a zephyr/module.yml that registers its Kconfig symbols, DTS bindings, and board definitions with the build system. Now that it is no longer in dfetch.yaml, dfetch_discover_zephyr_modules will not add it to ZEPHYR_MODULES. Add it explicitly in application/app/CMakeLists.txt before find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}):

list(APPEND ZEPHYR_MODULES "${WORKSPACE_ROOT}/application")

Commit application/ along with the updated manifest so the directory is fully tracked by your repository:

git add application dfetch.yaml
git commit -m "Take ownership of application, remove from dfetch manifest"

How west is configured

west-commands in application/west.yml

After completing the steps above, application/west.yml looks like this:

manifest:
  self:
    west-commands: scripts/west-commands.yml

  remotes:
    - name: zephyrproject-rtos
      url-base: https://github.com/zephyrproject-rtos
    - name: dfetch-org
      url-base: https://github.com/dfetch-org

  projects:
    - name: zephyr
      remote: zephyrproject-rtos
      revision: main
      west-commands: scripts/west-commands.yml

    - name: example-zephyr
      remote: dfetch-org
      revision: main
      path: dfetch
      west-commands: commands/west-commands.yml

There are three west-commands declarations:

Declaration Source What it provides
self: west-commands application/scripts/west-commands.yml application-specific extensions
zephyr: west-commands zephyr/scripts/west-commands.yml west build, west flash, etc.
example-zephyr: west-commands dfetch/commands/west-commands.yml dfetch-update

West resolves path: dfetch to the workspace-root dfetch/ directory and loads commands/west-commands.yml from there. Because the file lies inside that directory, no path escaping occurs and no separate git repository is required.

.west/config

The committed .west/config records the manifest location, the Zephyr base, and the dfetch-update alias set up in step 5:

[manifest]
path = application
file = west.yml

[zephyr]
base = zephyr

[alias]
update = dfetch-update

Build

Activate Zephyr's environment and run west build. No extra flags are needed — application/app/CMakeLists.txt reads dfetch.yaml at configure time, finds every dst: directory that contains a zephyr/module.yml, and adds them to ZEPHYR_MODULES automatically.

Unix/macOS
source zephyr/zephyr-env.sh
west build -b nucleo_f302r8 application/app
Windows (Command Prompt)
call zephyr\zephyr-env.cmd
west build -b nucleo_f302r8 application\app
Windows (PowerShell)

Zephyr does not ship a PowerShell environment script. The simplest option is to invoke the Command Prompt script within a cmd subshell:

cmd /c "zephyr\zephyr-env.cmd && west build -b nucleo_f302r8 application\app"

[!TIP] Zephyr development on Windows is also well-supported via WSL 2, where the Unix instructions apply directly.

When CMake runs you will see a status line for each discovered module:

-- Found dfetch module: modules/hal/cmsis_6
-- Found dfetch module: modules/hal/nordic
-- Found dfetch module: modules/hal/stm32

Adding a new module to dfetch.yaml (and running dfetch update) is all that is needed — the build picks it up on the next configure with no CMakeLists.txt changes required.

See Building without west for more details on standalone builds.


Flash

Flash the compiled firmware to the connected board:

west flash

The default runner for nucleo_f302r8 is stm32cubeprogrammer. To use a different runner:

# Use OpenOCD
west flash --runner openocd

# Use J-Link
west flash --runner jlink

Available runners for nucleo_f302r8: stm32cubeprogrammer (default), openocd, jlink.

About

Example repo for zephyr with dfetch

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors