All the West Commands You Should Know

West Commands Every Zephyr User Should Know

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

west
west build
west flash
west debug
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

west sdk

One of the newer commands, west sdk will pull up information about the currently installed SDK and toolchains versions. Add the “i” flag to it (west sdk -i)  to drop into the interactive installation script. This is the same as you get when you go to the releases page, download, and run an SDK release. But it cuts out those steps.

Help me with Kconfig

west build -t menuconfig

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

west boards
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

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.

➜ west flash --context
-- west flash: rebuilding
ninja: no work to do.
build configuration:
  build directory: /home/mike/golioth-compile/golioth-firmware-sdk/modules/lib/golioth-firmware-sdk/build
  board: mimxrt1024_evk/mimxrt1024
  runners.yaml: /home/mike/golioth-compile/golioth-firmware-sdk/modules/lib/golioth-firmware-sdk/build/zephyr/runners.yaml
zephyr runners which support "west flash":
  blackmagicprobe, nrfutil, arc-nsim, dediprog, uf2, dfu-util, xsdb,
  teensy, ezflashcli, linkserver, nrfjprog, silabs_commander, esp32,
  spi_burn, pyocd, stm32cubeprogrammer, native, mdb-nsim, gd32isp,
  nios2, intel_adsp, canopen, openocd, probe-rs, hifive1, stm32flash,
  misc-flasher, bossac, trace32, intel_cyclonev, jlink, mdb-hw

  Note: not all may work with this board and build directory.
  Available runners are listed below.
available runners in runners.yaml:
  linkserver, jlink, pyocd
default runner in runners.yaml:
  linkserver
common runner configuration:
  - build_dir: /home/mike/golioth-compile/golioth-firmware-sdk/modules/lib/golioth-firmware-sdk/build
  - board_dir: /home/mike/golioth-compile/golioth-firmware-sdk/zephyr/boards/nxp/mimxrt1024_evk
  - elf_file: /home/mike/golioth-compile/golioth-firmware-sdk/modules/lib/golioth-firmware-sdk/build/zephyr/zephyr.elf
  - exe_file: None
  - hex_file: /home/mike/golioth-compile/golioth-firmware-sdk/modules/lib/golioth-firmware-sdk/build/zephyr/zephyr.hex
  - bin_file: /home/mike/golioth-compile/golioth-firmware-sdk/modules/lib/golioth-firmware-sdk/build/zephyr/zephyr.bin
  - uf2_file: None
  - file: None
  - file_type: FileType.OTHER
  - gdb: /home/mike/zephyr-sdk-0.17.0/arm-zephyr-eabi/bin/arm-zephyr-eabi-gdb-py
  - openocd: /home/mike/zephyr-sdk-0.17.0/sysroots/x86_64-pokysdk-linux/usr/bin/openocd
  - openocd_search: ['/home/mike/zephyr-sdk-0.17.0/sysroots/x86_64-pokysdk-linux/usr/share/openocd/scripts']
  - rtt_address: None
