Skip to main content
BlogMember Blog

West Commands Every Zephyr User Should Know

By January 7, 2025No Comments

This blog was written by Mike Szczys of Golioth and was originally published in the blog section of the Golioth website.

Here is an abstract of the blog “West Commands Every Zephyr User Should Know”.

West is Zephyr’s meta tool, described as a Swiss army knife for wrapping many commands and tools. The blog highlights essential west commands like west build, west flash, west debug, and west attach, which are commonly used for building, flashing, and debugging projects. Newer commands such as west sdk install simplify SDK installation and management. The post also covers west build -t menuconfig for Kconfig editing, west boards for listing board definitions, and west flash --context for retrieving runner information. Manifest management is detailed with commands like west manifest --path and west manifest --freeze. The blog describes the depth of west’s functionality and its adaptability through custom commands.

Read the original blog below:

West is the meta tool used by Zephyr to wrap myriad commands and tools. Zephyr calls west a Swiss army knife, and just like its namesake, there are some west commands you have available but likely have never used.

Today we’ll survey useful west commands that you may not know about. But let’s start with the obvious ones!

West commands you already know

1. west
2. west build
3. west flash
4. west debug
5. west attach

These are the go-to’s that should already be at the tips of your fingers. A simple west without anything else prints out usage where you’ll see all of the commands covered in the rest of the post.

The west build command will rebuild a project, but you will need to specify the board and path the first time to get things set up. Programming the board is handled by west flash, and depending on the runner, you can open a debugging session with west attach or west debug.

Installing toolchains

1. west sdk

Another one of those you should always have under your fingers, west is used to launch the ncurses-style menuconfig editor for working with Kconfig symbols. Once inside, use / to search, or navigate the menu system. You can use the ? to bring up help information on any symbol currently highlighted.

Working with Boards

1. west boards
2. west boards -n 52840

List every board definition in the Zephyr tree with a simple west boards command. However, the search option using -n is likely more useful. The command above will return (almost) every board that is built on an nRF52840 chip. I found that it does not search the SoC of the Hardware Model v2 naming scheme, so rak5010 wasn’t returned in the search even though its more verbose rak5010/nrf52840 name is .

Working with runners

1. west flash –context

This one is a bit obscure, but absolutely crucial when you need it. Zephyr uses the concept of runners to flash and debug targets. Using the context flag pulls up a ton of useful information. Bear with me while I paste a really long example output so we can discuss.