runner-specific context:
  linkserver capabilities:
    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)
  linkserver options:
    -i DEV_ID, --dev-id DEV_ID
                          Device identifier. Use it to select which debugger, device, node or instance to target when multiple ones are available or connected.
    --dt-flash {Y,y,N,n,yes,no,YES,NO}
                          If 'yes', try to use flash address information from devicetree when flash addresses are unknown (e.g. when flashing a .bin)
    -f FILE, --file FILE  path to binary file
    -t FILE_TYPE, --file-type FILE_TYPE
                          type of binary file
    --elf-file FILE       Deprecated, use -f/--file instead.
    --hex-file FILE       Deprecated, use -f/--file instead.
    --bin-file FILE       Deprecated, use -f/--file instead.
    --erase, --no-erase   mass erase flash before loading, or don't. Default action depends on each specific runner.
    -O TOOL_OPT, --tool-opt TOOL_OPT
                          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
                          command line.
    --device DEVICE       device name
    --core CORE           core of the device
    --probe PROBE         interface to use (index, or serial number, default is #1
    --tui                 if given, GDB uses -tui
    --gdb-port GDB_PORT   gdb port to open, defaults to 3333
    --semihost-port SEMIHOST_PORT
                          semihost port to open, defaults to the empty string and runs a gdb server
    --linkserver LINKSERVER
                          LinkServer executable, default is LinkServer
    --override OVERRIDE   configuration overrides as defined bylinkserver. Example: /device/memory/0/location=0xcafecafe
  linkserver arguments from runners.yaml:
    --dt-flash=y
    --device=MIMXRT1024xxxxx:MIMXRT1024-EVK
  jlink capabilities:
    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)
  jlink options:
    -i DEV_ID, --dev-id DEV_ID
                          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.
    --dt-flash {Y,y,N,n,yes,no,YES,NO}
                          If 'yes', try to use flash address information from devicetree when flash addresses are unknown (e.g. when flashing a .bin)
    -f FILE, --file FILE  path to binary file
    -t FILE_TYPE, --file-type FILE_TYPE
                          type of binary file
    --elf-file FILE       Deprecated, use -f/--file instead.
    --hex-file FILE       Deprecated, use -f/--file instead.
    --bin-file FILE       Deprecated, use -f/--file instead.
    --erase, --no-erase   mass erase flash before loading, or don't. Default action depends on each specific runner.
    --reset, --no-reset   reset device after flashing, or don't. Default action depends on each specific runner.
    -O TOOL_OPT, --tool-opt TOOL_OPT
                          Additional options for JLink Commander, e.g. '-autoconnect 1'
    --rtt-address RTT_ADDRESS
                          address of RTT control block. If not supplied, it will be autodetected if possible
    --device DEVICE       device name
    --loader LOADER       specifies a loader type
    --id DEV_ID           obsolete synonym for -i/--dev-id
    --iface IFACE         interface to use, default is swd
    --speed SPEED         interface speed, default is autodetect
    --tui                 if given, GDB uses -tui
    --gdbserver GDBSERVER
                          GDB server, default is JLinkGDBServer
    --gdb-host GDB_HOST   custom gdb host, defaults to the empty string and runs a gdb server
    --gdb-port GDB_PORT   pyocd gdb port, defaults to 2331
    --commander COMMANDER
                          J-Link Commander, default is JLinkExe
    --reset-after-load, --no-reset-after-load
                          obsolete synonym for --reset/--no-reset
    --rtt-client RTT_CLIENT
                          RTT client, default is JLinkRTTClient
    --rtt-port RTT_PORT   jlink rtt port, defaults to 19021
  jlink arguments from runners.yaml:
    --dt-flash=y
    --device=MIMXRT1024xxx5A
  pyocd capabilities:
    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)
  pyocd options:
    -i DEV_ID, --dev-id DEV_ID
                          Device identifier. Use it to select the probe's unique ID or substring thereof.
    --dt-flash {Y,y,N,n,yes,no,YES,NO}
                          If 'yes', try to use flash address information from devicetree when flash addresses are unknown (e.g. when flashing a .bin)
    --elf-file FILE       path to zephyr.elf
    --hex-file FILE       path to zephyr.hex
    --bin-file FILE       path to zephyr.bin
    --erase, --no-erase   mass erase flash before loading, or don't. Default action depends on each specific runner.
    -O TOOL_OPT, --tool-opt TOOL_OPT
                          Additional options for pyocd commander, e.g. '--script=user.py'
    --rtt-address RTT_ADDRESS
                          address of RTT control block. If not supplied, it will be autodetected if possible
    --target TARGET       target override
    --daparg DAPARG       Additional -da arguments to pyocd tool
    --pyocd PYOCD         path to pyocd tool, default is pyocd
    --flash-opt FLASH_OPT
                          Additional options for pyocd flash, e.g. --flash-opt="-e=chip" to chip erase
    --frequency FREQUENCY
                          SWD clock frequency in Hz
    --gdb-port GDB_PORT   pyocd gdb port, defaults to 3333
    --telnet-port TELNET_PORT
                          pyocd telnet port, defaults to 4444
    --tui                 if given, GDB uses -tui
    --board-id DEV_ID     obsolete synonym for -i/--dev-id
  pyocd arguments from runners.yaml:
    --dt-flash=y
    --target=mimxrt1024

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

west manifest --path
west config manifest.file my-custom-manifest.yml
west manifest --resolve
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.

Talk with an Expert

Implementing an IoT project takes a team of people, and we want to help out as part of your team. If you want to troubleshoot a current problem or talk through a new project idea, we're here for you.

Start the discussion at forum.golioth.io