1. ➜ west flash --context
2. -- west flash: rebuilding
3. ninja: no work to do.
4. build configuration:
5. build directory: /home/mike/golioth-compile/golioth-firmware-sdk/modules/lib/golioth-firmware-sdk/build
6. board: mimxrt1024_evk/mimxrt1024
7. runners.yaml: /home/mike/golioth-compile/golioth-firmware-sdk/modules/lib/golioth-firmware-sdk/build/zephyr/runners.yaml
8. zephyr runners which support "west flash":
9. blackmagicprobe, nrfutil, arc-nsim, dediprog, uf2, dfu-util, xsdb,
10.  teensy, ezflashcli, linkserver, nrfjprog, silabs_commander, esp32,
11. spi_burn, pyocd, stm32cubeprogrammer, native, mdb-nsim, gd32isp,
12. nios2, intel_adsp, canopen, openocd, probe-rs, hifive1, stm32flash,
13. misc-flasher, bossac, trace32, intel_cyclonev, jlink, mdb-hw
14. 
15. Note: not all may work with this board and build directory.
16. Available runners are listed below.
17. available runners in runners.yaml:
18.  linkserver, jlink, pyocd
19. default runner in runners.yaml:
20. linkserver
21. common runner configuration:
22. - build_dir: /home/mike/golioth-compile/golioth-firmware-sdk/modules/lib/golioth-firmware-sdk/build
23. - board_dir: /home/mike/golioth-compile/golioth-firmware-sdk/zephyr/boards/nxp/mimxrt1024_evk
24. - elf_file: /home/mike/golioth-compile/golioth-firmware-sdk/modules/lib/golioth-firmware-sdk/build/zephyr/zephyr.elf
25. - exe_file: None
26. - hex_file: /home/mike/golioth-compile/golioth-firmware-sdk/modules/lib/golioth-firmware-sdk/build/zephyr/zephyr.hex
27. - bin_file: /home/mike/golioth-compile/golioth-firmware-sdk/modules/lib/golioth-firmware-sdk/build/zephyr/zephyr.bin
28. - uf2_file: None
29. - file: None
30.  - file_type: FileType.OTHER
31. - gdb: /home/mike/zephyr-sdk-0.17.0/arm-zephyr-eabi/bin/arm-zephyr-eabi-gdb-py
32. - openocd: /home/mike/zephyr-sdk-0.17.0/sysroots/x86_64-pokysdk-linux/usr/bin/openocd
33. - openocd_search: ['/home/mike/zephyr-sdk-0.17.0/sysroots/x86_64-pokysdk-linux/usr/share/openocd/scripts']
34. - rtt_address: None
35. runner-specific context:
36. linkserver capabilities:
37. RunnerCaps(commands={'debugserver', 'flash', 'debug', 'attach'}, dev_id=True, flash_addr=True, erase=True, reset=False, extload=False, tool_opt=True, file=True, hide_load_files=False, rtt=False)
38. linkserver options:
39. -i DEV_ID, --dev-id DEV_ID
40. Device identifier. Use it to select which debugger, device, node or instance to target when multiple ones are available or connected.
41. --dt-flash {Y,y,N,n,yes,no,YES,NO}
42.                      If 'yes', try to use flash address information from devicetree when flash addresses are unknown (e.g. when flashing a .bin)
43.  -f FILE, --file FILE  path to binary file
44. -t FILE_TYPE, --file-type FILE_TYPE
45.                       type of binary file
46. --elf-file FILE       Deprecated, use -f/--file instead.
47. --hex-file FILE       Deprecated, use -f/--file instead.
48. --bin-file FILE       Deprecated, use -f/--file instead.
49. --erase, --no-erase   mass erase flash before loading, or don't. Default action depends on each specific runner.
50. -O TOOL_OPT, --tool-opt TOOL_OPT
51.                     Option to pass on to the underlying tool used by this runner. This can be given multiple times; the resulting arguments will be given to the tool in the order they appear on the
52.                     command line.
53.  --device DEVICE       device name
54.  --core CORE           core of the device
55. --probe PROBE         interface to use (index, or serial number, default is #1
56.  --tui                 if given, GDB uses -tui
57. --gdb-port GDB_PORT   gdb port to open, defaults to 3333
58.  --semihost-port SEMIHOST_PORT
59.                       semihost port to open, defaults to the empty string and runs a gdb server
60.  --linkserver LINKSERVER
61.                        LinkServer executable, default is LinkServer
62. --override OVERRIDE   configuration overrides as defined bylinkserver. Example: /device/memory/0/location=0xcafecafe
63. linkserver arguments from runners.yaml:
64. --dt-flash=y
65.--device=MIMXRT1024xxxxx:MIMXRT1024-EVK
66. jlink capabilities:
67.  RunnerCaps(commands={'debugserver', 'rtt', 'debug', 'flash', 'attach'}, dev_id=True, flash_addr=True, erase=True, reset=True, extload=False, tool_opt=True, file=True, hide_load_files=False, rtt=True)
68. jlink options:
69.  -i DEV_ID, --dev-id DEV_ID
70.                      Device identifier. Use it to select the J-Link Serial Number of the device connected over USB. If the J-Link is connected over ip, the Device identifier is the ip.
71. --dt-flash {Y,y,N,n,yes,no,YES,NO}
72.                       If 'yes', try to use flash address information from devicetree when flash addresses are unknown (e.g. when flashing a .bin)
73.  -f FILE, --file FILE  path to binary file
74.  -t FILE_TYPE, --file-type FILE_TYPE
75.                       type of binary file
76.  --elf-file FILE       Deprecated, use -f/--file instead.
77.  --hex-file FILE       Deprecated, use -f/--file instead.
78.  --bin-file FILE       Deprecated, use -f/--file instead.
79. --erase, --no-erase   mass erase flash before loading, or don't. Default action depends on each specific runner.
80.  --reset, --no-reset   reset device after flashing, or don't. Default action depends on each specific runner.
81.  -O TOOL_OPT, --tool-opt TOOL_OPT
82.                        Additional options for JLink Commander, e.g. '-autoconnect 1'
83.  --rtt-address RTT_ADDRESS
84.                       address of RTT control block. If not supplied, it will be autodetected if possible
85.   --device DEVICE       device name
86.--loader LOADER       specifies a loader type
87.  --id DEV_ID           obsolete synonym for -i/--dev-id
88.  --iface IFACE         interface to use, default is swd
89.  --speed SPEED         interface speed, default is autodetect
90.  --tui                 if given, GDB uses -tui
91. --gdbserver GDBSERVER
92.                      GDB server, default is JLinkGDBServer
93. --gdb-host GDB_HOST   custom gdb host, defaults to the empty string and runs a gdb server
94.  --gdb-port GDB_PORT   pyocd gdb port, defaults to 2331
95.  --commander COMMANDER
96.                       J-Link Commander, default is JLinkExe
97.    --reset-after-load, --no-reset-after-load
98.                         obsolete synonym for --reset/--no-reset
99.   --rtt-client RTT_CLIENT
100.                          RTT client, default is JLinkRTTClient
101.   --rtt-port RTT_PORT   jlink rtt port, defaults to 19021
102.  jlink arguments from runners.yaml:
103.   --dt-flash=y
104.   --device=MIMXRT1024xxx5A
105.  pyocd capabilities:
106.   RunnerCaps(commands={'debugserver', 'rtt', 'debug', 'flash', 'attach'}, dev_id=True, flash_addr=True, erase=True, reset=False, extload=False, tool_opt=True, file=False, hide_load_files=False, rtt=True)
107.  pyocd options:
108.   -i DEV_ID, --dev-id DEV_ID
109.                         Device identifier. Use it to select the probe's unique ID or substring thereof.
110.   --dt-flash {Y,y,N,n,yes,no,YES,NO}
111.                        If 'yes', try to use flash address information from devicetree when flash addresses are unknown (e.g. when flashing a .bin)
112.    --elf-file FILE       path to zephyr.elf
113.    --hex-file FILE       path to zephyr.hex
114.    --bin-file FILE       path to zephyr.bin
115.    --erase, --no-erase   mass erase flash before loading, or don't. Default action depends on each specific runner.
116.    -O TOOL_OPT, --tool-opt TOOL_OPT
117.                         Additional options for pyocd commander, e.g. '--script=user.py'
118.    --rtt-address RTT_ADDRESS
119.                         address of RTT control block. If not supplied, it will be autodetected if possible
120.    --target TARGET       target override
121.    --daparg DAPARG       Additional -da arguments to pyocd tool
122.   --pyocd PYOCD         path to pyocd tool, default is pyocd
123.   --flash-opt FLASH_OPT
124.                         Additional options for pyocd flash, e.g. --flash-opt="-e=chip" to chip erase
125   --frequency FREQUENCY
126.                         SWD clock frequency in Hz
127.   --gdb-port GDB_PORT   pyocd gdb port, defaults to 3333
128.   --telnet-port TELNET_PORT
129.                         pyocd telnet port, defaults to 4444
130.   --tui                 if given, GDB uses -tui
131.   --board-id DEV_ID     obsolete synonym for -i/--dev-id
132. pyocd arguments from runners.yaml:
133.   --dt-flash=y
134.  --target=mimxrt1024
135.
136. Note: use -r RUNNER to limit information to one runner.

 

You can see so many helpful tidbits when running the west flash --context command after a successful build. First up, you get a list of what runners are currently supported for this board (line 17), along with all of the runners available to Zephyr (line 8). Not able to flash your chip? Perhaps the default runner (line 19) is different from the the programmer you have connected. This is the case for me with the mimxrt1024_evk board, so adding --runner jlink to all flash/attach commands is how I work with this board.

The rest of the output covers runner-specific configuration. Most of the time the defaults work great. But when you need to pass a different GDB port, or make some other tweak, this is where to go for help.

Managing Manifests

1. west manifest --path
2. west config manifest.file my-custom-manifest.yml
3. west manifest --resolve
4. west manifest --freeze

Manifests are near and dear to my heart. I think they are among the best features of the Zephyr ecosystem!

The Golioth Firmware SDK is an interesting use case for multiple distinct manifest files. We have one for projects that build on Zephyr, and another for projects that build on Nordic’s nrfConnect SDK (NCS). On workspaces installed with the Golioth SDK as the main manifest, I can switch between the two types of installations using west config manifest.file west-zephyr.yml.

When you just want to know where your manifest file is located, reach for west manifest --path. During development you might want to know what versions are being pulled in from inherited manifests. The west manifest --resolve will print that info out for you. When you’re getting to the end of the project, use west manifest --freeze to generate your manifest file with commit hashes for versions (locking in any branch names you used).

This tool goes deep

The west meta tool wraps up an incredible amount of functionality. Most of the time, you’ll find west can already do the things you want, it just takes a little digging to discover the syntax.

If west does fall short of your needs, you can always add your own custom commands. We do that here at Golioth, but Zephyr also does it to enable most of the commands mentioned above.  But that’s a story best saved for a future blog post.