0% found this document useful (0 votes)
23 views3,208 pages

Zephyr

Uploaded by

nahelyndubero
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
23 views3,208 pages

Zephyr

Uploaded by

nahelyndubero
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Zephyr Project Documentation

Release 3.4.0

The Zephyr Project Contributors


Jun 16, 2023
Table of contents

1 Introduction 1
1.1 Licensing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Distinguishing Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.3 Community Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.4 Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.5 Fundamental Terms and Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

2 Developing with Zephyr 5


2.1 Getting Started Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.1.1 Select and Update OS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.1.2 Install dependencies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.1.3 Get Zephyr and install Python dependencies . . . . . . . . . . . . . . . . . . . . . 7
2.1.4 Install Zephyr SDK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.1.5 Build the Blinky Sample . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.1.6 Flash the Sample . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.1.7 Next Steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.1.8 Troubleshooting Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.1.9 Asking for Help . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.2 Beyond the Getting Started Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.2.1 Python and pip . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.2.2 Advanced Platform Setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.2.3 Install a Toolchain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.2.4 Updating the Zephyr SDK toolchain . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.2.5 Cloning the Zephyr Repositories . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.2.6 Export Zephyr CMake package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.2.7 Board Aliases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.2.8 Build and Run an Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.3 Environment Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.3.1 Setting Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.3.2 Zephyr Environment Scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
2.3.3 Important Environment Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
2.4 Application Development . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.4.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.4.2 Application types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.4.3 Creating an Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.4.4 Important Build System Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.4.5 Application CMakeLists.txt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2.4.6 CMakeCache.txt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.4.7 Application Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.4.8 Application-Specific Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
2.4.9 Building an Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
2.4.10 Run an Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
2.4.11 Application Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
2.4.12 Custom Board, Devicetree and SOC Definitions . . . . . . . . . . . . . . . . . . . 42
2.4.13 Debug with Eclipse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
2.5 API Status and Guidelines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

i
2.5.1 API Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
2.5.2 API Lifecycle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
2.5.3 API Design Guidelines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
2.5.4 API Terminology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
2.6 Language Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
2.6.1 C Language Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
2.6.2 C++ Language Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
2.7 Optimizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
2.7.1 Optimizing for Footprint . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
2.7.2 Optimization Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
2.8 Flashing and Hardware Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
2.8.1 Flash & Debug Host Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
2.8.2 Debug Probes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
2.9 Modules (External projects) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
2.9.1 Modules vs west projects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
2.9.2 Module Repositories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
2.9.3 Contributing to Zephyr modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
2.9.4 Licensing requirements and policies . . . . . . . . . . . . . . . . . . . . . . . . . . 86
2.9.5 Documentation requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
2.9.6 Testing requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
2.9.7 Deprecating and removing modules . . . . . . . . . . . . . . . . . . . . . . . . . . 88
2.9.8 Integrate modules in Zephyr build system . . . . . . . . . . . . . . . . . . . . . . 88
2.9.9 Module yaml file description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
2.9.10 Submitting changes to modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
2.10 West (Zephyr’s meta-tool) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
2.10.1 Installing west . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
2.10.2 West Release Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
2.10.3 Troubleshooting West . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
2.10.4 Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
2.10.5 Built-in commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
2.10.6 Workspaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
2.10.7 West Manifests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
2.10.8 Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
2.10.9 Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
2.10.10 Building, Flashing and Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
2.10.11 Signing Binaries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
2.10.12 Additional Zephyr extension commands . . . . . . . . . . . . . . . . . . . . . . . 175
2.10.13 History and Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
2.10.14 Moving to West . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
2.10.15 Using Zephyr without west . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
2.11 Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
2.11.1 Test Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
2.11.2 Test Runner (Twister) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
2.11.3 Integration with pytest test framework . . . . . . . . . . . . . . . . . . . . . . . . 220
2.11.4 Generating coverage reports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
2.11.5 BabbleSim . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
2.11.6 ZTest Deprecated APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
2.12 Static Code Analysis (SCA) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
2.12.1 SCA Tool infrastructure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
2.12.2 Native SCA Tool support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232
2.13 Toolchains . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232
2.13.1 Zephyr SDK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232
2.13.2 Arm Compiler 6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236
2.13.3 Cadence Tensilica Xtensa C/C++ Compiler (XCC) . . . . . . . . . . . . . . . . . . 236
2.13.4 DesignWare ARC MetaWare Development Toolkit (MWDT) . . . . . . . . . . . . . 237
2.13.5 GNU Arm Embedded . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238
2.13.6 Intel oneAPI Toolkit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
2.13.7 Crosstool-NG (Deprecated) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239

ii
2.13.8 Host Toolchains . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
2.13.9 Other Cross Compilers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
2.13.10 Custom CMake Toolchains . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
2.14 Tools and IDEs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
2.14.1 Coccinelle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241

3 Kernel 251
3.1 Kernel Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
3.1.1 Scheduling, Interrupts, and Synchronization . . . . . . . . . . . . . . . . . . . . . 251
3.1.2 Data Passing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354
3.1.3 Memory Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396
3.1.4 Timing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396
3.1.5 Other . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412
3.2 Device Driver Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 431
3.2.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 431
3.2.2 Standard Drivers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 432
3.2.3 Synchronous Calls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 432
3.2.4 Driver APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 432
3.2.5 Driver Data Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433
3.2.6 Subsystems and API Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433
3.2.7 Device-Specific API Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 434
3.2.8 Single Driver, Multiple Instances . . . . . . . . . . . . . . . . . . . . . . . . . . . . 435
3.2.9 Initialization Levels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437
3.2.10 System Drivers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437
3.2.11 Error handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437
3.2.12 Memory Mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 438
3.2.13 API Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441
3.3 User Mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450
3.3.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450
3.3.2 Memory Protection Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 452
3.3.3 Kernel Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461
3.3.4 System Calls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466
3.3.5 MPU Stack Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 475
3.3.6 MPU Backed Userspace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 476
3.4 Memory Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 476
3.4.1 Memory Heaps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 476
3.4.2 Shared Multi Heap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 486
3.4.3 Memory Slabs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 490
3.4.4 Memory Blocks Allocator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 495
3.4.5 Demand Paging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 502
3.5 Data Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 508
3.5.1 Single-linked List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 508
3.5.2 Double-linked List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 519
3.5.3 Multi Producer Single Consumer Packet Buffer . . . . . . . . . . . . . . . . . . . . 527
3.5.4 Single Producer Single Consumer Packet Buffer . . . . . . . . . . . . . . . . . . . 528
3.5.5 Balanced Red/Black Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 529
3.5.6 Ring Buffers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 532
3.6 Executing Time Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 544
3.6.1 Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 544
3.6.2 Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 544
3.6.3 API documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 545
3.7 Time Utilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 546
3.7.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 546
3.7.2 Time Utility APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 547
3.7.3 Concepts Underlying Time Support in Zephyr . . . . . . . . . . . . . . . . . . . . 552
3.8 Utilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 553
3.9 Iterable Sections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 570
3.9.1 Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 570

iii
3.9.2 API Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 571
3.10 Code And Data Relocation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 575
3.10.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 575
3.10.2 Details . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 575

4 OS Services 579
4.1 Cryptography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 579
4.1.1 TinyCrypt Cryptographic Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . 579
4.1.2 Random Number Generation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 583
4.1.3 Crypto APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 585
4.2 Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 592
4.2.1 Thread analyzer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 592
4.2.2 Core Dump . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 594
4.2.3 GDB stub . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 600
4.2.4 Cortex-M Debug Monitor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 604
4.3 Device Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 605
4.3.1 MCUmgr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 605
4.3.2 MCUmgr Callbacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 618
4.3.3 Fixing and backporting fixes to Zephyr v2.7 MCUmgr . . . . . . . . . . . . . . . . 628
4.3.4 SMP Protocol Specification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 630
4.3.5 SMP Transport Specification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 653
4.3.6 Device Firmware Upgrade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 657
4.3.7 Over-the-Air Update . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 663
4.3.8 EC Host Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 664
4.3.9 SMP Groups . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 674
4.4 Digital Signal Processing (DSP) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 674
4.4.1 Using zDSP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 674
4.4.2 Optimizing for your architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . 675
4.4.3 API Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 675
4.5 File Systems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 675
4.5.1 Samples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 676
4.5.2 API Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 676
4.6 Formatted Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 688
4.6.1 Cbprintf Packaging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 689
4.6.2 API Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 691
4.7 Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 700
4.7.1 Input Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 700
4.7.2 Input Devices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 701
4.7.3 Application API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 701
4.7.4 Kscan Compatibility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 701
4.7.5 API Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 701
4.7.6 Input Event Definitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 704
4.8 Interprocessor Communication (IPC) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 708
4.8.1 IPC service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 708
4.9 Logging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 722
4.9.1 Global Kconfig Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 724
4.9.2 Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 725
4.9.3 Logging panic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 727
4.9.4 Printk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 727
4.9.5 Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 727
4.9.6 Recommendations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 733
4.9.7 Benchmark . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 733
4.9.8 Stack usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 734
4.9.9 API Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 734
4.10 Tracing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 752
4.10.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 752
4.10.2 Serialization Formats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 752
4.10.3 Transport Backends . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 754

iv
4.10.4 Using Tracing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 754
4.10.5 Visualisation Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 755
4.10.6 Future LTTng Inspiration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 755
4.10.7 Object tracking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 757
4.10.8 API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 757
4.11 Resource Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 787
4.11.1 On-Off Manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 787
4.12 Modbus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 796
4.12.1 Samples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 796
4.12.2 API Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 796
4.13 Asynchronous Notifications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 805
4.13.1 API Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 805
4.14 Power Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 808
4.14.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 808
4.14.2 System Power Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 809
4.14.3 Device Power Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 812
4.14.4 Device Runtime Power Management . . . . . . . . . . . . . . . . . . . . . . . . . 815
4.14.5 Power Domain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 820
4.14.6 Power Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 822
4.15 OS Abstraction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 843
4.15.1 POSIX Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 843
4.15.2 CMSIS RTOS v1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 850
4.15.3 CMSIS RTOS v2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 851
4.16 Shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 852
4.16.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 852
4.16.2 Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 853
4.16.3 Tab Feature . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 860
4.16.4 History Feature . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 860
4.16.5 Wildcards Feature . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 860
4.16.6 Meta Keys Feature . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 861
4.16.7 Getopt Feature . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 861
4.16.8 Obscured Input Feature . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 862
4.16.9 Shell Logger Backend Feature . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 862
4.16.10 RTT Backend Channel Selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . 863
4.16.11 Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 863
4.16.12 API Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 864
4.17 Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 883
4.17.1 Handlers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 884
4.17.2 Backends . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 884
4.17.3 Zephyr Storage Backends . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 884
4.17.4 Storage Location . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 885
4.17.5 Loading data from persisted storage . . . . . . . . . . . . . . . . . . . . . . . . . . 885
4.17.6 Storing data to persistent storage . . . . . . . . . . . . . . . . . . . . . . . . . . . 885
4.17.7 Secure domain settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 885
4.17.8 Example: Device Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . 886
4.17.9 Example: Persist Runtime State . . . . . . . . . . . . . . . . . . . . . . . . . . . . 886
4.17.10 Example: Custom Backend Implementation . . . . . . . . . . . . . . . . . . . . . 888
4.17.11 API Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 888
4.18 State Machine Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 897
4.18.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 897
4.18.2 State Creation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 897
4.18.3 State Machine Creation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 898
4.18.4 State Machine Execution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 898
4.18.5 State Machine Termination . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 898
4.18.6 Flat State Machine Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 898
4.18.7 Hierarchical State Machine Example . . . . . . . . . . . . . . . . . . . . . . . . . 900
4.18.8 Event Driven State Machine Example . . . . . . . . . . . . . . . . . . . . . . . . . 903
4.19 Storage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 905

v
4.19.1 Non-Volatile Storage (NVS) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 905
4.19.2 Disk Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 910
4.19.3 Flash map . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 915
4.19.4 Flash Circular Buffer (FCB) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 921
4.19.5 Stream Flash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 927
4.20 Task Watchdog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 930
4.20.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 930
4.20.2 Configuration Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 930
4.20.3 API Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 930
4.21 Trusted Firmware-M . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 932
4.21.1 Trusted Firmware-M Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 932
4.21.2 TF-M Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 936
4.21.3 TF-M Build System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 937
4.21.4 Trusted Firmware-M Integration . . . . . . . . . . . . . . . . . . . . . . . . . . . . 940
4.21.5 Test Suites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 941
4.22 Virtualization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 941
4.22.1 Inter-VM Shared Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 941
4.23 Retention System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 944
4.23.1 Devicetree setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 944
4.23.2 Boot mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 946
4.23.3 API Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 947
4.24 Real Time I/O (RTIO) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 949
4.24.1 Problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 951
4.24.2 Inspiration, introducing io_uring . . . . . . . . . . . . . . . . . . . . . . . . . . . 951
4.24.3 Submission Queue and Chaining . . . . . . . . . . . . . . . . . . . . . . . . . . . 951
4.24.4 Completion Queue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 952
4.24.5 Executor and IODev . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 952
4.24.6 Memory pools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 952
4.24.7 Outstanding Questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 953
4.24.8 When to Use . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 954
4.24.9 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 954
4.24.10 API Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 958
4.25 Zephyr message bus (zbus) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 970
4.25.1 Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 971
4.25.2 Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 976
4.25.3 Samples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 981
4.25.4 Suggested Uses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 982
4.25.5 Configuration Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 982
4.25.6 API Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 982
4.26 Miscellaneous . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 990
4.26.1 Checksum APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 990
4.26.2 Structured Data APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 995

5 Build and Configuration Systems 1007


5.1 Build System (CMake) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1007
5.1.1 Build and Configuration Phases . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1007
5.1.2 Supporting Scripts and Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1013
5.2 Devicetree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1017
5.2.1 Devicetree Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1017
5.2.2 Devicetree Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1077
5.3 Configuration System (Kconfig) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1246
5.3.1 Interactive Kconfig interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1246
5.3.2 Setting Kconfig configuration values . . . . . . . . . . . . . . . . . . . . . . . . . 1251
5.3.3 Kconfig - Tips and Best Practices . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1255
5.3.4 Custom Kconfig Preprocessor Functions . . . . . . . . . . . . . . . . . . . . . . . . 1270
5.3.5 Kconfig extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1271
5.4 Snippets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1272
5.4.1 Using Snippets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1273

vi
5.4.2 Built-in snippets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1273
5.4.3 Writing Snippets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1274
5.4.4 Snippets Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1277
5.5 Zephyr CMake Package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1277
5.5.1 Zephyr CMake package export (west) . . . . . . . . . . . . . . . . . . . . . . . . . 1278
5.5.2 Zephyr CMake package export (without west) . . . . . . . . . . . . . . . . . . . . 1278
5.5.3 Zephyr Base Environment Setting . . . . . . . . . . . . . . . . . . . . . . . . . . . 1278
5.5.4 Zephyr CMake Package Search Order . . . . . . . . . . . . . . . . . . . . . . . . . 1278
5.5.5 Zephyr CMake Package Version . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1279
5.5.6 Multiple Zephyr Installations (Zephyr workspace) . . . . . . . . . . . . . . . . . . 1280
5.5.7 Zephyr Build Configuration CMake package . . . . . . . . . . . . . . . . . . . . . 1281
5.5.8 Zephyr Build Configuration CMake package (Freestanding application) . . . . . . 1282
5.5.9 Zephyr CMake package source code . . . . . . . . . . . . . . . . . . . . . . . . . . 1283
5.6 Sysbuild (System build) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1283
5.6.1 Definitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1284
5.6.2 Architectural Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1284
5.6.3 Building with sysbuild . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1285
5.6.4 Configuration namespacing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1285
5.6.5 Sysbuild flashing using west flash . . . . . . . . . . . . . . . . . . . . . . . . . . 1287
5.6.6 Sysbuild debugging using west debug . . . . . . . . . . . . . . . . . . . . . . . . 1287
5.6.7 Building a sample with MCUboot . . . . . . . . . . . . . . . . . . . . . . . . . . . 1287
5.6.8 Sysbuild Kconfig file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1288
5.6.9 Sysbuild targets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1288
5.6.10 Dedicated image build targets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1289
5.6.11 Adding Zephyr applications to sysbuild . . . . . . . . . . . . . . . . . . . . . . . . 1289
5.6.12 Adding non-Zephyr applications to sysbuild . . . . . . . . . . . . . . . . . . . . . 1291
5.6.13 Extending sysbuild . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1292

6 Connectivity 1293
6.1 Bluetooth . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1293
6.1.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1293
6.1.2 Bluetooth Stack Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1295
6.1.3 Bluetooth Low Energy Controller . . . . . . . . . . . . . . . . . . . . . . . . . . . 1301
6.1.4 Bluetooth Audio Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1315
6.1.5 Bluetooth Qualification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1319
6.1.6 Bluetooth tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1339
6.1.7 Developing Bluetooth Applications . . . . . . . . . . . . . . . . . . . . . . . . . . 1342
6.1.8 AutoPTS on Windows 10 with nRF52 board . . . . . . . . . . . . . . . . . . . . . 1345
6.1.9 AutoPTS on Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1354
6.1.10 Bluetooth APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1365
6.1.11 Bluetooth Shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1960
6.2 Networking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1966
6.2.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1966
6.2.2 Network Stack Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1968
6.2.3 Network Connectivity API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1974
6.2.4 Networking with the host system . . . . . . . . . . . . . . . . . . . . . . . . . . . 1974
6.2.5 Monitor Network Traffic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1987
6.2.6 Networking APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1991
6.3 LoRa and LoRaWAN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2292
6.3.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2292
6.3.2 Configuration Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2293
6.3.3 API Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2293
6.4 USB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2303
6.4.1 USB device support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2303
6.4.2 USB device support APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2312
6.4.3 New experimental USB device support . . . . . . . . . . . . . . . . . . . . . . . . 2327
6.4.4 New USB device support APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2327
6.4.5 USB host support APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2345

vii
6.4.6 USB-C device stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2353
6.4.7 Human Interface Devices (HID) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2373

7 Hardware Support 2387


7.1 Architecture-related Guides . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2387
7.1.1 Zephyr support status on ARC processors . . . . . . . . . . . . . . . . . . . . . . . 2387
7.1.2 Arm Cortex-M Developer Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2388
7.1.3 Zephyr support status on RISC-V processors . . . . . . . . . . . . . . . . . . . . . 2398
7.1.4 Semihosting Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2398
7.1.5 Additional Functionality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2399
7.1.6 x86 Developer Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2403
7.2 Barriers API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2405
7.3 Cache Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2405
7.3.1 Cache API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2406
7.4 Peripheral and Hardware Emulators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2410
7.4.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2410
7.4.2 Concept . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2410
7.4.3 Creating a Device Driver Emulator . . . . . . . . . . . . . . . . . . . . . . . . . . 2412
7.4.4 Available Emulators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2412
7.4.5 Samples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2414
7.5 Peripherals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2417
7.5.1 1-Wire Bus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2417
7.5.2 Analog-to-Digital Converter (ADC) . . . . . . . . . . . . . . . . . . . . . . . . . . 2427
7.5.3 Auxiliary Display (auxdisplay) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2439
7.5.4 Audio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2447
7.5.5 Battery Backed RAM (BBRAM) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2469
7.5.6 BC1.2 Devices (Experimental) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2472
7.5.7 Clock Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2477
7.5.8 Controller Area Network (CAN) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2480
7.5.9 Coredump Device . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2508
7.5.10 Counter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2510
7.5.11 Digital-to-Analog Converter (DAC) . . . . . . . . . . . . . . . . . . . . . . . . . . 2517
7.5.12 Direct Memory Access (DMA) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2518
7.5.13 Display Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2526
7.5.14 Electrically Erasable Programmable Read-Only Memory (EEPROM) . . . . . . . . 2540
7.5.15 Enhanced Serial Peripheral Interface (eSPI) Bus . . . . . . . . . . . . . . . . . . . 2541
7.5.16 Entropy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2559
7.5.17 Error Detection And Correction (EDAC) . . . . . . . . . . . . . . . . . . . . . . . . 2560
7.5.18 Flash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2565
7.5.19 Fuel Gauge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2571
7.5.20 Gaussian & Neural Accelerator (GNA) . . . . . . . . . . . . . . . . . . . . . . . . . 2578
7.5.21 General-Purpose Input/Output (GPIO) . . . . . . . . . . . . . . . . . . . . . . . . 2580
7.5.22 Hardware Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2598
7.5.23 I2C EEPROM Target . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2600
7.5.24 Improved Inter-Integrated Circuit (I3C) Bus . . . . . . . . . . . . . . . . . . . . . 2601
7.5.25 Inter-Integrated Circuit (I2C) Bus . . . . . . . . . . . . . . . . . . . . . . . . . . . 2654
7.5.26 Inter-Processor Mailbox (IPM) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2670
7.5.27 Keyboard Scan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2673
7.5.28 Light-Emitting Diode (LED) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2674
7.5.29 Management Data Input/Output (MDIO) . . . . . . . . . . . . . . . . . . . . . . . 2680
7.5.30 MIPI Display Serial Interface (DSI) . . . . . . . . . . . . . . . . . . . . . . . . . . 2681
7.5.31 Multi-Channel Inter-Processor Mailbox (MBOX) . . . . . . . . . . . . . . . . . . . 2690
7.5.32 Platform Environment Control Interface (PECI) . . . . . . . . . . . . . . . . . . . 2695
7.5.33 PS/2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2702
7.5.34 Pulse Width Modulation (PWM) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2703
7.5.35 Real-Time Clock (RTC) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2717
7.5.36 Regulators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2724
7.5.37 Reset Controller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2729

viii
7.5.38 Retained Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2733
7.5.39 Secure Digital High Capacity (SDHC) . . . . . . . . . . . . . . . . . . . . . . . . . 2734
7.5.40 Sensors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2742
7.5.41 Serial Peripheral Interface (SPI) Bus . . . . . . . . . . . . . . . . . . . . . . . . . 2764
7.5.42 System Management Bus (SMBus) . . . . . . . . . . . . . . . . . . . . . . . . . . 2776
7.5.43 Universal Asynchronous Receiver-Transmitter (UART) . . . . . . . . . . . . . . . . 2787
7.5.44 USB-C VBUS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2805
7.5.45 USB Type-C Port Controller (TCPC) . . . . . . . . . . . . . . . . . . . . . . . . . . 2806
7.5.46 Video . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2841
7.5.47 Watchdog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2849
7.6 Pin Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2852
7.6.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2852
7.6.2 State model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2854
7.6.3 Dynamic pin control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2855
7.6.4 Devicetree representation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2856
7.6.5 Implementation guidelines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2858
7.6.6 Pin Control API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2860
7.6.7 Other reference material . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2865
7.7 Porting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2865
7.7.1 Architecture Porting Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2865
7.7.2 Board Porting Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2900
7.7.3 Shields . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2910

8 Contributing to Zephyr 2913


8.1 Contribution Guidelines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2913
8.1.1 Licensing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2913
8.1.2 Copyrights Notices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2914
8.1.3 Developer Certification of Origin (DCO) . . . . . . . . . . . . . . . . . . . . . . . 2914
8.1.4 Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2915
8.1.5 Source Tree Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2916
8.1.6 Pull Requests and Issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2917
8.1.7 Tools and Git Setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2917
8.1.8 Coding Style . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2918
8.1.9 Static Code Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2919
8.1.10 Contribution Workflow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2920
8.1.11 Commit Message Guidelines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2922
8.1.12 Continuous Integration (CI) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2925
8.1.13 Contributions to External Modules . . . . . . . . . . . . . . . . . . . . . . . . . . 2926
8.1.14 Treewide Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2926
8.2 Contributor Expectations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2927
8.2.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2927
8.2.2 PR Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2928
8.3 Reviewer Expectations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2929
8.4 Proposals and RFCs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2930
8.5 Coding Guidelines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2931
8.5.1 Main rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2931
8.5.2 Additional rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2940
8.5.3 Parasoft Codescan Tool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2945
8.6 Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2947
8.6.1 Documentation Guidelines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2947
8.6.2 Documentation Generation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2957
8.7 Contributing External Components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2961
8.7.1 Software License . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2961
8.7.2 Merit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2961
8.7.3 Mode of integration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2961
8.7.4 Ongoing maintenance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2962
8.7.5 Submission and review process . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2962
8.8 Contributing External Tooling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2963

ix
8.9 Additional considerations about the main manifest . . . . . . . . . . . . . . . . . . . . . . 2964
8.10 Binary Blobs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2964
8.10.1 Software license . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2964
8.10.2 Hosting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2964
8.10.3 Fetching blobs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2964
8.10.4 Tainting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2965
8.10.5 Allowed types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2965
8.10.6 Precompiled library-specific requirements . . . . . . . . . . . . . . . . . . . . . . 2966
8.10.7 Support and maintenance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2967
8.10.8 Submission and review process . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2967

9 Project and Governance 2969


9.1 TSC Project Roles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2969
9.1.1 Main Roles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2969
9.1.2 Role Retirement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2971
9.1.3 Teams and Supporting Activities . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2971
9.1.4 MAINTAINERS File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2972
9.1.5 Release Activity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2973
9.2 Release Process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2974
9.2.1 Development Phase . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2975
9.2.2 Stabilization Phase . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2975
9.2.3 Release Quality Criteria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2976
9.2.4 Release Milestones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2976
9.2.5 Releases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2976
9.2.6 Release Procedure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2979
9.3 Feature Tracking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2981
9.3.1 Roadmap and Release Plans . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2982
9.4 Code Flow and Branches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2982
9.4.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2982
9.4.2 Roles and Responsibilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2983
9.5 Modifying Contributions made by other developers . . . . . . . . . . . . . . . . . . . . . . 2983
9.5.1 Scenarios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2983
9.5.2 Accepted policies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2984
9.6 Development Environment and Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2984
9.6.1 Code Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2984
9.6.2 Continuous Integration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2987
9.6.3 Labeling issues and pull requests in GitHub . . . . . . . . . . . . . . . . . . . . . . 2988
9.7 Bug Reporting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2990
9.7.1 Reporting a regression issue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2990
9.8 Communication and Collaboration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2991
9.9 Code Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2991
9.9.1 API Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2991
9.9.2 Reference to Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2991
9.9.3 Test Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2991
9.9.4 Documentation Guidelines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2991
9.10 Terminology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2993

10 Security 2995
10.1 Zephyr Security Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2995
10.1.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2995
10.1.2 Current Security Definition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2996
10.1.3 Secure Development Process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2998
10.1.4 Secure Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3002
10.1.5 Security Certification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3004
10.2 Security Vulnerability Reporting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3005
10.2.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3005
10.2.2 Security Issue Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3005
10.2.3 Vulnerability Notification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3007

x
10.2.4 Backporting of Security Vulnerabilities . . . . . . . . . . . . . . . . . . . . . . . . 3008
10.2.5 Need to Know . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3008
10.3 Secure Coding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3008
10.3.1 Introduction and Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3008
10.3.2 Secure Coding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3009
10.3.3 Secure development knowledge . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3010
10.3.4 Code Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3011
10.3.5 Issues and Bug Tracking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3011
10.3.6 Modifications to This Document . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3011
10.4 Sensor Device Threat Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3011
10.4.1 Assets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3012
10.4.2 Communication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3013
10.4.3 Other Considerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3016
10.4.4 Threats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3016
10.4.5 Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3016
10.5 Hardening Tool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3016
10.5.1 Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3016
10.6 Vulnerabilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3017
10.6.1 CVE-2017 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3017
10.6.2 CVE-2019 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3018
10.6.3 CVE-2020 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3018
10.6.4 CVE-2021 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3026

Bibliography 3033

Python Module Index 3035

Index 3037

xi
xii
Chapter 1

Introduction

The Zephyr OS is based on a small-footprint kernel designed for use on resource-constrained and em-
bedded systems: from simple embedded environmental sensors and LED wearables to sophisticated
embedded controllers, smart watches, and IoT wireless applications.
The Zephyr kernel supports multiple architectures, including:
• ARCv2 (EM and HS) and ARCv3 (HS6X)
• ARMv6-M, ARMv7-M, and ARMv8-M (Cortex-M)
• ARMv7-A and ARMv8-A (Cortex-A, 32- and 64-bit)
• ARMv7-R, ARMv8-R (Cortex-R, 32- and 64-bit)
• Intel x86 (32- and 64-bit)
• MIPS (MIPS32 Release 1 specification)
• NIOS II Gen 2
• RISC-V (32- and 64-bit)
• SPARC V8
• Tensilica Xtensa
The full list of supported boards based on these architectures can be found here.

1.1 Licensing

Zephyr is permissively licensed using the Apache 2.0 license (as found in the LICENSE file in the project’s
GitHub repo). There are some imported or reused components of the Zephyr project that use other
licensing, as described in Licensing of Zephyr Project components.

1.2 Distinguishing Features

Zephyr offers a large and ever growing number of features including:


Extensive suite of Kernel services
Zephyr offers a number of familiar services for development:
• Multi-threading Services for cooperative, priority-based, non-preemptive, and preemptive
threads with optional round robin time-slicing. Includes POSIX pthreads compatible API sup-
port.
• Interrupt Services for compile-time registration of interrupt handlers.

1
Zephyr Project Documentation, Release 3.4.0

• Memory Allocation Services for dynamic allocation and freeing of fixed-size or variable-size
memory blocks.
• Inter-thread Synchronization Services for binary semaphores, counting semaphores, and mutex
semaphores.
• Inter-thread Data Passing Services for basic message queues, enhanced message queues, and
byte streams.
• Power Management Services such as overarching, application or policy-defined, System Power
Management and fine-grained, driver-defined, Device Power Management.
Multiple Scheduling Algorithms
Zephyr provides a comprehensive set of thread scheduling choices:
• Cooperative and Preemptive Scheduling
• Earliest Deadline First (EDF)
• Meta IRQ scheduling implementing “interrupt bottom half” or “tasklet” behavior
• Timeslicing: Enables time slicing between preemptible threads of equal priority
• Multiple queuing strategies:
– Simple linked-list ready queue
– Red/black tree ready queue
– Traditional multi-queue ready queue
Highly configurable / Modular for flexibility
Allows an application to incorporate only the capabilities it needs as it needs them, and to specify
their quantity and size.
Cross Architecture
Supports a wide variety of supported boards with different CPU architectures and developer tools.
Contributions have added support for an increasing number of SoCs, platforms, and drivers.
Memory Protection
Implements configurable architecture-specific stack-overflow protection, kernel object and device
driver permission tracking, and thread isolation with thread-level memory protection on x86, ARC,
and ARM architectures, userspace, and memory domains.
For platforms without MMU/MPU and memory constrained devices, supports combining
application-specific code with a custom kernel to create a monolithic image that gets loaded and
executed on a system’s hardware. Both the application code and kernel code execute in a single
shared address space.
Compile-time resource definition
Allows system resources to be defined at compile-time, which reduces code size and increases
performance for resource-limited systems.
Optimized Device Driver Model
Provides a consistent device model for configuring the drivers that are part of the platform/system
and a consistent model for initializing all the drivers configured into the system and Allows the
reuse of drivers across platforms that have common devices/IP blocks
Devicetree Support
Use of devicetree to describe hardware. Information from devicetree is used to create the application
image.
Native Networking Stack supporting multiple protocols
Networking support is fully featured and optimized, including LwM2M and BSD sockets compatible
support. OpenThread support (on Nordic chipsets) is also provided - a mesh network designed to
securely and reliably connect hundreds of products around the home.

2 Chapter 1. Introduction
Zephyr Project Documentation, Release 3.4.0

Bluetooth Low Energy 5.0 support


Bluetooth 5.0 compliant (ESR10) and Bluetooth Low Energy Controller support (LE Link Layer).
Includes Bluetooth mesh and a Bluetooth qualification-ready Bluetooth controller.
• Generic Access Profile (GAP) with all possible LE roles.
• GATT (Generic Attribute Profile)
• Pairing support, including the Secure Connections feature from Bluetooth 4.2
• Clean HCI driver abstraction
• Raw HCI interface to run Zephyr as a Controller instead of a full Host stack
• Verified with multiple popular controllers
• Highly configurable
Mesh Support:
• Relay, Friend Node, Low-Power Node (LPN) and GATT Proxy features
• Both Provisioning bearers supported (PB-ADV & PB-GATT)
• Highly configurable, fitting in devices with at least 16k RAM
Native Linux, macOS, and Windows Development
A command-line CMake build environment runs on popular developer OS systems. A native POSIX
port, lets you build and run Zephyr as a native application on Linux and other OSes, aiding devel-
opment and testing.
Virtual File System Interface with LittleFS and FATFS Support
LittleFS and FATFS Support, FCB (Flash Circular Buffer) for memory constrained applications, and
file system enhancements for logging and configuration.
Powerful multi-backend logging Framework
Support for log filtering, object dumping, panic mode, multiple backends (memory, networking,
filesystem, console, ..) and integration with the shell subsystem.
User friendly and full-featured Shell interface
A multi-instance shell subsystem with user-friendly features such as autocompletion, wildcards,
coloring, metakeys (arrows, backspace, ctrl+u, etc.) and history. Support for static commands and
dynamic sub-commands.
Settings on non-volatile storage
The settings subsystem gives modules a way to store persistent per-device configuration and run-
time state. Settings items are stored as key-value pair strings.
Non-volatile storage (NVS)
NVS allows storage of binary blobs, strings, integers, longs, and any combination of these.
Native POSIX port
Supports running Zephyr as a Linux application with support for various subsystems and network-
ing.

1.3 Community Support

Community support is provided via mailing lists and Discord; see the Resources below for details.

1.4 Resources

Here’s a quick summary of resources to help you find your way around:
• Help: Asking for Help Tips

1.3. Community Support 3


Zephyr Project Documentation, Release 3.4.0

• Documentation: http://docs.zephyrproject.org (Getting Started Guide)


• Source Code: https://github.com/zephyrproject-rtos/zephyr is the main repository; https://elixir.
bootlin.com/zephyr/latest/source contains a searchable index
• Releases: https://github.com/zephyrproject-rtos/zephyr/releases
• Samples and example code: see Sample and Demo Code Examples
• Mailing Lists: [email protected] and [email protected] are the main user
and developer mailing lists, respectively. You can join the developer’s list and search its archives at
Zephyr Development mailing list. The other Zephyr mailing list subgroups have their own archives
and sign-up pages.
• Nightly CI Build Status: https://lists.zephyrproject.org/g/builds The
[email protected] mailing list archives the CI nightly build results.
• Chat: Real-time chat happens in Zephyr’s Discord Server. Use this Discord Invite to register.
• Contributing: see the Contribution Guide
• Wiki: Zephyr GitHub wiki
• Issues: https://github.com/zephyrproject-rtos/zephyr/issues
• Security Issues: Email [email protected] to report security issues; also see our Se-
curity documentation. Security issues are tracked separately at https://zephyrprojectsec.atlassian.
net.
• Zephyr Project Website: https://zephyrproject.org

1.5 Fundamental Terms and Concepts

See glossary

4 Chapter 1. Introduction
Chapter 2

Developing with Zephyr

2.1 Getting Started Guide

Follow this guide to:


• Set up a command-line Zephyr development environment on Ubuntu, macOS, or Windows (in-
structions for other Linux distributions are discussed in Install Linux Host Dependencies)
• Get the source code
• Build, flash, and run a sample application

2.1.1 Select and Update OS

Click the operating system you are using.


Ubuntu
This guide covers Ubuntu version 18.04 LTS and later.

sudo apt update


sudo apt upgrade

macOS
On macOS Mojave or later, select System Preferences > Software Update. Click Update Now if necessary.
On other versions, see this Apple support topic.
Windows
Select Start > Settings > Update & Security > Windows Update. Click Check for updates and install any
that are available.

2.1.2 Install dependencies

Next, you’ll install some host dependencies using your package manager.
The current minimum required version for the main dependencies are:

Tool Min. Version


CMake 3.20.5
Python 3.8
Devicetree compiler 1.4.6

5
Zephyr Project Documentation, Release 3.4.0

Ubuntu
1. If using an Ubuntu version older than 22.04, it is necessary to add extra repositories to meet the
minimum required versions for the main dependencies listed above. In that case, download, inspect
and execute the Kitware archive script to add the Kitware APT repository to your sources list. A
detailed explanation of kitware-archive.sh can be found here kitware third-party apt repository:

wget https://apt.kitware.com/kitware-archive.sh
sudo bash kitware-archive.sh

2. Use apt to install the required dependencies:

sudo apt install --no-install-recommends git cmake ninja-build gperf \


ccache dfu-util device-tree-compiler wget \
python3-dev python3-pip python3-setuptools python3-tk python3-wheel xz-utils␣
˓→file \

make gcc gcc-multilib g++-multilib libsdl2-dev libmagic1

3. Verify the versions of the main dependencies installed on your system by entering:

cmake --version
python3 --version
dtc --version

Check those against the versions in the table in the beginning of this section. Refer to the Install
Linux Host Dependencies page for additional information on updating the dependencies manually.
macOS
1. Install Homebrew:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/


˓→HEAD/install.sh)"

2. Use brew to install the required dependencies:

brew install cmake ninja gperf python3 ccache qemu dtc wget libmagic

Windows

Note: Due to issues finding executables, the Zephyr Project doesn’t currently support application flash-
ing using the Windows Subsystem for Linux (WSL) (WSL).
Therefore, we don’t recommend using WSL when getting started.

These instructions must be run in a cmd.exe command prompt. The required commands differ on
PowerShell.
These instructions rely on Chocolatey. If Chocolatey isn’t an option, you can install dependencies from
their respective websites and ensure the command line tools are on your PATH environment variable.

1. Install chocolatey.
2. Open a cmd.exe window as Administrator. To do so, press the Windows key, type “cmd.exe”,
right-click the result, and choose Run as Administrator.
3. Disable global confirmation to avoid having to confirm the installation of individual programs:

choco feature enable -n allowGlobalConfirmation

4. Use choco to install the required dependencies:

6 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

choco install cmake --installargs 'ADD_CMAKE_TO_PATH=System'


choco install ninja gperf python git dtc-msys2 wget 7zip

5. Close the window and open a new cmd.exe window as a regular user to continue.

2.1.3 Get Zephyr and install Python dependencies

Next, clone Zephyr and its modules into a new west workspace named zephyrproject. You’ll also install
Zephyr’s additional Python dependencies.

Note: It is easy to run into Python package incompatibilities when installing dependencies at a system
or user level. This situation can happen, for example, if working on multiple Zephyr versions or other
projects using Python on the same machine.
For this reason it is suggested to use Python virtual environments.

Ubuntu
Install within virtual environment
1. Use apt to install Python venv package:

sudo apt install python3-venv

2. Create a new virtual environment:

python3 -m venv ~/zephyrproject/.venv

3. Activate the virtual environment:

source ~/zephyrproject/.venv/bin/activate

Once activated your shell will be prefixed with (.venv). The virtual environment can be deacti-
vated at any time by running deactivate.

Note: Remember to activate the virtual environment every time you start working.

4. Install west:

pip install west

5. Get the Zephyr source code:

west init ~/zephyrproject


cd ~/zephyrproject
west update

6. Export a Zephyr CMake package. This allows CMake to automatically load boilerplate code required
for building Zephyr applications.

west zephyr-export

7. Zephyr’s scripts/requirements.txt file declares additional Python dependencies. Install them


with pip.

pip install -r ~/zephyrproject/zephyr/scripts/requirements.txt

Install globally

2.1. Getting Started Guide 7


Zephyr Project Documentation, Release 3.4.0

1. Install west, and make sure ~/.local/bin is on your PATH environment variable:

pip3 install --user -U west


echo 'export PATH=~/.local/bin:"$PATH"' >> ~/.bashrc
source ~/.bashrc

2. Get the Zephyr source code:

west init ~/zephyrproject


cd ~/zephyrproject
west update

3. Export a Zephyr CMake package. This allows CMake to automatically load boilerplate code required
for building Zephyr applications.

west zephyr-export

4. Zephyr’s scripts/requirements.txt file declares additional Python dependencies. Install them


with pip3.

pip3 install --user -r ~/zephyrproject/zephyr/scripts/requirements.txt

macOS
Install within virtual environment
1. Create a new virtual environment:

python3 -m venv ~/zephyrproject/.venv

2. Activate the virtual environment:

source ~/zephyrproject/.venv/bin/activate

Once activated your shell will be prefixed with (.venv). The virtual environment can be deacti-
vated at any time by running deactivate.

Note: Remember to activate the virtual environment every time you start working.

3. Install west:

pip install west

4. Get the Zephyr source code:

west init ~/zephyrproject


cd ~/zephyrproject
west update

5. Export a Zephyr CMake package. This allows CMake to automatically load boilerplate code required
for building Zephyr applications.

west zephyr-export

6. Zephyr’s scripts/requirements.txt file declares additional Python dependencies. Install them


with pip.

pip install -r ~/zephyrproject/zephyr/scripts/requirements.txt

Install globally

8 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

1. Install west:

pip3 install -U west

2. Get the Zephyr source code:

west init ~/zephyrproject


cd ~/zephyrproject
west update

3. Export a Zephyr CMake package. This allows CMake to automatically load boilerplate code required
for building Zephyr applications.

west zephyr-export

4. Zephyr’s scripts/requirements.txt file declares additional Python dependencies. Install them


with pip3.

pip3 install -r ~/zephyrproject/zephyr/scripts/requirements.txt

Windows
Install within virtual environment
1. Create a new virtual environment:

cd %HOMEPATH%
python -m venv zephyrproject\.venv

2. Activate the virtual environment:

:: cmd.exe
zephyrproject\.venv\Scripts\activate.bat
:: PowerShell
zephyrproject\.venv\Scripts\Activate.ps1

Once activated your shell will be prefixed with (.venv). The virtual environment can be deacti-
vated at any time by running deactivate.

Note: Remember to activate the virtual environment every time you start working.

3. Install west:

pip install west

4. Get the Zephyr source code:

west init zephyrproject


cd zephyrproject
west update

5. Export a Zephyr CMake package. This allows CMake to automatically load boilerplate code required
for building Zephyr applications.

west zephyr-export

6. Zephyr’s scripts\requirements.txt file declares additional Python dependencies. Install them


with pip.

pip install -r %HOMEPATH%\zephyrproject\zephyr\scripts\requirements.txt

2.1. Getting Started Guide 9


Zephyr Project Documentation, Release 3.4.0

Install globally
1. Install west:

pip3 install -U west

2. Get the Zephyr source code:

cd %HOMEPATH%
west init zephyrproject
cd zephyrproject
west update

3. Export a Zephyr CMake package. This allows CMake to automatically load boilerplate code required
for building Zephyr applications.

west zephyr-export

4. Zephyr’s scripts\requirements.txt file declares additional Python dependencies. Install them


with pip3.

pip3 install -r %HOMEPATH%\zephyrproject\zephyr\scripts\requirements.txt

2.1.4 Install Zephyr SDK

The Zephyr Software Development Kit (SDK) contains toolchains for each of Zephyr’s supported architec-
tures, which include a compiler, assembler, linker and other programs required to build Zephyr applica-
tions.
It also contains additional host tools, such as custom QEMU and OpenOCD builds that are used to
emulate, flash and debug Zephyr applications.
Ubuntu
1. Download and verify the Zephyr SDK bundle:

cd ~
wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.1/
˓→zephyr-sdk-0.16.1_linux-x86_64.tar.xz

wget -O - https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.1/
˓→sha256.sum | shasum --check --ignore-missing

If your host architecture is 64-bit ARM (for example, Raspberry Pi), replace x86_64 with aarch64
in order to download the 64-bit ARM Linux SDK.
2. Extract the Zephyr SDK bundle archive:

tar xvf zephyr-sdk-0.16.1_linux-x86_64.tar.xz

Note: It is recommended to extract the Zephyr SDK bundle at one of the following locations:
• $HOME
• $HOME/.local
• $HOME/.local/opt
• $HOME/bin
• /opt
• /usr/local

10 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

The Zephyr SDK bundle archive contains the zephyr-sdk-0.16.1 directory and, when extracted
under $HOME, the resulting installation path will be $HOME/zephyr-sdk-0.16.1.

3. Run the Zephyr SDK bundle setup script:

cd zephyr-sdk-0.16.1
./setup.sh

Note: You only need to run the setup script once after extracting the Zephyr SDK bundle.
You must rerun the setup script if you relocate the Zephyr SDK bundle directory after the initial
setup.

4. Install udev rules, which allow you to flash most Zephyr boards as a regular user:

sudo cp ~/zephyr-sdk-0.16.1/sysroots/x86_64-pokysdk-linux/usr/share/openocd/
˓→contrib/60-openocd.rules /etc/udev/rules.d

sudo udevadm control --reload

macOS
1. Download and verify the Zephyr SDK bundle:

cd ~
wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.1/
˓→zephyr-sdk-0.16.1_macos-x86_64.tar.xz

wget -O - https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.1/
˓→sha256.sum | shasum --check --ignore-missing

If your host architecture is 64-bit ARM (Apple Silicon, also known as M1), replace x86_64 with
aarch64 in order to download the 64-bit ARM macOS SDK.
2. Extract the Zephyr SDK bundle archive:

tar xvf zephyr-sdk-0.16.1_macos-x86_64.tar.xz

Note: It is recommended to extract the Zephyr SDK bundle at one of the following locations:
• $HOME
• $HOME/.local
• $HOME/.local/opt
• $HOME/bin
• /opt
• /usr/local
The Zephyr SDK bundle archive contains the zephyr-sdk-0.16.1 directory and, when extracted
under $HOME, the resulting installation path will be $HOME/zephyr-sdk-0.16.1.

3. Run the Zephyr SDK bundle setup script:

cd zephyr-sdk-0.16.1
./setup.sh

Note: You only need to run the setup script once after extracting the Zephyr SDK bundle.

2.1. Getting Started Guide 11


Zephyr Project Documentation, Release 3.4.0

You must rerun the setup script if you relocate the Zephyr SDK bundle directory after the initial
setup.

Windows
1. Open a cmd.exe window by pressing the Windows key typing “cmd.exe”.
2. Download the Zephyr SDK bundle:

cd %HOMEPATH%
wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.1/
˓→zephyr-sdk-0.16.1_windows-x86_64.7z

3. Extract the Zephyr SDK bundle archive:

7z x zephyr-sdk-0.16.1_windows-x86_64.7z

Note: It is recommended to extract the Zephyr SDK bundle at one of the following locations:
• %HOMEPATH%
• %PROGRAMFILES%
The Zephyr SDK bundle archive contains the zephyr-sdk-0.16.1 directory and, when extracted
under %HOMEPATH%, the resulting installation path will be %HOMEPATH%\zephyr-sdk-0.16.1.

4. Run the Zephyr SDK bundle setup script:

cd zephyr-sdk-0.16.1
setup.cmd

Note: You only need to run the setup script once after extracting the Zephyr SDK bundle.
You must rerun the setup script if you relocate the Zephyr SDK bundle directory after the initial
setup.

2.1.5 Build the Blinky Sample

Note: Blinky is compatible with most, but not all, boards. If your board does not meet Blinky’s blinky-
sample-requirements, then hello_world is a good alternative.
If you are unsure what name west uses for your board, west boards can be used to obtain a list of all
boards Zephyr supports.

Build the blinky-sample with west build, changing <your-board-name> appropriately for your board:
Ubuntu

cd ~/zephyrproject/zephyr
west build -p always -b <your-board-name> samples/basic/blinky

macOS

cd ~/zephyrproject/zephyr
west build -p always -b <your-board-name> samples/basic/blinky

Windows

12 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

cd %HOMEPATH%\zephyrproject\zephyr
west build -p always -b <your-board-name> samples\basic\blinky

The -p always option forces a pristine build, and is recommended for new users. Users may also use
the -p auto option, which will use heuristics to determine if a pristine build is required, such as when
building another sample.

2.1.6 Flash the Sample

Connect your board, usually via USB, and turn it on if there’s a power switch. If in doubt about what to
do, check your board’s page in boards.
Then flash the sample using west flash:

west flash

You may need to install additional host tools required by your board. The west flash command will
print an error if any required dependencies are missing.
If you’re using blinky, the LED will start to blink as shown in this figure:

Fig. 1: Phytec reel_board running blinky

2.1.7 Next Steps

Here are some next steps for exploring Zephyr:


• Try other samples-and-demos
• Learn about Application Development and the west tool
• Find out about west’s flashing and debugging features, or more about Flashing and Hardware De-
bugging in general
• Check out Beyond the Getting Started Guide for additional setup alternatives and ideas
• Discover Resources for getting help from the Zephyr community

2.1. Getting Started Guide 13


Zephyr Project Documentation, Release 3.4.0

2.1.8 Troubleshooting Installation

Here are some tips for fixing some issues related to the installation process.

Double Check the Zephyr SDK Variables When Updating

When updating Zephyr SDK, check whether the ZEPHYR_TOOLCHAIN_VARIANT or


ZEPHYR_SDK_INSTALL_DIR environment variables are already set. See Updating the Zephyr SDK
toolchain for more information.
For more information about these environment variables in Zephyr, see Important Environment Variables.

2.1.9 Asking for Help

You can ask for help on a mailing list or on Discord. Please send bug reports and feature requests to
GitHub.
• Mailing Lists: [email protected] is usually the right list to ask for help. Search archives
and sign up here.
• Discord: You can join with this Discord invite.
• GitHub: Use GitHub issues for bugs and feature requests.

How to Ask

Important: Please search this documentation and the mailing list archives first. Your question may have
an answer there.

Don’t just say “this isn’t working” or ask “is this working?”. Include as much detail as you can about:
1. What you want to do
2. What you tried (commands you typed, etc.)
3. What happened (output of each command, etc.)

Use Copy/Paste

Please copy/paste text instead of taking a picture or a screenshot of it. Text includes source code,
terminal commands, and their output.
Doing this makes it easier for people to help you, and also helps other users search the archives. Unnec-
essary screenshots exclude vision impaired developers; some are major Zephyr contributors. Accessibility
has been recognized as a basic human right by the United Nations.
When copy/pasting more than 5 lines of computer text into Discord or Github, create a snippet using
three backticks to delimit the snippet.

2.2 Beyond the Getting Started Guide

The Getting Started Guide gives a straight-forward path to set up your Linux, macOS, or Windows en-
vironment for Zephyr development. In this document, we delve deeper into Zephyr development setup
issues and alternatives.

14 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

2.2.1 Python and pip

Python 3 and its package manager, pip1 , are used extensively by Zephyr to install and run scripts required
to compile and run Zephyr applications, set up and maintain the Zephyr development environment, and
build project documentation.
Depending on your operating system, you may need to provide the --user flag to the pip3 command
when installing new packages. This is documented throughout the instructions. See Installing Packages
in the Python Packaging User Guide for more information about pip1 , including information on -\-user.
• On Linux, make sure ~/.local/bin is at the front of your PATH environment variable, or programs
installed with --user won’t be found. Installing with --user avoids conflicts between pip and the
system package manager, and is the default on Debian-based distributions.
• On macOS, Homebrew disables -\-user.
• On Windows, see the Installing Packages information on --user if you require using this option.
On all operating systems, pip’s -U flag installs or updates the package if the package is already installed
locally but a more recent version is available. It is good practice to use this flag if the latest version of a
package is required. (Check the scripts/requirements.txt file to see if a specific Python package version
is expected.)

2.2.2 Advanced Platform Setup

Here are some alternative instructions for more advanced platform setup configurations for supported
development platforms:

Install Linux Host Dependencies

Documentation is available for these Linux distributions:


• Ubuntu
• Fedora
• Clear Linux
• Arch Linux
For distributions that are not based on rolling releases, some of the requirements and dependencies may
not be met by your package manager. In that case please follow the additional instructions that are
provided to find software from sources other than the package manager.

Note: If you’re working behind a corporate firewall, you’ll likely need to configure a proxy for accessing
the internet, if you haven’t done so already. While some tools use the environment variables http_proxy
and https_proxy to get their proxy settings, some use their own configuration files, most notably apt
and git.

Update Your Operating System Ensure your host system is up to date.


Ubuntu
1 pip is Python’s package installer. Its install command first tries to re-use packages and package dependencies already

installed on your computer. If that is not possible, pip install downloads them from the Python Package Index (PyPI) on the
Internet.
The package versions requested by Zephyr’s requirements.txt may conflict with other requirements on your system, in which
case you may want to set up a virtualenv for Zephyr development.

2.2. Beyond the Getting Started Guide 15


Zephyr Project Documentation, Release 3.4.0

sudo apt-get update


sudo apt-get upgrade

Fedora

sudo dnf upgrade

Clear Linux

sudo swupd update

Arch Linux

sudo pacman -Syu

Install Requirements and Dependencies Note that both Ninja and Make are installed with these
instructions; you only need one.
Ubuntu

sudo apt-get install --no-install-recommends git cmake ninja-build gperf \


ccache dfu-util device-tree-compiler wget \
python3-dev python3-pip python3-setuptools python3-tk python3-wheel xz-utils file␣
˓→libpython3.8-dev \

make gcc gcc-multilib g++-multilib libsdl2-dev libmagic1

Fedora

sudo dnf group install "Development Tools" "C Development Tools and Libraries"
sudo dnf install git cmake ninja-build gperf ccache dfu-util dtc wget \
python3-pip python3-tkinter xz file glibc-devel.i686 libstdc++-devel.i686 python38 \
SDL2-devel

Clear Linux

sudo swupd bundle-add c-basic dev-utils dfu-util dtc \


os-core-dev python-basic python3-basic python3-tcl

The Clear Linux focus is on native performance and security and not cross-compilation. For that reason
it uniquely exports by default to the environment of all users a list of compiler and linker flags. Zephyr’s
CMake build system will either warn or fail because of these. To clear the C/C++ flags among these and
fix the Zephyr build, run the following command as root then log out and back in:

echo 'unset CFLAGS CXXFLAGS' >> /etc/profile.d/unset_cflags.sh

Note this command unsets the C/C++ flags for all users on the system. Each Linux distribution has a
unique, relatively complex and potentially evolving sequence of bash initialization files sourcing each
other and Clear Linux is no exception. If you need a more flexible solution, start by looking at the logic
in /usr/share/defaults/etc/profile.
Arch Linux

sudo pacman -S git cmake ninja gperf ccache dfu-util dtc wget \
python-pip python-setuptools python-wheel tk xz file make

CMake A recent CMake version is required. Check what version you have by using cmake --version.
If you have an older version, there are several ways of obtaining a more recent one:

16 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

• On Ubuntu, you can follow the instructions for adding the kitware third-party apt repository to get
an updated version of cmake using apt.
• Download and install a packaged cmake from the CMake project site. (Note this won’t uninstall
the previous version of cmake.)

cd ~
wget https://github.com/Kitware/CMake/releases/download/v3.21.1/cmake-3.21.1-
˓→Linux-x86_64.sh

chmod +x cmake-3.21.1-Linux-x86_64.sh
sudo ./cmake-3.21.1-Linux-x86_64.sh --skip-license --prefix=/usr/local
hash -r

The hash -r command may be necessary if the installation script put cmake into a new location
on your PATH.
• Download and install from the pre-built binaries provided by the CMake project itself in the CMake
Downloads page. For example, to install version 3.21.1 in ~/bin/cmake:

mkdir $HOME/bin/cmake && cd $HOME/bin/cmake


wget https://github.com/Kitware/CMake/releases/download/v3.21.1/cmake-3.21.1-
˓→Linux-x86_64.sh

yes | sh cmake-3.21.1-Linux-x86_64.sh | cat


echo "export PATH=$PWD/cmake-3.21.1-Linux-x86_64/bin:\$PATH" >> $HOME/.zephyrrc

• Use pip3:

pip3 install --user cmake

Note this won’t uninstall the previous version of cmake and will install the new cmake into your
~/.local/bin folder so you’ll need to add ~/.local/bin to your PATH. (See Python and pip for de-
tails.)
• Check your distribution’s beta or unstable release package library for an update.
• On Ubuntu you can also use snap to get the latest version available:

sudo snap install cmake

After updating cmake, verify that the newly installed cmake is found using cmake --version. You might
also want to uninstall the CMake provided by your package manager to avoid conflicts. (Use whereis
cmake to find other installed versions.)

DTC (Device Tree Compiler) A recent DTC version is required. Check what version you have by using
dtc --version. If you have an older version, either install a more recent one by building from source,
or use the one that is bundled in the Zephyr SDK by installing it.

Python A modern Python 3 version is required. Check what version you have by using python3
--version.
If you have an older version, you will need to install a more recent Python 3. You can build from source,
or use a backport from your distribution’s package manager channels if one is available. Isolating this
Python in a virtual environment is recommended to avoid interfering with your system Python.

Install the Zephyr Software Development Kit (SDK) The Zephyr Software Development Kit (SDK)
contains toolchains for each of Zephyr’s supported architectures. It also includes additional host tools,
such as custom QEMU and OpenOCD.
Use of the Zephyr SDK is highly recommended and may even be required under certain conditions (for
example, running tests in QEMU for some architectures).

2.2. Beyond the Getting Started Guide 17


Zephyr Project Documentation, Release 3.4.0

The Zephyr SDK supports the following target architectures:


• ARC (32-bit and 64-bit; ARCv1, ARCv2, ARCv3)
• ARM (32-bit and 64-bit; ARMv6, ARMv7, ARMv8; A/R/M Profiles)
• MIPS (32-bit and 64-bit)
• Nios II
• RISC-V (32-bit and 64-bit; RV32I, RV32E, RV64I)
• x86 (32-bit and 64-bit)
• Xtensa
Follow these steps to install the Zephyr SDK:
1. Download and verify the Zephyr SDK bundle:

wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.1/
˓→zephyr-sdk-0.16.1_linux-x86_64.tar.xz

wget -O - https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.1/
˓→sha256.sum | shasum --check --ignore-missing

You can change 0.16.1 to another version if needed; the Zephyr SDK Releases page contains all
available SDK releases.
If your host architecture is 64-bit ARM (for example, Raspberry Pi), replace x86_64 with aarch64
in order to download the 64-bit ARM Linux SDK.
2. Extract the Zephyr SDK bundle archive:

cd <sdk download directory>


tar xvf zephyr-sdk-0.16.1_linux-x86_64.tar.xz

3. Run the Zephyr SDK bundle setup script:

cd zephyr-sdk-0.16.1
./setup.sh

If this fails, make sure Zephyr’s dependencies were installed as described in Install Requirements
and Dependencies.
If you want to uninstall the SDK, remove the directory where you installed it. If you relocate the SDK
directory, you need to re-run the setup script.

Note: It is recommended to extract the Zephyr SDK bundle at one of the following locations:
• $HOME
• $HOME/.local
• $HOME/.local/opt
• $HOME/bin
• /opt
• /usr/local
The Zephyr SDK bundle archive contains the zephyr-sdk-0.16.1 directory and, when extracted under
$HOME, the resulting installation path will be $HOME/zephyr-sdk-0.16.1.
If you install the Zephyr SDK outside any of these locations, you must register the Zephyr SDK in the
CMake package registry by running the setup script, or set ZEPHYR_SDK_INSTALL_DIR to point to the
Zephyr SDK installation directory.

18 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

You can also use ZEPHYR_SDK_INSTALL_DIR for pointing to a directory containing multiple Zephyr SDKs,
allowing for automatic toolchain selection. For example, ZEPHYR_SDK_INSTALL_DIR=/company/tools,
where the company/tools folder contains the following subfolders:
• /company/tools/zephyr-sdk-0.13.2
• /company/tools/zephyr-sdk-a.b.c
• /company/tools/zephyr-sdk-x.y.z
This allows the Zephyr build system to choose the correct version of the SDK, while allowing multiple
Zephyr SDKs to be grouped together at a specific path.

Building on Linux without the Zephyr SDK The Zephyr SDK is provided for convenience and ease of
use. It provides toolchains for all Zephyr target architectures, and does not require any extra flags when
building applications or running tests. In addition to cross-compilers, the Zephyr SDK also provides pre-
built host tools. It is, however, possible to build without the SDK’s toolchain by using another toolchain
as as described in the Toolchains section.
As already noted above, the SDK also includes prebuilt host tools. To use the SDK’s prebuilt host tools
with a toolchain from another source, you must set the ZEPHYR_SDK_INSTALL_DIR environment variable
to the Zephyr SDK installation directory. To build without the Zephyr SDK’s prebuilt host tools, the
ZEPHYR_SDK_INSTALL_DIR environment variable must be unset.
To make sure this variable is unset, run:

unset ZEPHYR_SDK_INSTALL_DIR

macOS alternative setup instructions

Important note about Gatekeeper Starting with macOS 10.15 Catalina, applications launched from
the macOS Terminal application (or any other terminal emulator) are subject to the same system security
policies that are applied to applications launched from the Dock. This means that if you download
executable binaries using a web browser, macOS will not let you execute those from the Terminal by
default. In order to get around this issue you can take two different approaches:
• Run xattr -r -d com.apple.quarantine /path/to/folder where path/to/folder is the path
to the enclosing folder where the executables you want to run are located.
• Open “System Preferences” -> “Security and Privacy” -> “Privacy” and then scroll down to “Devel-
oper Tools”. Then unlock the lock to be able to make changes and check the checkbox correspond-
ing to your terminal emulator of choice. This will apply to any executable being launched from
such terminal program.
Note that this section does not apply to executables installed with Homebrew, since those are automati-
cally un-quarantined by brew itself. This is however relevant for most Toolchains.

Additional notes for MacPorts users While MacPorts is not officially supported in this guide, it is
possible to use MacPorts instead of Homebrew to get all the required dependencies on macOS. Note also
that you may need to install rust and cargo for the Python dependencies to install correctly.

Windows alternative setup instructions

Windows 10 WSL (Windows Subsystem for Linux) If you are running a recent version of Windows
10 you can make use of the built-in functionality to natively run Ubuntu binaries directly on a standard
command-prompt. This allows you to use software such as the Zephyr SDK without setting up a virtual
machine.

2.2. Beyond the Getting Started Guide 19


Zephyr Project Documentation, Release 3.4.0

Warning: Windows 10 version 1803 has an issue that will cause CMake to not work properly and is
fixed in version 1809 (and later). More information can be found in Zephyr Issue 10420.

1. Install the Windows Subsystem for Linux (WSL).

Note: For the Zephyr SDK to function properly you will need Windows 10 build 15002 or greater.
You can check which Windows 10 build you are running in the “About your PC” section of the
System Settings. If you are running an older Windows 10 build you might need to install the
Creator’s Update.

2. Follow the Ubuntu instructions in the Install Linux Host Dependencies document.

2.2.3 Install a Toolchain

Zephyr binaries are compiled and linked by a toolchain comprised of a cross-compiler and related tools
which are different from the compiler and tools used for developing software that runs natively on your
host operating system.
You can install the Zephyr SDK to get toolchains for all supported architectures, or install an alternate
toolchain recommended by the SoC vendor or a specific board (check your specific board-level documen-
tation).
You can configure the Zephyr build system to use a specific toolchain by setting environment variables
such as ZEPHYR_TOOLCHAIN_VARIANT to a supported value, along with additional variable(s) specific to
the toolchain variant.

2.2.4 Updating the Zephyr SDK toolchain

When updating Zephyr SDK, check whether the ZEPHYR_TOOLCHAIN_VARIANT or


ZEPHYR_SDK_INSTALL_DIR environment variables are already set.
• If the variables are not set, the latest compatible version of Zephyr SDK will be selected by default.
Proceed to next step without making any changes.
• If ZEPHYR_TOOLCHAIN_VARIANT is set, the corresponding toolchain will be selected at build time.
Zephyr SDK is identified by the value zephyr. If the ZEPHYR_TOOLCHAIN_VARIANT environment
variable is not zephyr, then either unset it or change its value to zephyr to make sure Zephyr SDK
is selected.
• If the ZEPHYR_SDK_INSTALL_DIR environment variable is set, it will override the default lookup
location for Zephyr SDK. If you install Zephyr SDK to one of the recommended locations, you can
unset this variable. Otherwise, set it to your chosen install location.
For more information about these environment variables in Zephyr, see Important Environment Variables.

2.2.5 Cloning the Zephyr Repositories

The Zephyr project source is maintained in the GitHub zephyr repo. External modules used by Zephyr
are found in the parent GitHub Zephyr project. Because of these dependencies, it’s convenient to use the
Zephyr-created west tool to fetch and manage the Zephyr and external module source code. See Basics
for more details.
Once your development tools are installed, use West (Zephyr’s meta-tool) to create, initialize, and down-
load sources from the zephyr and external module repos. We’ll use the name zephyrproject, but you
can choose any name that does not contain a space anywhere in the path.

20 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

west init zephyrproject


cd zephyrproject
west update

The west update command fetches and keeps Modules (External projects) in the zephyrproject folder
in sync with the code in the local zephyr repo.

Warning: You must run west update any time the zephyr/west.yml changes, caused, for example,
when you pull the zephyr repository, switch branches in it, or perform a git bisect inside of it.

Keeping Zephyr updated

To update the Zephyr project source code, you need to get the latest changes via git. Afterwards, run
west update as mentioned in the previous paragraph.

# replace zephyrproject with the path you gave west init


cd zephyrproject/zephyr
git pull
west update

2.2.6 Export Zephyr CMake package

The Zephyr CMake Package can be exported to CMake’s user package registry if it has not already been
done as part of Getting Started Guide.

2.2.7 Board Aliases

Developers who work with multiple boards may find explicit board names cumbersome and want to use
aliases for common targets. This is supported by a CMake file with content like this:

# Variable foo_BOARD_ALIAS=bar replaces BOARD=foo with BOARD=bar and


# sets BOARD_ALIAS=foo in the CMake cache.
set(pca10028_BOARD_ALIAS nrf51dk_nrf51422)
set(pca10056_BOARD_ALIAS nrf52840dk_nrf52840)
set(k64f_BOARD_ALIAS frdm_k64f)
set(sltb004a_BOARD_ALIAS efr32mg_sltb004a)

and specifying its location in ZEPHYR_BOARD_ALIASES . This enables use of aliases pca10028 in contexts
like cmake -DBOARD=pca10028 and west -b pca10028.

2.2.8 Build and Run an Application

You can build, flash, and run Zephyr applications on real hardware using a supported host system. De-
pending on your operating system, you can also run it in emulation with QEMU, or as a native POSIX
application. Additional information about building applications can be found in the Building an Applica-
tion section.

Build Blinky

Let’s build the blinky-sample sample application.

2.2. Beyond the Getting Started Guide 21


Zephyr Project Documentation, Release 3.4.0

Zephyr applications are built to run on specific hardware, called a “board”2 . We’ll use the Phytec
reel_board here, but you can change the reel_board build target to another value if you have a dif-
ferent board. See boards or run west boards from anywhere inside the zephyrproject directory for a
list of supported boards.
1. Go to the zephyr repository:

cd zephyrproject/zephyr

2. Build the blinky sample for the reel_board:

west build -b reel_board samples/basic/blinky

The main build products will be in build/zephyr; build/zephyr/zephyr.elf is the blinky application
binary in ELF format. Other binary formats, disassembly, and map files may be present depending on
your board.
The other sample applications in the samples folder are documented in samples-and-demos.

Note: If you want to re-use an existing build directory for another board or application, you need to
add the parameter -p=auto to west build to clean out settings and artifacts from the previous build.

Run the Application by Flashing to a Board

Most hardware boards supported by Zephyr can be flashed by running west flash. This may require
board-specific tool installation and configuration to work properly.
See Run an Application and your specific board’s documentation in boards for additional details.

Setting udev rules

Flashing a board requires permission to directly access the board hardware, usually managed by installa-
tion of the flashing tools. On Linux systems, if the west flash command fails, you likely need to define
udev rules to grant the needed access permission.
Udev is a device manager for the Linux kernel and the udev daemon handles all user space events raised
when a hardware device is added (or removed) from the system. We can add a rules file to grant access
permission by non-root users to certain USB-connected devices.
The OpenOCD (On-Chip Debugger) project conveniently provides a rules file that defined board-specific
rules for most Zephyr-supported arm-based boards, so we recommend installing this rules file by down-
loading it from their sourceforge repo, or if you’ve installed the Zephyr SDK there is a copy of this rules
file in the SDK folder:
• Either download the OpenOCD rules file and copy it to the right location:

wget -O 60-openocd.rules https://sf.net/p/openocd/code/ci/master/tree/contrib/60-


˓→openocd.rules?format=raw

sudo cp 60-openocd.rules /etc/udev/rules.d

• or copy the rules file from the Zephyr SDK folder:

sudo cp ${ZEPHYR_SDK_INSTALL_DIR}/sysroots/x86_64-pokysdk-linux/usr/share/
˓→openocd/contrib/60-openocd.rules /etc/udev/rules.d

2 This has become something of a misnomer over time. While the target can be, and often is, a microprocessor running on its

own dedicated hardware board, Zephyr also supports using QEMU to run targets built for other architectures in emulation, targets
which produce native host system binaries that implement Zephyr’s driver interfaces with POSIX APIs, and even running different
Zephyr-based binaries on CPU cores of differing architectures on the same physical chip. Each of these hardware configurations is
called a “board,” even though that doesn’t always make perfect sense in context.

22 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

Then, in either case, ask the udev daemon to reload these rules:

sudo udevadm control --reload

Unplug and plug in the USB connection to your board, and you should have permission to access the
board hardware for flashing. Check your board-specific documentation (boards) for further information
if needed.

Run the Application in QEMU

On Linux and macOS, you can run Zephyr applications via emulation on your host system using QEMU
when targeting either the x86 or ARM Cortex-M3 architectures. (QEMU is included with the Zephyr SDK
installation.)
For example, you can build and run the hello_world sample using the x86 emulation board configuration
(qemu_x86), with:

# From the root of the zephyr repository


west build -b qemu_x86 samples/hello_world
west build -t run

To exit QEMU, type Ctrl-a, then x.


Use qemu_cortex_m3 to target an emulated Arm Cortex-M3 sample.

Run a Sample Application natively (POSIX OS)

You can compile some samples to run as host processes on a POSIX OS. This is currently only tested
on Linux hosts. See native_posix for more information. On 64-bit host operating systems, you need to
install a 32-bit C library; see native_posix_deps for details.
First, build Hello World for native_posix.

# From the root of the zephyr repository


west build -b native_posix samples/hello_world

Next, run the application.

west build -t run


# or just run zephyr.exe directly:
./build/zephyr/zephyr.exe

Press Ctrl-C to exit.


You can run ./build/zephyr/zephyr.exe --help to get a list of available options.
This executable can be instrumented using standard tools, such as gdb or valgrind.

2.3 Environment Variables

Various pages in this documentation refer to setting Zephyr-specific environment variables. This page
describes how.

2.3.1 Setting Variables

2.3. Environment Variables 23


Zephyr Project Documentation, Release 3.4.0

Option 1: Just Once

To set the environment variable MY_VARIABLE to foo for the lifetime of your current terminal window:
Linux/macOS

export MY_VARIABLE=foo

Windows

set MY_VARIABLE=foo

Warning: This is best for experimentation. If you close your terminal window, use another terminal
window or tab, restart your computer, etc., this setting will be lost forever.
Using options 2 or 3 is recommended if you want to keep using the setting.

Option 2: In all Terminals

Linux/macOS
Add the export MY_VARIABLE=foo line to your shell’s startup script in your home directory. For Bash,
this is usually ~/.bashrc on Linux or ~/.bash_profile on macOS. Changes in these startup scripts don’t
affect shell instances already started; try opening a new terminal window to get the new settings.
Windows
You can use the setx program in cmd.exe or the third-party RapidEE program.
To use setx, type this command, then close the terminal window. Any new cmd.exe windows will have
MY_VARIABLE set to foo.

setx MY_VARIABLE foo

To install RapidEE, a freeware graphical environment variable editor, using Chocolatey in an Adminis-
trator command prompt:

choco install rapidee

You can then run rapidee from your terminal to launch the program and set environment variables.
Make sure to use the “User” environment variables area – otherwise, you have to run RapidEE as admin-
istrator. Also make sure to save your changes by clicking the Save button at top left before exiting.Settings
you make in RapidEE will be available whenever you open a new terminal window.

Option 3: Using zephyrrc files

Choose this option if you don’t want to make the variable’s setting available to all of your terminals, but
still want to save the value for loading into your environment when you are using Zephyr.
Linux/macOS
Create a file named ~/.zephyrrc if it doesn’t exist, then add this line to it:

export MY_VARIABLE=foo

To get this value back into your current terminal environment, you must run source zephyr-env.sh
from the main zephyr repository. Among other things, this script sources ~/.zephyrrc.
The value will be lost if you close the window, etc.; run source zephyr-env.sh again to get it back.
Windows

24 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

Add the line set MY_VARIABLE=foo to the file %userprofile%\zephyrrc.cmd using a text editor such as
Notepad to save the value.
To get this value back into your current terminal environment, you must run zephyr-env.cmd in a cmd.
exe window after changing directory to the main zephyr repository. Among other things, this script runs
%userprofile%\zephyrrc.cmd.
The value will be lost if you close the window, etc.; run zephyr-env.cmd again to get it back.
These scripts:
• set ZEPHYR_BASE to the location of the zephyr repository
• adds some Zephyr-specific locations (such as zephyr’s scripts directory) to your PATH environ-
ment variable
• loads any settings from the zephyrrc files described above in Option 3: Using zephyrrc files.
You can thus use them any time you need any of these settings.

2.3.2 Zephyr Environment Scripts

You can use the zephyr repository scripts zephyr-env.sh (for macOS and Linux) and zephyr-env.cmd
(for Windows) to load Zephyr-specific settings into your current terminal’s environment. To do so, run
this command from the zephyr repository:
Linux/macOS

source zephyr-env.sh

Windows

zephyr-env.cmd

These scripts:
• set ZEPHYR_BASE to the location of the zephyr repository
• adds some Zephyr-specific locations (such as zephyr’s scripts directory) to your PATH environment
variable
• loads any settings from the zephyrrc files described above in Option 3: Using zephyrrc files.
You can thus use them any time you need any of these settings.

2.3.3 Important Environment Variables

Some Important Build System Variables can also be set in the environment. Here is a description of some
of these important environment variables. This is not a comprehensive list.
BOARD
See Important Build System Variables.
CONF_FILE
See Important Build System Variables.
SHIELD
See Shields.
ZEPHYR_BASE
See Important Build System Variables.

2.3. Environment Variables 25


Zephyr Project Documentation, Release 3.4.0

EXTRA_ZEPHYR_MODULES
See Important Build System Variables.
ZEPHYR_MODULES
See Important Build System Variables.
ZEPHYR_BOARD_ALIASES
See Board Aliases
The following additional environment variables are significant when configuring the toolchain used to
build Zephyr applications.
ZEPHYR_SDK_INSTALL_DIR
Path where Zephyr SDK is installed.
ZEPHYR_TOOLCHAIN_VARIANT
The name of the toolchain to use.
{TOOLCHAIN}_TOOLCHAIN_PATH
Path to the toolchain specified by ZEPHYR_TOOLCHAIN_VARIANT . For example, if
ZEPHYR_TOOLCHAIN_VARIANT=llvm, use LLVM_TOOLCHAIN_PATH. (Note the capitalization when
forming the environment variable name.)
You might need to update some of these variables when you update the Zephyr SDK toolchain.
Emulators and boards may also depend on additional programs. The build system will try to locate those
programs automatically, but may rely on additional CMake or environment variables to do so. Please
consult your emulator’s or board’s documentation for more information. The following environment
variables may be useful in such situations:
PATH
PATH is an environment variable used on Unix-like or Microsoft Windows operating systems to
specify a set of directories where executable programs are located.

2.4 Application Development

Note: In this document, we’ll assume:


• your application directory, <app>, is something like <home>/zephyrproject/app
• its build directory is <app>/build
These terms are defined below. On Linux/macOS, <home> is equivalent to ~. On Windows, it’s
%userprofile%.
Keeping your application inside the workspace (<home>/zephyrproject) makes it easier to use west
build and other commands with it. (You can put your application anywhere as long as ZEPHYR_BASE is
set appropriately, though.)

2.4.1 Overview

Zephyr’s build system is based on CMake.


The build system is application-centric, and requires Zephyr-based applications to initiate building the
Zephyr source code. The application build controls the configuration and build process of both the
application and Zephyr itself, compiling them into a single binary.

26 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

The main zephyr repository contains Zephyr’s source code, configuration files, and build system. You also
likely have installed various Modules (External projects) alongside the zephyr repository, which provide
third party source code integration.
The files in the application directory link Zephyr and any modules with the application. This directory
contains all application-specific files, such as application-specific configuration files and source code.
Here are the files in a simple Zephyr application:

<app>
CMakeLists.txt
app.overlay
prj.conf
src
main.c

These contents are:


• CMakeLists.txt: This file tells the build system where to find the other application files, and links
the application directory with Zephyr’s CMake build system. This link provides features supported
by Zephyr’s build system, such as board-specific configuration files, the ability to run and debug
compiled binaries on real or emulated hardware, and more.
• app.overlay: This is a devicetree overlay file that specifies application-specific changes which
should be applied to the base devicetree for any board you build for. The purpose of devicetree
overlays is usually to configure something about the hardware used by the application.
The build system looks for app.overlay by default, but you can add more devicetree overlays, and
other default files are also searched for.
See Devicetree for more information about devicetree.
• prj.conf: This is a Kconfig fragment that specifies application-specific values for one or more Kcon-
fig options. These application settings are merged with other settings to produce the final configu-
ration. The purpose of Kconfig fragments is usually to configure the software features used by the
application.
The build system looks for prj.conf by default, but you can add more Kconfig fragments, and
other default files are also searched for.
See Kconfig Configuration below for more information.
• main.c: A source code file. Applications typically contain source files written in C, C++, or assem-
bly language. The Zephyr convention is to place them in a subdirectory of <app> named src.
Once an application has been defined, you will use CMake to generate a build directory, which contains
the files you need to build the application and Zephyr, then link them together into a final binary you can
run on your board. The easiest way to do this is with west build, but you can use CMake directly also.
Application build artifacts are always generated in a separate build directory: Zephyr does not support
“in-tree” builds.
The following sections describe how to create, build, and run Zephyr applications, followed by more
detailed reference material.

2.4.2 Application types

We distinguish three basic types of Zephyr application based on where <app> is located:

Application type <app> location


repository zephyr repository
workspace west workspace where Zephyr is installed
freestanding other locations

2.4. Application Development 27


Zephyr Project Documentation, Release 3.4.0

We’ll discuss these more below. To learn how the build system supports each type, see Zephyr CMake
Package.

Zephyr repository application

An application located within the zephyr source code repository in a Zephyr west workspace is referred
to as a Zephyr repository application. In the following example, the hello_world sample is a Zephyr
repository application:

zephyrproject/
.west/
config
zephyr/
arch/
boards/
cmake/
samples/
hello_world/
...
tests/
...

Zephyr workspace application

An application located within a workspace, but outside the zephyr repository itself, is referred to as a
Zephyr workspace application. In the following example, app is a Zephyr workspace application:

zephyrproject/
.west/
config
zephyr/
bootloader/
modules/
tools/
<vendor/private-repositories>/
applications/
app/

Zephyr freestanding application

A Zephyr application located outside of a Zephyr workspace is referred to as a Zephyr freestanding


application. In the following example, app is a Zephyr freestanding application:

<home>/
zephyrproject/
.west/
config
zephyr/
bootloader/
modules/
...

app/
CMakeLists.txt
(continues on next page)

28 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

(continued from previous page)


prj.conf
src/
main.c

2.4.3 Creating an Application

example-application

The example-application Git repository contains a reference workspace application. It is recommended to


use it as a reference when creating your own application as described in the following sections.
The example-application repository demonstrates how to use several commonly-used features, such as:
• Custom board ports
• Custom devicetree bindings
• Custom device drivers
• Continuous Integration (CI) setup, including using twister
• A custom west extension command

Basic example-application Usage

The easiest way to get started with the example-application repository within an existing Zephyr
workspace is to follow these steps:

cd <home>/zephyrproject
git clone https://github.com/zephyrproject-rtos/example-application my-app

The directory name my-app above is arbitrary: change it as needed. You can now go into this directory
and adapt its contents to suit your needs. Since you are using an existing Zephyr workspace, you can use
west build or any other west commands to build, flash, and debug.

Advanced example-application Usage

You can also use the example-application repository as a starting point for building your own customized
Zephyr-based software distribution. This lets you do things like:
• remove Zephyr modules you don’t need
• add additional custom repositories of your own
• override repositories provided by Zephyr with your own versions
• share the results with others and collaborate further
The example-application repository contains a west.yml file and is therefore also a west manifest reposi-
tory. Use this to create a new, customized workspace by following these steps:

cd <home>
mkdir my-workspace
cd my-workspace
git clone https://github.com/zephyrproject-rtos/example-application my-manifest-repo
west init -l my-manifest-repo

2.4. Application Development 29


Zephyr Project Documentation, Release 3.4.0

This will create a new workspace with the T2 topology, with my-manifest-repo as the manifest reposi-
tory. The my-workspace and my-manifest-repo names are arbitrary: change them as needed.
Next, customize the manifest repository. The initial contents of this repository will match the example-
application’s contents when you clone it. You can then edit my-manifest-repo/west.yml to your liking,
changing the set of repositories in it as you wish. See Manifest Imports for many examples of how to add
or remove different repositories from your workspace as needed. Make any other changes you need to
other files.
When you are satisfied, you can run:

west update

and your workspace will be ready for use.


If you push the resulting my-manifest-repo repository somewhere else, you can share your work with
others. For example, let’s say you push the repository to https://git.example.com/my-manifest-repo.
Other people can then set up a matching workspace by running:

west init -m https://git.example.com/my-manifest-repo my-workspace


cd my-workspace
west update

From now on, you can collaborate on the shared software by pushing changes to the repositories you are
using and updating my-manifest-repo/west.yml as needed to add and remove repositories, or change
their contents.

Creating an Application by Hand

You can follow these steps to create a basic application directory from scratch. However, using the
example-application repository or one of Zephyr’s samples-and-demos as a starting point is likely to be
easier.
1. Create an application directory.
For example, in a Unix shell or Windows cmd.exe prompt:

mkdir app

Warning: Building Zephyr or creating an application in a directory with spaces anywhere


on the path is not supported. So the Windows path C:\Users\YourName\app will work, but
C:\Users\Your Name\app will not.

2. Create your source code files.


It’s recommended to place all application source code in a subdirectory named src. This makes it
easier to distinguish between project files and sources.
Continuing the previous example, enter:

cd app
mkdir src

3. Place your application source code in the src sub-directory. For this example, we’ll assume you
created a file named src/main.c.
4. Create a file named CMakeLists.txt in the app directory with the following contents:

30 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

cmake_minimum_required(VERSION 3.20.0)

find_package(Zephyr)
project(my_zephyr_app)

target_sources(app PRIVATE src/main.c)

Notes:
• The cmake_minimum_required() call is required by CMake. It is also invoked by the Zephyr
package on the next line. CMake will error out if its version is older than either the version in
your CMakeLists.txt or the version number in the Zephyr package.
• find_package(Zephyr) pulls in the Zephyr build system, which creates a CMake target
named app (see Zephyr CMake Package). Adding sources to this target is how you include
them in the build. The Zephyr package will define Zephyr-Kernel as a CMake project and
enable support for the C, CXX, ASM languages.
• project(my_zephyr_app) defines your application’s CMake project. This must be called after
find_package(Zephyr) to avoid interference with Zephyr’s project(Zephyr-Kernel).
• target_sources(app PRIVATE src/main.c) is to add your source file to the app target. This
must come after find_package(Zephyr) which defines the target. You can add as many files
as you want with target_sources().
5. Create at least one Kconfig fragment for your application (usually named prj.conf) and set Kconfig
option values needed by your application there. See Kconfig Configuration. If no Kconfig options
need to be set, create an empty file.
6. Configure any devicetree overlays needed by your application, usually in a file named app.
overlay. See Set devicetree overlays.
7. Set up any other files you may need, such as twister configuration files, continuous integration files,
documentation, etc.

2.4.4 Important Build System Variables

You can control the Zephyr build system using many variables. This section describes the most important
ones that every Zephyr developer should know about.

Note: The variables BOARD, CONF_FILE, and DTC_OVERLAY_FILE can be supplied to the build system in
3 ways (in order of precedence):
• As a parameter to the west build or cmake invocation via the -D command-line switch. If you
have multiple overlay files, you should use quotations, "file1.overlay;file2.overlay"
• As Environment Variables.
• As a set(<VARIABLE> <VALUE>) statement in your CMakeLists.txt

• ZEPHYR_BASE: Zephyr base variable used by the build system. find_package(Zephyr) will auto-
matically set this as a cached CMake variable. But ZEPHYR_BASE can also be set as an environment
variable in order to force CMake to use a specific Zephyr installation.
• BOARD: Selects the board that the application’s build will use for the default configuration. See
boards for built-in boards, and Board Porting Guide for information on adding board support.
• CONF_FILE: Indicates the name of one or more Kconfig configuration fragment files. Multiple file-
names can be separated with either spaces or semicolons. Each file includes Kconfig configuration
values that override the default configuration values.
See The Initial Configuration for more information.

2.4. Application Development 31


Zephyr Project Documentation, Release 3.4.0

• EXTRA_CONF_FILE: Additional Kconfig configuration fragment files. Multiple filenames can be sep-
arated with either spaces or semicolons. This can be useful in order to leave CONF_FILE at its
default value, but “mix in” some additional configuration options.
• DTC_OVERLAY_FILE: One or more devicetree overlay files to use. Multiple files can be separated
with semicolons. See Set devicetree overlays for examples and Introduction to devicetree for infor-
mation about devicetree and Zephyr.
• SHIELD: see Shields
• ZEPHYR_MODULES: A CMake list containing absolute paths of additional directories with source code,
Kconfig, etc. that should be used in the application build. See Modules (External projects) for details.
If you set this variable, it must be a complete list of all modules to use, as the build system will not
automatically pick up any modules from west.
• EXTRA_ZEPHYR_MODULES: Like ZEPHYR_MODULES, except these will be added to the list of modules
found via west, instead of replacing it.

Note: You can use a Zephyr Build Configuration CMake package to share common settings for these
variables.

2.4.5 Application CMakeLists.txt

Every application must have a CMakeLists.txt file. This file is the entry point, or top level, of the build
system. The final zephyr.elf image contains both the application and the kernel libraries.
This section describes some of what you can do in your CMakeLists.txt. Make sure to follow these
steps in order.
1. If you only want to build for one board, add the name of the board configuration for your applica-
tion on a new line. For example:

set(BOARD qemu_x86)

Refer to boards for more information on available boards.


The Zephyr build system determines a value for BOARD by checking the following, in order (when
a BOARD value is found, CMake stops looking further down the list):
• Any previously used value as determined by the CMake cache takes highest precedence. This
ensures you don’t try to run a build with a different BOARD value than you set during the build
configuration step.
• Any value given on the CMake command line (directly or indirectly via west build) using
-DBOARD=YOUR_BOARD will be checked for and used next.
• If an environment variable BOARD is set, its value will then be used.
• Finally, if you set BOARD in your application CMakeLists.txt as described in this step, this
value will be used.
2. If your application uses a configuration file or files other than the usual prj.conf (or
prj_YOUR_BOARD.conf, where YOUR_BOARD is a board name), add lines setting the CONF_FILE vari-
able to these files appropriately. If multiple filenames are given, separate them by a single space
or semicolon. CMake lists can be used to build up configuration fragment files in a modular way
when you want to avoid setting CONF_FILE in a single place. For example:

set(CONF_FILE "fragment_file1.conf")
list(APPEND CONF_FILE "fragment_file2.conf")

See The Initial Configuration for more information.

32 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

3. If your application uses devicetree overlays, you may need to set DTC_OVERLAY_FILE. See Set
devicetree overlays.
4. If your application has its own kernel configuration options, create a Kconfig file in the same
directory as your application’s CMakeLists.txt.
See the Kconfig section of the manual for detailed Kconfig documentation.
An (unlikely) advanced use case would be if your application has its own unique configuration
options that are set differently depending on the build configuration.
If you just want to set application specific values for existing Zephyr configuration options, refer
to the CONF_FILE description above.
Structure your Kconfig file like this:

# SPDX-License-Identifier: Apache-2.0

mainmenu "Your Application Name"

# Your application configuration options go here

# Sources Kconfig.zephyr in the Zephyr root directory.


#
# Note: All 'source' statements work relative to the Zephyr root directory (due
# to the $srctree environment variable being set to $ZEPHYR_BASE). If you want
# to 'source' relative to the current Kconfig file instead, use 'rsource' (or a
# path relative to the Zephyr root).
source "Kconfig.zephyr"

Note: Environment variables in source statements are expanded directly, so you do not need to
define an option env="ZEPHYR_BASE" Kconfig “bounce” symbol. If you use such a symbol, it must
have the same name as the environment variable.
See Kconfig extensions for more information.

The Kconfig file is automatically detected when placed in the application directory, but it is also
possible for it to be found elsewhere if the CMake variable KCONFIG_ROOT is set with an absolute
path.
5. Specify that the application requires Zephyr on a new line, after any lines added from the steps
above:

find_package(Zephyr)
project(my_zephyr_app)

Note: find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) can be used if enforcing a


specific Zephyr installation by explicitly setting the ZEPHYR_BASE environment variable should be
supported. All samples in Zephyr supports the ZEPHYR_BASE environment variable.

6. Now add any application source files to the ‘app’ target library, each on their own line, like so:

target_sources(app PRIVATE src/main.c)

Below is a simple example CMakeList.txt:

set(BOARD qemu_x86)

find_package(Zephyr)
(continues on next page)

2.4. Application Development 33


Zephyr Project Documentation, Release 3.4.0

(continued from previous page)


project(my_zephyr_app)

target_sources(app PRIVATE src/main.c)

The Cmake property HEX_FILES_TO_MERGE leverages the application configuration provided by Kconfig
and CMake to let you merge externally built hex files with the hex file generated when building the
Zephyr application. For example:

set_property(GLOBAL APPEND PROPERTY HEX_FILES_TO_MERGE


${app_bootloader_hex}
${PROJECT_BINARY_DIR}/${KERNEL_HEX_NAME}
${app_provision_hex})

2.4.6 CMakeCache.txt

CMake uses a CMakeCache.txt file as persistent key/value string storage used to cache values between
runs, including compile and build options and paths to library dependencies. This cache file is created
when CMake is run in an empty build folder.
For more details about the CMakeCache.txt file see the official CMake documentation runningcmake .

2.4.7 Application Configuration

Application Configuration Directory

Zephyr will use configuration files from the application’s configuration directory except for files with an
absolute path provided by the arguments described earlier, for example CONF_FILE, EXTRA_CONF_FILE,
DTC_OVERLAY_FILE, and EXTRA_DTC_OVERLAY_FILE.
The application configuration directory is defined by the APPLICATION_CONFIG_DIR variable.
APPLICATION_CONFIG_DIR will be set by one of the sources below with the highest priority listed first.
1. If APPLICATION_CONFIG_DIR is specified by the user with -DAPPLICATION_CONFIG_DIR=<path> or
in a CMake file before find_package(Zephyr) then this folder is used a the application’s configu-
ration directory.
2. The application’s source directory.

Kconfig Configuration

Application configuration options are usually set in prj.conf in the application directory. For example,
C++ support could be enabled with this assignment:

CONFIG_CPP=y

Looking at existing samples is a good way to get started.


See Setting Kconfig configuration values for detailed documentation on setting Kconfig configuration val-
ues. The The Initial Configuration section on the same page explains how the initial configuration is
derived. See kconfig-search for a complete list of configuration options. See Hardening Tool for security
information related with Kconfig options.
The other pages in the Kconfig section of the manual are also worth going through, especially if you
planning to add new configuration options.

34 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

Experimental features Zephyr is a project under constant development and thus there are features
that are still in early stages of their development cycle. Such features will be marked [EXPERIMENTAL]
in their Kconfig title.
The CONFIG_WARN_EXPERIMENTAL setting can be used to enable warnings at CMake configure time if any
experimental feature is enabled.

CONFIG_WARN_EXPERIMENTAL=y

For example, if option CONFIG_FOO is experimental, then enabling it and CONFIG_WARN_EXPERIMENTAL


will print the following warning at CMake configure time when you build an application:

warning: Experimental symbol FOO is enabled.

Devicetree Overlays

See Set devicetree overlays.

2.4.8 Application-Specific Code

Application-specific source code files are normally added to the application’s src directory. If the ap-
plication adds a large number of files the developer can group them into sub-directories under src, to
whatever depth is needed.
Application-specific source code should not use symbol name prefixes that have been reserved by the
kernel for its own use. For more information, see Naming Conventions.

Third-party Library Code

It is possible to build library code outside the application’s src directory but it is important that both
application and library code targets the same Application Binary Interface (ABI). On most architectures
there are compiler flags that control the ABI targeted, making it important that both libraries and ap-
plications have certain compiler flags in common. It may also be useful for glue code to have access to
Zephyr kernel header files.
To make it easier to integrate third-party components, the Zephyr build system has defined CMake
functions that give application build scripts access to the zephyr compiler options. The func-
tions are documented and defined in cmake/extensions.cmake and follow the naming convention
zephyr_get_<type>_<format>.
The following variables will often need to be exported to the third-party build system.
• CMAKE_C_COMPILER, CMAKE_AR.
• ARCH and BOARD, together with several variables that identify the Zephyr kernel version.
samples/application_development/external_lib is a sample project that demonstrates some of these fea-
tures.

2.4.9 Building an Application

The Zephyr build system compiles and links all components of an application into a single application
image that can be run on simulated hardware or real hardware.
Like any other CMake-based system, the build process takes place in two stages. First, build files (also
known as a buildsystem) are generated using the cmake command-line tool while specifying a generator.
This generator determines the native build tool the buildsystem will use in the second stage. The second

2.4. Application Development 35


Zephyr Project Documentation, Release 3.4.0

stage runs the native build tool to actually build the source files and generate an image. To learn more
about these concepts refer to the CMake introduction in the official CMake documentation.
Although the default build tool in Zephyr is west, Zephyr’s meta-tool, which invokes cmake and the
underlying build tool (ninja or make) behind the scenes, you can also choose to invoke cmake directly
if you prefer. On Linux and macOS you can choose between the make and ninja generators (i.e. build
tools), whereas on Windows you need to use ninja, since make is not supported on this platform. For
simplicity we will use ninja throughout this guide, and if you choose to use west build to build your
application know that it will default to ninja under the hood.
As an example, let’s build the Hello World sample for the reel_board:
Using west:

west build -b reel_board samples/hello_world

Using CMake and ninja:

# Use cmake to configure a Ninja-based buildsystem:


cmake -Bbuild -GNinja -DBOARD=reel_board samples/hello_world

# Now run ninja on the generated build system:


ninja -Cbuild

On Linux and macOS, you can also build with make instead of ninja:
Using west:
• to use make just once, add -- -G"Unix Makefiles" to the west build command line; see the west
build documentation for an example.
• to use make by default from now on, run west config build.generator "Unix Makefiles".
Using CMake directly:

# Use cmake to configure a Make-based buildsystem:


cmake -Bbuild -DBOARD=reel_board samples/hello_world

# Now run ninja on the generated build system:


make -Cbuild

Basics

1. Navigate to the application directory <app>.


2. Enter the following commands to build the application’s zephyr.elf image for the board specified
in the command-line parameters:
Using west:

west build -b <board>

Using CMake and ninja:

mkdir build && cd build

# Use cmake to configure a Ninja-based buildsystem:


cmake -GNinja -DBOARD=<board> ..

# Now run ninja on the generated build system:


ninja

36 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

If desired, you can build the application using the configuration settings specified in an alternate
.conf file using the CONF_FILE parameter. These settings will override the settings in the applica-
tion’s .config file or its default .conf file. For example:
Using west:

west build -b <board> -- -DCONF_FILE=prj.alternate.conf

Using CMake and ninja:

mkdir build && cd build


cmake -GNinja -DBOARD=<board> -DCONF_FILE=prj.alternate.conf ..
ninja

As described in the previous section, you can instead choose to permanently set the board and
configuration settings by either exporting BOARD and CONF_FILE environment variables or by setting
their values in your CMakeLists.txt using set() statements. Additionally, west allows you to set
a default board.

Build Directory Contents

When using the Ninja generator a build directory looks like this:

<app>/build
build.ninja
CMakeCache.txt
CMakeFiles
cmake_install.cmake
rules.ninja
zephyr

The most notable files in the build directory are:


• build.ninja, which can be invoked to build the application.
• A zephyr directory, which is the working directory of the generated build system, and where most
generated files are created and stored.
After running ninja, the following build output files will be written to the zephyr sub-directory of the
build directory. (This is not the Zephyr base directory, which contains the Zephyr source code etc. and
is described above.)
• .config, which contains the configuration settings used to build the application.

Note: The previous version of .config is saved to .config.old whenever the configuration is
updated. This is for convenience, as comparing the old and new versions can be handy.

• Various object files (.o files and .a files) containing compiled kernel and application code.
• zephyr.elf, which contains the final combined application and kernel binary. Other binary output
formats, such as .hex and .bin, are also supported.

Rebuilding an Application

Application development is usually fastest when changes are continually tested. Frequently rebuilding
your application makes debugging less painful as the application becomes more complex. It’s usually a
good idea to rebuild and test after any major changes to the application’s source files, CMakeLists.txt
files, or configuration settings.

2.4. Application Development 37


Zephyr Project Documentation, Release 3.4.0

Important: The Zephyr build system rebuilds only the parts of the application image potentially affected
by the changes. Consequently, rebuilding an application is often significantly faster than building it the
first time.

Sometimes the build system doesn’t rebuild the application correctly because it fails to recompile one or
more necessary files. You can force the build system to rebuild the entire application from scratch with
the following procedure:
1. Open a terminal console on your host computer, and navigate to the build directory <app>/build.
2. Enter one of the following commands, depending on whether you want to use west or cmake
directly to delete the application’s generated files, except for the .config file that contains the
application’s current configuration information.

west build -t clean

or

ninja clean

Alternatively, enter one of the following commands to delete all generated files, including the .
config files that contain the application’s current configuration information for those board types.

west build -t pristine

or

ninja pristine

If you use west, you can take advantage of its capability to automatically make the build folder
pristine whenever it is required.
3. Rebuild the application normally following the steps specified in Building an Application above.

Building for a board revision

The Zephyr build system has support for specifying multiple hardware revisions of a single board with
small variations. Using revisions allows the board support files to make minor adjustments to a board
configuration without duplicating all the files described in Create your board directory for each revision.
To build for a particular revision, use <board>@<revision> instead of plain <board>. For example:
Using west:

west build -b <board>@<revision>

Using CMake and ninja:

mkdir build && cd build


cmake -GNinja -DBOARD=<board>@<revision> ..
ninja

Check your board’s documentation for details on whether it has multiple revisions, and what revisions
are supported.
When targeting a board revision, the active revision will be printed at CMake configure time, like this:

-- Board: plank, Revision: 1.5.0

38 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

2.4.10 Run an Application

An application image can be run on a real board or emulated hardware.

Running on a Board

Most boards supported by Zephyr let you flash a compiled binary using the flash target to copy the
binary to the board and run it. Follow these instructions to flash and run an application on real hardware:
1. Build your application, as described in Building an Application.
2. Make sure your board is attached to your host computer. Usually, you’ll do this via USB.
3. Run one of these console commands from the build directory, <app>/build, to flash the compiled
Zephyr image and run it on your board:

west flash

or

ninja flash

The Zephyr build system integrates with the board support files to use hardware-specific tools to flash
the Zephyr binary to your hardware, then run it.
Each time you run the flash command, your application is rebuilt and flashed again.
In cases where board support is incomplete, flashing via the Zephyr build system may not be supported. If
you receive an error message about flash support being unavailable, consult your board’s documentation
for additional information on how to flash your board.

Note: When developing on Linux, it’s common to need to install board-specific udev rules to enable
USB device access to your board as a non-root user. If flashing fails, consult your board’s documentation
to see if this is necessary.

Running in an Emulator

The kernel has built-in emulator support for QEMU (on Linux/macOS only, this is not yet supported
on Windows). It allows you to run and test an application virtually, before (or in lieu of) loading and
running it on actual target hardware. Follow these instructions to run an application via QEMU:
1. Build your application for one of the QEMU boards, as described in Building an Application.
For example, you could set BOARD to:
• qemu_x86 to emulate running on an x86-based board
• qemu_cortex_m3 to emulate running on an ARM Cortex M3-based board
2. Run one of these console commands from the build directory, <app>/build, to run the Zephyr
binary in QEMU:

west build -t run

or

ninja run

3. Press Ctrl A, X to stop the application from running in QEMU.


The application stops running and the terminal console prompt redisplays.

2.4. Application Development 39


Zephyr Project Documentation, Release 3.4.0

Each time you execute the run command, your application is rebuilt and run again.

Note: If the (Linux only) Zephyr SDK is installed, the run target will use the SDK’s QEMU binary by
default. To use another version of QEMU, set the environment variable QEMU_BIN_PATH to the path of the
QEMU binary you want to use instead.

Note: You can choose a specific emulator by appending _<emulator> to your target name, for example
west build -t run_qemu or ninja run_qemu for QEMU.

2.4.11 Application Debugging

This section is a quick hands-on reference to start debugging your application with QEMU. Most content
in this section is already covered in QEMU and GNU_Debugger reference manuals.
In this quick reference, you’ll find shortcuts, specific environmental variables, and parameters that can
help you to quickly set up your debugging environment.
The simplest way to debug an application running in QEMU is using the GNU Debugger and setting a
local GDB server in your development system through QEMU.
You will need an ELF (Executable and Linkable Format) binary image for debugging purposes. The build
system generates the image in the build directory. By default, the kernel binary name is zephyr.elf.
The name can be changed using CONFIG_KERNEL_BIN_NAME.

GDB server

We will use the standard 1234 TCP port to open a GDB (GNU Debugger) server instance. This port
number can be changed for a port that best suits the development environment. There are multiple ways
to do this. Each way starts a QEMU instance with the processor halted at startup and with a GDB server
instance listening for a connection.

Running QEMU directly You can run QEMU to listen for a “gdb connection” before it starts executing
any code to debug it.

qemu -s -S <image>

will setup Qemu to listen on port 1234 and wait for a GDB connection to it.
The options used above have the following meaning:
• -S Do not start CPU at startup; rather, you must type ‘c’ in the monitor.
• -s Shorthand for -gdb tcp::1234: open a GDB server on TCP port 1234.

Running QEMU via ninja Run the following inside the build directory of an application:

ninja debugserver

QEMU will write the console output to the path specified in ${QEMU_PIPE} via CMake, typically
qemu-fifo within the build directory. You may monitor this file during the run with tail -f qemu-fifo.

Running QEMU via west Run the following from your project root:

40 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

west build -t debugserver_qemu

QEMU will write the console output to the terminal from which you invoked west.

Configuring the gdbserver listening device The Kconfig option


CONFIG_QEMU_GDBSERVER_LISTEN_DEV controls the listening device, which can be a TCP port number or
a path to a character device. GDB releases 9.0 and newer also support Unix domain sockets.
If the option is unset, then the QEMU invocation will lack a -s or a -gdb parameter. You can then use
the QEMU_EXTRA_FLAGS shell environment variable to pass in your own listen device configuration.

GDB client

Connect to the server by running gdb and giving these commands:

$ path/to/gdb path/to/zephyr.elf
(gdb) target remote localhost:1234
(gdb) dir ZEPHYR_BASE

Note: Substitute the correct ZEPHYR_BASE for your system.

You can use a local GDB configuration .gdbinit to initialize your GDB instance on every run. Your home
directory is a typical location for .gdbinit, but you can configure GDB to load from other locations,
including the directory from which you invoked gdb. This example file performs the same configuration
as above:

target remote localhost:1234


dir ZEPHYR_BASE

Alternate interfaces GDB provides a curses-based interface that runs in the terminal. Pass the --tui
option when invoking gdb or give the tui enable command within gdb.

Note: The GDB version on your development system might not support the --tui option. Please make
sure you use the GDB binary from the SDK which corresponds to the toolchain that has been used to
build the binary.

Finally, the command below connects to the GDB server using the DDD (Data Display Debugger), a
graphical frontend for GDB. The following command loads the symbol table from the ELF binary file, in
this instance, zephyr.elf.

ddd --gdb --debugger "gdb zephyr.elf"

Both commands execute gdb. The command name might change depending on the toolchain you are
using and your cross-development tools.
ddd may not be installed in your development system by default. Follow your system instructions to
install it. For example, use sudo apt-get install ddd on an Ubuntu system.

Debugging

As configured above, when you connect the GDB client, the application will be stopped at system startup.
You may set breakpoints, step through code, etc. as when running the application directly within gdb.

2.4. Application Development 41


Zephyr Project Documentation, Release 3.4.0

Note: gdb will not print the system console output as the application runs, unlike when you run a native
application in GDB directly. If you just continue after connecting the client, the application will run, but
nothing will appear to happen. Check the console output as described above.

2.4.12 Custom Board, Devicetree and SOC Definitions

In cases where the board or platform you are developing for is not yet supported by Zephyr, you can
add board, Devicetree and SOC definitions to your application without having to add them to the Zephyr
tree.
The structure needed to support out-of-tree board and SOC development is similar to how boards and
SOCs are maintained in the Zephyr tree. By using this structure, it will be much easier to upstream your
platform related work into the Zephyr tree after your initial development is done.
Add the custom board to your application or a dedicated repository using the following structure:

boards/
soc/
CMakeLists.txt
prj.conf
README.rst
src/

where the boards directory hosts the board you are building for:

.
boards
x86
my_custom_board
doc
img
support
src

and the soc directory hosts any SOC code. You can also have boards that are supported by a SOC that is
available in the Zephyr tree.

Boards

Use the proper architecture folder name (e.g., x86, arm, etc.) under boards for my_custom_board. (See
boards for a list of board architectures.)
Documentation (under doc/) and support files (under support/) are optional, but will be needed when
submitting to Zephyr.
The contents of my_custom_board should follow the same guidelines for any Zephyr board, and provide
the following files:

my_custom_board_defconfig
my_custom_board.dts
my_custom_board.yaml
board.cmake
board.h
CMakeLists.txt
doc/
Kconfig.board
(continues on next page)

42 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

(continued from previous page)


Kconfig.defconfig
pinmux.c
support/

Once the board structure is in place, you can build your application targeting this board by specifying
the location of your custom board information with the -DBOARD_ROOT parameter to the CMake build
system:
Using west:

west build -b <board name> -- -DBOARD_ROOT=<path to boards>

Using CMake and ninja:

cmake -Bbuild -GNinja -DBOARD=<board name> -DBOARD_ROOT=<path to boards> .


ninja -Cbuild

This will use your custom board configuration and will generate the Zephyr binary into your application
directory.
You can also define the BOARD_ROOT variable in the application CMakeLists.txt file. Make sure to do so
before pulling in the Zephyr boilerplate with find_package(Zephyr ...).

Note: When specifying BOARD_ROOT in a CMakeLists.txt, then an absolute path must be provided,
for example list(APPEND BOARD_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/<extra-board-root>). When
using -DBOARD_ROOT=<board-root> both absolute and relative paths can be used. Relative paths are
treated relatively to the application directory.

SOC Definitions

Similar to board support, the structure is similar to how SOCs are maintained in the Zephyr tree, for
example:

soc
arm
st_stm32
common
stm32l0

The file soc/Kconfig will create the top-level SoC/CPU/Configuration Selection menu in Kconfig.
Out of tree SoC definitions can be added to this menu using the SOC_ROOT CMake variable. This variable
contains a semicolon-separated list of directories which contain SoC support files.
Following the structure above, the following files can be added to load more SoCs into the menu.

soc
arm
st_stm32
Kconfig
Kconfig.soc
Kconfig.defconfig

The Kconfig files above may describe the SoC or load additional SoC Kconfig files.
An example of loading stm31l0 specific Kconfig files in this structure:

2.4. Application Development 43


Zephyr Project Documentation, Release 3.4.0

soc
arm
st_stm32
Kconfig.soc
stm32l0
Kconfig.series

can be done with the following content in st_stm32/Kconfig.soc:

rsource "*/Kconfig.series"

Once the SOC structure is in place, you can build your application targeting this platform by specifying
the location of your custom platform information with the -DSOC_ROOT parameter to the CMake build
system:
Using west:

west build -b <board name> -- -DSOC_ROOT=<path to soc> -DBOARD_ROOT=<path to boards>

Using CMake and ninja:

cmake -Bbuild -GNinja -DBOARD=<board name> -DSOC_ROOT=<path to soc> -DBOARD_ROOT=


˓→<path to boards> .

ninja -Cbuild

This will use your custom platform configurations and will generate the Zephyr binary into your appli-
cation directory.
See Build settings for information on setting SOC_ROOT in a module’s zephyr/module.yml file.
Or you can define the SOC_ROOT variable in the application CMakeLists.txt file. Make sure to do so
before pulling in the Zephyr boilerplate with find_package(Zephyr ...).

Note: When specifying SOC_ROOT in a CMakeLists.txt, then an absolute path must be provided,
for example list(APPEND SOC_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/<extra-soc-root>. When us-
ing -DSOC_ROOT=<soc-root> both absolute and relative paths can be used. Relative paths are treated
relatively to the application directory.

Devicetree Definitions

Devicetree directory trees are found in APPLICATION_SOURCE_DIR, BOARD_DIR, and ZEPHYR_BASE, but
additional trees, or DTS_ROOTs, can be added by creating this directory tree:

include/
dts/common/
dts/arm/
dts/
dts/bindings/

Where ‘arm’ is changed to the appropriate architecture. Each directory is optional. The binding directory
contains bindings and the other directories contain files that can be included from DT sources.
Once the directory structure is in place, you can use it by specifying its location through the DTS_ROOT
CMake Cache variable:
Using west:

west build -b <board name> -- -DDTS_ROOT=<path to dts root>

44 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

Using CMake and ninja:

cmake -Bbuild -GNinja -DBOARD=<board name> -DDTS_ROOT=<path to dts root> .


ninja -Cbuild

You can also define the variable in the application CMakeLists.txt file. Make sure to do so before
pulling in the Zephyr boilerplate with find_package(Zephyr ...).

Note: When specifying DTS_ROOT in a CMakeLists.txt, then an absolute path must be provided,
for example list(APPEND DTS_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/<extra-dts-root>. When us-
ing -DDTS_ROOT=<dts-root> both absolute and relative paths can be used. Relative paths are treated
relatively to the application directory.

Devicetree source are passed through the C preprocessor, so you can include files that can be located in
a DTS_ROOT directory. By convention devicetree include files have a .dtsi extension.
You can also use the preprocessor to control the content of a devicetree file, by specifying directives
through the DTS_EXTRA_CPPFLAGS CMake Cache variable:
Using west:

west build -b <board name> -- -DDTS_EXTRA_CPPFLAGS=-DTEST_ENABLE_FEATURE

Using CMake and ninja:

cmake -Bbuild -GNinja -DBOARD=<board name> -DDTS_EXTRA_CPPFLAGS=-DTEST_ENABLE_FEATURE␣


˓→.

ninja -Cbuild

2.4.13 Debug with Eclipse

Overview

CMake supports generating a project description file that can be imported into the Eclipse Integrated
Development Environment (IDE) and used for graphical debugging.
The GNU MCU Eclipse plug-ins provide a mechanism to debug ARM projects in Eclipse with pyOCD,
Segger J-Link, and OpenOCD debugging tools.
The following tutorial demonstrates how to debug a Zephyr application in Eclipse with pyOCD in Win-
dows. It assumes you have already installed the GCC ARM Embedded toolchain and pyOCD.

Set Up the Eclipse Development Environment

1. Download and install Eclipse IDE for C/C++ Developers.


2. In Eclipse, install the GNU MCU Eclipse plug-ins by opening the menu Window->Eclipse
Marketplace..., searching for GNU MCU Eclipse, and clicking Install on the matching result.
3. Configure the path to the pyOCD GDB server by opening the menu Window->Preferences, navi-
gating to MCU, and setting the Global pyOCD Path.

Generate and Import an Eclipse Project

1. Set up a GNU Arm Embedded toolchain as described in GNU Arm Embedded.


2. Navigate to a folder outside of the Zephyr tree to build your application.

2.4. Application Development 45


Zephyr Project Documentation, Release 3.4.0

# On Windows
cd %userprofile%

Note: If the build directory is a subdirectory of the source directory, as is usually done in Zephyr,
CMake will warn:
“The build directory is a subdirectory of the source directory.
This is not supported well by Eclipse. It is strongly recommended to use a build directory which is
a sibling of the source directory.”

3. Configure your application with CMake and build it with ninja. Note the different CMake gener-
ator specified by the -G"Eclipse CDT4 - Ninja" argument. This will generate an Eclipse project
description file, .project, in addition to the usual ninja build files.
Using west:

west build -b frdm_k64f %ZEPHYR_BASE%\samples\synchronization -- -G"Eclipse CDT4␣


˓→- Ninja"

Using CMake and ninja:

cmake -Bbuild -GNinja -DBOARD=frdm_k64f -G"Eclipse CDT4 - Ninja" %ZEPHYR_BASE%\


˓→samples\synchronization

ninja -Cbuild

4. In Eclipse, import your generated project by opening the menu File->Import... and selecting the
option Existing Projects into Workspace. Browse to your application build directory in the
choice, Select root directory:. Check the box for your project in the list of projects found and
click the Finish button.

Create a Debugger Configuration

1. Open the menu Run->Debug Configurations....


2. Select GDB PyOCD Debugging, click the New button, and configure the following options:
• In the Main tab:
– Project: my_zephyr_app@build
– C/C++ Application: zephyr/zephyr.elf
• In the Debugger tab:
– pyOCD Setup

* Executable path: $pyocd_path \$pyocd_executable


* Uncheck “Allocate console for semihosting”
– Board Setup

* Bus speed: 8000000 Hz


* Uncheck “Enable semihosting”
– GDB Client Setup

* Executable path example (use your GNUARMEMB_TOOLCHAIN_PATH): C:\


gcc-arm-none-eabi-6_2017-q2-update\bin\arm-none-eabi-gdb.exe
• In the SVD Path tab:
– File path: <workspace top>\modules\hal\nxp\mcux\devices\MK64F12\MK64F12.xml

46 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

Note: This is optional. It provides the SoC’s memory-mapped register addresses and bitfields
to the debugger.

3. Click the Debug button to start debugging.

RTOS Awareness

Support for Zephyr RTOS awareness is implemented in pyOCD v0.11.0 and later. It is compatible with
GDB PyOCD Debugging in Eclipse, but you must enable CONFIG_DEBUG_THREAD_INFO=y in your
application.

2.5 API Status and Guidelines

2.5.1 API Overview

The table lists Zephyr’s APIs and information about them, including their current stability level. More
details about API changes between major releases are available in the zephyr_release_notes.

API Status Version Introduced


Analog-to-Digital Converter (ADC) Stable 1.0
Audio Codec Experimental 1.13
Digital Microphone (DMIC) Experimental 1.13
Auxiliary Display (auxdisplay) Experimental 3.4
Barriers API Experimental 3.4
Bluetooth APIs Stable 1.0
Clock Control Stable 1.0
CoAP Unstable 1.10
CAN Controller Stable 1.14
Counter Unstable 1.14
Crypto APIs Stable 1.7
Digital-to-Analog Converter (DAC) Unstable 2.3
Digital Audio Interface (DAI) Experimental 3.1
Direct Memory Access (DMA) Stable 1.5
Device Driver Model Stable 1.0
Devicetree API Stable 2.2
Disk Access Stable 1.6
Display Interface Unstable 1.14
EC Host Command Experimental 2.4
Error Detection And Correction (EDAC) Unstable 2.5
Electrically Erasable Programmable Read-Only Memory (EEPROM) Stable 2.1
Entropy Stable 1.10
File Systems Stable 1.5
Flash Stable 1.2
Flash Circular Buffer (FCB) Stable 1.11
Fuel Gauge Experimental 3.3
Flash map Stable 1.11
Gaussian & Neural Accelerator (GNA) Experimental 1.14
General-Purpose Input/Output (GPIO) Stable 1.0
Hardware Information Stable 1.14
I2C EEPROM Target Stable 1.13
Inter-Integrated Circuit (I2C) Bus Stable 1.0
continues on next page

2.5. API Status and Guidelines 47


Zephyr Project Documentation, Release 3.4.0

Table 1 – continued from previous page


API Status Version Introduced
I2C Target API Experimental 1.12
Inter-IC Sound (I2S) Bus Stable 1.9
Improved Inter-Integrated Circuit (I3C) Bus Experimental 3.2
Input Experimental 3.4
Inter-Processor Mailbox (IPM) Stable 1.0
Keyboard Scan Stable 2.1
Kernel Services Stable 1.0
Light-Emitting Diode (LED) Stable 1.12
Lightweight M2M (LWM2M) Unstable 1.9
Logging Stable 1.13
LoRa and LoRaWAN Experimental 2.2
LoRa and LoRaWAN Experimental 2.5
Multi-Channel Inter-Processor Mailbox (MBOX) Experimental 1.0
MCUmgr Stable 1.11
MQTT Unstable 1.14
MIPI Display Serial Interface (DSI) Experimental 3.1
Miscellaneous Stable 1.0
Networking APIs Stable 1.0
Non-Volatile Storage (NVS) Stable 1.12
Platform Environment Control Interface (PECI) Stable 2.1
PS/2 Stable 2.1
Pulse Width Modulation (PWM) Stable 1.0
Pin Control API Experimental 3.0
Power Management Experimental 1.2
Random Number Generation Stable 1.0
Regulators Experimental 2.4
Reset Controller Experimental 3.1
Retained Memory Experimental 3.4
Retention System Experimental 3.4
Real-Time Clock (RTC) Experimental 3.4
Real Time I/O (RTIO) Experimental 3.2
System Management Bus (SMBus) Experimental 3.4
Serial Peripheral Interface (SPI) Bus Stable 1.0
Sensors Stable 1.2
Settings Stable 1.12
Shell Stable 1.14
Stream Flash Experimental 2.3
Secure Digital High Capacity (SDHC) Experimental 3.1
Task Watchdog Unstable 2.5
USB Type-C Port Controller (TCPC) Experimental 3.1
Universal Asynchronous Receiver-Transmitter (UART) Stable 1.0
UART async Unstable 1.14
USB device support APIs Stable 1.5
USB-C device stack Experimental 3.3
User Mode Stable 1.11
USB-C VBUS Experimental 3.3
Utilities Experimental 2.4
Video Stable 2.1
1-Wire Bus Experimental 3.2
Watchdog Stable 1.0
Digital Signal Processing (DSP) Experimental 3.3

48 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

2.5.2 API Lifecycle

Developers using Zephyr’s APIs need to know how long they can trust that a given API will not change
in future releases. At the same time, developers maintaining and extending Zephyr’s APIs need to be
able to introduce new APIs that aren’t yet fully proven, and to potentially retire old APIs when they’re no
longer optimal or supported by the underlying platforms.

Fig. 2: API Life Cycle

An up-to-date table of all APIs and their maturity level can be found in the API Overview page.

Experimental

Experimental APIs denote that a feature was introduced recently, and may change or be removed in
future versions. Try it out and provide feedback to the community via the Developer mailing list.
The following requirements apply to all new APIs:
• Documentation of the API (usage) explaining its design and assumptions, how it is to be used,
current implementation limitations, and future potential, if appropriate.
• The API introduction should be accompanied by at least one implementation of said API (in the
case of peripheral APIs, this corresponds to one driver)
• At least one sample using the new API (may only build on one single board)

Peripheral APIs (Hardware Related) When introducing an API (public header file with documen-
tation) for a new peripheral or driver subsystem, review of the API is enforced and is driven by the
Architecture working group consisting of representatives from different vendors.
The API shall be promoted to unstable when it has at least two implementations on different hardware
platforms.

Unstable

The API is in the process of settling, but has not yet had sufficient real-world testing to be considered
stable. The API is considered generic in nature and can be used on different hardware platforms.

2.5. API Status and Guidelines 49


Zephyr Project Documentation, Release 3.4.0

Note: Changes will not be announced.

Peripheral APIs (Hardware Related) The API shall be promoted from experimental to unstable
when it has at least two implementations on different hardware platforms.

Hardware Agnostic APIs For hardware agnostic APIs, multiple applications using it are required to
promote an API from experimental to unstable.

Stable

The API has proven satisfactory, but cleanup in the underlying code may cause minor changes.
Backwards-compatibility will be maintained if reasonable.
An API can be declared stable after fulfilling the following requirements:
• Test cases for the new API with 100% coverage
• Complete documentation in code. All public interfaces shall be documented and available in online
documentation.
• The API has been in-use and was available in at least 2 development releases
• Stable APIs can get backward compatible updates, bug fixes and security fixes at any time.
In order to declare an API stable, the following steps need to be followed:
1. A Pull Request must be opened that changes the corresponding entry in the API Overview table
2. An email must be sent to the devel mailing list announcing the API upgrade request
3. The Pull Request must be submitted for discussion in the next Zephyr Architecture meeting where,
barring any objections, the Pull Request will be merged

Introducing incompatible changes A stable API, as described above strives to remain backwards-
compatible through its life-cycle. There are however cases where fulfilling this objective prevents tech-
nical progress or is simply unfeasible without unreasonable burden on the maintenance of the API and
its implementation(s).
An incompatible change is defined as one that forces users to modify their existing code in order to
maintain the current behavior of their application. The need for recompilation of applications (without
changing the application itself) is not considered an incompatible change.
In order to restrict and control the introduction of a change that breaks the promise of backwards com-
patibility the following steps must be followed whenever such a change is considered necessary in order
to accept it in the project:
1. An RFC issue must be opened on GitHub with the following content:

Title: RFC: API Change: <subsystem>


Contents: - Problem Description:
- Background information on why the change is required
- Proposed Change (detailed):
- Brief description of the API change
- Detailed RFC:
- Function call changes
- Device Tree changes (source and bindings)
- Kconfig option changes
- Dependencies:
(continues on next page)

50 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

(continued from previous page)


- Impact to users of the API, including the steps required
to adapt out-of-tree users of the API to the change

Instead of a written description of the changes, the RFC issue may link to a Pull Request containing
those changes in code form.
2. The RFC issue must be labeled with the GitHub Stable API Change label
3. The RFC issue must be submitted for discussion in the next Zephyr Architecture meeting
4. An email must be sent to the devel mailing list with a subject identical to the RFC issue title and
that links to the RFC issue
The RFC will then receive feedback through issue comments and will also be discussed in the Zephyr
Architecture meeting, where the stakeholders and the community at large will have a chance to discuss
it in detail.
Finally, and if not done as part of the first step, a Pull Request must be opened on GitHub. It is left to
the person proposing the change to decide whether to introduce both the RFC and the Pull Request at
the same time or to wait until the RFC has gathered consensus enough so that the implementation can
proceed with confidence that it will be accepted. The Pull Request must include the following:
• A title that matches the RFC issue
• A link to the RFC issue
• The actual changes to the API
– Changes to the API header file
– Changes to the API implementation(s)
– Changes to the relevant API documentation
– Changes to Device Tree source and bindings
• The changes required to adapt in-tree users of the API to the change. Depending on the scope of
this task this might require additional help from the corresponding maintainers
• An entry in the “API Changes” section of the release notes for the next upcoming release
• The labels API, Stable API Change and Release Notes, as well as any others that are applicable
Once the steps above have been completed, the outcome of the proposal will depend on the approval
of the actual Pull Request by the maintainer of the corresponding subsystem. As with any other Pull
Request, the author can request for it to be discussed and ultimately even voted on in the Zephyr TSC
meeting.
If the Pull Request is merged then an email must be sent to the devel and user mailing lists informing
them of the change.

Note: Incompatible changes will be announced in the “API Changes” section of the release notes.

Deprecated

Note: Unstable APIs can be removed without deprecation at any time. Deprecation and removal of APIs
will be announced in the “API Changes” section of the release notes.

The following are the requirements for deprecating an existing API:

2.5. API Status and Guidelines 51


Zephyr Project Documentation, Release 3.4.0

• Deprecation Time (stable APIs): 2 Releases The API needs to be marked as deprecated in at least
two full releases. For example, if an API was first deprecated in release 1.14, it will be ready
to be removed in 1.16 at the earliest. There may be special circumstances, determined by the
Architecture working group, where an API is deprecated sooner.
• What is required when deprecating:
– Mark as deprecated. This can be done by using the compiler itself (__deprecated for function
declarations and __DEPRECATED_MACRO for macro definitions), or by introducing a Kconfig
option (typically one that contains the DEPRECATED word in it) that, when enabled, reverts the
APIs back to their previous form
– Document the deprecation
– Include the deprecation in the “API Changes” of the release notes for the next upcoming release
– Code using the deprecated API needs to be modified to remove usage of said API
– The change needs to be atomic and bisectable
– Create a GitHub issue to track the removal of the deprecated API, and add it to the roadmap
targeting the appropriate release (in the example above, 1.16).
During the deprecation waiting period, the API will be in the deprecated state. The Zephyr maintainers
will track usage of deprecated APIs on docs.zephyrproject.org and support developers migrating their
code. Zephyr will continue to provide warnings:
• API documentation will inform users that the API is deprecated.
• Attempts to use a deprecated API at build time will log a warning to the console.

Retired

In this phase, the API is removed.


The target removal date is 2 releases after deprecation is announced. The Zephyr maintainers will decide
when to actually remove the API: this will depend on how many developers have successfully migrated
from the deprecated API, and on how urgently the API needs to be removed.
If it’s OK to remove the API, it will be removed. The maintainers will remove the corresponding doc-
umentation, and communicate the removal in the usual ways: the release notes, mailing lists, Github
issues and pull-requests.
If it’s not OK to remove the API, the maintainers will continue to support migration and update the
roadmap with the aim to remove the API in the next release.

2.5.3 API Design Guidelines

Zephyr development and evolution is a group effort, and to simplify maintenance and enhancements
there are some general policies that should be followed when developing a new capability or interface.

Using Callbacks

Many APIs involve passing a callback as a parameter or as a member of a configuration structure. The
following policies should be followed when specifying the signature of a callback:
• The first parameter should be a pointer to the object most closely associated with the callback. In
the case of device drivers this would be const struct device *dev. For library functions it may
be a pointer to another object that was referenced when the callback was provided.
• The next parameter(s) should be additional information specific to the callback invocation, such as
a channel identifier, new status value, and/or a message pointer followed by the message length.

52 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

• The final parameter should be a void *user_data pointer carrying context that allows a shared
callback function to locate additional material necessary to process the callback.
An exception to providing user_data as the last parameter may be allowed when the callback itself was
provided through a structure that will be embedded in another structure. An example of such a case is
gpio_callback , normally defined within a data structure specific to the code that also defines the call-
back function. In those cases further context can accessed by the callback indirectly by CONTAINER_OF .

Examples
• The requirements of k_timer_expiry_t invoked when a system timer alarm fires are satisfied by:

void handle_timeout(struct k_timer *timer)


{ ... }

The assumption here, as with gpio_callback , is that the timer is embedded in a structure reach-
able from CONTAINER_OF that can provide additional context to the callback.
• The requirements of counter_alarm_callback_t invoked when a counter device alarm fires are
satisfied by:

void handle_alarm(const struct device *dev,


uint8_t chan_id,
uint32_t ticks,
void *user_data)
{ ... }

This provides more complete useful information, including which counter channel timed-out and
the counter value at which the timeout occurred, as well as user context which may or may not be
the counter_alarm_cfg used to register the callback, depending on user needs.

Conditional Data and APIs

APIs and libraries may provide features that are expensive in RAM or code size but are optional in
the sense that some applications can be implemented without them. Examples of such feature include
capturing a timestamp or providing an alternative interface. The developer in coordination
with the community must determine whether enabling the features is to be controllable through a Kconfig
option.
In the case where a feature is determined to be optional the following practices should be followed.
• Any data that is accessed only when the feature is enabled should be conditionally included via
#ifdef CONFIG_MYFEATURE in the structure or union declaration. This reduces memory use for
applications that don’t need the capability.
• Function declarations that are available only when the option is enabled should be provided un-
conditionally. Add a note in the description that the function is available only when the specified
feature is enabled, referencing the required Kconfig symbol by name. In the cases where the func-
tion is used but not enabled the definition of the function shall be excluded from compilation, so
references to the unsupported API will result in a link-time error.
• Where code specific to the feature is isolated in a source file that has no other content that file
should be conditionally included in CMakeLists.txt:

zephyr_sources_ifdef(CONFIG_MYFEATURE foo_funcs.c)

• Where code specific to the feature is part of a source file that has other content the feature-specific
code should be conditionally processed using #ifdef CONFIG_MYFEATURE.
The Kconfig flag used to enable the feature should be added to the PREDEFINED variable in doc/zephyr.
doxyfile.in to ensure the conditional API and functions appear in generated documentation.

2.5. API Status and Guidelines 53


Zephyr Project Documentation, Release 3.4.0

Return Codes

Implementations of an API, for example an API for accessing a peripheral might implement only a subset
of the functions that is required for minimal operation. A distinction is needed between APIs that are not
supported and those that are not implemented or optional:
• APIs that are supported but not implemented shall return -ENOSYS.
• Optional APIs that are not supported by the hardware should be implemented and the return code
in this case shall be -ENOTSUP.
• When an API is implemented, but the particular combination of options requested in the call cannot
be satisfied by the implementation the call shall return -ENOTSUP. (For example, a request for a
level-triggered GPIO interrupt on hardware that supports only edge-triggered interrupts)

2.5.4 API Terminology

The following terms may be used as shorthand API tags to indicate the allowed calling context (thread,
ISR, pre-kernel), the effect of a call on the current thread state, and other behavioral characteristics.
reschedule
if executing the function reaches a reschedule point
sleep
if executing the function can cause the invoking thread to sleep
no-wait
if a parameter to the function can prevent the invoking thread from trying to sleep
isr-ok
if the function can be safely called and will have its specified effect whether invoked from interrupt
or thread context
pre-kernel-ok
if the function can be safely called before the kernel has been fully initialized and will have its
specified effect when invoked from that context.
async
if the function may return before the operation it initializes is complete (i.e. function return and
operation completion are asynchronous)
supervisor
if the calling thread must have supervisor privileges to execute the function
Details on the behavioral impact of each attribute are in the following sections.

reschedule

The reschedule attribute is used on a function that can reach a reschedule point within its execution.

Details The significance of this attribute is that when a rescheduling function is invoked by a thread
it is possible for that thread to be suspended as a consequence of a higher-priority thread being made
ready. Whether the suspension actually occurs depends on the operation associated with the reschedule
point and the relative priorities of the invoking thread and the head of the ready queue.
Note that in the case of timeslicing, or reschedule points executed from interrupts, any thread may be
suspended in any function.
Functions that are not reschedule may be invoked from either thread or interrupt context.
Functions that are reschedule may be invoked from thread context.
Functions that are reschedule but not sleep may be invoked from interrupt context.

54 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

sleep

The sleep attribute is used on a function that can cause the invoking thread to sleep.

Explanation This attribute is of relevance specifically when considering applications that use only non-
preemptible threads, because the kernel will not replace a running cooperative-only thread at a resched-
ule point unless that thread has explicitly invoked an operation that caused it to sleep.
This attribute does not imply the function will sleep unconditionally, but that the operation may require
an invoking thread that would have to suspend, wait, or invoke k_yield() before it can complete its
operation. This behavior may be mediated by no-wait.
Functions that are sleep are implicitly reschedule.
Functions that are sleep may be invoked from thread context.
Functions that are sleep may be invoked from interrupt and pre-kernel contexts if and only if invoked in
no-wait mode.

no-wait

The no-wait attribute is used on a function that is also sleep to indicate that a parameter to the function
can force an execution path that will not cause the invoking thread to sleep.

Explanation The paradigmatic case of a no-wait function is a function that takes a timeout, to which
K_NO_WAIT can be passed. The semantics of this special timeout value are to execute the function’s
operation as long as it can be completed immediately, and to return an error code rather than sleep if it
cannot.
It is use of the no-wait feature that allows functions like k_sem_take() to be invoked from ISRs, since it
is not permitted to sleep in interrupt context.
A function with a no-wait path does not imply that taking that path guarantees the function is syn-
chronous.
Functions with this attribute may be invoked from interrupt and pre-kernel contexts only when the
parameter selects the no-wait path.

isr-ok

The isr-ok attribute is used on a function to indicate that it works whether it is being invoked from
interrupt or thread context.

Explanation Any function that is not sleep is inherently isr-ok. Functions that are sleep are isr-ok
if the implementation ensures that the documented behavior is implemented even if called from an
interrupt context. This may be achieved by having the implementation detect the calling context and
transfer the operation that would sleep to a thread, or by documenting that when invoked from a non-
thread context the function will return a specific error (generally -EWOULDBLOCK).
Note that a function that is no-wait is safe to call from interrupt context only when the no-wait path is
selected. isr-ok functions need not provide a no-wait path.

pre-kernel-ok

The pre-kernel-ok attribute is used on a function to indicate that it works as documented even when
invoked before the kernel main thread has been started.

2.5. API Status and Guidelines 55


Zephyr Project Documentation, Release 3.4.0

Explanation This attribute is similar to isr-ok in function, but is intended for use by any API that is
expected to be called in DEVICE_DEFINE() or SYS_INIT() calls that may be invoked with PRE_KERNEL_1
or PRE_KERNEL_2 initialization levels.
Generally a function that is pre-kernel-ok checks k_is_pre_kernel() when determining whether it can
fulfill its required behavior. In many cases it would also check k_is_in_isr() so it can be isr-ok as well.

async

A function is async (i.e. asynchronous) if it may return before the operation it initiates has completed. An
asynchronous function will generally provide a mechanism by which operation completion is reported,
e.g. a callback or event.
A function that is not asynchronous is synchronous, i.e. the operation will always be complete when the
function returns. As most functions are synchronous this behavior does not have a distinct attribute to
identify it.

Explanation Be aware that async is orthogonal to context-switching. Some APIs may provide comple-
tion information through a callback, but may suspend while waiting for the resource necessary to initiate
the operation; an example is spi_transceive_async().
If a function is both no-wait and async then selecting the no-wait path only guarantees that the function
will not sleep. It does not affect whether the operation will be completed before the function returns.

supervisor

The supervisor attribute is relevant only in user-mode applications, and indicates that the function cannot
be invoked from user mode.

2.6 Language Support

2.6.1 C Language Support

C is a general-purpose low-level programming language that is widely used for writing code for embed-
ded systems.
Zephyr is primarily written in C and natively supports applications written in the C language. All Zephyr
API functions and macros are implemented in C and available as part of the C header files under the
include directory, so writing Zephyr applications in C gives the developers access to the most features.
The main() function must have the return type of int as Zephyr applications run in a “hosted” environ-
ment as defined by the C standard. Applications must return zero (0) from main. All non-zero return
values are reserved.

Language Standards

Zephyr does not target a specific version of the C standards; however, the Zephyr codebase makes exten-
sive use of the features newly introduced in the 1999 release of the ISO C standard (ISO/IEC 9899:1999,
hereinafter referred to as C99) such as those listed below, effectively requiring the use of a compiler
toolchain that supports the C99 standard and above:
• inline functions
• standard boolean types (bool in <stdbool.h>)
• fixed-width integer types ([u]intN_t in <stdint.h>)

56 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

• designated initializers
• variadic macros
• restrict qualification
Some Zephyr components make use of the features newly introduced in the 2011 release of the ISO
C standard (ISO/IEC 9899:2011, hereinafter referred to as C11) such as the type-generic expressions
using the _Generic keyword. For example, the cbprintf() component, used as the default formatted
output processor for Zephyr, makes use of the C11 type-generic expressions, and this effectively requires
most Zephyr applications to be compiled using a compiler toolchain that supports the C11 standard and
above.
In summary, it is recommended to use a compiler toolchain that supports at least the C11 standard for
developing with Zephyr. It is, however, important to note that some optional Zephyr components and
external modules may make use of the C language features that have been introduced in more recent
versions of the standards, in which case it will be necessary to use a more up-to-date compiler toolchain
that supports such standards.

Standard Library

The C Standard Library is an integral part of any C program, and Zephyr provides the support for a
number of different C libraries for the applications to choose from, depending on the compiler toolchain
being used to build the application.

Common C library code Zephyr provides some C library functions that are designed to be used in
conjunction with multiple C libraries. These either provide functions not available in multiple C libraries
or are designed to replace functionality in the C library with code better suited for use in the Zephyr
environment

Time function This provides an implementation of the standard C function, time(), relying on the
Zephyr function, clock_gettime(). This function can be enabled by selecting COMMON_LIBC_TIME.

Dynamic Memory Management The common dynamic memory management implementation can be
enabled by selecting the CONFIG_COMMON_LIBC_MALLOC in the application configuration file.
The common C library internally uses the kernel memory heap API to manage the memory heap used by
the standard dynamic memory management interface functions such as malloc() and free().
The internal memory heap is normally located in the .bss section. When userspace is enabled,
however, it is placed in a dedicated memory partition called z_malloc_partition, which can be
accessed from the user mode threads. The size of the internal memory heap is specified by the
CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE.
The default heap size for applications using the common C library is zero (no heap). For other C library
users, if there is an MMU present, then the default heap is 16kB. Otherwise, the heap uses all available
memory.
There are also separate controls to select calloc() (COMMON_LIBC_CALLOC) and reallocarray()
(COMMON_LIBC_REALLOCARRAY). Both of these are enabled by default as that doesn’t impact memory
usage in applications not using them.
The standard dynamic memory management interface functions implemented by the common C library
are thread safe and may be simultaneously called by multiple threads. These functions are implemented
in lib/libc/common/source/stdlib/malloc.c.

2.6. Language Support 57


Zephyr Project Documentation, Release 3.4.0

Minimal libc The most basic C library, named “minimal libc”, is part of the Zephyr codebase and
provides the minimal subset of the standard C library required to meet the needs of Zephyr and its
subsystems, primarily in the areas of string manipulation and display.
It is very low footprint and is suitable for projects that do not rely on less frequently used portions of the
ISO C standard library. It can also be used with a number of different toolchains.
The minimal libc implementation can be found in lib/libc/minimal in the main Zephyr tree.

Functions The minimal libc implements the minimal subset of the ISO/IEC 9899:2011 standard C
library functions required to meet the needs of the Zephyr kernel, as defined by the Coding Guidelines
Rule A.4.

Formatted Output The minimal libc does not implement its own formatted output processor; instead,
it maps the C standard formatted output functions such as printf and sprintf to the cbprintf()
function, which is Zephyr’s own C99-compatible formatted output implementation.
For more details, refer to the Formatted Output OS service documentation.

Dynamic Memory Management The minimal libc uses the malloc api family implementation provided
by the common C library, which itself is built upon the kernel memory heap API.

Error numbers Error numbers are used throughout Zephyr APIs to signal error conditions as return
values from functions. They are typically returned as the negative value of the integer literals defined in
this section, and are defined in the errno.h header file.
A subset of the error numbers defined in the POSIX errno.h specification and other de-facto standard
sources have been added to the minimal libc.
A conscious effort is made in Zephyr to keep the values of the minimal libc error numbers consistent
with the different implementations of the C standard libraries supported by Zephyr. The minimal libc
errno.h is checked against that of the Newlib to ensure that the error numbers are kept aligned.
Below is a list of the error number definitions. For the actual numeric values please refer to errno.h.

group system_errno
System error numbers Error codes returned by functions. Includes a list of those defined by IEEE
Std 1003.1-2017.

Defines

errno

EPERM
Not owner

ENOENT
No such file or directory

ESRCH
No such context

58 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

EINTR
Interrupted system call

EIO
I/O error

ENXIO
No such device or address

E2BIG
Arg list too long

ENOEXEC
Exec format error

EBADF
Bad file number

ECHILD
No children

EAGAIN
No more contexts

ENOMEM
Not enough core

EACCES
Permission denied

EFAULT
Bad address

ENOTBLK
Block device required

EBUSY
Mount device busy

EEXIST
File exists

EXDEV
Cross-device link

ENODEV
No such device

2.6. Language Support 59


Zephyr Project Documentation, Release 3.4.0

ENOTDIR
Not a directory

EISDIR
Is a directory

EINVAL
Invalid argument

ENFILE
File table overflow

EMFILE
Too many open files

ENOTTY
Not a typewriter

ETXTBSY
Text file busy

EFBIG
File too large

ENOSPC
No space left on device

ESPIPE
Illegal seek

EROFS
Read-only file system

EMLINK
Too many links

EPIPE
Broken pipe

EDOM
Argument too large

ERANGE
Result too large

ENOMSG
Unexpected message type

60 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

EDEADLK
Resource deadlock avoided

ENOLCK
No locks available

ENOSTR
STREAMS device required

ENODATA
Missing expected message data

ETIME
STREAMS timeout occurred

ENOSR
Insufficient memory

EPROTO
Generic STREAMS error

EBADMSG
Invalid STREAMS message

ENOSYS
Function not implemented

ENOTEMPTY
Directory not empty

ENAMETOOLONG
File name too long

ELOOP
Too many levels of symbolic links

EOPNOTSUPP
Operation not supported on socket

EPFNOSUPPORT
Protocol family not supported

ECONNRESET
Connection reset by peer

ENOBUFS
No buffer space available

2.6. Language Support 61


Zephyr Project Documentation, Release 3.4.0

EAFNOSUPPORT
Addr family not supported

EPROTOTYPE
Protocol wrong type for socket

ENOTSOCK
Socket operation on non-socket

ENOPROTOOPT
Protocol not available

ESHUTDOWN
Can’t send after socket shutdown

ECONNREFUSED
Connection refused

EADDRINUSE
Address already in use

ECONNABORTED
Software caused connection abort

ENETUNREACH
Network is unreachable

ENETDOWN
Network is down

ETIMEDOUT
Connection timed out

EHOSTDOWN
Host is down

EHOSTUNREACH
No route to host

EINPROGRESS
Operation now in progress

EALREADY
Operation already in progress

EDESTADDRREQ
Destination address required

62 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

EMSGSIZE
Message size

EPROTONOSUPPORT
Protocol not supported

ESOCKTNOSUPPORT
Socket type not supported

EADDRNOTAVAIL
Can’t assign requested address

ENETRESET
Network dropped connection on reset

EISCONN
Socket is already connected

ENOTCONN
Socket is not connected

ETOOMANYREFS
Too many references: can’t splice

ENOTSUP
Unsupported value

EILSEQ
Illegal byte sequence

EOVERFLOW
Value overflow

ECANCELED
Operation canceled

EWOULDBLOCK
Operation would block

Newlib Newlib is a complete C library implementation written for the embedded systems. It is a
separate open source project and is not included in source code form with Zephyr. Instead, the Zephyr
SDK includes a precompiled library for each supported architecture (libc.a and libm.a).

Note: Other 3rd-party toolchains, such as GNU Arm Embedded, also bundle the Newlib as a precompiled
library.

Zephyr implements the “API hook” functions that are invoked by the C standard library functions in the
Newlib. These hook functions are implemented in lib/libc/newlib/libc-hooks.c and translate the
library internal system calls to the equivalent Zephyr API calls.

2.6. Language Support 63


Zephyr Project Documentation, Release 3.4.0

Types of Newlib The Newlib included in the Zephyr SDK comes in two versions: ‘full’ and ‘nano’
variants.

Full Newlib The Newlib full variant (libc.a and libm.a) is the most capable variant of the Newlib
available in the Zephyr SDK, and supports almost all standard C library features. It is optimized for
performance (prefers performance over code size) and its footprint is significantly larger than the the
nano variant.
This variant can be enabled by selecting the CONFIG_NEWLIB_LIBC and de-selecting the
CONFIG_NEWLIB_LIBC_NANO in the application configuration file.

Nano Newlib The Newlib nano variant (libc_nano.a and libm_nano.a) is the size-optimized version
of the Newlib, and supports all features that the full variant supports except the new format specifiers
introduced in C99, such as the char, long long type format specifiers (i.e. %hhX and %llX).
This variant can be enabled by selecting the CONFIG_NEWLIB_LIBC and CONFIG_NEWLIB_LIBC_NANO in
the application configuration file.
Note that the Newlib nano variant is not available for all architectures. The availability of the nano
variant is specified by the CONFIG_HAS_NEWLIB_LIBC_NANO.

Formatted Output Newlib supports all standard C formatted input and output functions, including
printf, fprintf, sprintf and sscanf.
The Newlib formatted input and output function implementation supports all format specifiers defined
by the C standard with the following exceptions:
• Floating point format specifiers (e.g. %f) require CONFIG_NEWLIB_LIBC_FLOAT_PRINTF and
CONFIG_NEWLIB_LIBC_FLOAT_SCANF to be enabled.
• C99 format specifiers are not supported in the Newlib nano variant (i.e. %hhX for char, %llX for
long long, %jX for intmax_t, %zX for size_t, %tX for ptrdiff_t).

Dynamic Memory Management Newlib implements an internal heap allocator to manage the memory
blocks used by the standard dynamic memory management interface functions (for example, malloc()
and free()).
The internal heap allocator implemented by the Newlib may vary across the different types of the Newlib
used. For example, the heap allocator implemented in the Full Newlib (libc.a and libm.a) of the Zephyr
SDK requests larger memory chunks to the operating system and has a significantly higher minimum
memory requirement compared to that of the Nano Newlib (libc_nano.a and libm_nano.a).
The only interface between the Newlib dynamic memory management functions and the Zephyr-side
libc hooks is the sbrk() function, which is used by the Newlib to manage the size of the memory pool
reserved for its internal heap allocator.
The _sbrk() hook function, implemented in libc-hooks.c, handles the memory pool size change re-
quests from the Newlib and ensures that the Newlib internal heap allocator memory pool size does not
exceed the amount of available memory space by returning an error when the system is out of memory.
When userspace is enabled, the Newlib internal heap allocator memory pool is placed in a dedicated
memory partition called z_malloc_partition, which can be accessed from the user mode threads.
The amount of memory space available for the Newlib heap depends on the system configurations:
• When MMU is enabled (CONFIG_MMU is selected), the amount of memory space reserved for the
Newlib heap is set by the size of the free memory space returned by the k_mem_free_get() function
or the CONFIG_NEWLIB_LIBC_MAX_MAPPED_REGION_SIZE, whichever is the smallest.
• When MPU is enabled and the MPU requires power-of-two partition size and address alignment
(CONFIG_NEWLIB_LIBC_ALIGNED_HEAP_SIZE is set to a non-zero value), the amount of memory
space reserved for the Newlib heap is set by the CONFIG_NEWLIB_LIBC_ALIGNED_HEAP_SIZE.

64 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

• Otherwise, the amount of memory space reserved for the Newlib heap is equal to the amount of
free (unallocated) memory in the SRAM region.
The standard dynamic memory management interface functions implemented by the Newlib are thread
safe and may be simultaneously called by multiple threads.

Picolibc Picolibc is a complete C library implementation written for the embedded systems, targeting
C17 (ISO/IEC 9899:2018) and POSIX 2018 (IEEE Std 1003.1-2017) standards. Picolibc is an external
open source project which is provided for Zephyr as a module, and included as part of the Zephyr SDK
in precompiled form for each supported architecture (libc.a).

Note: Picolibc is also available for other 3rd-party toolchains, such as GNU Arm Embedded.

Zephyr implements the “API hook” functions that are invoked by the C standard library functions in the
Picolibc. These hook functions are implemented in lib/libc/picolibc/libc-hooks.c and translate
the library internal system calls to the equivalent Zephyr API calls.

Picolibc Module When built as a Zephyr module, there are several configuration knobs available to
adjust the feature set in the library, balancing what the library supports versus the code size of the
resulting functions. Because the standard C++ library must be compiled for the target C library, the
Picolibc module cannot be used with applications which use the standard C++ library. Building the
Picolibc module will increase the time it takes to compile the application.
The Picolibc module can be enabled by selecting CONFIG_PICOLIBC_USE_MODULE in the application con-
figuration file.
When updating the Picolibc module to a newer version, the toolchain-bundled Picolibc in the Zephyr SDK
must also be updated to the same version.

Toolchain Picolibc Starting with version 0.16, the Zephyr SDK includes precompiled versions of Picol-
ibc for every target architecture, along with precompiled versions of libstdc++.
The toolchain version of Picolibc can be enabled by de-selecting CONFIG_PICOLIBC_USE_MODULE in the
application configuration file.
For every release of Zephyr, the toolchain-bundled Picolibc and the Picolibc module are guaranteed to be
in sync when using the recommended version of Zephyr SDK.

Formatted Output Picolibc supports all standard C formatted input and output functions, including
printf(), fprintf(), sprintf() and sscanf().
Picolibc formatted input and output function implementation supports all format specifiers defined by
the C17 and POSIX 2018 standards with the following exceptions:
• Floating point format specifiers (e.g. %f) require CONFIG_PICOLIBC_IO_FLOAT.
• Long long format specifiers (e.g. %lld) require CONFIG_PICOLIBC_IO_LONG_LONG. This option is
automatically enabled with CONFIG_PICOLIBC_IO_FLOAT.

Printk, cbprintf and friends When using Picolibc, Zephyr formatted output functions are implemented
in terms of stdio calls. This includes:
• printk, snprintk and vsnprintk
• cbprintf and cbvprintf
• fprintfcb, vfprintfcb, printfcb, vprintfcb, snprintfcb and vsnprintfcb

2.6. Language Support 65


Zephyr Project Documentation, Release 3.4.0

When using tagged args (CONFIG_CBPRINTF_PACKAGE_SUPPORT_TAGGED_ARGUMENTS and


CBPRINTF_PACKAGE_ARGS_ARE_TAGGED), calls to cbpprintf will not use Picolibc, so formatting of
output using those code will differ from Picolibc results as the cbprintf functions are not completely
C/POSIX compliant.

Math Functions Picolibc provides full C17/IEEE STD 754-2019 support for float, double and long
double math operations, except for long double versions of the Bessel functions.

Thread Local Storage Picolibc uses Thread Local Storage (TLS) (where supported) for data which is
supposed to remain local to each thread, like errno . This means that TLS support is enabled when
using Picolibc. As all TLS variables are allocated out of the thread stack area, this can affect stack size
requirements by a few bytes.

C Library Local Variables Picolibc uses a few internal variables for things like heap management.
These are collected in a dedicated memory partition called z_libc_partition. Applications using
CONFIG_USERSPACE and memory domains must ensure that this partition is included in any domain
active during Picolibc calls.

Dynamic Memory Management Picolibc uses the malloc api family implementation provided by the
common C library, which itself is built upon the kernel memory heap API.

Formatted Output

C defines standard formatted output functions such as printf and sprintf and these functions are
implemented by the C standard libraries.
Each C standard library has its own set of requirements and configurations for selecting the formatted
output modes and capabilities. Refer to each C standard library documentation for more details.

Dynamic Memory Management

C defines a standard dynamic memory management interface (for example, malloc() and free()) and
these functions are implemented by the C standard libraries.
While the details of the dynamic memory management implementation varies across different C standard
libraries, all supported libraries must conform to the following conventions. Every supported C standard
library shall:
• manage its own memory heap either internally or by invoking the hook functions (for example,
sbrk()) implemented in libc-hooks.c.
• maintain the architecture- and memory region-specific alignment requirements for the memory
blocks allocated by the standard dynamic memory allocation interface (for example, malloc()).
• allocate memory blocks inside the z_malloc_partition memory partition when userspace is en-
abled. See Pre-defined Memory Partitions.
For more details regarding the C standard library-specific memory management implementation, refer
to each C standard library documentation.

Note: Native Zephyr applications should use the memory management API supported by the Zephyr
kernel such as k_malloc() in order to take advantage of the advanced features that they offer.
C standard dynamic memory management interface functions such as malloc() should be used only by
the portable applications and libraries that target multiple operating systems.

66 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

2.6.2 C++ Language Support

C++ is a general-purpose object-oriented programming language that is based on the C language.

Enabling C++ Support

Zephyr supports applications written in both C and C++. However, to use C++ in an application
you must configure Zephyr to include C++ support by selecting the CONFIG_CPP in the application
configuration file.
To enable C++ support, the compiler toolchain must also include a C++ compiler and the included
compiler must be supported by the Zephyr build system. The Zephyr SDK, which includes the GNU C++
Compiler (part of GCC), is supported by Zephyr, and the features and their availability documented here
assume the use of the Zephyr SDK.
The default C++ standard level (i.e. the language enforced by the compiler flags passed) for Zephyr
apps is C++11. Other standards are available via kconfig choice, for example CONFIG_STD_CPP98. The
oldest standard supported and tested in Zephyr is C++98.
When compiling a source file, the build system selects the C++ compiler based on the suffix (extension)
of the files. Files identified with either a cpp or a cxx suffix are compiled using the C++ compiler. For
example, myCplusplusApp.cpp is compiled using C++.
The C++ standard requires the main() function to have the return type of int. Your main() must be
defined as int main(void). Zephyr ignores the return value from main, so applications should not
return status information and should, instead, return zero.

Note: Do not use C++ for kernel, driver, or system initialization code.

Language Features

Zephyr currently provides only a subset of C++ functionality. The following features are not supported:
• Static global object destruction
• OS-specific C++ standard library classes (e.g. std::thread, std::mutex)
While not an exhaustive list, support for the following functionality is included:
• Inheritance
• Virtual functions
• Virtual tables
• Static global object constructors
• Dynamic object management with the new and delete operators
• Exceptions
• RTTI (runtime type information)
• Standard Template Library (STL)
Static global object constructors are initialized after the drivers are initialized but before the application
main() function. Therefore, use of C++ is restricted to application code.
In order to make use of the C++ exceptions, the CONFIG_CPP_EXCEPTIONS must be selected in the
application configuration file.

2.6. Language Support 67


Zephyr Project Documentation, Release 3.4.0

Zephyr Minimal C++ Library

Zephyr minimal C++ library (lib/cpp/minimal) provides a minimal subset of the C++ standard library
and application binary interface (ABI) functions to enable basic C++ language support. This includes:
• new and delete operators
• virtual function stub and vtables
• static global initializers for global constructors
The scope of the minimal C++ library is strictly limited to providing the basic C++ language support,
and it does not implement any Standard Template Library (STL) classes and functions. For this reason,
it is only suitable for use in the applications that implement their own (non-standard) class library and
do rely on the Standard Template Library (STL) components.
Any application that makes use of the Standard Template Library (STL) components, such as
std::string and std::vector, must enable the C++ standard library support.

C++ Standard Library

The C++ Standard Library is a collection of classes and functions that are part of the ISO C++ standard
(std namespace).
Zephyr does not include any C++ standard library implementation in source code form. Instead, it
allows configuring the build system to link against the pre-built C++ standard library included in the
C++ compiler toolchain.
To enable C++ standard library, select an applicable toolchain-specific C++ standard library type from
the CONFIG_LIBCPP_IMPLEMENTATION in the application configuration file.
For instance, when building with the Zephyr SDK, the build system can be configured to link against
the GNU C++ Library (libstdc++.a), which is a fully featured C++ standard library that provides all
features required by the ISO C++ standard including the Standard Template Library (STL), by selecting
CONFIG_GLIBCXX_LIBCPP in the application configuration file.
The following C++ standard libraries are supported by Zephyr:
• GNU C++ Library (CONFIG_GLIBCXX_LIBCPP)
• ARC MetaWare C++ Library (CONFIG_ARCMWDT_LIBCPP)
A Zephyr subsystem that requires the features from the full C++ standard library can select, from its
config, CONFIG_REQUIRES_FULL_LIBCPP, which automatically selects a compatible C++ standard library
unless the Kconfig symbol for a specific C++ standard library is selected.

2.7 Optimizations

Guides on how to optimize Zephyr for performance, power and footprint.

2.7.1 Optimizing for Footprint

Stack Sizes

Stack sizes of various system threads are specified generously to allow for usage in different scenarios
on as many supported platforms as possible. You should start the optimization process by reviewing all
stack sizes and adjusting them for your application:
CONFIG_ISR_STACK_SIZE
Set to 2048 by default

68 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

CONFIG_MAIN_STACK_SIZE
Set to 1024 by default
CONFIG_IDLE_STACK_SIZE
Set to 320 by default
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE
Set to 1024 by default
CONFIG_PRIVILEGED_STACK_SIZE
Set to 1024 by default, depends on userspace feature.

Unused Peripherals

Some peripherals are enabled by default. You can disable unused peripherals in your project configura-
tion, for example:

CONFIG_GPIO=n
CONFIG_SPI=n

Various Debug/Informational Options

The following options are enabled by default to provide more information about the running application
and to provide means for debugging and error handling:
CONFIG_BOOT_BANNER
This option can be disabled to save a few bytes.
CONFIG_DEBUG
This option can be disabled for production builds

MPU/MMU Support

Depending on your application and platform needs, you can disable MPU/MMU support to gain some
memory and improve performance. Consider the consequences of this configuration choice though,
because you’ll lose advanced stack checking and support.

2.7.2 Optimization Tools

Footprint and Memory Usage

The build system offers 3 targets to view and analyse RAM, ROM and stack usage in generated images.
The tools run on the final image and give information about size of symbols and code being used in
both RAM and ROM. Additionally, with features available through the compiler, we can also generate
worst-case stack usage analysis:
Tools that are available as build system targets:

Build Target: puncover This target uses a 3rd party tools called puncover which can be found here.
When this target is built, it will launch a local web server which will allow you to open a web client and
browse the files and view their ROM, RAM and stack usage. Before you can use this target, you will have
to install the puncover python module:

pip3 install git+https://github.com/HBehrens/puncover --user

2.7. Optimizations 69
Zephyr Project Documentation, Release 3.4.0

Then:
Using west:

west build -b reel_board samples/hello_world


west build -t puncover

Using CMake and ninja:

# Use cmake to configure a Ninja-based buildsystem:


cmake -Bbuild -GNinja -DBOARD=reel_board samples/hello_world

# Now run ninja on the generated build system:


ninja -Cbuild puncover

To view worst-case stack usage analysis, build this with the CONFIG_STACK_USAGE enabled.
Using west:

west build -b reel_board samples/hello_world -- -DCONFIG_STACK_USAGE=y


west build -t puncover

Using CMake and ninja:

# Use cmake to configure a Ninja-based buildsystem:


cmake -Bbuild -GNinja -DBOARD=reel_board -DCONFIG_STACK_USAGE=y samples/hello_world

# Now run ninja on the generated build system:


ninja -Cbuild puncover

Build Target: ram_report List all compiled objects and their RAM usage in a tabular form with bytes
per symbol and the percentage it uses. The data is grouped based on the file system location of the object
in the tree and the file containing the symbol.
Use the ram_report target with your board:
Using west:

west build -b reel_board samples/hello_world


west build -t ram_report

Using CMake and ninja:

# Use cmake to configure a Ninja-based buildsystem:


cmake -Bbuild -GNinja -DBOARD=reel_board samples/hello_world

# Now run ninja on the generated build system:


ninja -Cbuild ram_report

which will generate something similar to the output below:

Path ␣
˓→ Size %
=====================================================================================================
...
...
SystemCoreClock ␣
˓→ 4 0.08%
_kernel ␣
˓→ 48 0.99%
(continues on next page)

70 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

(continued from previous page)


_sw_isr_table ␣
˓→ 384 7.94%
cli.10544 ␣
˓→ 16 0.33%
gpio_initialized.9765 ␣
˓→ 1 0.02%
on.10543 ␣
˓→ 4 0.08%
poll_out_lock.9764 ␣
˓→ 4 0.08%
z_idle_threads ␣
˓→ 128 2.65%
z_interrupt_stacks ␣
˓→2048 42.36%
z_main_thread ␣
˓→ 128 2.65%
arch ␣
˓→ 1 0.02%
arm ␣
˓→ 1 0.02%
core ␣
˓→ 1 0.02%
aarch32 ␣
˓→ 1 0.02%
cortex_m ␣
˓→ 1 0.02%
mpu ␣
˓→ 1 0.02%
arm_mpu.c ␣
˓→ 1 0.02%
static_regions_num ␣
˓→ 1 0.02%
drivers ␣
˓→ 536 11.09%
clock_control ␣
˓→ 100 2.07%
nrf_power_clock.c ␣
˓→ 100 2.07%
__device_clock_nrf ␣
˓→ 16 0.33%
data ␣
˓→ 80 1.65%
hfclk_users ␣
˓→ 4 0.08%
...
...

Build Target: rom_report List all compiled objects and their ROM usage in a tabular form with bytes
per symbol and the percentage it uses. The data is grouped based on the file system location of the object
in the tree and the file containing the symbol.
Use the rom_report to get the ROM report:
Using west:

2.7. Optimizations 71
Zephyr Project Documentation, Release 3.4.0

west build -b reel_board samples/hello_world


west build -t rom_report

Using CMake and ninja:

# Use cmake to configure a Ninja-based buildsystem:


cmake -Bbuild -GNinja -DBOARD=reel_board samples/hello_world

# Now run ninja on the generated build system:


ninja -Cbuild rom_report

which will generate something similar to the output below:

Path ␣
˓→ Size %
=====================================================================================================
...
...
CSWTCH.5 ␣
˓→ 4 0.02%
SystemCoreClock ␣
˓→ 4 0.02%
__aeabi_idiv0 ␣
˓→ 2 0.01%
__udivmoddi4 ␣
˓→ 702 3.37%
_sw_isr_table ␣
˓→ 384 1.85%
delay_machine_code.9114 ␣
˓→ 6 0.03%
levels.8826 ␣
˓→ 20 0.10%
mpu_config ␣
˓→ 8 0.04%
transitions.10558 ␣
˓→ 12 0.06%
arch ␣
˓→1194 5.74%
arm ␣
˓→1194 5.74%
core ␣
˓→1194 5.74%
aarch32 ␣
˓→1194 5.74%
cortex_m ␣
˓→ 852 4.09%
fault.c ␣
˓→ 400 1.92%
bus_fault.isra.0 ␣
˓→ 60 0.29%
mem_manage_fault.isra.0 ␣
˓→ 56 0.27%
usage_fault.isra.0 ␣
˓→ 36 0.17%
z_arm_fault ␣
˓→ 232 1.11%
z_arm_fault_init ␣
(continues on next page)

72 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

(continued from previous page)


˓→ 16 0.08%
irq_init.c ␣
˓→ 24 0.12%
z_arm_interrupt_init ␣
˓→ 24 0.12%
mpu ␣
˓→ 352 1.69%
arm_core_mpu.c ␣
˓→ 56 0.27%
z_arm_configure_static_mpu_regions ␣
˓→ 56 0.27%
arm_mpu.c ␣
˓→ 296 1.42%
__init_sys_init_arm_mpu_init0 ␣
˓→ 8 0.04%
arm_core_mpu_configure_static_mpu_regions ␣
˓→ 20 0.10%
arm_core_mpu_disable ␣
˓→ 16 0.08%
arm_core_mpu_enable ␣
˓→ 20 0.10%
arm_mpu_init ␣
˓→ 92 0.44%
mpu_configure_regions ␣
˓→ 140 0.67%
thread_abort.c ␣
˓→ 76 0.37%
z_impl_k_thread_abort
76 0.37%
...
...

Data Structures

Build Target: pahole Poke-a-hole (pahole) is an object-file analysis tool to find the size of the data
structures, and the holes caused due to aligning the data elements to the word-size of the CPU by the
compiler.
Poke-a-hole (pahole) must be installed prior to using this target. It can be obtained from https://git.
kernel.org/pub/scm/devel/pahole/pahole.git and is available in the dwarves package in both fedora
and ubuntu:

sudo apt-get install dwarves

or in fedora:

sudo dnf install dwarves

Using west:

west build -b reel_board samples/hello_world


west build -t pahole

Using CMake and ninja:

2.7. Optimizations 73
Zephyr Project Documentation, Release 3.4.0

# Use cmake to configure a Ninja-based buildsystem:


cmake -Bbuild -GNinja -DBOARD=reel_board samples/hello_world

# Now run ninja on the generated build system:


ninja -Cbuild pahole

After running this target, pahole will output the results to the console:

/* Used at: zephyr/isr_tables.c */


/* <80> ../include/sw_isr_table.h:30 */
struct _isr_table_entry {
void * arg; /* 0 4 */
void (*isr)(void *); /* 4 4 */

/* size: 8, cachelines: 1, members: 2 */


/* last cacheline: 8 bytes */
};
/* Used at: zephyr/isr_tables.c */
/* <eb> ../include/arch/arm/aarch32/cortex_m/mpu/arm_mpu_v7m.h:134 */
struct arm_mpu_region_attr {
uint32_t rasr; /* 0 4 */

/* size: 4, cachelines: 1, members: 1 */


/* last cacheline: 4 bytes */
};
/* Used at: zephyr/isr_tables.c */
/* <112> ../include/arch/arm/aarch32/cortex_m/mpu/arm_mpu.h:24 */
struct arm_mpu_region {
uint32_t base; /* 0 4 */
const char * name; /* 4 4 */
arm_mpu_region_attr_t attr; /* 8 4 */

/* size: 12, cachelines: 1, members: 3 */


/* last cacheline: 12 bytes */
};
...
...

2.8 Flashing and Hardware Debugging

2.8.1 Flash & Debug Host Tools

This guide describes the software tools you can run on your host workstation to flash and debug Zephyr
applications.
Zephyr’s west tool has built-in support for all of these in its flash, debug, debugserver, and attach
commands, provided your board hardware supports them and your Zephyr board directory’s board.
cmake file declares that support properly. See Building, Flashing and Debugging for more information on
these commands.

SAM Boot Assistant (SAM-BA)

Atmel SAM Boot Assistant (Atmel SAM-BA) allows In-System Programming (ISP) from USB or UART host
without any external programming interface. Zephyr allows users to develop and program boards with

74 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

SAM-BA support using west. Zephyr supports devices with/without ROM bootloader and both extensions
from Arduino and Adafruit. Full support was introduced in Zephyr SDK 0.12.0.
The typical command to flash the board is:

west flash [ -r bossac ] [ -p /dev/ttyX ]

Flash configuration for devices:


With ROM bootloader
These devices don’t need any special configuration. After building your application, just run west flash
to flash the board.
Without ROM bootloader
For these devices, the user should:
1. Define flash partitions required to accommodate the bootloader and application image; see Flash
map for details.
2. Have board .defconfig file with the CONFIG_USE_DT_CODE_PARTITION Kconfig option set to y to
instruct the build system to use these partitions for code relocation. This option can also be set in
prj.conf or any other Kconfig fragment.
3. Build and flash the SAM-BA bootloader on the device.
With compatible SAM-BA bootloader
For these devices, the user should:
1. Define flash partitions required to accommodate the bootloader and application image; see Flash
map for details.
2. Have board .defconfig file with the CONFIG_BOOTLOADER_BOSSA Kconfig option set to y. This
will automatically select the CONFIG_USE_DT_CODE_PARTITION Kconfig option which instruct the
build system to use these partitions for code relocation. The board .defconfig file should
have CONFIG_BOOTLOADER_BOSSA_ARDUINO , CONFIG_BOOTLOADER_BOSSA_ADAFRUIT_UF2 or the
CONFIG_BOOTLOADER_BOSSA_LEGACY Kconfig option set to y to select the right compatible SAM-
BA bootloader mode. These options can also be set in prj.conf or any other Kconfig fragment.
3. Build and flash the SAM-BA bootloader on the device.

Note: The CONFIG_BOOTLOADER_BOSSA_LEGACY Kconfig option should be used as last resource. Try
configure first with Devices without ROM bootloader.

Typical flash layout and configuration For bootloaders that reside on flash, the devicetree partition
layout is mandatory. For devices that have a ROM bootloader, they are mandatory when the application
uses a storage or other non-application partition. In this special case, the boot partition should be omitted
and code_partition should start from offset 0. It is necessary to define the partitions with sizes that avoid
overlaps, always.
A typical flash layout for devices without a ROM bootloader is:

/ {
chosen {
zephyr,code-partition = &code_partition;
};
};

&flash0 {
partitions {
(continues on next page)

2.8. Flashing and Hardware Debugging 75


Zephyr Project Documentation, Release 3.4.0

(continued from previous page)


compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;

boot_partition: partition@0 {
label = "sam-ba";
reg = <0x00000000 0x2000>;
read-only;
};

code_partition: partition@2000 {
label = "code";
reg = <0x2000 0x3a000>;
read-only;
};

/*
* The final 16 KiB is reserved for the application.
* Storage partition will be used by FCB/LittleFS/NVS
* if enabled.
*/
storage_partition: partition@3c000 {
label = "storage";
reg = <0x0003c000 0x00004000>;
};
};
};

A typical flash layout for devices with a ROM bootloader and storage partition is:

/ {
chosen {
zephyr,code-partition = &code_partition;
};
};

&flash0 {
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;

code_partition: partition@0 {
label = "code";
reg = <0x0 0xF0000>;
read-only;
};

/*
* The final 64 KiB is reserved for the application.
* Storage partition will be used by FCB/LittleFS/NVS
* if enabled.
*/
storage_partition: partition@F0000 {
label = "storage";
reg = <0x000F0000 0x00100000>;
(continues on next page)

76 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

(continued from previous page)


};
};
};

Enabling SAM-BA runner In order to instruct Zephyr west tool to use the SAM-BA bootloader the
board.cmake file must have include(${ZEPHYR_BASE}/boards/common/bossac.board.cmake) entry.
Note that Zephyr tool accept more entries to define multiple runners. By default, the first one will be
selected when using west flash command. The remaining options are available passing the runner
option, for instance west flash -r bossac.
More implementation details can be found in the boards documentation. As a quick reference, see these
three board documentation pages:
• sam4e_xpro (ROM bootloader)
• adafruit_feather_m0_basic_proto (Adafruit UF2 bootloader)
• arduino_nano_33_iot (Arduino bootloader)
• arduino_nano_33_ble (Arduino legacy bootloader)

Enabling BOSSAC on Windows Native [Experimental] Zephyr SDK´s bossac is only currenty support
on Linux and macOS. Windows support can be achieved by using the bossac version from BOSSA oficial
releases. After installing using default options, the bossac.exe must be added to Windows PATH. A
specific bossac executable can be used by passing the --bossac option, as follows:

west flash -r bossac --bossac="C:\Program Files (x86)\BOSSA\bossac.exe" --bossac-port=


˓→"COMx"

Note: WSL is not currently supported.

J-Link Debug Host Tools

Segger provides a suite of debug host tools for Linux, macOS, and Windows operating systems:
• J-Link GDB Server: GDB remote debugging
• J-Link Commander: Command-line control and flash programming
• RTT Viewer: RTT terminal input and output
• SystemView: Real-time event visualization and recording
These debug host tools are compatible with the following debug probes:
• LPC-Link2 J-Link Onboard Debug Probe
• OpenSDA J-Link Onboard Debug Probe
• J-Link External Debug Probe
• ST-LINK/V2-1 Onboard Debug Probe
Check if your SoC is listed in J-Link Supported Devices.
Download and install the J-Link Software and Documentation Pack to get the J-Link GDB Server and
Commander, and to install the associated USB device drivers. RTT Viewer and SystemView can be
downloaded separately, but are not required.
Note that the J-Link GDB server does not yet support Zephyr RTOS-awareness.

2.8. Flashing and Hardware Debugging 77


Zephyr Project Documentation, Release 3.4.0

OpenOCD Debug Host Tools

OpenOCD is a community open source project that provides GDB remote debugging and flash program-
ming support for a wide range of SoCs. A fork that adds Zephyr RTOS-awareness is included in the
Zephyr SDK; otherwise see Getting OpenOCD for options to download OpenOCD from official reposito-
ries.
These debug host tools are compatible with the following debug probes:
• OpenSDA DAPLink Onboard Debug Probe
• J-Link External Debug Probe
• ST-LINK/V2-1 Onboard Debug Probe
Check if your SoC is listed in OpenOCD Supported Devices.

Note: On Linux, openocd is available though the Zephyr SDK. Windows users should use the following
steps to install openocd:
• Download openocd for Windows from here: OpenOCD Windows
• Copy bin and share dirs to C:\Program Files\OpenOCD\
• Add C:\Program Files\OpenOCD\bin to ‘PATH’ environment variable

pyOCD Debug Host Tools

pyOCD is an open source project from Arm that provides GDB remote debugging and flash programming
support for Arm Cortex-M SoCs. It is distributed on PyPi and installed when you complete the Get Zephyr
and install Python dependencies step in the Getting Started Guide. pyOCD includes support for Zephyr
RTOS-awareness.
These debug host tools are compatible with the following debug probes:
• OpenSDA DAPLink Onboard Debug Probe
• ST-LINK/V2-1 Onboard Debug Probe
Check if your SoC is listed in pyOCD Supported Devices.

Lauterbach TRACE32 Debug Host Tools

Lauterbach TRACE32 is a product line of microprocessor development tools, debuggers and real-time
tracer with support for JTAG, SWD, NEXUS or ETM over multiple core architectures, including Arm
Cortex-A/-R/-M, RISC-V, Xtensa, etc. Zephyr allows users to develop and program boards with Lauter-
bach TRACE32 support using west.
The runner consists of a wrapper around TRACE32 software, and allows a Zephyr board to execute a
custom start-up script (Practice Script) for the different commands supported, including the ability to
pass extra arguments from CMake. Is up to the board using this runner to define the actions performed
on each command.

Install Lauterbach TRACE32 Software Download Lauterbach TRACE32 software from the Lauter-
bach TRACE32 download website (registration required) and follow the installation steps described in
Lauterbach TRACE32 Installation Guide.

78 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

Flashing and Debugging Set the environment variable T32_DIR to the TRACE32 system directory. Then
execute west flash or west debug commands to flash or debug the Zephyr application as detailed in
Building, Flashing and Debugging. The debug command launches TRACE32 GUI to allow debug the
Zephyr application, while the flash command hides the GUI and perform all operations in the back-
ground.
By default, the t32 runner will launch TRACE32 using the default configuration file named config.t32
located in the TRACE32 system directory. To use a different configuration file, supply the argument
--config CONFIG to the runner, for example:

west flash --config myconfig.t32

For more options, run west flash --context -r t32 to print the usage.

Zephyr RTOS Awareness To enable Zephyr RTOS awareness follow the steps described in Lauterbach
TRACE32 Zephyr OS Awareness Manual.

2.8.2 Debug Probes

A debug probe is special hardware which allows you to control execution of a Zephyr application running
on a separate board. Debug probes usually allow reading and writing registers and memory, and support
breakpoint debugging of the Zephyr application on your host workstation using tools like GDB. They
may also support other debug software and more advanced features such as tracing program execution.
For details on the related host software supported by Zephyr, see Flash & Debug Host Tools.
Debug probes are usually connected to your host workstation via USB; they are sometimes also accessible
via an IP network or other means. They usually connect to the device running Zephyr using the JTAG or
SWD protocols. Debug probes are either separate hardware devices or circuitry integrated into the same
board which runs Zephyr.
Many supported boards in Zephyr include a second microcontroller that serves as an onboard debug
probe, usb-to-serial adapter, and sometimes a drag-and-drop flash programmer. This eliminates the need
to purchase an external debug probe and provides a variety of debug host tool options.
Several hardware vendors have their own branded onboard debug probe implementations: NXP LPC
boards have LPC-Link2, NXP Kinetis (former Freescale) boards have OpenSDA, and ST boards have
ST-LINK. Each onboard debug probe microcontroller can support one or more types of firmware that
communicate with their respective debug host tools. For example, an OpenSDA microcontroller can be
programmed with DAPLink firmware to communicate with pyOCD or OpenOCD debug host tools, or
with J-Link firmware to communicate with J-Link debug host tools.

Debug Probes & Host Tools Host Tools


Compatibility Chart
J-Link Debug OpenOCD pyOCD

Debug Probes LPC-Link2 J-Link ✓


OpenSDA ✓ ✓
DAPLink
OpenSDA J-Link ✓
J-Link External ✓ ✓
ST-LINK/V2-1 ✓ ✓ some STM32
boards

Some supported boards in Zephyr do not include an onboard debug probe and therefore require an
external debug probe. In addition, boards that do include an onboard debug probe often also have an
SWD or JTAG header to enable the use of an external debug probe instead. One reason this may be useful
is that the onboard debug probe may have limitations, such as lack of support for advanced debuggers or

2.8. Flashing and Hardware Debugging 79


Zephyr Project Documentation, Release 3.4.0

high-speed tracing. You may need to adjust jumpers to prevent the onboard debug probe from interfering
with the external debug probe.

LPC-Link2 J-Link Onboard Debug Probe

The LPC-Link2 J-Link is an onboard debug probe and usb-to-serial adapter supported on many NXP LPC
and i.MX RT development boards.
This debug probe is compatible with the following debug host tools:
• Enabling BOSSAC on Windows Native [Experimental]
This probe is realized by programming the LPC-Link2 microcontroller with J-Link LPC-Link2 firmware.
Download and install LPCScrypt to get the firmware and programming scripts.

Note: Verify the firmware supports your board by visiting Firmware for LPCXpresso

1. Put the LPC-Link2 microcontroller into DFU boot mode by attaching the DFU jumper, then power-
ing up the board.
2. Run the program_JLINK script.
3. Remove the DFU jumper and power cycle the board.

OpenSDA DAPLink Onboard Debug Probe

The OpenSDA DAPLink is an onboard debug probe and usb-to-serial adapter supported on many NXP
Kinetis and i.MX RT development boards. It also includes drag-and-drop flash programming support.
This debug probe is compatible with the following debug host tools:
• pyOCD Debug Host Tools
• OpenOCD Debug Host Tools
This probe is realized by programming the OpenSDA microcontroller with DAPLink OpenSDA firmware.
NXP provides OpenSDA DAPLink Board-Specific Firmwares.
Install the debug host tools before you program the firmware.
As with all OpenSDA debug probes, the steps for programming the firmware are:
1. Put the OpenSDA microcontroller into bootloader mode by holding the reset button while you
power on the board. Note that “bootloader mode” in this context applies to the OpenSDA micro-
controller itself, not the target microcontroller of your Zephyr application.
2. After you power on the board, release the reset button. A USB mass storage device called BOOT-
LOADER or MAINTENANCE will enumerate.
3. Copy the OpenSDA firmware binary to the USB mass storage device.
4. Power cycle the board, this time without holding the reset button. You should see three USB
devices enumerate: a CDC device (serial port), a HID device (debug port), and a mass storage
device (drag-and-drop flash programming).

OpenSDA J-Link Onboard Debug Probe

The OpenSDA J-Link is an onboard debug probe and usb-to-serial adapter supported on many NXP
Kinetis and i.MX RT development boards.
This debug probe is compatible with the following debug host tools:
• Enabling BOSSAC on Windows Native [Experimental]

80 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

This probe is realized by programming the OpenSDA microcontroller with J-Link OpenSDA firmware.
Segger provides OpenSDA J-Link Generic Firmwares and OpenSDA J-Link Board-Specific Firmwares,
where the latter is generally recommended when available. Board-specific firmwares are required for
i.MX RT boards to support their external flash memories, whereas generic firmwares are compatible with
all Kinetis boards.
Install the debug host tools before you program the firmware.
As with all OpenSDA debug probes, the steps for programming the firmware are:
1. Put the OpenSDA microcontroller into bootloader mode by holding the reset button while you
power on the board. Note that “bootloader mode” in this context applies to the OpenSDA micro-
controller itself, not the target microcontroller of your Zephyr application.
2. After you power on the board, release the reset button. A USB mass storage device called BOOT-
LOADER or MAINTENANCE will enumerate.
3. Copy the OpenSDA firmware binary to the USB mass storage device.
4. Power cycle the board, this time without holding the reset button. You should see two USB devices
enumerate: a CDC device (serial port) and a vendor-specific device (debug port).

J-Link External Debug Probe

Segger J-Link is a family of external debug probes, including J-Link EDU, J-Link PLUS, J-Link ULTRA+,
and J-Link PRO, that support a large number of devices from different hardware architectures and ven-
dors.
This debug probe is compatible with the following debug host tools:
• Enabling BOSSAC on Windows Native [Experimental]
• OpenOCD Debug Host Tools
Install the debug host tools before you program the firmware.

ST-LINK/V2-1 Onboard Debug Probe

ST-LINK/V2-1 is a serial and debug adapter built into all Nucleo and Discovery boards. It provides a
bridge between your computer (or other USB host) and the embedded target processor, which can be
used for debugging, flash programming, and serial communication, all over a simple USB cable.
It is compatible with the following host debug tools:
• OpenOCD Debug Host Tools
• Enabling BOSSAC on Windows Native [Experimental]
For some STM32 based boards, it is also compatible with:
• pyOCD Debug Host Tools
While it works out of the box with OpenOCD, it requires some flashing to work with J-Link. To do this,
SEGGER offers a firmware upgrading the ST-LINK/V2-1 on board on the Nucleo and Discovery boards.
This firmware makes the ST-LINK/V2-1 compatible with J-LinkOB, allowing users to take advantage of
most J-Link features like the ultra fast flash download and debugging speed or the free-to-use GDBServer.
More information about upgrading ST-LINK/V2-1 to JLink or restore ST-Link/V2-1 firmware please visit:
Segger over ST-Link

Flash and debug with ST-Link Using OpenOCD


OpenOCD is available by default on ST-Link and configured as the default flash and debug tool. Flash
and debug can be done as follows:

2.8. Flashing and Hardware Debugging 81


Zephyr Project Documentation, Release 3.4.0

# From the root of the zephyr repository


west build -b None samples/hello_world
west flash

# From the root of the zephyr repository


west build -b None samples/hello_world
west debug

Using Segger J-Link


Once STLink is flashed with SEGGER FW and J-Link GDB server is installed on your host computer, you
can flash and debug as follows:
Use CMake with -DBOARD_FLASH_RUNNER=jlink to change the default OpenOCD runner to J-Link. Al-
ternatively, you might add the following line to your application CMakeList.txt file.

set(BOARD_FLASH_RUNNER jlink)

If you use West (Zephyr’s meta-tool) you can modify the default runner using the --runner (or -r)
option.

west flash --runner jlink

To attach a debugger to your board and open up a debug console with jlink.

west debug --runner jlink

For more information about West and available options, see West (Zephyr’s meta-tool).
If you configured your Zephyr application to use Segger RTT console instead, open telnet:

$ telnet localhost 19021


Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
SEGGER J-Link V6.30f - Real time terminal output
J-Link STLink V21 compiled Jun 26 2017 10:35:16 V1.0, SN=773895351
Process: JLinkGDBServerCLExe
Zephyr Shell, Zephyr version: 1.12.99
Type 'help' for a list of available commands
shell>

If you get no RTT output you might need to disable other consoles which conflict with the RTT one
if they are enabled by default in the particular sample or application you are running, such as disable
UART_CONSOLE in menuconfig

Updating or restoring ST-Link firmware ST-Link firmware can be updated using


STM32CubeProgrammer Tool. It is usually useful when facing flashing issues, for instance when
using twister’s device-testing option.
Once installed, you can update attached board ST-Link firmware with the following command

s java -jar ~/STMicroelectronics/STM32Cube/STM32CubeProgrammer/Drivers/


˓→FirmwareUpgrade/STLinkUpgrade.jar -sn <board_uid>

Where board_uid can be obtained using twister’s generate-hardware-map option. For more information
about twister and available options, see Test Runner (Twister).

82 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

2.9 Modules (External projects)

Zephyr relies on the source code of several externally maintained projects in order to avoid reinventing
the wheel and to reuse as much well-established, mature code as possible when it makes sense. In the
context of Zephyr’s build system those are called modules. These modules must be integrated with the
Zephyr build system, as described in more detail in other sections on this page.
To be classified as a candidate for being included in the default list of modules, an external project is
required to have its own life-cycle outside the Zephyr Project, that is, reside in its own repository, and
have its own contribution and maintenance workflow and release process. Zephyr modules should not
contain code that is written exclusively for Zephyr. Instead, such code should be contributed to the main
zephyr tree.
Modules to be included in the default manifest of the Zephyr project need to provide functionality or
features endorsed and approved by the project Technical Steering Committee and should comply with
the module licensing requirements and contribution guidelines. They should also have a Zephyr developer
that is committed to maintain the module codebase.
Zephyr depends on several categories of modules, including but not limited to:
• Debugger integration
• Silicon vendor Hardware Abstraction Layers (HALs)
• Cryptography libraries
• File Systems
• Inter-Process Communication (IPC) libraries
Additionally, in some cases modules (particularly vendor HALs) can contain references to optional binary
blobs.
This page summarizes a list of policies and best practices which aim at better organizing the workflow in
Zephyr modules.

2.9.1 Modules vs west projects

Zephyr modules, described in this page, are not the same as west projects. In fact, modules do not require
west at all. However, when using modules with west, then the build system uses west in order to find
modules.
In summary:
Modules are repositories that contain a zephyr/module.yml file, so that the Zephyr build system can pull
in the source code from the repository. West projects are entries in the projects: section in the west.yml
manifest file. West projects are often also modules, but not always. There are west projects that are not
included in the final firmware image (eg. tools) and thus do not need to be modules. Modules are found
by the Zephyr build system either via west itself , or via the ZEPHYR_MODULES CMake variable.
The contents of this page only apply to modules, and not to west projects in general (unless they are a
module themselves).

2.9.2 Module Repositories

• All modules included in the default manifest shall be hosted in repositories under the zephyrproject-
rtos GitHub organization.
• The module repository codebase shall include a module.yml file in a zephyr/ folder at the root of
the repository.

2.9. Modules (External projects) 83


Zephyr Project Documentation, Release 3.4.0

• Module repository names should follow the convention of using lowercase letters and dashes in-
stead of underscores. This rule will apply to all new module repositories, except for repositories
that are directly tracking external projects (hosted in Git repositories); such modules may be named
as their external project counterparts.

Note: Existing module repositories that do not conform to the above convention do not need to
be renamed to comply with the above convention.

• Module repositories names should be explicitly set in the zephyr/module.yml file.


• Modules should use “zephyr” as the default name for the repository main branch. Branches for
specific purposes, for example, a module branch for an LTS Zephyr version, shall have names
starting with the ‘zephyr_’ prefix.
• If the module has an external (upstream) project repository, the module repository should preserve
the upstream repository folder structure.

Note: It is not required in module repositories to maintain a ‘master’ branch mirroring the master
branch of the external repository. It is not recommended as this may generate confusion around
the module’s main branch, which should be ‘zephyr’.

• Modules should expose all provided header files with an include pathname beginning
with the module-name. (E.g., mcuboot should expose its bootutil/bootutil.h as “mcu-
boot/bootutil/bootutil.h”.)

Synchronizing with upstream

It is preferred to synchronize a module repository with the latest stable release of the corresponding
external project. It is permitted, however, to update a Zephyr module repository with the latest develop-
ment branch tip, if this is required to get important updates in the module codebase. When synchronizing
a module with upstream it is mandatory to document the rationale for performing the particular update.

Requirements for allowed practices Changes to the main branch of a module repository, including
synchronization with upstream code base, may only be applied via pull requests. These pull requests shall
be verifiable by Zephyr CI and mergeable (e.g. with the Rebase and merge, or Create a merge commit option
using Github UI). This ensures that the incoming changes are always reviewable, and the downstream
module repository history is incremental (that is, existing commits, tags, etc. are always preserved). This
policy also allows to run Zephyr CI, git lint, identity, and license checks directly on the set of changes
that are to be brought into the module repository.

Note: Force-pushing to a module’s main branch is not allowed.

Allowed practices The following practices conform to the above requirements and should be followed
in all modules repositories. It is up to the module code owner to select the preferred synchronization
practice, however, it is required that the selected practice is consistently followed in the respective mod-
ule repository.
Updating modules with a diff from upstream: Upstream changes brought as a single snapshot commit
(manual diff) in a pull request against the module’s main branch, which may be merged using the Rebase
& merge operation. This approach is simple and should be applicable to all modules with the downside
of suppressing the upstream history in the module repository.

84 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

Note: The above practice is the only allowed practice in modules where the external project
is not hosted in an upstream Git repository.

The commit message is expected to identify the upstream project URL, the version to which the module
is updated (upstream version, tag, commit SHA, if applicable, etc.), and the reason for the doing the
update.
Updating modules by merging the upstream branch: Upstream changes brought in by performing a
Git merge of the intended upstream branch (e.g. main branch, latest release branch, etc.) submitting the
result in pull request against the module main branch, and merging the pull request using the Create a
merge commit operation. This approach is applicable to modules with an upstream project Git repository.
The main advantages of this approach is that the upstream repository history (that is, the original commit
SHAs) is preserved in the module repository. The downside of this approach is that two additional merge
commits are generated in the downstream main branch.

2.9.3 Contributing to Zephyr modules

Individual Roles & Responsibilities

To facilitate management of Zephyr module repositories, the following individual roles are defined.
Administrator: Each Zephyr module shall have an administrator who is responsible for managing access
to the module repository, for example, for adding individuals as Collaborators in the repository at the
request of the module owner. Module administrators are members of the Administrators team, that is a
group of project members with admin rights to module GitHub repositories.
Module owner: Each module shall have a module code owner. Module owners will have the overall
responsibility of the contents of a Zephyr module repository. In particular, a module owner will:
• coordinate code reviewing in the module repository
• be the default assignee in pull-requests against the repository’s main branch
• request additional collaborators to be added to the repository, as they see fit
• regularly synchronize the module repository with its upstream counterpart following the policies
described in Synchronizing with upstream
• be aware of security vulnerability issues in the external project and update the module repository
to include security fixes, as soon as the fixes are available in the upstream code base
• list any known security vulnerability issues, present in the module codebase, in Zephyr release
notes.

Note: Module owners are not required to be Zephyr Maintainers.

Merger: The Zephyr Release Engineering team has the right and the responsibility to merge approved
pull requests in the main branch of a module repository.

Maintaining the module codebase

Updates in the zephyr main tree, for example, in public Zephyr APIs, may require patching a module’s
codebase. The responsibility for keeping the module codebase up to date is shared between the contrib-
utor of such updates in Zephyr and the module owner. In particular:
• the contributor of the original changes in Zephyr is required to submit the corresponding changes
that are required in module repositories, to ensure that Zephyr CI on the pull request with the
original changes, as well as the module integration testing are successful.

2.9. Modules (External projects) 85


Zephyr Project Documentation, Release 3.4.0

• the module owner has the overall responsibility for synchronizing and testing the module codebase
with the zephyr main tree. This includes occasional advanced testing of the module’s codebase in
addition to the testing performed by Zephyr’s CI. The module owner is required to fix issues in the
module’s codebase that have not been caught by Zephyr pull request CI runs.

Contributing changes to modules

Submitting and merging changes directly to a module’s codebase, that is, before they have been merged
in the corresponding external project repository, should be limited to:
• changes required due to updates in the zephyr main tree
• urgent changes that should not wait to be merged in the external project first, such as fixes to
security vulnerabilities.
Non-trivial changes to a module’s codebase, including changes in the module design or functionality
should be discouraged, if the module has an upstream project repository. In that case, such changes shall
be submitted to the upstream project, directly.
Submitting changes to modules describes in detail the process of contributing changes to module reposi-
tories.

Contribution guidelines Contributing to Zephyr modules shall follow the generic project Contribution
guidelines.
Pull Requests: may be merged with minimum of 2 approvals, including an approval by the PR assignee.
In addition to this, pull requests in module repositories may only be merged if the introduced changes
are verified with Zephyr CI tools, as described in more detail in other sections on this page.
The merging of pull requests in the main branch of a module repository must be coupled with the
corresponding manifest file update in the zephyr main tree.
Issue Reporting: GitHub issues are intentionally disabled in module repositories, in favor of a central-
ized policy for issue reporting. Tickets concerning, for example, bugs or enhancements in modules shall
be opened in the main zephyr repository. Issues should be appropriately labeled using GitHub labels
corresponding to each module, where applicable.

Note: It is allowed to file bug reports for zephyr modules to track the corresponding up-
stream project bugs in Zephyr. These bug reports shall not affect the Release Quality Criteria.

2.9.4 Licensing requirements and policies

All source files in a module’s codebase shall include a license header, unless the module repository has
main license file that covers source files that do not include license headers.
Main license files shall be added in the module’s codebase by Zephyr developers, only if they exist as part
of the external project, and they contain a permissive OSI-compliant license. Main license files should
preferably contain the full license text instead of including an SPDX license identifier. If multiple main
license files are present it shall be made clear which license applies to each source file in a module’s
codebase.
Individual license headers in module source files supersede the main license.
Any new content to be added in a module repository will require to have license coverage.

Note: Zephyr recommends conveying module licensing via individual license headers and
main license files. This not a hard requirement; should an external project have its own
practice of conveying how licensing applies in the module’s codebase (for example, by having

86 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

a single or multiple main license files), this practice may be accepted by and be referred to
in the Zephyr module, as long as licensing requirements, for example OSI compliance, are
satisfied.

License policies

When creating a module repository a developer shall:


• import the main license files, if they exist in the external project, and
• document (for example in the module README or .yml file) the default license that covers the
module’s codebase.

License checks License checks (via CI tools) shall be enabled on every pull request that adds new
content in module repositories.

2.9.5 Documentation requirements

All Zephyr module repositories shall include an .rst file documenting:


• the scope and the purpose of the module
• how the module integrates with Zephyr
• the owner of the module repository
• synchronization information with the external project (commit, SHA, version etc.)
• licensing information as described in Licensing requirements and policies.
The file shall be required for the inclusion of the module and the contained information should be kept
up to date.

2.9.6 Testing requirements

All Zephyr modules should provide some level of integration testing, ensuring that the integration with
Zephyr works correctly. Integration tests:
• may be in the form of a minimal set of samples and tests that reside in the zephyr main tree
• should verify basic usage of the module (configuration, functional APIs, etc.) that is integrated
with Zephyr.
• shall be built and executed (for example in QEMU) as part of twister runs in pull requests that
introduce changes in module repositories.

Note: New modules, that are candidates for being included in the Zephyr default manifest, shall
provide some level of integration testing.

Note: Vendor HALs are implicitly tested via Zephyr tests built or executed on target platforms, so
they do not need to provide integration tests.

The purpose of integration testing is not to provide functional verification of the module; this should be
part of the testing framework of the external project.

2.9. Modules (External projects) 87


Zephyr Project Documentation, Release 3.4.0

Certain external projects provide test suites that reside in the upstream testing infrastructure but are
written explicitly for Zephyr. These tests may (but are not required to) be part of the Zephyr test frame-
work.

2.9.7 Deprecating and removing modules

Modules may be deprecated for reasons including, but not limited to:
• Lack of maintainership in the module
• Licensing changes in the external project
• Codebase becoming obsolete
The module information shall indicate whether a module is deprecated and the build system shall issue
a warning when trying to build Zephyr using a deprecated module.
Deprecated modules may be removed from the Zephyr default manifest after 2 Zephyr releases.

Note: Repositories of removed modules shall remain accessible via their original URL, as
they are required by older Zephyr versions.

2.9.8 Integrate modules in Zephyr build system

The build system variable ZEPHYR_MODULES is a CMake list of absolute paths to the directories containing
Zephyr modules. These modules contain CMakeLists.txt and Kconfig files describing how to build
and configure them, respectively. Module CMakeLists.txt files are added to the build using CMake’s
add_subdirectory() command, and the Kconfig files are included in the build’s Kconfig menu tree.
If you have west installed, you don’t need to worry about how this variable is defined unless you are
adding a new module. The build system knows how to use west to set ZEPHYR_MODULES. You can add
additional modules to this list by setting the EXTRA_ZEPHYR_MODULES CMake variable or by adding a
EXTRA_ZEPHYR_MODULES line to .zephyrrc (See the section on Environment Variables for more details).
This can be useful if you want to keep the list of modules found with west and also add your own.

Note: If the module FOO is provided by west but also given with -DEXTRA_ZEPHYR_MODULES=/<path>/
foo then the module given by the command line variable EXTRA_ZEPHYR_MODULES will take precedence.
This allows you to use a custom version of FOO when building and still use other Zephyr modules provided
by west. This can for example be useful for special test purposes.

If you want to permanently add modules to the zephyr workspace and you are using zephyr as your
manifest repository, you can also add a west manifest file into the submanifests directory. See submani-
fests/README.txt for more details.
See Basics for more on west workspaces.
Finally, you can also specify the list of modules yourself in various ways, or not use modules at all if your
application doesn’t need them.

2.9.9 Module yaml file description

A module can be described using a file named zephyr/module.yml. The format of zephyr/module.yml
is described in the following:

88 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

Module name

Each Zephyr module is given a name by which it can be referred to in the build system.
The name should be specified in the zephyr/module.yml file. This will ensure the module name is not
changeable through user-defined directory names or west manifest files:

name: <name>

In CMake the location of the Zephyr module can then be referred to using the CMake variable
ZEPHYR_<MODULE_NAME>_MODULE_DIR and the variable ZEPHYR_<MODULE_NAME>_CMAKE_DIR holds the lo-
cation of the directory containing the module’s CMakeLists.txt file.

Note: When used for CMake and Kconfig variables, all letters in module names are converted to up-
percase and all non-alphanumeric characters are converted to underscores (_). As example, the module
foo-bar must be referred to as ZEPHYR_FOO_BAR_MODULE_DIR in CMake and Kconfig.

Here is an example for the Zephyr module foo:

name: foo

Note: If the name field is not specified then the Zephyr module name will be set to the name of the
module folder. As example, the Zephyr module located in <workspace>/modules/bar will use bar as its
module name if nothing is specified in zephyr/module.yml.

Module integration files (in-module)

Inclusion of build files, CMakeLists.txt and Kconfig, can be described as:

build:
cmake: <cmake-directory>
kconfig: <directory>/Kconfig

The cmake: <cmake-directory> part specifies that <cmake-directory> contains the CMakeLists.txt
to use. The kconfig: <directory>/Kconfig part specifies the Kconfig file to use. Neither is required:
cmake defaults to zephyr, and kconfig defaults to zephyr/Kconfig.
Here is an example module.yml file referring to CMakeLists.txt and Kconfig files in the root directory
of the module:

build:
cmake: .
kconfig: Kconfig

Sysbuild integration

Sysbuild is the Zephyr build system that allows for building multiple images as part of a single application,
the sysbuild build process can be extended externally with modules as needed, for example to add custom
build steps or add additional targets to a build. Inclusion of sysbuild-specific build files, CMakeLists.txt
and Kconfig, can be described as:

build:
sysbuild-cmake: <cmake-directory>
sysbuild-kconfig: <directory>/Kconfig

2.9. Modules (External projects) 89


Zephyr Project Documentation, Release 3.4.0

The sysbuild-cmake: <cmake-directory> part specifies that <cmake-directory> contains the


CMakeLists.txt to use. The sysbuild-kconfig: <directory>/Kconfig part specifies the Kconfig
file to use.
Here is an example module.yml file referring to CMakeLists.txt and Kconfig files in the sysbuild direc-
tory of the module:

build:
sysbuild-cmake: sysbuild
sysbuild-kconfig: sysbuild/Kconfig

The module description file zephyr/module.yml can also be used to specify that the build files,
CMakeLists.txt and Kconfig, are located in a Module integration files (external).
Build files located in a MODULE_EXT_ROOT can be described as:

build:
sysbuild-cmake-ext: True
sysbuild-kconfig-ext: True

This allows control of the build inclusion to be described externally to the Zephyr module.

Build system integration

When a module has a module.yml file, it will automatically be included into the Zephyr build system.
The path to the module is then accessible through Kconfig and CMake variables.

Zephyr modules In both Kconfig and CMake, the variable ZEPHYR_<MODULE_NAME>_MODULE_DIR con-
tains the absolute path to the module.
In CMake, ZEPHYR_<MODULE_NAME>_CMAKE_DIR contains the absolute path to the directory containing
the CMakeLists.txt file that is included into CMake build system. This variable’s value is empty if the
module.yml file does not specify a CMakeLists.txt.
To read these variables for a Zephyr module named foo:
• In CMake: use ${ZEPHYR_FOO_MODULE_DIR} for the module’s top level directory, and
${ZEPHYR_FOO_CMAKE_DIR} for the directory containing its CMakeLists.txt
• In Kconfig: use $(ZEPHYR_FOO_MODULE_DIR) for the module’s top level directory
Notice how a lowercase module name foo is capitalized to FOO in both CMake and Kconfig.
These variables can also be used to test whether a given module exists. For example, to verify that foo
is the name of a Zephyr module:

if(ZEPHYR_FOO_MODULE_DIR)
# Do something if FOO exists.
endif()

In Kconfig, the variable may be used to find additional files to include. For example, to include the file
some/Kconfig in module foo:

source "$(ZEPHYR_FOO_MODULE_DIR)/some/Kconfig"

During CMake processing of each Zephyr module, the following two variables are also available:
• the current module’s top level directory: ${ZEPHYR_CURRENT_MODULE_DIR}
• the current module’s CMakeLists.txt directory: ${ZEPHYR_CURRENT_CMAKE_DIR}
This removes the need for a Zephyr module to know its own name during CMake processing. The module
can source additional CMake files using these CURRENT variables. For example:

90 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

include(${ZEPHYR_CURRENT_MODULE_DIR}/cmake/code.cmake)

It is possible to append values to a Zephyr CMake list variable from the module’s first CMakeLists.txt file.
To do so, append the value to the list and then set the list in the PARENT_SCOPE of the CMakeLists.txt
file. For example, to append bar to the FOO_LIST variable in the Zephyr CMakeLists.txt scope:

list(APPEND FOO_LIST bar)


set(FOO_LIST ${FOO_LIST} PARENT_SCOPE)

An example of a Zephyr list where this is useful is when adding additional directories to the
SYSCALL_INCLUDE_DIRS list.

Sysbuild modules In both Kconfig and CMake, the variable SYSBUILD_CURRENT_MODULE_DIR contains
the absolute path to the sysbuild module. In CMake, SYSBUILD_CURRENT_CMAKE_DIR contains the abso-
lute path to the directory containing the CMakeLists.txt file that is included into CMake build system.
This variable’s value is empty if the module.yml file does not specify a CMakeLists.txt.
To read these variables for a sysbuild module:
• In CMake: use ${SYSBUILD_CURRENT_MODULE_DIR} for the module’s top level directory, and
${SYSBUILD_CURRENT_CMAKE_DIR} for the directory containing its CMakeLists.txt
• In Kconfig: use $(SYSBUILD_CURRENT_MODULE_DIR) for the module’s top level directory
In Kconfig, the variable may be used to find additional files to include. For example, to include the file
some/Kconfig:

source "$(SYSBUILD_CURRENT_MODULE_DIR)/some/Kconfig"

The module can source additional CMake files using these variables. For example:

include(${SYSBUILD_CURRENT_MODULE_DIR}/cmake/code.cmake)

It is possible to append values to a Zephyr CMake list variable from the module’s first CMakeLists.txt file.
To do so, append the value to the list and then set the list in the PARENT_SCOPE of the CMakeLists.txt
file. For example, to append bar to the FOO_LIST variable in the Zephyr CMakeLists.txt scope:

list(APPEND FOO_LIST bar)


set(FOO_LIST ${FOO_LIST} PARENT_SCOPE)

Sysbuild modules hooks Sysbuild provides an infrastructure which allows a sysbuild module to define
a function which will be invoked by sysbuild at a pre-defined point in the CMake flow.
Functions invoked by sysbuild:
• <module-name>_pre_cmake(IMAGES <images>): This function is called for each sysbuild module
before CMake configure is invoked for all images.
• <module-name>_post_cmake(IMAGES <images>): This function is called for each sysbuild module
after CMake configure has completed for all images.
• <module-name>_pre_domains(IMAGES <images>): This function is called for each sysbuild mod-
ule before domains yaml is created by sysbuild.
• <module-name>_post_domains(IMAGES <images>): This function is called for each sysbuild mod-
ule after domains yaml has been created by sysbuild.
arguments passed from sysbuild to the function defined by a module:
• <images> is the list of Zephyr images that will be created by the build system.

2.9. Modules (External projects) 91


Zephyr Project Documentation, Release 3.4.0

If a module foo want to provide a post CMake configure function, then the module’s sysbuild
CMakeLists.txt file must define function foo_post_cmake().
To facilitate naming of functions, the module name is provided by sysbuild CMake through the
SYSBUILD_CURRENT_MODULE_NAME CMake variable when loading the module’s sysbuild CMakeLists.txt
file.
Example of how the foo sysbuild module can define foo_post_cmake():
function(${SYSBUILD_CURRENT_MODULE_NAME}_post_cmake)
cmake_parse_arguments(POST_CMAKE "" "" "IMAGES" ${ARGN})

message("Invoking ${CMAKE_CURRENT_FUNCTION}. Images: ${POST_CMAKE_IMAGES}")


endfunction()

Zephyr module dependencies

A Zephyr module may be dependent on other Zephyr modules to be present in order to function correctly.
Or it might be that a given Zephyr module must be processed after another Zephyr module, due to
dependencies of certain CMake targets.
Such a dependency can be described using the depends field.
build:
depends:
- <module>

Here is an example for the Zephyr module foo that is dependent on the Zephyr module bar to be present
in the build system:
name: foo
build:
depends:
- bar

This example will ensure that bar is present when foo is included into the build system, and it will also
ensure that bar is processed before foo.

Module integration files (external)

Module integration files can be located externally to the Zephyr module itself. The MODULE_EXT_ROOT
variable holds a list of roots containing integration files located externally to Zephyr modules.

Module integration files in Zephyr The Zephyr repository contain CMakeLists.txt and Kconfig
build files for certain known Zephyr modules.
Those files are located under
<ZEPHYR_BASE>
modules
<module_name>
CMakeLists.txt
Kconfig

Module integration files in a custom location You can create a similar MODULE_EXT_ROOT for addi-
tional modules, and make those modules known to Zephyr build system.
Create a MODULE_EXT_ROOT with the following structure

92 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

<MODULE_EXT_ROOT>
modules
modules.cmake
<module_name>
CMakeLists.txt
Kconfig

and then build your application by specifying -DMODULE_EXT_ROOT parameter to the CMake build system.
The MODULE_EXT_ROOT accepts a CMake list of roots as argument.
A Zephyr module can automatically be added to the MODULE_EXT_ROOT list using the module description
file zephyr/module.yml, see Build settings.

Note: ZEPHYR_BASE is always added as a MODULE_EXT_ROOT with the lowest priority. This allows you
to overrule any integration files under <ZEPHYR_BASE>/modules/<module_name> with your own imple-
mentation your own MODULE_EXT_ROOT.

The modules.cmake file must contain the logic that specifies the integration files for Zephyr modules via
specifically named CMake variables.
To include a module’s CMake file, set the variable ZEPHYR_<MODULE_NAME>_CMAKE_DIR to the path con-
taining the CMake file.
To include a module’s Kconfig file, set the variable ZEPHYR_<MODULE_NAME>_KCONFIG to the path to the
Kconfig file.
The following is an example on how to add support the the FOO module.
Create the following structure

<MODULE_EXT_ROOT>
modules
modules.cmake
foo
CMakeLists.txt
Kconfig

and inside the modules.cmake file, add the following content

set(ZEPHYR_FOO_CMAKE_DIR ${CMAKE_CURRENT_LIST_DIR}/foo)
set(ZEPHYR_FOO_KCONFIG ${CMAKE_CURRENT_LIST_DIR}/foo/Kconfig)

Module integration files (zephyr/module.yml) The module description file zephyr/module.yml can
be used to specify that the build files, CMakeLists.txt and Kconfig, are located in a Module integration
files (external).
Build files located in a MODULE_EXT_ROOT can be described as:

build:
cmake-ext: True
kconfig-ext: True

This allows control of the build inclusion to be described externally to the Zephyr module.
The Zephyr repository itself is always added as a Zephyr module ext root.

2.9. Modules (External projects) 93


Zephyr Project Documentation, Release 3.4.0

Build settings

It is possible to specify additional build settings that must be used when including the module into the
build system.
All root settings are relative to the root of the module.
Build settings supported in the module.yml file are:
• board_root: Contains additional boards that are available to the build system. Additional boards
must be located in a <board_root>/boards folder.
• dts_root: Contains additional dts files related to the architecture/soc families. Additional dts files
must be located in a <dts_root>/dts folder.
• snippet_root: Contains additional snippets that are available for use. These snippets must
be defined in snippet.yml files underneath the <snippet_root>/snippets folder. For exam-
ple, if you have snippet_root: foo, then you should place your module’s snippet.yml files in
<your-module>/foo/snippets or any nested subdirectory.
• soc_root: Contains additional SoCs that are available to the build system. Additional SoCs must
be located in a <soc_root>/soc folder.
• arch_root: Contains additional architectures that are available to the build system. Additional
architectures must be located in a <arch_root>/arch folder.
• module_ext_root: Contains CMakeLists.txt and Kconfig files for Zephyr modules, see also Mod-
ule integration files (external).
• sca_root: Contains additional SCA tool implementations available to the build system. Each tool
must be located in <sca_root>/sca/<tool> folder. The folder must contain a sca.cmake.
Example of a module.yaml file containing additional roots, and the corresponding file system layout.
build:
settings:
board_root: .
dts_root: .
soc_root: .
arch_root: .
module_ext_root: .

requires the following folder structure:


<zephyr-module-root>
arch
boards
dts
modules
soc

Twister (Test Runner)

To execute both tests and samples available in modules, the Zephyr test runner (twister) should be
pointed to the directories containing those samples and tests. This can be done by specifying the path
to both samples and tests in the zephyr/module.yml file. Additionally, if a module defines out of tree
boards, the module file can point twister to the path where those files are maintained in the module. For
example:
build:
cmake: .
samples:
(continues on next page)

94 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

(continued from previous page)


- samples
tests:
- tests
boards:
- boards

Binary Blobs

Zephyr supports fetching and using binary blobs, and their metadata is contained entirely in zephyr/
module.yml. This is because a binary blob must always be associated with a Zephyr module, and thus
the blob metadata belongs in the module’s description itself.
Binary blobs are fetched using west blobs. If west is not used, they must be downloaded and verified
manually.
The blobs section in zephyr/module.yml consists of a sequence of maps, each of which has the following
entries:
• path: The path to the binary blob, relative to the zephyr/blobs/ folder in the module repository
• sha256: SHA-256 checksum of the binary blob file
• type: The type of binary blob. Currently limited to img or lib
• version: A version string
• license-path: Path to the license file for this blob, relative to the root of the module repository
• url: URL that identifies the location the blob will be fetched from, as well as the fetching scheme
to use
• description: Human-readable description of the binary blob
• doc-url: A URL pointing to the location of the official documentation for this blob

Module Inclusion

Using West If west is installed and ZEPHYR_MODULES is not already set, the build system finds all the
modules in your west installation and uses those. It does this by running west list to get the paths of
all the projects in the installation, then filters the results to just those projects which have the necessary
module metadata files.
Each project in the west list output is tested like this:
• If the project contains a file named zephyr/module.yml, then the content of that file will be used
to determine which files should be added to the build, as described in the previous section.
• Otherwise (i.e. if the project has no zephyr/module.yml), the build system looks for zephyr/
CMakeLists.txt and zephyr/Kconfig files in the project. If both are present, the project is con-
sidered a module, and those files will be added to the build.
• If neither of those checks succeed, the project is not considered a module, and is not added to
ZEPHYR_MODULES.

Without West If you don’t have west installed or don’t want the build system to use it to find Zephyr
modules, you can set ZEPHYR_MODULES yourself using one of the following options. Each of the directo-
ries in the list must contain either a zephyr/module.yml file or the files zephyr/CMakeLists.txt and
Kconfig, as described in the previous section.
1. At the CMake command line, like this:

2.9. Modules (External projects) 95


Zephyr Project Documentation, Release 3.4.0

cmake -DZEPHYR_MODULES=<path-to-module1>[;<path-to-module2>[...]] ...

2. At the top of your application’s top level CMakeLists.txt, like this:

set(ZEPHYR_MODULES <path-to-module1> <path-to-module2> [...])


find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})

If you choose this option, make sure to set the variable before calling find_package(Zephyr ...),
as shown above.
3. In a separate CMake script which is pre-loaded to populate the CMake cache, like this:

# Put this in a file with a name like "zephyr-modules.cmake"


set(ZEPHYR_MODULES <path-to-module1> <path-to-module2>
CACHE STRING "pre-cached modules")

You can tell the build system to use this file by adding -C zephyr-modules.cmake to your CMake
command line.

Not using modules If you don’t have west installed and don’t specify ZEPHYR_MODULES yourself, then
no additional modules are added to the build. You will still be able to build any applications that don’t
require code or Kconfig options defined in an external repository.

2.9.10 Submitting changes to modules

When submitting new or making changes to existing modules the main repository Zephyr needs a ref-
erence to the changes to be able to verify the changes. In the main tree this is done using revisions.
For code that is already merged and part of the tree we use the commit hash, a tag, or a branch name.
For pull requests however, we require specifying the pull request number in the revision field to allow
building the zephyr main tree with the changes submitted to the module.
To avoid merging changes to master with pull request information, the pull request should be marked as
DNM (Do Not Merge) or preferably a draft pull request to make sure it is not merged by mistake and to
allow for the module to be merged first and be assigned a permanent commit hash. Drafts reduce noise
by not automatically notifying anyone until marked as “Ready for review”. Once the module is merged,
the revision will need to be changed either by the submitter or by the maintainer to the commit hash of
the module which reflects the changes.
Note that multiple and dependent changes to different modules can be submitted using exactly the same
process. In this case you will change multiple entries of all modules that have a pull request against
them.

Process for submitting a new module

Please follow the process in Submission and review process and obtain the TSC approval to integrate the
external source code as a module
If the request is approved, a new repository will created by the project team and initialized with basic
information that would allow submitting code to the module project following the project contribution
guidelines.
If a module is maintained as a fork of another project on Github, the Zephyr module related files and
changes in relation to upstream need to be maintained in a special branch named zephyr.
Maintainers from the Zephyr project will create the repository and initialize it. You will be added as a
collaborator in the new repository. Submit the module content (code) to the new repository following
the guidelines described here, and then add a new entry to the west.yml with the following information:

96 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

- name: <name of repository>


path: <path to where the repository should be cloned>
revision: <ref pointer to module pull request>

For example, to add my_module to the manifest:

- name: my_module
path: modules/lib/my_module
revision: pull/23/head

Where 23 in the example above indicated the pull request number submitted to the my_module reposi-
tory. Once the module changes are reviewed and merged, the revision needs to be changed to the commit
hash from the module repository.

Process for submitting changes to existing modules

1. Submit the changes using a pull request to an existing repository following the contribution guide-
lines and expectations.
2. Submit a pull request changing the entry referencing the module into the west.yml of the main
Zephyr tree with the following information:

- name: <name of repository>


path: <path to where the repository should be cloned>
revision: <ref pointer to module pull request>

For example, to add my_module to the manifest:

- name: my_module
path: modules/lib/my_module
revision: pull/23/head

Where 23 in the example above indicated the pull request number submitted to the my_module reposi-
tory. Once the module changes are reviewed and merged, the revision needs to be changed to the commit
hash from the module repository.

2.10 West (Zephyr’s meta-tool)

The Zephyr project includes a swiss-army knife command line tool named west1 . West is developed in
its own repository.
West’s built-in commands provide a multiple repository management system with features inspired by
Google’s Repo tool and Git submodules. West is also “pluggable”: you can write your own west extension
commands which add additional features to west. Zephyr uses this to provide conveniences for building
applications, flashing and debugging them, and more.
Like git and docker, the top-level west command takes some common options, a sub-command to run,
and then options and arguments for that sub-command:

west [common-opts] <command> [opts] <args>

Since west v0.8, you can also run west like this:

python3 -m west [common-opts] <command> [opts] <args>


1 Zephyr is an English name for the Latin Zephyrus, the ancient Greek god of the west wind.

2.10. West (Zephyr’s meta-tool) 97


Zephyr Project Documentation, Release 3.4.0

You can run west --help (or west -h for short) to get top-level help for available west commands, and
west <command> -h for detailed help on each command.
The following pages document west’s v1.0.y releases, and provide additional context about the tool.

2.10.1 Installing west

West is written in Python 3 and distributed through PyPI. Use pip3 to install or upgrade west:
On Linux:

pip3 install --user -U west

On Windows and macOS:

pip3 install -U west

Note: See Python and pip for additional clarification on using the --user switch.

Afterwards, you can run pip3 show -f west for information on where the west binary and related files
were installed.
Once west is installed, you can use it to clone the Zephyr repositories.

Structure

West’s code is distributed via PyPI in a Python package named west. This distribution includes a launcher
executable, which is also named west (or west.exe on Windows).
When west is installed, the launcher is placed by pip3 somewhere in the user’s filesystem (exactly where
depends on the operating system, but should be on the PATH environment variable). This launcher is the
command-line entry point to running both built-in commands like west init, west update, along with
any extensions discovered in the workspace.
In addition to its command-line interface, you can also use west’s Python APIs directly. See west-apis for
details.

Enabling shell completion

West currently supports shell completion in the following combinations of platform and shell:
• Linux: bash
• macOS: bash
• Windows: not available
In order to enable shell completion, you will need to obtain the corresponding completion script and
have it sourced every time you enter a new shell session.
To obtain the completion script you can use the west completion command:

cd /path/to/zephyr/
west completion bash > ~/west-completion.bash

Note: Remember to update your local copy of the completion script using west completion when you
update Zephyr.

98 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

Next, you need to import west-completion.bash into your bash shell.


On Linux, you have the following options:
• Copy west-completion.bash to /etc/bash_completion.d/.
• Copy west-completion.bash to /usr/share/bash-completion/completions/.
• Copy west-completion.bash to a local folder and source it from your ~/.bashrc.
On macOS, you have the following options:
• Copy west-completion.bash to a local folder and source it from your ~/.bash_profile
• Install the bash-completion package with brew:

brew install bash-completion

then source the main bash completion script in your ~/.bash_profile:

source /usr/local/etc/profile.d/bash_completion.sh

and finally copy west-completion.bash to /usr/local/etc/bash_completion.d/.

2.10.2 West Release Notes

v1.1.0

Major changes:
• west compare: new command that compares the state of the workspace against the manifest.
• Support for a new manifest.project-filter configuration option. See Built-in Configuration Op-
tions for details. The west manifest --freeze and west manifest --resolve commands cur-
rently cannot be used when this option is set. This restriction can be removed in a later release.
• Project names which contain comma (,) or whitespace now generate warnings. These warnings
are errors if the new manifest.project-filter configuration option is set. The warnings may be
promoted to errors in a future major version of west.
Other changes:
• west forall now takese a --group argument that can be used to restrict the command to only
run in one or more groups. Run west help forall for details.
• All west commands will now output log messages from west API modules at warning level or
higher. In addition, the --verbose argument to west can be used once to include informational
messages, or twice to include debug messages, from all commands.
Bug fixes:
• Various improvements to error messages, debug logging, and error handling.
API changes:
• west.manifest.Manifest.is_active() now respects the manifest.project-filter configura-
tion option’s value.

v1.0.1

Major changes:
• Manifest schema version “1.0” is now available for use in this release. This is identical to the “0.13”
schema version in terms of features, but can be used by applications that do not wish to use a “0.x”
manifest “version:” field. See Version for details on this feature.

2.10. West (Zephyr’s meta-tool) 99


Zephyr Project Documentation, Release 3.4.0

Bug fixes:
• West no longer exits with a successful error code when sent an interrupt signal. Instead, it exits
with a platform-specific error code and signals to the calling environment that the process was
interrupted.

v1.0.0

Major changes in this release:


• The west-apis are now declared stable. Any breaking changes will be communicated by a major
version bump from v1.x.y to v2.x.y.
• West v1.0 no longer works with the Zephyr v1.14 LTS releases. This LTS has long been obsoleted
by Zephyr v2.7 LTS. If you need to use Zephyr v1.14, you must use west v0.14 or earlier.
• Like the rest of Zephyr, west now requires Python v3.8 or later
• West commands no longer accept abbreviated command line arguments. For example, you must
now specify west update --keep-descendants instead of using an abbreviation like west update
--keep-d. This is part of a change applied to all of Zephyr’s Python scripts’ command-line inter-
faces. The abbreviations were causing problems in practice when commands were updated to add
new options with similar names but different behavior to existing ones.
Other changes:
• All built-in west functions have stopped using west.log
• west update: new --submodule-init-config option. See commit 9ba92b05 for details.
Bug fixes:
• West extension commands that failed to load properly sometimes dumped stack. This has been
fixed and west now prints a sensible error message in this case.
• west config now fails on malformed configuration option arguments which lack a . in the option
name
API changes:
• The west package now contains the metadata files necessary for some static analyzers (such as
mypy) to auto-detect its type annotations. See commit d9f00e24 for details.
• the deprecated west.build module used for Zephyr v1.14 LTS compatibility was removed
• the deprecated west.cmake module used for Zephyr v1.14 LTS compatibility was removed
• the west.log module is now deprecated. This module uses global state, which can make it awk-
ward to use it as an API which multiple different python modules may rely on.
• The west-apis-commands module got some new APIs which lay groundwork for a future change to
add a global verbosity control to a command’s output, and work to remove global state from the
west package’s API:
– New west.commands.WestCommand.__init__() keyword argument: verbosity
– New west.commands.WestCommand property: color_ui
– New west.commands.WestCommand methods, which should be used to print output from ex-
tension commands instead of writing directly to sys.stdout or sys.stderr: inf(), wrn(), err(),
die(), banner(), small_banner()
– New west.commands.VERBOSITY enum

100 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

v0.14.0

Bug fixes:
• West commands that were run with a bad local configuration file dumped stack in a confusing way.
This has been fixed and west now prints a sensible error message in this case.
• A bug in the way west looks for the zephyr repository was fixed. The bug itself usually appeared
when running an extension command like west build in a new workspace for the first time; this
used to fail (just for the first time, not on subsequent command invocations) unless you ran the
command in the workspace’s top level directory.
• West now prints sensible error messages when the user lacks permission to open the manifest file
instead of dumping stack traces.
API changes:
• The west.manifest.MalformedConfig exception type has been moved to the west.
configuration module
• The west.manifest.MalformedConfig exception type has been moved to the west.configuration
module
• The west.configuration.Configuration class now raises MalformedConfig instead of
RuntimeError in some cases

v0.13.1

Bug fix:
• When calling west.manifest.Manifest.from_file() when outside of a workspace, west again falls
back on the ZEPHYR_BASE environment variable to locate the workspace.

v0.13.0

New features:
• You can now associate arbitrary user data with the manifest repository itself in the manifest:
self: userdata: value, like so:

manifest:
self:
userdata: <any YAML value can go here>

Bug fixes:
• The path to the manifest repository reported by west could be incorrect in certain circumstances
detailed in [issue #572](https://github.com/zephyrproject-rtos/west/issues/572). This has been
fixed as part of a larger overhaul of path handling support in the west.manifest API module.
• The west.Manifest.ManifestProject.__repr__ return value was fixed
API changes:
• west.configuration.Configuration: new object-oriented interface to the current configuration.
This reflects the system, global, and workspace-local configuration values, and allows you to read,
write, and delete configuration options from any or all of these locations.
• west.commands.WestCommand:
– config: new attribute, returns a Configuration object or aborts the program if none is set.
This is always usable from within extension command do_run() implementations.

2.10. West (Zephyr’s meta-tool) 101


Zephyr Project Documentation, Release 3.4.0

– has_config: new boolean attribute, which is True if and only if reading self.config will
abort the program.
• The path handling in the west.manifest package has been overhauled in a backwards-
incompatible way. For more details, see commit [56cfe8d1d1](https://github.com/
zephyrproject-rtos/west/commit/56cfe8d1d1f3c9b45de3e793c738acd62db52aca).
• west.manifest.Manifest.validate(): this now returns the validated data as a Python dict. This
can be useful if the value passed to this function was a str, and the dict is desired.
• west.manifest.Manifest: new:
– path attributes abspath, posixpath, relative_path, yaml_path, repo_path,
repo_posixpath
– userdata attribute, which contains the parsed value from manifest: self: userdata:,
or is None
– from_topdir() factory method
• west.manifest.ManifestProject: new userdata attribute, which also contains the parsed value
from manifest: self: userdata:, or is None
• west.manifest.ManifestImportFailed: the constructor can now take any value; this can be used
to reflect failed imports from a map or other compound value.
• Deprecated configuration APIs:
The following APIs are now deprecated in favor of using a Configuration object. Usually this
will be done via self.config from a WestCommand instance, but this can be done directly by
instantiating a Configuration object for other usages.
– west.configuration.config
– west.configuration.read_config
– west.configuration.update_config
– west.configuration.delete_config

v0.12.0

New features:
• West now works on the MSYS2 platform.
• West manifest files can now contain arbitrary user data associated with each project. See Repository
user data for details.
Bug fixes:
• The west list command’s {sha} format key has been fixed for the manifest repository; it now
prints N/A (“not applicable”) as expected.
API changes:
• The west.manifest.Project.userdata attribute was added to support project user data.

v0.11.1

New features:
• west status now only prints output for projects which have a nonempty status.
Bug fixes:

102 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

• The manifest file parser was incorrectly allowing project names which contain the path separator
characters / and \. These invalid characters are now rejected.
Note: if you need to place a project within a subdirectory of the workspace topdir, use the
path: key. If you need to customize a project’s fetch URL relative to its remote url-base:, use
repo-path:. See Projects for examples.
• The changes made in west v0.10.1 to the west init --manifest-rev option which selected the
default branch name were leaving the manifest repository in a detached HEAD state. This has
been fixed by using git clone internally instead of git init and git fetch. See issue #522 for
details.
• The WEST_CONFIG_LOCAL environment variable now correctly overrides the default location,
<workspace topdir>/.west/config.
• west update --fetch=smart (smart is the default) now correctly skips fetches for project revi-
sions which are lightweight tags (it already worked correctly for annotated tags; only lightweight
tags were unnecessarily fetched).
Other changes:
• The fix for issue #522 mentioned above introduces a new restriction. The west init
--manifest-rev option value, if given, must now be either a branch or a tag. In particular,
“pseudo-branches” like GitHub’s pull/1234/head references which could previously be used to
fetch a pull request can no longer be passed to --manifest-rev. Users must now fetch and check
out such revisions manually after running west init.
API changes:
• west.manifest.Manifest.get_projects() avoids incorrect results in some edge cases described
in issue #523.
• west.manifest.Project.sha() now works correctly for tag revisions. (This applies to both
lightweight and annotated tags.)

v0.11.0

New features:
• west update now supports --narrow, --name-cache, and --path-cache options. These can be
influenced by the update.narrow, update.name-cache, and update.path-cache Configuration
options. These can be used to optimize the speed of the update.
• west update now supports a --fetch-opt option that will be passed to the git fetch command
used to fetch remote revisions when updating each project.
Bug fixes:
• west update now synchronizes Git submodules in projects by default. This avoids issues if the
URL changes in the manifest file from when the submodule was first initialized. This behavior can
be disabled by setting the update.sync-submodules configuration option to false.
Other changes:
• the west-apis-manifest module has fixed docstrings for the Project class

v0.10.1

New features:
• The west init command’s --manifest-rev (--mr) option no longer defaults to master. Instead, the
command will query the repository for its default branch name and use that instead. This allows
users to move from master to main without breaking scripts that do not provide this option.

2.10. West (Zephyr’s meta-tool) 103


Zephyr Project Documentation, Release 3.4.0

v0.10.0

New features:
• The name key in a project’s submodules list is now optional.
Bug fixes:
• West now checks that the manifest schema version is one of the explicitly allowed vlaues docu-
mented in Version. The old behavior was just to check that the schema version was newer than
the west version where the manifest: version: key was introduced. This incorrectly allowed
invalid schema versions, like 0.8.2.
Other changes:
• A manifest file’s group-filter is now propagated through an import. This is a change from how
west v0.9.x handled this. In west v0.9.x, only the top level manifest file’s group-filter had any
effect; the group filter lists from any imported manifests were ignored.
Starting with west v0.10.0, the group filter lists from imported manifests are also imported. For
details, see Group Filters and Imports.
The new behavior will take effect if manifest: version: is not given or is at least 0.10. The old
behavior is still available in the top level manifest file only with an explicit manifest: version:
0.9. See Version for more information on schema versions.
See west pull request #482 for the motivation for this change and additional context.

v0.9.1

Bug fixes:
• Commands like west manifest --resolve now correctly include group and group filter informa-
tion.
Other changes:
• West now warns if you combine import with group-filter. Semantics for this combination have
changed starting with v0.10.x. See the v0.10.0 release notes above for more information.

v0.9.0

Warning: The west config fix described below comes at a cost: any comments or other manual
edits in configuration files will be removed when setting a configuration option via that command or
the west.configuration API.

Warning: Combining the group-filter feature introduced in this release with manifest imports is
discouraged. The resulting behavior has changed in west v0.10.

New features:
• West manifests now support Git Submodules in Projects. This allows you to clone Git submodules
into a west project repository in addition to the project repository itself.
• West manifests now support Project Groups. Project groups can be enabled and disabled to de-
termine what projects are “active”, and therefore will be acted upon by the following commands:
west update, west list, west diff, west status, west forall.

104 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

• west update no longer updates inactive projects by default. It now supports a --group-filter
option which allows for one-time modifications to the set of enabled and disabled project groups.
• Running west list, west diff, west status, or west forall with no arguments does not print
information for inactive projects by default. If the user specifies a list of projects explicitly at the
command line, output for them is included regardless of whether they are active.
These commands also now support --all arguments to include all projects, even inactive ones.
• west list now supports a {groups} format string key in its --format argument.
Bug fixes:
• The west config command and west.configuration API did not correctly store some configura-
tion values, such as strings which contain commas. This has been fixed; see commit 36f3f91e for
details.
• A manifest file with an empty manifest: self: path: value is invalid, but west used to let it
pass silently. West now rejects such manifests.
• A bug affecting the behavior of the west init -l . command was fixed; see issue #435.
API changes:
• added west.manifest.Manifest.is_active()
• added west.manifest.Manifest.group_filter
• added submodules attribute to west.manifest.Project, which has newly added type west.
manifest.Submodule
Other changes:
• The Manifest Imports feature now supports the terms allowlist and blocklist instead of
whitelist and blacklist, respectively.
The old terms are still supported for compatibility, but the documentation has been updated to use
the new ones exclusively.

v0.8.0

This is a feature release which changes the manifest schema by adding support for a path-prefix: key
in an import: mapping, along with some other features and fixes.
• Manifest import mappings now support a path-prefix: key, which places the project and its im-
ported repositories in a subdirectory of the workspace. See Example 3.4: Import into a subdirectory
for an example.
• The west command line application can now also be run using python3 -m west. This makes it
easier to run west under a particular Python interpreter without modifying the PATH environment
variable.
• west manifest –path prints the absolute path to west.yml
• west init now supports an --mf foo.yml option, which initializes the workspace using foo.yml
instead of west.yml.
• west list now prints the manifest repository’s path using the manifest.path configuration option,
which may differ from the self: path: value in the manifest data. The old behavior is still
available, but requires passing a new --manifest-path-from-yaml option.
• Various Python API changes; see west-apis for details.

2.10. West (Zephyr’s meta-tool) 105


Zephyr Project Documentation, Release 3.4.0

v0.7.3

This is a bugfix release.


• Fix an error where a failed import could leave the workspace in an unusable state (see [PR
#415](https://github.com/zephyrproject-rtos/west/pull/415) for details)

v0.7.2

This is a bugfix and minor feature release.


• Filter out duplicate extension commands brought in by manifest imports
• Fix west.Manifest.get_projects() when finding the manifest repository by path

v0.7.1

This is a bugfix and minor feature release.


• west update --stats now prints timing for operations which invoke a subprocess, time spent in
west’s Python process for each project, and total time updating each project.
• west topdir always prints a POSIX style path
• minor console output changes

v0.7.0

The main user-visible feature in west 0.7 is the Manifest Imports feature. This allows users to load west
manifest data from multiple different files, resolving the results into a single logical manifest.
Additional user-visible changes:
• The idea of a “west installation” has been renamed to “west workspace” in this documentation and
in the west API documentation. The new term seems to be easier for most people to work with
than the old one.
• West manifests now support a schema version.
• The “west config” command can now be run outside of a workspace, e.g. to run west config
--global section.key value to set a configuration option’s value globally.
• There is a new west topdir command, which prints the root directory of the current west workspace.
• The west -vv init command now prints the git operations being performed, and their results.
• The restriction that no project can be named “manifest” is now enforced; the name “manifest” is
reserved for the manifest repository, and is usable as such in commands like west list manifest,
instead of west list path-to-manifest-repository being the only way to say that
• It’s no longer an error if there is no project named “zephyr”. This is part of an effort to make west
generally usable for non-Zephyr use cases.
• Various bug fixes.
The developer-visible changes to the west-apis are:
• west.build and west.cmake: deprecated; this is Zephyr-specific functionality and should never
have been part of west. Since Zephyr v1.14 LTS relies on it, it will continue to be included in the
distribution, but will be removed when that version of Zephyr is obsoleted.
• west.commands:
– WestCommand.requires_installation: deprecated; use requires_workspace instead

106 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

– WestCommand.requires_workspace: new
– WestCommand.has_manifest: new
– WestCommand.manifest: this is now settable
• west.configuration: callers can now identify the workspace directory when reading and writing
configuration files
• west.log:
– msg(): new
• west.manifest:
– The module now uses the standard logging module instead of west.log
– QUAL_REFS_WEST: new
– SCHEMA_VERSION: new
– Defaults: removed
– Manifest.as_dict(): new
– Manifest.as_frozen_yaml(): new
– Manifest.as_yaml(): new
– Manifest.from_file() and from_data(): these factory methods are more flexible to use and less
reliant on global state
– Manifest.validate(): new
– ManifestImportFailed: new
– ManifestProject: semi-deprecated and will likely be removed later.
– Project: the constructor now takes a topdir argument
– Project.format() and its callers are removed. Use f-strings instead.
– Project.name_and_path: new
– Project.remote_name: new
– Project.sha() now captures stderr
– Remote: removed
West now requires Python 3.6 or later. Additionally, some features may rely on Python dictionaries being
insertion-ordered; this is only an implementation detail in CPython 3.6, but is is part of the language
specification as of Python 3.7.

v0.6.3

This point release fixes an error in the behavior of the deprecated west.cmake module.

v0.6.2

This point release fixes an error in the behavior of west update --fetch=smart, introduced in v0.6.1.
All v0.6.1 users must upgrade.

2.10. West (Zephyr’s meta-tool) 107


Zephyr Project Documentation, Release 3.4.0

v0.6.1

Warning: Do not use this point release. Make sure to use v0.6.2 instead.

The user-visible features in this point release are:


• The west update command has a new --fetch command line flag and update.fetch configuration
option. The default value, “smart”, skips fetching SHAs and tags which are available locally.
• Better and more consistent error-handling in the west diff, west status, west forall, and west
update commands. Each of these commands can operate on multiple projects; if a subprocess
related to one project fails, these commands now continue to operate on the rest of the projects.
All of them also now report a nonzero error code from the west process if any of these subprocesses
fails (this was previously not true of west forall in particular).
• The west manifest command also handles errors better.
• The west list command now works even when the projects are not cloned, as long as its format
string only requires information which can be read from the manifest file. It still fails if the format
string requires data stored in the project repository, e.g. if it includes the {sha} format string key.
• Commands and options which operate on git revisions now accept abbreviated SHAs. For example,
west init --mr SHA_PREFIX now works. Previously, the --mr argument needed to be the entire
40 character SHA if it wasn’t a branch or a tag.
The developer-visible changes to the west-apis are:
• west.log.banner(): new
• west.log.small_banner(): new
• west.manifest.Manifest.get_projects(): new
• west.manifest.Project.is_cloned(): new
• west.commands.WestCommand instances can now access the parsed Manifest object via a new
self.manifest property during the do_run() call. If read, it returns the Manifest object or aborts the
command if it could not be parsed.
• west.manifest.Project.git() now has a capture_stderr kwarg

v0.6.0

• No separate bootstrapper
In west v0.5.x, the program was split into two components, a bootstrapper and a per-installation
clone. See Multiple Repository Management in the v1.14 documentation for more details.
This is similar to how Google’s Repo tool works, and lets west iterate quickly at first. It caused
confusion, however, and west is now stable enough to be distributed entirely as one piece via PyPI.
From v0.6.x onwards, all of the core west commands and helper classes are part of the west package
distributed via PyPI. This eliminates complexity and makes it possible to import west modules from
anywhere in the system, not just extension commands.
• The selfupdate command still exists for backwards compatibility, but now simply exits after print-
ing an error message.
• Manifest syntax changes
– A west manifest file’s projects elements can now specify their fetch URLs directly, like so:

108 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

manifest:
projects:
- name: example-project-name
url: https://github.com/example/example-project

Project elements with url attributes set in this way may not also have remote attributes.
– Project names must be unique: this restriction is needed to support future work, but was not
possible in west v0.5.x because distinct projects may have URLs with the same final pathname
component, like so:

manifest:
remotes:
- name: remote-1
url-base: https://github.com/remote-1
- name: remote-2
url-base: https://github.com/remote-2
projects:
- name: project
remote: remote-1
path: remote-1-project
- name: project
remote: remote-2
path: remote-2-project

These manifests can now be written with projects that use url instead of remote, like so:

manifest:
projects:
- name: remote-1-project
url: https://github.com/remote-1/project
- name: remote-2-project
url: https://github.com/remote-2/project

• The west list command now supports a {sha} format string key
• The default format string for west list was changed to "{name:12} {path:28} {revision:40}
{url}".
• The command west manifest --validate can now be run to load and validate the current man-
ifest file, among other error-handling fixes related to manifest parsing.
• Incompatible API changes were made to west’s APIs. Further changes are expected until API sta-
bility is declared in west v1.0.
– The west.manifest.Project constructor’s remote and defaults positional arguments are
now kwargs. A new url kwarg was also added; if given, the Project URL is set to that value,
and the remote kwarg is ignored.
– west.manifest.MANIFEST_SECTIONS was removed. There is only one section now, namely
manifest. The sections kwargs in the west.manifest.Manifest factory methods and con-
structor were also removed.
– The west.manifest.SpecialProject class was removed. Use west.manifest.
ManifestProject instead.

v0.5.x

West v0.5.x is the first version used widely by the Zephyr Project as part of its v1.14 Long-Term Support
(LTS) release. The west v0.5.x documentation is available as part of the Zephyr’s v1.14 documentation.

2.10. West (Zephyr’s meta-tool) 109


Zephyr Project Documentation, Release 3.4.0

West’s main features in v0.5.x are:


• Multiple repository management using Git repositories, including self-update of west itself
• Hierarchical configuration files
• Extension commands

Versions Before v0.5.x

Tags in the west repository before v0.5.x are prototypes which are of historical interest only.

2.10.3 Troubleshooting West

This page covers common issues with west and how to solve them.

west update fetching failures

One good way to troubleshoot fetching issues is to run west update in verbose mode, like this:

west -v update

The output includes Git commands run by west and their outputs. Look for something like this:

=== updating your_project (path/to/your/project):


west.manifest: your_project: checking if cloned
[...other west.manifest logs...]
--- your_project: fetching, need revision SOME_SHA
west.manifest: running 'git fetch ... https://github.com/your-username/your_project ..
˓→.' in /some/directory

The git fetch command example in the last line above is what needs to succeed.
One strategy is to go to /path/to/your/project, copy/paste and run the entire git fetch command,
then debug from there using the documentation for your credential storage helper.
If you’re behind a corporate firewall and may have proxy or other issues, curl -v FETCH_URL (for HTTPS
URLs) or ssh -v FETCH_URL (for SSH URLs) may be helpful.
If you can get the git fetch command to run successfully without prompting for a password when you
run it directly, you will be able to run west update without entering your password in that same shell.

“‘west’ is not recognized as an internal or external command, operable program or batch file.’

On Windows, this means that either west is not installed, or your PATH environment variable does not
contain the directory where pip installed west.exe.
First, make sure you’ve installed west; see Installing west. Then try running west from a new cmd.exe
window. If that still doesn’t work, keep reading.
You need to find the directory containing west.exe, then add it to your PATH . (This PATH change should
have been done for you when you installed Python and pip, so ordinarily you should not need to follow
these steps.)
Run this command in cmd.exe:

pip3 show west

Then:

110 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

1. Look for a line in the output that looks like Location: C:\foo\python\python38\lib\
site-packages. The exact location will be different on your computer.
2. Look for a file named west.exe in the scripts directory C:\foo\python\python38\scripts.

Important: Notice how lib\site-packages in the pip3 show output was changed to scripts!

3. If you see west.exe in the scripts directory, add the full path to scripts to your PATH using a
command like this:

setx PATH "%PATH%;C:\foo\python\python38\scripts"

Do not just copy/paste this command. The scripts directory location will be different on your
system.
4. Close your cmd.exe window and open a new one. You should be able to run west.

“Error: unexpected keyword argument ‘requires_workspace’”

This error occurs on some Linux distributions after upgrading to west 0.7.0 or later from 0.6.x. For
example:

$ west update
[... stack trace ...]
TypeError: __init__() got an unexpected keyword argument 'requires_workspace'

This appears to be a problem with the distribution’s pip; see this comment in west issue 373 for details.
Some versions of Ubuntu and Linux Mint are known to have this problem. Some users report issues on
Fedora as well.
Neither macOS nor Windows users have reported this issue. There have been no reports of this issue on
other Linux distributions, like Arch Linux, either.
Workaround 1: remove the old version, then upgrade:

$ pip3 show west | grep Location: | cut -f 2 -d ' '


/home/foo/.local/lib/python3.6/site-packages
$ rm -r /home/foo/.local/lib/python3.6/site-packages/west
$ pip3 install --user west==0.7.0

Workaround 2: install west in a Python virtual environment


One option is to use the venv module that’s part of the Python 3 standard library. Some distributions
remove this module from their base Python 3 packages, so you may need to do some additional work to
get it installed on your system.

“invalid choice: ‘build’” (or ‘flash’, etc.)

If you see an unexpected error like this when trying to run a Zephyr extension command (like west flash,
west build, etc.):

$ west build [...]


west: error: argument <command>: invalid choice: 'build' (choose from 'init', [...])

$ west flash [...]


west: error: argument <command>: invalid choice: 'flash' (choose from 'init', [...])

2.10. West (Zephyr’s meta-tool) 111


Zephyr Project Documentation, Release 3.4.0

The most likely cause is that you’re running the command outside of a west workspace. West needs to
know where your workspace is to find Extensions.
To fix this, you have two choices:
1. Run the command from inside a workspace (e.g. the zephyrproject directory you created when
you got started).
For example, create your build directory inside the workspace, or run west flash --build-dir
YOUR_BUILD_DIR from inside the workspace.
2. Set the ZEPHYR_BASE environment variable and re-run the west extension command. If set, west
will use ZEPHYR_BASE to find your workspace.
If you’re unsure whether a command is built-in or an extension, run west help from inside your
workspace. The output prints extension commands separately, and looks like this for mainline Zephyr:

$ west help

built-in commands for managing git repositories:


init: create a west workspace
[...]

other built-in commands:


help: get help for west or a command
[...]

extension commands from project manifest (path: zephyr):


build: compile a Zephyr application
flash: flash and run a binary on a board
[...]

“invalid choice: ‘post-init’”

If you see this error when running west init:

west: error: argument <command>: invalid choice: 'post-init'


(choose from 'init', 'update', 'list', 'manifest', 'diff',
'status', 'forall', 'config', 'selfupdate', 'help')

Then you have an old version of west installed, and are trying to use it in a workspace that requires a
more recent version.
The easiest way to resolve this issue is to upgrade west and retry as follows:
1. Install the latest west with the -U option for pip3 install as shown in Installing west.
2. Back up any contents of zephyrproject/.west/config that you want to save. (If you don’t have
any configuration options set, it’s safe to skip this step.)
3. Completely remove the zephyrproject/.west directory (if you don’t, you will get the “already in
a workspace” error message discussed next).
4. Run west init again.

“already in an installation”

You may see this error when running west init with west 0.6:

FATAL ERROR: already in an installation (<some directory>), aborting

112 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

If this is unexpected and you’re really trying to create a new west workspace, then it’s likely that west is
using the ZEPHYR_BASE environment variable to locate a workspace elsewhere on your system.
This is intentional; it allows you to put your Zephyr applications in any directory and still use west to
build, flash, and debug them, for example.
To resolve this issue, unset ZEPHYR_BASE and try again.

2.10.4 Basics

This page introduces west’s basic concepts and provides references to further reading.
West’s built-in commands allow you to work with projects (Git repositories) under a common workspace
directory.

Example workspace

If you’ve followed the upstream Zephyr getting started guide, your workspace looks like this:

zephyrproject/ # west topdir


.west/ # marks the location of the topdir
config # per-workspace local configuration file

# The manifest repository, never modified by west after creation:


zephyr/ # .git/ repo
west.yml # manifest file
[... other files ...]

# Projects managed by west:


modules/
lib/
zcbor/ # .git/ project
net-tools/ # .git/ project
[ ... other projects ...]

Workspace concepts

Here are the basic concepts you should understand about this structure. Additional details are in
Workspaces.
topdir
Above, zephyrproject is the name of the workspace’s top level directory, or topdir. (The name
zephyrproject is just an example – it could be anything, like z, my-zephyr-workspace, etc.)
You’ll typically create the topdir and a few other files and directories using west init.
.west directory
The topdir contains the .west directory. When west needs to find the topdir, it searches for .west,
and uses its parent directory. The search starts from the current working directory (and starts again
from the location in the ZEPHYR_BASE environment variable as a fallback if that fails).
configuration file
The file .west/config is the workspace’s local configuration file.
manifest repository
Every west workspace contains exactly one manifest repository, which is a Git repository containing
a manifest file. The location of the manifest repository is given by the manifest.path configuration
option in the local configuration file.

2.10. West (Zephyr’s meta-tool) 113


Zephyr Project Documentation, Release 3.4.0

For upstream Zephyr, zephyr is the manifest repository, but you can configure west to use any Git
repository in the workspace as the manifest repository. The only requirement is that it contains a
valid manifest file. See Topologies supported for information on other options, and West Manifests
for details on the manifest file format.
manifest file
The manifest file is a YAML file that defines projects, which are the additional Git repositories in
the workspace managed by west. The manifest file is named west.yml by default; this can be
overridden using the manifest.file local configuration option.
You use the west update command to update the workspace’s projects based on the contents of the
manifest file.
projects
Projects are Git repositories managed by west. Projects are defined in the manifest file and can be
located anywhere inside the workspace. In the above example workspace, zcbor and net-tools
are projects.
By default, the Zephyr build system uses west to get the locations of all the projects in the
workspace, so any code they contain can be used as Modules (External projects). Note however
that modules and projects are conceptually different.
extensions
Any repository known to west (either the manifest repository or any project repository) can define
Extensions. Extensions are extra west commands you can run when using that workspace.
The zephyr repository uses this feature to provide Zephyr-specific commands like west build. Defin-
ing these as extensions keeps west’s core agnostic to the specifics of any workspace’s Zephyr version,
etc.
ignored files
A workspace can contain additional Git repositories or other files and directories not managed by
west. West basically ignores anything in the workspace except .west, the manifest repository, and
the projects specified in the manifest file.

west init and west update

The two most important workspace-related commands are west init and west update.

west init basics This command creates a west workspace.

Important: West doesn’t change your manifest repository contents after west init is run. Use ordinary
Git commands to pull new versions, etc.

You will typically run it once, like this:

west init -m https://github.com/zephyrproject-rtos/zephyr --mr v2.5.0 zephyrproject

This will:
1. Create the topdir, zephyrproject, along with .west and .west/config inside it
2. Clone the manifest repository from https://github.com/zephyrproject-rtos/zephyr, placing it into
zephyrproject/zephyr
3. Check out the v2.5.0 git tag in your local zephyr clone
4. Set manifest.path to zephyr in .west/config
5. Set manifest.file to west.yml

114 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

Your workspace is now almost ready to use; you just need to run west update to clone the rest of the
projects into the workspace to finish.
For more details, see west init.

west update basics This command makes sure your workspace contains Git repositories matching the
projects in the manifest file.

Important: Whenever you check out a different revision in your manifest repository, you should run
west update to make sure your workspace contains the project repositories the new revision expects.

The west update command reads the manifest file’s contents by:
1. Finding the topdir. In the west init example above, that means finding zephyrproject.
2. Loading .west/config in the topdir to read the manifest.path (e.g. zephyr) and manifest.file
(e.g. west.yml) options.
3. Loading the manifest file given by these options (e.g. zephyrproject/zephyr/west.yml).
It then uses the manifest file to decide where missing projects should be placed within the workspace,
what URLs to clone them from, and what Git revisions should be checked out locally. Project repositories
which already exist are updated in place by fetching and checking out their respective Git revisions in
the manifest file.
For more details, see west update.

Other built-in commands

See Built-in commands.

Zephyr Extensions

See the following pages for information on Zephyr’s extension commands:


• Building, Flashing and Debugging
• Signing Binaries
• Additional Zephyr extension commands
• Enabling shell completion

Troubleshooting

See Troubleshooting West.

2.10.5 Built-in commands

This page describes west’s built-in commands, some of which were introduced in Basics, in more detail.
Some commands are related to Git commands with the same name, but operate on the entire workspace.
For example, west diff shows local changes in multiple Git repositories in the workspace.
Some commands take projects as arguments. These arguments can be project names as specified in
the manifest file, or (as a fallback) paths to them on the local file system. Omitting project arguments
to commands which accept them (such as west list, west forall, etc.) usually defaults to using all
projects in the manifest file plus the manifest repository itself.

2.10. West (Zephyr’s meta-tool) 115


Zephyr Project Documentation, Release 3.4.0

For additional help, run west <command> -h (e.g. west init -h).

west init

This command creates a west workspace. It can be used in two ways:


1. Cloning a new manifest repository from a remote URL
2. Creating a workspace around an existing local manifest repository
Option 1: to clone a new manifest repository from a remote URL, use:

west init [-m URL] [--mr REVISION] [--mf FILE] [directory]

The new workspace is created in the given directory, creating a new .west inside this directory. You
can give the manifest URL using the -m switch, the initial revision to check out using --mr, and the
location of the manifest file within the repository using --mf.
For example, running:

west init -m https://github.com/zephyrproject-rtos/zephyr --mr v1.14.0 zp

would clone the upstream official zephyr repository into zp/zephyr, and check out the v1.14.0 release.
This command creates zp/.west, and set the manifest.path configuration option to zephyr to record
the location of the manifest repository in the workspace. The default manifest file location is used.
The -m option defaults to https://github.com/zephyrproject-rtos/zephyr. The --mf option defaults
to west.yml. Since west v0.10.1, west will use the default branch in the manifest repository unless the
--mr option is used to override it. (In prior versions, --mr defaulted to master.)
If no directory is given, the current working directory is used.
Option 2: to create a workspace around an existing local manifest repository, use:

west init -l [--mf FILE] directory

This creates .west next to directory in the file system, and sets manifest.path to directory.
As above, --mf defaults to west.yml.
Reconfiguring the workspace:
If you change your mind later, you are free to change manifest.path and manifest.file using west
config after running west init. Just be sure to run west update afterwards to update your workspace
to match the new manifest file.

west update

west update [-f {always,smart}] [-k] [-r]


[--group-filter FILTER] [--stats] [PROJECT ...]

Which projects are updated:


By default, this command parses the manifest file, usually west.yml, and updates each project specified
there. If your manifest uses project groups, then only the active projects are updated.
To operate on a subset of projects only, give PROJECT argument(s). Each PROJECT is either a project name
as given in the manifest file, or a path that points to the project within the workspace. If you specify
projects explicitly, they are updated regardless of whether they are active.
Project update procedure:
For each project that is updated, this command:

116 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

1. Initializes a local Git repository for the project in the workspace, if it does not already exist
2. Inspects the project’s revision field in the manifest, and fetches it from the remote if it is not
already available locally
3. Sets the project’s manifest-rev branch to the commit specified by the revision in the previous step
4. Checks out manifest-rev in the local working copy as a detached HEAD
5. If the manifest file specifies a submodules key for the project, recursively updates the project’s
submodules as described below.
To avoid unnecessary fetches, west update will not fetch project revision values which are Git SHAs or
tags that are already available locally. This is the behavior when the -f (--fetch) option has its default
value, smart. To force this command to fetch from project remotes even if the revisions appear to be
available locally, either use -f always or set the update.fetch configuration option to always. SHAs
may be given as unique prefixes as long as they are acceptable to Git1 .
If the project revision is a Git ref that is neither a tag nor a SHA (i.e. if the project is tracking a branch),
west update always fetches, regardless of -f and update.fetch.
Some branch names might look like short SHAs, like deadbeef. West treats these like SHAs. You can dis-
ambiguate by prefixing the revision value with refs/heads/, e.g. revision: refs/heads/deadbeef.
For safety, west update uses git checkout --detach to check out a detached HEAD at the manifest
revision for each updated project, leaving behind any branches which were already checked out. This is
typically a safe operation that will not modify any of your local branches.
However, if you had added some local commits onto a previously detached HEAD checked out by west,
then git will warn you that you’ve left behind some commits which are no longer referred to by any
branch. These may be garbage-collected and lost at some point in the future. To avoid this if you
have local commits in the project, make sure you have a local branch checked out before running west
update.
If you would rather rebase any locally checked out branches instead, use the -r (--rebase) option.
If you would like west update to keep local branches checked out as long as they point to commits that
are descendants of the new manifest-rev, use the -k (--keep-descendants) option.

Note: west update --rebase will fail in projects that have git conflicts between your branch and new
commits brought in by the manifest. You should immediately resolve these conflicts as you usually do
with git, or you can use git -C <project_path> rebase --abort to ignore incoming changes for the
moment.
With a clean working tree, a plain west update never fails because it does not try to hold on to your
commits and simply leaves them aside.
west update --keep-descendants offers an intermediate option that never fails either but does not
treat all projects the same:
• in projects where your branch diverged from the incoming commits, it does not even try to rebase
and leaves your branches behind just like a plain west update does;
• in all other projects where no rebase or merge is needed it keeps your branches in place.

One-time project group manipulation:


The --group-filter option can be used to change which project groups are enabled or disabled for the
duration of a single west update command. See Project Groups for details on the project group feature.
The west update command behaves as if the --group-filter option’s value were appended to the
manifest.group-filter configuration option.
1 West may fetch all refs from the Git server when given a SHA as a revision. This is because some Git servers have historically

not allowed fetching SHAs directly.

2.10. West (Zephyr’s meta-tool) 117


Zephyr Project Documentation, Release 3.4.0

For example, running west update --group-filter=+foo,-bar would behave the same way as if you
had temporarily appended the string "+foo,-bar" to the value of manifest.group-filter, run west
update, then restored manifest.group-filter to its original value.
Note that using the syntax --group-filter=VALUE instead of --group-filter VALUE avoids issues pars-
ing command line options if you just want to disable a single group, e.g. --group-filter=-bar.
Submodule update procedure:
If a project in the manifest has a submodules key, the submodules are updated as follows, depending on
the value of the submodules key.
If the project has submodules: true, west first synchronizes the project’s submodules with:

git submodule sync --recursive

West then runs one of the following in the project repository, depending on whether you run west
update with the --rebase option or without it:

# without --rebase, e.g. "west update":


git submodule update --init --checkout --recursive

# with --rebase, e.g. "west update --rebase":


git submodule update --init --rebase --recursive

Otherwise, the project has submodules: <list-of-submodules>. In this case, west synchronizes the
project’s submodules with:

git submodule sync --recursive -- <submodule-path>

Then it updates each submodule in the list as follows, depending on whether you run west update with
the --rebase option or without it:

# without --rebase, e.g. "west update":


git submodule update --init --checkout --recursive <submodule-path>

# with --rebase, e.g. "west update --rebase":


git submodule update --init --rebase --recursive <submodule-path>

The git submodule sync commands are skipped if the update.sync-submodules Configuration option
is false.

Other project commands

West has a few more commands for managing the projects in the workspace, which are summarized
here. Run west <command> -h for detailed help.
• west list: print a line of information about each project in the manifest, according to a format
string
• west manifest: manage the manifest file. See Manifest Command.
• west diff: run git diff in local project repositories
• west status: run git status in local project repositories
• west forall: run an arbitrary command in local project repositories
• west compare: compare the state of the workspace against the manifest

118 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

Other built-in commands

Finally, here is a summary of other built-in commands.


• west config: get or set configuration options
• west topdir: print the top level directory of the west workspace
• west help: get help about a command, or print information about all commands in the workspace,
including Extensions

2.10.6 Workspaces

This page describes the west workspace concept introduced in Basics in more detail.

The manifest-rev branch

West creates and controls a Git branch named manifest-rev in each project. This branch points to
the revision that the manifest file specified for the project at the time west update was last run. Other
workspace management commands may use manifest-rev as a reference point for the upstream revision
as of this latest update. Among other purposes, the manifest-rev branch allows the manifest file to use
SHAs as project revisions.
Although manifest-rev is a normal Git branch, west will recreate and/or reset it on the next update. For
this reason, it is dangerous to check it out or otherwise modify it yourself. For instance, any commits you
manually add to this branch may be lost the next time you run west update. Instead, check out a local
branch with another name, and either rebase it on top of a new manifest-rev, or merge manifest-rev
into it.

Note: West does not create a manifest-rev branch in the manifest repository, since west does not
manage the manifest repository’s branches or revisions.

The refs/west/* Git refs

West also reserves all Git refs that begin with refs/west/ (such as refs/west/foo) for itself in local
project repositories. Unlike manifest-rev, these refs are not regular branches. West’s behavior here is
an implementation detail; users should not rely on these refs’ existence or behavior.

Private repositories

You can use west to fetch from private repositories. There is nothing west-specific about this.
The west update command essentially runs git fetch YOUR_PROJECT_URL when a project’s
manifest-rev branch must be updated to a newly fetched commit. It’s up to your environment to
make sure the fetch succeeds.
You can either enter the password manually or use any of the credential helpers built in to Git. Since Git
has credential storage built in, there is no need for a west-specific feature.
The following sections cover common cases for running west update without having to enter your
password, as well as how to troubleshoot issues.

2.10. West (Zephyr’s meta-tool) 119


Zephyr Project Documentation, Release 3.4.0

Fetching via HTTPS On Windows when fetching from GitHub, recent versions of Git prompt you for
your GitHub password in a graphical window once, then store it for future use (in a default installation).
Passwordless fetching from GitHub should therefore work “out of the box” on Windows after you have
done it once.
In general, you can store your credentials on disk using the “store” git credential helper. See the git-
credential-store manual page for details.
To use this helper for all the repositories in your workspace, run:

west forall -c "git config credential.helper store"

To use this helper on just the projects foo and bar, run:

west forall -c "git config credential.helper store" foo bar

To use this helper by default on your computer, run:

git config --global credential.helper store

On GitHub, you can set up a personal access token to use in place of your account password. (This may
be required if your account has two-factor authentication enabled, and may be preferable to storing your
account password in plain text even if two-factor authentication is disabled.)
You can use the Git credential store to authenticate with a GitHub PAT (Personal Access Token) like so:

echo "https://x-access-token:[email protected]" >> ~/.git-credentials

If you don’t want to store any credentials on the file system, you can store them in memory temporarily
using git-credential-cache instead.
If you setup fetching via SSH, you can use Git URL rewrite feature. The following command instructs Git
to use SSH URLs for GitHub instead of HTTPS ones:

git config --global url."[email protected]:".insteadOf "https://github.com/"

Fetching via SSH If your SSH key has no password, fetching should just work. If it does have a
password, you can avoid entering it manually every time using ssh-agent.
On GitHub, see Connecting to GitHub with SSH for details on configuration and key creation.

Project locations

Projects can be located anywhere inside the workspace, but they may not “escape” it.
In other words, project repositories need not be located in subdirectories of the manifest repository or as
immediate subdirectories of the topdir. However, projects must have paths inside the workspace.
You may replace a project’s repository directory within the workspace with a symbolic link to elsewhere
on your computer, but west will not do this for you.

Topologies supported

The following are example source code topologies supported by west.


• T1: star topology, zephyr is the manifest repository
• T2: star topology, a Zephyr application is the manifest repository
• T3: forest topology, freestanding manifest repository

120 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

T1: Star topology, zephyr is the manifest repository


• The zephyr repository acts as the central repository and specifies its Modules (External projects) in
its west.yml
• Analogy with existing mechanisms: Git submodules with zephyr as the super-project
This is the default. See Workspace concepts for how mainline Zephyr is an example of this topology.

T2: Star topology, application is the manifest repository


• Useful for those focused on a single application
• A repository containing a Zephyr application acts as the central repository and names other projects
required to build it in its west.yml. This includes the zephyr repository and any modules.
• Analogy with existing mechanisms: Git submodules with the application as the super-project,
zephyr and other projects as submodules
A workspace using this topology looks like this:

west-workspace/

application/ # .git/
CMakeLists.txt
prj.conf never modified by west
src/
main.c
west.yml # main manifest with optional import(s) and override(s)

modules/
lib/
zcbor/ # .git/ project from either the main manifest or some import.

zephyr/ # .git/ project


west.yml # This can be partially imported with lower precedence or␣
˓→ignored.

# Only the 'manifest-rev' version can be imported.

Here is an example application/west.yml which uses Manifest Imports, available since west 0.7, to
import Zephyr v2.5.0 and its modules into the application manifest file:

# Example T2 west.yml, using manifest imports.


manifest:
remotes:
- name: zephyrproject-rtos
url-base: https://github.com/zephyrproject-rtos
projects:
- name: zephyr
remote: zephyrproject-rtos
revision: v2.5.0
import: true
self:
path: application

You can still selectively “override” individual Zephyr modules if you use import: in this way; see Example
1.3: Downstream of a Zephyr release, with module fork for an example.
Another way to do the same thing is to copy/paste zephyr/west.yml to application/west.yml, adding
an entry for the zephyr project itself, like this:

2.10. West (Zephyr’s meta-tool) 121


Zephyr Project Documentation, Release 3.4.0

# Equivalent to the above, but with manually maintained Zephyr modules.


manifest:
remotes:
- name: zephyrproject-rtos
url-base: https://github.com/zephyrproject-rtos
defaults:
remote: zephyrproject-rtos
projects:
- name: zephyr
revision: v2.5.0
west-commands: scripts/west-commands.yml
- name: net-tools
revision: some-sha-goes-here
path: tools/net-tools
# ... other Zephyr modules go here ...
self:
path: application

(The west-commands is there for Building, Flashing and Debugging and other Zephyr-specific Extensions.
It’s not necessary when using import.)
The main advantage to using import is not having to track the revisions of imported projects separately.
In the above example, using import means Zephyr’s module versions are automatically determined from
the zephyr/west.yml revision, instead of having to be copy/pasted (and maintained) on their own.

T3: Forest topology


• Useful for those supporting multiple independent applications or downstream distributions with
no “central” repository
• A dedicated manifest repository which contains no Zephyr source code, and specifies a list of
projects all at the same “level”
• Analogy with existing mechanisms: Google repo-based source distribution
A workspace using this topology looks like this:

west-workspace/
app1/ # .git/ project
CMakeLists.txt
prj.conf
src/
main.c
app2/ # .git/ project
CMakeLists.txt
prj.conf
src/
main.c
manifest-repo/ # .git/ never modified by west
west.yml # main manifest with optional import(s) and override(s)
modules/
lib/
zcbor/ # .git/ project from either the main manifest or
# from some import

zephyr/ # .git/ project


west.yml # This can be partially imported with lower precedence or␣
˓→ignored.

# Only the 'manifest-rev' version can be imported.

122 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

Here is an example T3 manifest-repo/west.yml which uses Manifest Imports, available since west 0.7,
to import Zephyr v2.5.0 and its modules, then add the app1 and app2 projects:

manifest:
remotes:
- name: zephyrproject-rtos
url-base: https://github.com/zephyrproject-rtos
- name: your-git-server
url-base: https://git.example.com/your-company
defaults:
remote: your-git-server
projects:
- name: zephyr
remote: zephyrproject-rtos
revision: v2.5.0
import: true
- name: app1
revision: SOME_SHA_OR_BRANCH_OR_TAG
- name: app2
revision: ANOTHER_SHA_OR_BRANCH_OR_TAG
self:
path: manifest-repo

You can also do this “by hand” by copy/pasting zephyr/west.yml as shown above for the T2 topology,
with the same caveats.

2.10.7 West Manifests

This page contains detailed information about west’s multiple repository model, manifest files, and
the west manifest command. For API documentation on the west.manifest module, see west-apis-
manifest. For a more general introduction and command overview, see Basics.

Multiple Repository Model

West’s view of the repositories in a west workspace, and their history, looks like the following figure
(though some parts of this example are specific to upstream Zephyr’s use of west):
The history of the manifest repository is the line of Git commits which is “floating” on top of the gray
plane. Parent commits point to child commits using solid arrows. The plane below contains the Git
commit history of the repositories in the workspace, with each project repository boxed in by a rectangle.
Parent/child commit relationships in each repository are also shown with solid arrows.
The commits in the manifest repository (again, for upstream Zephyr this is the zephyr repository itself)
each have a manifest file. The manifest file in each commit specifies the corresponding commits which
it expects in each of the project repositories. This relationship is shown using dotted line arrows in the
diagram. Each dotted line arrow points from a commit in the manifest repository to a corresponding
commit in a project repository.
Notice the following important details:
• Projects can be added (like P1 between manifest repository commits D and E) and removed (P2
between the same manifest repository commits)
• Project and manifest repository histories don’t have to move forwards or backwards together:
– P2 stays the same from A → B, as do P1 and P3 from F → G.
– P3 moves forward from A → B.
– P3 moves backward from C → D.

2.10. West (Zephyr’s meta-tool) 123


Zephyr Project Documentation, Release 3.4.0

Fig. 3: West multi-repo history

One use for moving backward in project history is to “revert” a regression by going back to a
revision before it was introduced.
• Project repository commits can be “skipped”: P3 moves forward multiple commits in its history
from B → C.
• In the above diagram, no project repository has two revisions “at the same time”: every manifest
file refers to exactly one commit in the projects it cares about. This can be relaxed by using a
branch name as a manifest revision, at the cost of being able to bisect manifest repository history.

Manifest Files

West manifests are YAML files. Manifests have a top-level manifest section with some subsections, like
this:

manifest:
remotes:
# short names for project URLs
projects:
# a list of projects managed by west
defaults:
# default project attributes
self:
# configuration related to the manifest repository itself,
# i.e. the repository containing west.yml
version: "<schema-version>"
group-filter:
# a list of project groups to enable or disable

In YAML terms, the manifest file contains a mapping, with a manifest key. Any other keys and their
contents are ignored (west v0.5 also required a west key, but this is ignored starting with v0.6).
The manifest contains subsections, like defaults, remotes, projects, and self. In YAML terms, the
value of the manifest key is also a mapping, with these “subsections” as keys. As of west v0.10, all of

124 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

these “subsection” keys are optional.


The projects value is a list of repositories managed by west and associated metadata. We’ll discuss it
soon, but first we will describe the remotes section, which can be used to save typing in the projects
list.

Remotes The remotes subsection contains a sequence which specifies the base URLs where projects
can be fetched from.
Each remotes element has a name and a “URL base”. These are used to form the complete Git fetch URL
for each project. A project’s fetch URL can be set by appending a project-specific path onto a remote URL
base. (As we’ll see below, projects can also specify their complete fetch URLs.)
For example:

manifest:
# ...
remotes:
- name: remote1
url-base: https://git.example.com/base1
- name: remote2
url-base: https://git.example.com/base2

The remotes keys and their usage are in the following table.

Table 2: remotes keys


Key Description
name Mandatory; a unique name for the remote.
url-base A prefix that is prepended to the fetch URL for each project with this remote.

Above, two remotes are given, with names remote1 and remote2. Their URL bases are respectively
https://git.example.com/base1 and https://git.example.com/base2. You can use SSH URL bases
as well; for example, you might use [email protected]:base1 if remote1 supported Git over SSH as well.
Anything acceptable to Git will work.

Projects The projects subsection contains a sequence describing the project repositories in the west
workspace. Every project has a unique name. You can specify what Git remote URLs to use when cloning
and fetching the projects, what revisions to track, and where the project should be stored on the local
file system. Note that west projects are different from modules.
Here is an example. We’ll assume the remotes given above.

manifest:
# [... same remotes as above...]
projects:
- name: proj1
remote: remote1
path: extra/project-1
- name: proj2
repo-path: my-path
remote: remote2
revision: v1.3
- name: proj3
url: https://github.com/user/project-three
revision: abcde413a111

In this manifest:

2.10. West (Zephyr’s meta-tool) 125


Zephyr Project Documentation, Release 3.4.0

• proj1 has remote remote1, so its Git fetch URL is https://git.example.com/base1/proj1. The
remote url-base is appended with a / and the project name to form the URL.
Locally, this project will be cloned at path extra/project-1 relative to the west workspace’s root
directory, since it has an explicit path attribute with this value.
Since the project has no revision specified, master is used by default. The current tip of this
branch will be fetched and checked out as a detached HEAD when west next updates this project.
• proj2 has a remote and a repo-path, so its fetch URL is https://git.example.com/base2/
my-path. The repo-path attribute, if present, overrides the default name when forming the fetch
URL.
Since the project has no path attribute, its name is used by default. It will be cloned into a directory
named proj2. The commit pointed to by the v1.3 tag will be checked out when west updates the
project.
• proj3 has an explicit url, so it will be fetched from https://github.com/user/project-three.
Its local path defaults to its name, proj3. Commit abcde413a111 will be checked out when it is
next updated.
The available project keys and their usage are in the following table. Sometimes we’ll refer to the
defaults subsection; it will be described next.

Table 3: projects elements keys


Key(s) Description
name Mandatory; a unique name for the project. The name cannot be one of the reserved
values “west” or “manifest”. The name must be unique in the manifest file.
remote, url Mandatory (one of the two, but not both).
If the project has a remote, that remote’s url-base will be combined with the
project’s name (or repo-path, if it has one) to form the fetch URL instead.
If the project has a url, that’s the complete fetch URL for the remote Git repository.
If the project has neither, the defaults section must specify a remote, which will be
used as the the project’s remote. Otherwise, the manifest is invalid.
repo-path Optional. If given, this is concatenated on to the remote’s url-base instead of the
project’s name to form its fetch URL. Projects may not have both url and repo-path
attributes.
revision Optional. The Git revision that west update should check out. This will be checked
out as a detached HEAD by default, to avoid conflicting with local branch names. If
not given, the revision value from the defaults subsection will be used if present.
A project revision can be a branch, tag, or SHA.
The default revision is master if not otherwise specified.
Using HEAD~01 as the revision will cause west to keep the current state of the
project.
path Optional. Relative path specifying where to clone the repository locally, relative to
the top directory in the west workspace. If missing, the project’s name is used as a
directory name.
clone-depth Optional. If given, a positive integer which creates a shallow history in the cloned
repository limited to the given number of commits. This can only be used if the
revision is a branch or tag.
west-commands Optional. If given, a relative path to a YAML file within the project which de-
scribes additional west commands provided by that project. This file is named
west-commands.yml by convention. See Extensions for details.
import Optional. If true, imports projects from manifest files in the given repository into
the current manifest. See Manifest Imports for details.
groups Optional, a list of groups the project belongs to. See Project Groups for details.
submodules Optional. You can use this to make west update also update Git submodules defined
by the project. See Git Submodules in Projects for details.
userdata Optional. The value is an arbitrary YAML value. See Repository user data.

126 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

Defaults The defaults subsection can provide default values for project attributes. In particular, the
default remote name and revision can be specified here. Another way to write the same manifest we
have been describing so far using defaults is:

manifest:
defaults:
remote: remote1
revision: v1.3

remotes:
- name: remote1
url-base: https://git.example.com/base1
- name: remote2
url-base: https://git.example.com/base2

projects:
- name: proj1
path: extra/project-1
revision: master
- name: proj2
repo-path: my-path
remote: remote2
- name: proj3
url: https://github.com/user/project-three
revision: abcde413a111

The available defaults keys and their usage are in the following table.

Table 4: defaults keys


Key Description
remote Optional. This will be used for a project’s remote if it does not have a url or remote
key set.
revision Optional. This will be used for a project’s revision if it does not have one set. If not
given, the default is master.

Self The self subsection can be used to control the manifest repository itself.
As an example, let’s consider this snippet from the zephyr repository’s west.yml:

manifest:
# ...
self:
path: zephyr
west-commands: scripts/west-commands.yml

This ensures that the zephyr repository is cloned into path zephyr, though as explained above
that would have happened anyway if cloning from the default manifest URL, https://github.com/
zephyrproject-rtos/zephyr. Since the zephyr repository does contain extension commands, its self
entry declares the location of the corresponding west-commands.yml relative to the repository root.
The available self keys and their usage are in the following table.
1 In git, HEAD is a reference, whereas HEAD~<n> is a valid revision but not a reference. West fetches references, such as

refs/heads/main or HEAD, and commits not available locally, but will not fetch commits if they are already available. HEAD~0
is resolved to a specific commit that is locally available, and therefore west will simply checkout the locally available commit,
identified by HEAD~0.

2.10. West (Zephyr’s meta-tool) 127


Zephyr Project Documentation, Release 3.4.0

Table 5: self keys


Key Description
path Optional. The path west init should clone the manifest repository into, relative to
the west workspace topdir.
If not given, the basename of the path component in the manifest repository
URL will be used by default. For example, if the URL is https://git.example.
com/project-repo, the manifest repository would be cloned to the directory
project-repo.
west-commands Optional. This is analogous to the same key in a project sequence element.
import Optional. This is also analogous to the projects key, but allows importing projects
from other files in the manifest repository. See Manifest Imports.

Version The version subsection declares that the manifest file uses features which were introduced in
some version of west. Attempts to load the manifest with older versions of west will fail with an error
message that explains the minimum required version of west which is needed.
Here is an example:

manifest:
# Marks that this file uses version 0.10 of the west manifest
# file format.
#
# An attempt to load this manifest file with west v0.8.0 will
# fail with an error message saying that west v0.10.0 or
# later is required.
version: "0.10"

The pykwalify schema manifest-schema.yml in the west source code repository is used to validate the
manifest section.
Here is a table with the valid version values, along with information about the manifest file features
that were introduced in that version.

version New features


"0.7" Initial support for the version feature. All manifest file features that are not
otherwise mentioned in this table were introduced in west v0.7.0 or earlier.
"0.8" Support for import: path-prefix: (Option 3: Mapping)
"0.9" Use of west v0.9.x is discouraged.
This schema version is provided to allow users to explicitly request compatibility
with west v0.9.0. However, west v0.10.0 and later have incompatible behavior
for features that were introduced in west v0.9.0. You should ignore version “0.9”
if possible.
"0.10" Support for:
• submodules: in projects: (Git Submodules in Projects)
• manifest: group-filter:, and groups: in projects: (Project Groups)
• The import: feature now supports allowlist: and blocklist:; these
are respectively recommended as replacements for older names as part of
a general Zephyr-wide inclusive language change. The older key names
are still supported for backwards compatibility. (Manifest Imports, Option
3: Mapping)

"0.12" Support for userdata: in projects: (Repository user data)


"0.13" Support for self: userdata: (Repository user data)
"1.0" Identical to "0.13", but available for use by users that do not wish to use a "0.x"
version field.

128 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

Note: Versions of west without any new features in the manifest file format do not change the list
of valid version values. For example, version: "0.11" is not valid, because west v0.11.x did not
introduce new manifest file format features.

Quoting the version value as shown above forces the YAML parser to treat it as a string. Without quotes,
0.10 in YAML is just the floating point value 0.1. You can omit the quotes if the value is the same when
cast to string, but it’s best to include them. Always use quotes if you’re not sure.
If you do not include a version in your manifest, each new release of west assumes that it should try to
load it using the features that were available in that release. This may result in error messages that are
harder to understand if that version of west is too old to load the manifest.

Group-filter See Project Groups.

Active and Inactive Projects

Projects defined in the west manifest can be inactive or active. The difference is that an inactive project
is generally ignored by west. For example, west update will not update inactive projects, and west
list will not print information about them by default. As another example, any Manifest Imports in an
inactive project will be ignored by west.
There are two ways to make a project inactive:
1. Using the manifest.project-filter configuration option. If a project is made active or inactive
using this option, then the rules related to making a project inactive using its groups: are ignored.
That is, if a regular expression in manifest.project-filter applies to a project, the project’s
groups have no effect on whether it is active or inactive.
See the entry for this option in Built-in Configuration Options for details.
2. Otherwise, if a project has groups, and they are all disabled, then the project is inactive.
See the following section for details.

Project Groups

You can use the groups and group-filter keys briefly described above to place projects into groups,
and to enable or disable groups.
For example, this lets you run a west forall command only on the projects in the group by using
west forall --group. This can also let you make projects inactive; see the previous section for more
information on inactive projects.
The next section introduces project groups. The following section describes Enabled and Disabled Project
Groups. There are some basic examples in Project Group Examples. Finally, Group Filters and Imports
provides a simplified overview of how group-filter interacts with the Manifest Imports feature.

Groups Basics The groups: and group-filter: keys appear in the manifest like this:

manifest:
projects:
- name: some-project
groups: ...
group-filter: ...

2.10. West (Zephyr’s meta-tool) 129


Zephyr Project Documentation, Release 3.4.0

The groups key’s value is a list of group names. Group names are strings.
You can enable or disable project groups using group-filter. Projects whose groups are all disabled,
and which are not otherwise made active by a manifest.project-filter configuration option, are
inactive.
For example, in this manifest fragment:

manifest:
projects:
- name: project-1
groups:
- groupA
- name: project-2
groups:
- groupB
- groupC
- name: project-3

The projects are in these groups:


• project-1: one group, named groupA
• project-2: two groups, named groupB and groupC
• project-3: no groups
Project group names must not contain commas (,), colons (:), or whitespace.
Group names must not begin with a dash (-) or the plus sign (+), but they may contain these characters
elsewhere in their names. For example, foo-bar and foo+bar are valid groups, but -foobar and +foobar
are not.
Group names are otherwise arbitrary strings. Group names are case sensitive.
As a restriction, no project may use both import: and groups:. (This is necessary to avoid some
pathological edge cases.)

Enabled and Disabled Project Groups All project groups are enabled by default. You can enable or
disable groups in both your manifest file and Configuration.
Within a manifest file, manifest: group-filter: is a YAML list of groups to enable and disable.
To enable a group, prefix its name with a plus sign (+). For example, groupA is enabled in this manifest
fragment:

manifest:
group-filter: [+groupA]

Although this is redundant for groups that are already enabled by default, it can be used to override
settings in an imported manifest file. See Group Filters and Imports for more information.
To disable a group, prefix its name with a dash (-). For example, groupA and groupB are disabled in this
manifest fragment:

manifest:
group-filter: [-groupA,-groupB]

Note: Since group-filter is a YAML list, you could have written this fragment as follows:

manifest:
group-filter:
(continues on next page)

130 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

(continued from previous page)


- -groupA
- -groupB

However, this syntax is harder to read and therefore discouraged.

In addition to the manifest file, you can control which groups are enabled and disabled using the
manifest.group-filter configuration option. This option is a comma-separated list of groups to enable
and/or disable.
To enable a group, add its name to the list prefixed with +. To disable a group, add its name prefixed
with -. For example, setting manifest.group-filter to +groupA,-groupB enables groupA, and disables
groupB.
The value of the configuration option overrides any data in the manifest file. You can think of this as if
the manifest.group-filter configuration option is appended to the manifest: group-filter: list
from YAML, with “last entry wins” semantics.

Project Group Examples This section contains example situations involving project groups and active
projects. The examples use both manifest: group-filter: YAML lists and manifest.group-filter
configuration lists, to show how they work together.
Note that the defaults and remotes data in the following manifests isn’t relevant except to make the
examples complete and self-contained.

Note: In all of the examples that follow, the manifest.project-filter option is assumed to be unset.

Example 1: no disabled groups The entire manifest file is:

manifest:
projects:
- name: foo
groups:
- groupA
- name: bar
groups:
- groupA
- groupB
- name: baz

defaults:
remote: example-remote
remotes:
- name: example-remote
url-base: https://git.example.com

The manifest.group-filter configuration option is not set (you can ensure this by running west
config -D manifest.group-filter).
No groups are disabled, because all groups are enabled by default. Therefore, all three projects (foo,
bar, and baz) are active. Note that there is no way to make project baz inactive, since it has no groups.

Example 2: Disabling one group via manifest The entire manifest file is:

2.10. West (Zephyr’s meta-tool) 131


Zephyr Project Documentation, Release 3.4.0

manifest:
projects:
- name: foo
groups:
- groupA
- name: bar
groups:
- groupA
- groupB

group-filter: [-groupA]

defaults:
remote: example-remote
remotes:
- name: example-remote
url-base: https://git.example.com

The manifest.group-filter configuration option is not set (you can ensure this by running west
config -D manifest.group-filter).
Since groupA is disabled, project foo is inactive. Project bar is active, because groupB is enabled.

Example 3: Disabling multiple groups via manifest The entire manifest file is:
manifest:
projects:
- name: foo
groups:
- groupA
- name: bar
groups:
- groupA
- groupB

group-filter: [-groupA,-groupB]

defaults:
remote: example-remote
remotes:
- name: example-remote
url-base: https://git.example.com

The manifest.group-filter configuration option is not set (you can ensure this by running west
config -D manifest.group-filter).
Both foo and bar are inactive, because all of their groups are disabled.

Example 4: Disabling a group via configuration The entire manifest file is:
manifest:
projects:
- name: foo
groups:
- groupA
- name: bar
groups:
(continues on next page)

132 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

(continued from previous page)


- groupA
- groupB

defaults:
remote: example-remote
remotes:
- name: example-remote
url-base: https://git.example.com

The manifest.group-filter configuration option is set to -groupA (you can ensure this by running
west config manifest.group-filter -- -groupA; the extra -- is required so the argument parser
does not treat -groupA as a command line option -g with value roupA).
Project foo is inactive because groupA has been disabled by the manifest.group-filter configuration
option. Project bar is active because groupB is enabled.

Example 5: Overriding a disabled group via configuration The entire manifest file is:
manifest:
projects:
- name: foo
- name: bar
groups:
- groupA
- name: baz
groups:
- groupA
- groupB

group-filter: [-groupA]

defaults:
remote: example-remote
remotes:
- name: example-remote
url-base: https://git.example.com

The manifest.group-filter configuration option is set to +groupA (you can ensure this by running
west config manifest.group-filter +groupA).
In this case, groupA is enabled: the manifest.group-filter configuration option has higher precedence
than the manifest: group-filter: [-groupA] content in the manifest file.
Therefore, projects foo and bar are both active.

Example 6: Overriding multiple disabled groups via configuration The entire manifest file is:
manifest:
projects:
- name: foo
- name: bar
groups:
- groupA
- name: baz
groups:
- groupA
- groupB
(continues on next page)

2.10. West (Zephyr’s meta-tool) 133


Zephyr Project Documentation, Release 3.4.0

(continued from previous page)

group-filter: [-groupA,-groupB]

defaults:
remote: example-remote
remotes:
- name: example-remote
url-base: https://git.example.com

The manifest.group-filter configuration option is set to +groupA,+groupB (you can ensure this by
running west config manifest.group-filter "+groupA,+groupB").
In this case, both groupA and groupB are enabled, because the configuration value overrides the manifest
file for both groups.
Therefore, projects foo and bar are both active.

Example 7: Disabling multiple groups via configuration The entire manifest file is:

manifest:
projects:
- name: foo
- name: bar
groups:
- groupA
- name: baz
groups:
- groupA
- groupB

defaults:
remote: example-remote
remotes:
- name: example-remote
url-base: https://git.example.com

The manifest.group-filter configuration option is set to -groupA,-groupB (you can ensure this by
running west config manifest.group-filter -- "-groupA,-groupB").
In this case, both groupA and groupB are disabled.
Therefore, projects foo and bar are both inactive.

Group Filters and Imports This section provides a simplified description of how the manifest:
group-filter: value behaves when combined with Manifest Imports. For complete details, see Man-
ifest Import Details.

Warning: The below semantics apply to west v0.10.0 and later. West v0.9.x semantics are different,
and combining group-filter with import in west v0.9.x is discouraged.

In short:
• if you only import one manifest, any groups it disables in its group-filter are also disabled in
your manifest
• you can override this in your manifest file’s manifest: group-filter: value, your workspace’s
manifest.group-filter configuration option, or both

134 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

Here are some examples.

Example 1: no overrides You are using this parent/west.yml manifest:

# parent/west.yml:
manifest:
projects:
- name: child
url: https://git.example.com/child
import: true
- name: project-1
url: https://git.example.com/project-1
groups:
- unstable

And child/west.yml contains:

# child/west.yml:
manifest:
group-filter: [-unstable]
projects:
- name: project-2
url: https://git.example.com/project-2
- name: project-3
url: https://git.example.com/project-3
groups:
- unstable

Only child and project-2 are active in the resolved manifest.


The unstable group is disabled in child/west.yml, and that is not overridden in parent/west.yml.
Therefore, the final group-filter for the resolved manifest is [-unstable].
Since project-1 and project-3 are in the unstable group and are not in any other group, they are
inactive.

Example 2: overriding an imported group-filter via manifest You are using this parent/west.yml
manifest:

# parent/west.yml:
manifest:
group-filter: [+unstable,-optional]
projects:
- name: child
url: https://git.example.com/child
import: true
- name: project-1
url: https://git.example.com/project-1
groups:
- unstable

And child/west.yml contains:

# child/west.yml:
manifest:
group-filter: [-unstable]
projects:
- name: project-2
(continues on next page)

2.10. West (Zephyr’s meta-tool) 135


Zephyr Project Documentation, Release 3.4.0

(continued from previous page)


url: https://git.example.com/project-2
groups:
- optional
- name: project-3
url: https://git.example.com/project-3
groups:
- unstable

Only the child, project-1, and project-3 projects are active.


The [-unstable] group filter in child/west.yml is overridden in parent/west.yml, so the unstable
group is enabled. Since project-1 and project-3 are in the unstable group, they are active.
The same parent/west.yml file disables the optional group, so project-2 is inactive.
The final group filter specified by parent/west.yml is [+unstable,-optional].

Example 3: overriding an imported group-filter via configuration You are using this parent/
west.yml manifest:

# parent/west.yml:
manifest:
projects:
- name: child
url: https://git.example.com/child
import: true
- name: project-1
url: https://git.example.com/project-1
groups:
- unstable

And child/west.yml contains:

# child/west.yml:
manifest:
group-filter: [-unstable]
projects:
- name: project-2
url: https://git.example.com/project-2
groups:
- optional
- name: project-3
url: https://git.example.com/project-3
groups:
- unstable

If you run:

west config manifest.group-filter +unstable,-optional

Then only the child, project-1, and project-3 projects are active.
The -unstable group filter in child/west.yml is overridden in the manifest.group-filter configu-
ration option, so the unstable group is enabled. Since project-1 and project-3 are in the unstable
group, they are active.
The same configuration option disables the optional group, so project-2 is inactive.
The final group filter specified by parent/west.yml and the manifest.group-filter configuration op-
tion is [+unstable,-optional].

136 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

Git Submodules in Projects

You can use the submodules keys briefly described above to force west update to also handle any Git
submodules configured in project’s git repository. The submodules key can appear inside projects, like
this:

manifest:
projects:
- name: some-project
submodules: ...

The submodules key can be a boolean or a list of mappings. We’ll describe these in order.

Option 1: Boolean This is the easiest way to use submodules.


If submodules is true as a projects attribute, west update will recursively update the project’s Git
submodules whenever it updates the project itself. If it’s false or missing, it has no effect.
For example, let’s say you have a source code repository foo, which has some submodules, and you
want west update to keep all of them them in sync, along with another project named bar in the same
workspace.
You can do that with this manifest file:

manifest:
projects:
- name: foo
submodules: true
- name: bar

Here, west update will initialize and update all submodules in foo. If bar has any submodules, they are
ignored, because bar does not have a submodules value.

Option 2: List of mappings The submodules key may be a list of mappings, one list element for each
desired submodule. Each submodule listed is updated recursively. You can still track and update unlisted
submodules with git commands manually; present or not they will be completely ignored by west.
The path key must match exactly the path of one submodule relative to its parent west project, as shown
in the output of git submodule status. The name key is optional and not used by west for now; it’s not
passed to git submodule commands either. The name key was briefly mandatory in west version 0.9.0,
but was made optional in 0.9.1.
For example, let’s say you have a source code repository foo, which has many submodules, and you
want west update to keep some but not all of them in sync, along with another project named bar in
the same workspace.
You can do that with this manifest file:

manifest:
projects:
- name: foo
submodules:
- path: path/to/foo-first-sub
- name: foo-second-sub
path: path/to/foo-second-sub
- name: bar

Here, west update will recursively initialize and update just the submodules in foo with paths path/
to/foo-first-sub and path/to/foo-second-sub. Any submodules in bar are still ignored.

2.10. West (Zephyr’s meta-tool) 137


Zephyr Project Documentation, Release 3.4.0

Repository user data

West versions v0.12 and later support an optional userdata key in projects.
West versions v0.13 and later supports this key in the manifest: self: section.
It is meant for consumption by programs that require user-specific project metadata. Beyond parsing it
as YAML, west itself ignores the value completely.
The key’s value is arbitrary YAML. West parses the value and makes it accessible to programs using
west-apis as the userdata attribute of the corresponding west.manifest.Project object.
Example manifest fragment:

manifest:
projects:
- name: foo
- name: bar
userdata: a-string
- name: baz
userdata:
key: value
self:
userdata: blub

Example Python usage:

manifest = west.manifest.Manifest.from_file()

foo, bar, baz = manifest.get_projects(['foo', 'bar', 'baz'])

foo.userdata # None
bar.userdata # 'a-string'
baz.userdata # {'key': 'value'}
manifest.userdata # 'blub'

Manifest Imports

You can use the import key briefly described above to include projects from other manifest files in your
west.yml. This key can be either a project or self section attribute:

manifest:
projects:
- name: some-project
import: ...
self:
import: ...

You can use a “self: import:” to load additional files from the repository containing your west.yml. You
can use a “project: . . . import:” to load additional files defined in that project’s Git history.
West resolves the final manifest from individual manifest files in this order:
1. imported files in self
2. your west.yml file
3. imported files in projects
During resolution, west ignores projects which have already been defined in other files. For example, a
project named foo in your west.yml makes west ignore other projects named foo imported from your
projects list.

138 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

The import key can be a boolean, path, mapping, or sequence. We’ll describe these in order, using
examples:
• Boolean
– Example 1.1: Downstream of a Zephyr release
– Example 1.2: “Rolling release” Zephyr downstream
– Example 1.3: Downstream of a Zephyr release, with module fork
• Relative path
– Example 2.1: Downstream of a Zephyr release with explicit path
– Example 2.2: Downstream with directory of manifest files
– Example 2.3: Continuous Integration overrides
• Mapping with additional configuration
– Example 3.1: Downstream with name allowlist
– Example 3.2: Downstream with path allowlist
– Example 3.3: Downstream with path blocklist
– Example 3.4: Import into a subdirectory
• Sequence of paths and mappings
– Example 4.1: Downstream with sequence of manifest files
– Example 4.2: Import order illustration
A more formal description of how this works is last, after the examples.

Troubleshooting Note If you’re using this feature and find west’s behavior confusing, try resolving your
manifest to see the final results after imports are done.

Option 1: Boolean This is the easiest way to use import.


If import is true as a projects attribute, west imports projects from the west.yml file in that project’s
root directory. If it’s false or missing, it has no effect. For example, this manifest would import west.yml
from the p1 git repository at revision v1.0:

manifest:
# ...
projects:
- name: p1
revision: v1.0
import: true # Import west.yml from p1's v1.0 git tag
- name: p2
import: false # Nothing is imported from p2.
- name: p3 # Nothing is imported from p3 either.

It’s an error to set import to either true or false inside self, like this:

manifest:
# ...
self:
import: true # Error

2.10. West (Zephyr’s meta-tool) 139


Zephyr Project Documentation, Release 3.4.0

Example 1.1: Downstream of a Zephyr release You have a source code repository you want to use
with Zephyr v1.14.1 LTS. You want to maintain the whole thing using west. You don’t want to modify
any of the mainline repositories.
In other words, the west workspace you want looks like this:

my-downstream/
.west/ # west directory
zephyr/ # mainline zephyr repository
west.yml # the v1.14.1 version of this file is imported
modules/ # modules from mainline zephyr
hal/
[...other directories..]
[ ... other projects ...] # other mainline repositories
my-repo/ # your downstream repository
west.yml # main manifest importing zephyr/west.yml v1.14.1
[...other files..]

You can do this with the following my-repo/west.yml:

# my-repo/west.yml:
manifest:
remotes:
- name: zephyrproject-rtos
url-base: https://github.com/zephyrproject-rtos
projects:
- name: zephyr
remote: zephyrproject-rtos
revision: v1.14.1
import: true

You can then create the workspace on your computer like this, assuming my-repo is hosted at https://
git.example.com/my-repo:

west init -m https://git.example.com/my-repo my-downstream


cd my-downstream
west update

After west init, my-downstream/my-repo will be cloned.


After west update, all of the projects defined in the zephyr repository’s west.yml at revision v1.14.1
will be cloned into my-downstream as well.
You can add and commit any code to my-repo you please at this point, including your own Zephyr
applications, drivers, etc. See Application Development.

Example 1.2: “Rolling release” Zephyr downstream This is similar to Example 1.1: Downstream of a
Zephyr release, except we’ll use revision: main for the zephyr repository:

# my-repo/west.yml:
manifest:
remotes:
- name: zephyrproject-rtos
url-base: https://github.com/zephyrproject-rtos
projects:
- name: zephyr
remote: zephyrproject-rtos
revision: main
import: true

140 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

You can create the workspace in the same way:

west init -m https://git.example.com/my-repo my-downstream


cd my-downstream
west update

This time, whenever you run west update, the special manifest-rev branch in the zephyr reposi-
tory will be updated to point at a newly fetched main branch tip from the URL https://github.com/
zephyrproject-rtos/zephyr.
The contents of zephyr/west.yml at the new manifest-rev will then be used to import projects from
Zephyr. This lets you stay up to date with the latest changes in the Zephyr project. The cost is that
running west update will not produce reproducible results, since the remote main branch can change
every time you run it.
It’s also important to understand that west ignores your working tree’s zephyr/west.yml entirely when
resolving imports. West always uses the contents of imported manifests as they were committed to the
latest manifest-rev when importing from a project.
You can only import manifest from the file system if they are in your manifest repository’s working tree.
See Example 2.2: Downstream with directory of manifest files for an example.

Example 1.3: Downstream of a Zephyr release, with module fork This manifest is similar to the
one in Example 1.1: Downstream of a Zephyr release, except it:
• is a downstream of Zephyr 2.0
• includes a downstream fork of the modules/hal/nordic module which was included in that release

# my-repo/west.yml:
manifest:
remotes:
- name: zephyrproject-rtos
url-base: https://github.com/zephyrproject-rtos
- name: my-remote
url-base: https://git.example.com
projects:
- name: hal_nordic # higher precedence
remote: my-remote
revision: my-sha
path: modules/hal/nordic
- name: zephyr
remote: zephyrproject-rtos
revision: v2.0.0
import: true # imported projects have lower precedence

# subset of zephyr/west.yml contents at v2.0.0:


manifest:
defaults:
remote: zephyrproject-rtos
remotes:
- name: zephyrproject-rtos
url-base: https://github.com/zephyrproject-rtos
projects:
# ...
- name: hal_nordic # lower precedence, values ignored
path: modules/hal/nordic
revision: another-sha

With this manifest file, the project named hal_nordic:

2.10. West (Zephyr’s meta-tool) 141


Zephyr Project Documentation, Release 3.4.0

• is cloned from https://git.example.com/hal_nordic instead of https://github.com/


zephyrproject-rtos/hal_nordic.
• is updated to commit my-sha by west update, instead of the mainline commit another-sha
In other words, when your top-level manifest defines a project, like hal_nordic, west will ignore any
other definition it finds later on while resolving imports.
This does mean you have to copy the path: modules/hal/nordic value into my-repo/west.yml when
defining hal_nordic there. The value from zephyr/west.yml is ignored entirely. See Resolving Manifests
for troubleshooting advice if this gets confusing in practice.
When you run west update, west will:
• update zephyr’s manifest-rev to point at the v2.0.0 tag
• import zephyr/west.yml at that manifest-rev
• locally check out the v2.0.0 revisions for all zephyr projects except hal_nordic
• update hal_nordic to my-sha instead of another-sha

Option 2: Relative path The import value can also be a relative path to a manifest file or a directory
containing manifest files. The path is relative to the root directory of the projects or self repository
the import key appears in.
Here is an example:
manifest:
projects:
- name: project-1
revision: v1.0
import: west.yml
- name: project-2
revision: main
import: p2-manifests
self:
import: submanifests

This will import the following:


• the contents of project-1/west.yml at manifest-rev, which points at tag v1.0 after running
west update
• any YAML files in the directory tree project-2/p2-manifests at the latest commit in the main
branch, as fetched by west update, sorted by file name
• YAML files in submanifests in your manifest repository, as they appear on your file system, sorted
by file name
Notice how projects imports get data from Git using manifest-rev, while self imports get data from
your file system. This is because as usual, west leaves version control for your manifest repository up to
you.

Example 2.1: Downstream of a Zephyr release with explicit path This is an explicit way to write an
equivalent manifest to the one in Example 1.1: Downstream of a Zephyr release.
manifest:
remotes:
- name: zephyrproject-rtos
url-base: https://github.com/zephyrproject-rtos
projects:
- name: zephyr
(continues on next page)

142 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

(continued from previous page)


remote: zephyrproject-rtos
revision: v1.14.1
import: west.yml

The setting import: west.yml means to use the file west.yml inside the zephyr project. This example
is contrived, but shows the idea.
This can be useful in practice when the name of the manifest file you want to import is not west.yml.

Example 2.2: Downstream with directory of manifest files Your Zephyr downstream has a lot of
additional repositories. So many, in fact, that you want to split them up into multiple manifest files, but
keep track of them all in a single manifest repository, like this:

my-repo/
submanifests
01-libraries.yml
02-vendor-hals.yml
03-applications.yml
west.yml

You want to add all the files in my-repo/submanifests to the main manifest file, my-repo/west.yml, in
addition to projects in zephyr/west.yml. You want to track the latest development code in the Zephyr
repository’s main branch instead of using a fixed revision.
Here’s how:

# my-repo/west.yml:
manifest:
remotes:
- name: zephyrproject-rtos
url-base: https://github.com/zephyrproject-rtos
projects:
- name: zephyr
remote: zephyrproject-rtos
revision: main
import: true
self:
import: submanifests

Manifest files are imported in this order during resolution:


1. my-repo/submanifests/01-libraries.yml
2. my-repo/submanifests/02-vendor-hals.yml
3. my-repo/submanifests/03-applications.yml
4. my-repo/west.yml
5. zephyr/west.yml

Note: The .yml file names are prefixed with numbers in this example to make sure they are imported
in the specified order.
You can pick arbitrary names. West sorts files in a directory by name before importing.

Notice how the manifests in submanifests are imported before my-repo/west.yml and zephyr/west.
yml. In general, an import in the self section is processed before the manifest files in projects and the
main manifest file.

2.10. West (Zephyr’s meta-tool) 143


Zephyr Project Documentation, Release 3.4.0

This means projects defined in my-repo/submanifests take highest precedence. For example, if
01-libraries.yml defines hal_nordic, the project by the same name in zephyr/west.yml is simply
ignored. As usual, see Resolving Manifests for troubleshooting advice.
This may seem strange, but it allows you to redefine projects “after the fact”, as we’ll see in the next
example.

Example 2.3: Continuous Integration overrides Your continuous integration system needs to fetch
and test multiple repositories in your west workspace from a developer’s forks instead of your mainline
development trees, to see if the changes all work well together.
Starting with Example 2.2: Downstream with directory of manifest files, the CI scripts add a file 00-ci.yml
in my-repo/submanifests, with these contents:

# my-repo/submanifests/00-ci.yml:
manifest:
projects:
- name: a-vendor-hal
url: https://github.com/a-developer/hal
revision: a-pull-request-branch
- name: an-application
url: https://github.com/a-developer/application
revision: another-pull-request-branch

The CI scripts run west update after generating this file in my-repo/submanifests. The projects defined
in 00-ci.yml have higher precedence than other definitions in my-repo/submanifests, because the
name 00-ci.yml comes before the other file names.
Thus, west update always checks out the developer’s branches in the projects named a-vendor-hal and
an-application, even if those same projects are also defined elsewhere.

Option 3: Mapping The import key can also contain a mapping with the following keys:
• file: Optional. The name of the manifest file or directory to import. This defaults to west.yml if
not present.
• name-allowlist: Optional. If present, a name or sequence of project names to include.
• path-allowlist: Optional. If present, a path or sequence of project paths to match against. This
is a shell-style globbing pattern, currently implemented with pathlib. Note that this means case
sensitivity is platform specific.
• name-blocklist: Optional. Like name-allowlist, but contains project names to exclude rather
than include.
• path-blocklist: Optional. Like path-allowlist, but contains project paths to exclude rather
than include.
• path-prefix: Optional (new in v0.8.0). If given, this will be prepended to the project’s path in the
workspace, as well as the paths of any imported projects. This can be used to place these projects
in a subdirectory of the workspace.
Allowlists override blocklists if both are given. For example, if a project is blocked by path, then allowed
by name, it will still be imported.

Example 3.1: Downstream with name allowlist Here is a pair of manifest files, representing a main-
line and a downstream. The downstream doesn’t want to use all the mainline projects, however. We’ll
assume the mainline west.yml is hosted at https://git.example.com/mainline/manifest.

144 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

# mainline west.yml:
manifest:
projects:
- name: mainline-app # included
path: examples/app
url: https://git.example.com/mainline/app
- name: lib
path: libraries/lib
url: https://git.example.com/mainline/lib
- name: lib2 # included
path: libraries/lib2
url: https://git.example.com/mainline/lib2

# downstream west.yml:
manifest:
projects:
- name: mainline
url: https://git.example.com/mainline/manifest
import:
name-allowlist:
- mainline-app
- lib2
- name: downstream-app
url: https://git.example.com/downstream/app
- name: lib3
path: libraries/lib3
url: https://git.example.com/downstream/lib3

An equivalent manifest in a single file would be:


manifest:
projects:
- name: mainline
url: https://git.example.com/mainline/manifest
- name: downstream-app
url: https://git.example.com/downstream/app
- name: lib3
path: libraries/lib3
url: https://git.example.com/downstream/lib3
- name: mainline-app # imported
path: examples/app
url: https://git.example.com/mainline/app
- name: lib2 # imported
path: libraries/lib2
url: https://git.example.com/mainline/lib2

If an allowlist had not been used, the lib project from the mainline manifest would have been imported.

Example 3.2: Downstream with path allowlist Here is an example showing how to allowlist main-
line’s libraries only, using path-allowlist.
# mainline west.yml:
manifest:
projects:
- name: app
path: examples/app
url: https://git.example.com/mainline/app
(continues on next page)

2.10. West (Zephyr’s meta-tool) 145


Zephyr Project Documentation, Release 3.4.0

(continued from previous page)


- name: lib
path: libraries/lib # included
url: https://git.example.com/mainline/lib
- name: lib2
path: libraries/lib2 # included
url: https://git.example.com/mainline/lib2

# downstream west.yml:
manifest:
projects:
- name: mainline
url: https://git.example.com/mainline/manifest
import:
path-allowlist: libraries/*
- name: app
url: https://git.example.com/downstream/app
- name: lib3
path: libraries/lib3
url: https://git.example.com/downstream/lib3

An equivalent manifest in a single file would be:

manifest:
projects:
- name: lib # imported
path: libraries/lib
url: https://git.example.com/mainline/lib
- name: lib2 # imported
path: libraries/lib2
url: https://git.example.com/mainline/lib2
- name: mainline
url: https://git.example.com/mainline/manifest
- name: app
url: https://git.example.com/downstream/app
- name: lib3
path: libraries/lib3
url: https://git.example.com/downstream/lib3

Example 3.3: Downstream with path blocklist Here’s an example showing how to block all vendor
HALs from mainline by common path prefix in the workspace, add your own version for the chip you’re
targeting, and keep everything else.

# mainline west.yml:
manifest:
defaults:
remote: mainline
remotes:
- name: mainline
url-base: https://git.example.com/mainline
projects:
- name: app
- name: lib
path: libraries/lib
- name: lib2
path: libraries/lib2
(continues on next page)

146 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

(continued from previous page)


- name: hal_foo
path: modules/hals/foo # excluded
- name: hal_bar
path: modules/hals/bar # excluded
- name: hal_baz
path: modules/hals/baz # excluded

# downstream west.yml:
manifest:
projects:
- name: mainline
url: https://git.example.com/mainline/manifest
import:
path-blocklist: modules/hals/*
- name: hal_foo
path: modules/hals/foo
url: https://git.example.com/downstream/hal_foo

An equivalent manifest in a single file would be:

manifest:
defaults:
remote: mainline
remotes:
- name: mainline
url-base: https://git.example.com/mainline
projects:
- name: app # imported
- name: lib # imported
path: libraries/lib
- name: lib2 # imported
path: libraries/lib2
- name: mainline
repo-path: https://git.example.com/mainline/manifest
- name: hal_foo
path: modules/hals/foo
url: https://git.example.com/downstream/hal_foo

Example 3.4: Import into a subdirectory You want to import a manifest and its projects, placing
everything into a subdirectory of your west workspace.
For example, suppose you want to import this manifest from project foo, adding this project and its
projects bar and baz to your workspace:

# foo/west.yml:
manifest:
defaults:
remote: example
remotes:
- name: example
url-base: https://git.example.com
projects:
- name: bar
- name: baz

Instead of importing these into the top level workspace, you want to place all three project repositories
in an external-code subdirectory, like this:

2.10. West (Zephyr’s meta-tool) 147


Zephyr Project Documentation, Release 3.4.0

workspace/
external-code/
foo/
bar/
baz/

You can do this using this manifest:

manifest:
projects:
- name: foo
url: https://git.example.com/foo
import:
path-prefix: external-code

An equivalent manifest in a single file would be:

# foo/west.yml:
manifest:
defaults:
remote: example
remotes:
- name: example
url-base: https://git.example.com
projects:
- name: foo
path: external-code/foo
- name: bar
path: external-code/bar
- name: baz
path: external-code/baz

Option 4: Sequence The import key can also contain a sequence of files, directories, and mappings.

Example 4.1: Downstream with sequence of manifest files This example manifest is equivalent to
the manifest in Example 2.2: Downstream with directory of manifest files, with a sequence of explicitly
named files.

# my-repo/west.yml:
manifest:
projects:
- name: zephyr
url: https://github.com/zephyrproject-rtos/zephyr
import: west.yml
self:
import:
- submanifests/01-libraries.yml
- submanifests/02-vendor-hals.yml
- submanifests/03-applications.yml

Example 4.2: Import order illustration This more complicated example shows the order that west
imports manifest files:

148 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

# my-repo/west.yml
manifest:
# ...
projects:
- name: my-library
- name: my-app
- name: zephyr
import: true
- name: another-manifest-repo
import: submanifests
self:
import:
- submanifests/libraries.yml
- submanifests/vendor-hals.yml
- submanifests/applications.yml
defaults:
remote: my-remote

For this example, west resolves imports in this order:


1. the listed files in my-repo/submanifests are first, in the order they occur (e.g. libraries.yml
comes before applications.yml, since this is a sequence of files), since the self: import: is
always imported first
2. my-repo/west.yml is next (with projects my-library etc. as long as they weren’t already defined
somewhere in submanifests)
3. zephyr/west.yml is after that, since that’s the first import key in the projects list in my-repo/
west.yml
4. files in another-manifest-repo/submanifests are last (sorted by file name), since that’s the final
project import

Manifest Import Details This section describes how west resolves a manifest file that uses import a
bit more formally.

Overview The import key can appear in a west manifest’s projects and self sections. The general
case looks like this:

# Top-level manifest file.


manifest:
projects:
- name: foo
import:
... # import-1
- name: bar
import:
... # import-2
# ...
- name: baz
import:
... # import-N
self:
import:
... # self-import

Import keys are optional. If any of import-1, ..., import-N are missing, west will not import addi-
tional manifest data from that project. If self-import is missing, no additional files in the manifest

2.10. West (Zephyr’s meta-tool) 149


Zephyr Project Documentation, Release 3.4.0

repository (beyond the top-level file) are imported.


The ultimate outcomes of resolving manifest imports are:
• a projects list, which is produced by combining the projects defined in the top-level file with
those defined in imported files
• a set of extension commands, which are drawn from the the west-commands keys in in the top-level
file and any imported files
• a group-filter list, which is produced by combining the top-level and any imported filters
Importing is done in this order:
1. Manifests from self-import are imported first.
2. The top-level manifest file’s definitions are handled next.
3. Manifests from import-1, . . . , import-N, are imported in that order.
When an individual import key refers to multiple manifest files, they are processed in this order:
• If the value is a relative path naming a directory (or a map whose file is a directory), the manifest
files it contains are processed in lexicographic order – i.e., sorted by file name.
• If the value is a sequence, its elements are recursively imported in the order they appear.
This process recurses if necessary. E.g., if import-1 produces a manifest file that contains an import key,
it is resolved recursively using the same rules before its contents are processed further.
The following sections describe these outcomes.

Projects This section describes how the final projects list is created.
Projects are identified by name. If the same name occurs in multiple manifests, the first definition is
used, and subsequent definitions are ignored. For example, if import-1 contains a project named bar,
that is ignored, because the top-level west.yml has already defined a project by that name.
The contents of files named by import-1 through import-N are imported from Git at the latest
manifest-rev revisions in their projects. These revisions can be updated to the values rev-1 through
rev-N by running west update. If any manifest-rev reference is missing or out of date, west update
also fetches project data from the remote fetch URL and updates the reference.
Also note that all imported manifests, from the root manifest to the repository which defines a project P,
must be up to date in order for west to update P itself. For example, this means west update P would up-
date manifest-rev in the baz project if baz/west.yml defines P, as well as updating the manifest-rev
branch in the local git clone of P. Confusingly, updating baz may result in the removal of P from baz/
west.yml, which “should” cause west update P to fail with an unrecognized project!
For this reason, it’s not possible to run west update P if P is defined in an imported manifest; you must
update this project along with all the others with a plain west update.
By default, west won’t fetch any project data over the network if a project’s revision is a SHA or tag which
is already available locally, so updating the extra projects shouldn’t take too much time unless it’s really
needed. See the documentation for the update.fetch configuration option for more information.

Extensions All extension commands defined using west-commands keys discovered while handling
imports are available in the resolved manifest.
If an imported manifest file has a west-commands: definition in its self: section, the extension com-
mands defined there are added to the set of available extensions at the time the manifest is imported.
They will thus take precedence over any extension commands with the same names added later on.

150 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

Group filters The resolved manifest has a group-filter value which is the result of concatenating the
group-filter values in the top-level manifest and any imported manifests.
Manifest files which appear earlier in the import order have higher precedence and are therefore con-
catenated later into the final group-filter.
In other words, let:
• the submanifest resolved from self-import have group filter self-filter
• the top-level manifest file have group filter top-filter
• the submanifests resolved from import-1 through import-N have group filters filter-1 through
filter-N respectively
The final resolved group-filter value is then filterN + ... + filter-2 + filter-1 + top-filter
+ self-filter, where + here refers to list concatenation.

Important: The order that filters appear in the above list matters.
The last filter element in the final concatenated list “wins” and determines if the group is enabled or
disabled.

For example, in [-foo] + [+foo], group foo is enabled. However, in [+foo] + [-foo], group foo is
disabled.
For simplicity, west and this documentation may elide concatenated group filter elements which are
redundant using these rules. For example, [+foo] + [-foo] could be written more simply as [-foo],
for the reasons given above. As another example, [-foo] + [+foo] could be written as the empty list
[], since all groups are enabled by default.

Manifest Command

The west manifest command can be used to manipulate manifest files. It takes an action, and action-
specific arguments.
The following sections describe each action and provides a basic signature for simple uses. Run west
manifest --help for full details on all options.

Resolving Manifests The --resolve action outputs a single manifest file equivalent to your current
manifest and all its imported manifests:

west manifest --resolve [-o outfile]

The main use for this action is to see the “final” manifest contents after performing any imports.
To print detailed information about each imported manifest file and how projects are handled during
manifest resolution, set the maximum verbosity level using -v:

west -v manifest --resolve

Freezing Manifests The --freeze action outputs a frozen manifest:

west manifest --freeze [-o outfile]

A “frozen” manifest is a manifest file where every project’s revision is a SHA. You can use --freeze to
produce a frozen manifest that’s equivalent to your current manifest file. The -o option specifies an
output file; if not given, standard output is used.

2.10. West (Zephyr’s meta-tool) 151


Zephyr Project Documentation, Release 3.4.0

Validating Manifests The --validate action either succeeds if the current manifest file is valid, or
fails with an error:
west manifest --validate

The error message can help diagnose errors.


Here, “invalid” means that the syntax of the manifest file doesn’t follow the rules documented on this
page.
If your manifest is valid but it’s not working the way you want it to, turning up the verbosity with -v is
a good way to get detailed information about what decisions west made about your manifest, and why:
west -v manifest --validate

Get the manifest path The --path action prints the path to the top level manifest file:
west manifest --path

The output is something like /path/to/workspace/west.yml. The path format depends on your oper-
ating system.

2.10.8 Configuration

This page documents west’s configuration file system, the west config command, and configuration
options used by built-in commands. For API documentation on the west.configuration module, see
west-apis-configuration.

West Configuration Files

West’s configuration file syntax is INI-like; here is an example file:


[manifest]
path = zephyr

[zephyr]
base = zephyr

Above, the manifest section has option path set to zephyr. Another way to say the same thing is that
manifest.path is zephyr in this file.
There are three types of configuration file:
1. System: Settings in this file affect west’s behavior for every user logged in to the computer. Its
location depends on the platform:
• Linux: /etc/westconfig
• macOS: /usr/local/etc/westconfig
• Windows: %PROGRAMDATA%\west\config
2. Global (per user): Settings in this file affect how west behaves when run by a particular user on
the computer.
• All platforms: the default is .westconfig in the user’s home directory.
• Linux note: if the environment variable XDG_CONFIG_HOME is set, then $XDG_CONFIG_HOME/
west/config is used.
• Windows note: the following environment variables are tested to find the home directory:
%HOME%, then %USERPROFILE%, then a combination of %HOMEDRIVE% and %HOMEPATH%.

152 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

3. Local: Settings in this file affect west’s behavior for the current west workspace. The file is .west/
config, relative to the workspace’s root directory.
A setting in a file which appears lower down on this list overrides an earlier setting. For example, if
color.ui is true in the system’s configuration file, but false in the workspace’s, then the final value is
false. Similarly, settings in the user configuration file override system settings, and so on.

west config

The built-in config command can be used to get and set configuration values. You can pass west config
the options --system, --global, or --local to specify which configuration file to use. Only one of these
can be used at a time. If none is given, then writes default to --local, and reads show the final value
after applying overrides.
Some examples for common uses follow; run west config -h for detailed help, and see Built-in Config-
uration Options for more details on built-in options.
To set manifest.path to some-other-manifest:

west config manifest.path some-other-manifest

Doing the above means that commands like west update will look for the west manifest inside the
some-other-manifest directory (relative to the workspace root directory) instead of the directory given
to west init, so be careful!
To read zephyr.base, the value which will be used as ZEPHYR_BASE if it is unset in the calling environ-
ment (also relative to the workspace root):

west config zephyr.base

You can switch to another zephyr repository without changing manifest.path – and thus the behavior
of commands like west update – using:

west config zephyr.base some-other-zephyr

This can be useful if you use commands like git worktree to create your own zephyr directories, and
want commands like west build to use them instead of the zephyr repository specified in the manifest.
(You can go back to using the directory in the upstream manifest by running west config zephyr.base
zephyr.)
To set color.ui to false in the global (user-wide) configuration file, so that west will no longer print
colored output for that user when run in any workspace:

west config --global color.ui false

To undo the above change:

west config --global color.ui true

Built-in Configuration Options

The following table documents configuration options supported by west’s built-in commands. Configu-
ration options supported by Zephyr’s extension commands are documented in the pages for those com-
mands.

2.10. West (Zephyr’s meta-tool) 153


Zephyr Project Documentation, Release 3.4.0

Option Description
color.ui Boolean. If true (the default), then west output is colorized when stdout is
a terminal.
commands. Boolean, default true, disables Extensions if false
allow_extensions
manifest.file String, default west.yml. Relative path from the manifest repository root
directory to the manifest file used by west init and other commands which
parse the manifest.
manifest. String, default empty. A comma-separated list of project groups to enable
group-filter and disable within the workspace. Prefix enabled groups with + and dis-
abled groups with -. For example, the value "+foo,-bar" enables group
foo and disables bar. See Project Groups.
manifest.path String, relative path from the west workspace root directory to the mani-
fest repository used by west update and other commands which parse the
manifest. Set locally by west init.
manifest. Comma-separated list of strings.
project-filter The option’s value is a comma-separated list of regular expressions, each
prefixed with + or -, like this:
+re1,-re2,-re3
Project names are matched against each regular expression (re1, re2, re3,
. . . ) in the list, in order. If the entire project name matches the regular ex-
pression, that element of the list either deactivates or activates the project.
The project is deactivated if the element begins with -. The project is acti-
vated if the element begins with +. (Project names cannot contain , if this
option is used, so the regular expressions do not need to contain a literal ,
character.)
If a project’s name matches multiple regular expressions in the list, the re-
sult from the last regular expression is used. For example, if manifest.
project-filter is:
-hal_.*,+hal_foo
Then a project named hal_bar is inactive, but a project named hal_foo is
active.
If a project is made inactive or active by a list element, the project is active
or not regardless of whether any or all of its groups are disabled. (This is
currently the only way to make a project that has no groups inactive.)
Otherwise, i.e. if a project does not match any regular expressions in the
list, it is active or inactive according to the usual rules related to its groups
(see Project Group Examples for examples in that case).
Within an element of a manifest.project-filter list, leading and trailing
whitespace are ignored. That means these example values are equivalent:
+foo,-bar
+foo , -bar
Any empty elements are ignored. That means these example values are
equivalent:
+foo,,-bar
+foo,-bar

update.fetch String, one of "smart" (the default behavior starting in v0.6.1) or "always"
(the previous behavior). If set to "smart", the west update command will
skip fetching from project remotes when those projects’ revisions in the
manifest file are SHAs or tags which are already available locally. The
"always" behavior is to unconditionally fetch from the remote.
update.name-cache String. If non-empty, west update will use its value as the --name-cache
option’s value if not given on the command line.
update.narrow Boolean. If true, west update behaves as if --narrow was given on the
command line. The default is false.
update.path-cache String. If non-empty, west update will use its value as the --path-cache
154 Chapter
option’s value if not given on the command line.2. Developing with Zephyr
update. Boolean. If true (the default), west update will synchronize Git submodules
sync-submodules before updating them.
zephyr.base String, default value to set for the ZEPHYR_BASE environment variable while
Zephyr Project Documentation, Release 3.4.0

2.10.9 Extensions

West is “pluggable”: you can add your own commands to west without editing its source code. These are
called west extension commands, or just “extensions” for short. Extensions show up in the west --help
output in a special section for the project which defines them. This page provides general information
on west extension commands, and has a tutorial for writing your own.
Some commands you can run when using west with Zephyr, like the ones used to build, flash, and debug
and the ones described here , are extensions. That’s why help for them shows up like this in west --help:

commands from project at "zephyr":


completion: display shell completion scripts
boards: display information about supported boards
build: compile a Zephyr application
sign: sign a Zephyr binary for bootloader chain-loading
flash: flash and run a binary on a board
debug: flash and interactively debug a Zephyr application
debugserver: connect to board and launch a debug server
attach: interactively debug a board

See zephyr/scripts/west-commands.yml and the zephyr/scripts/west_commands directory for the


implementation details.

Disabling Extension Commands

To disable support for extension commands, set the commands.allow_extensions configuration option
to false. To set this globally for whenever you run west, use:

west config --global commands.allow_extensions false

If you want to, you can then re-enable them in a particular west workspace with:

west config --local commands.allow_extensions true

Note that the files containing extension commands are not imported by west unless the commands are
explicitly run. See below for details.

Adding a West Extension

There are three steps to adding your own extension:


1. Write the code implementing the command.
2. Add information about it to a west-commands.yml file.
3. Make sure the west-commands.yml file is referenced in the west manifest.
Note that west ignores extension commands whose names are the same as a built-in command.

Step 1: Implement Your Command Create a Python file to contain your command implementation
(see the “Meta > Requires” information on the west PyPI page for details on the currently supported
versions of Python). You can put it in anywhere in any project tracked by your west manifest, or the
manifest repository itself. This file must contain a subclass of the west.commands.WestCommand class;
this class will be instantiated and used when your extension is run.
Here is a basic skeleton you can use to get started. It contains a subclass of WestCommand, with imple-
mentations for all the abstract methods. For more details on the west APIs you can use, see west-apis.

2.10. West (Zephyr’s meta-tool) 155


Zephyr Project Documentation, Release 3.4.0

'''my_west_extension.py

Basic example of a west extension.'''

from textwrap import dedent # just for nicer code indentation

from west.commands import WestCommand # your extension must subclass this


from west import log # use this for user output

class MyCommand(WestCommand):

def __init__(self):
super().__init__(
'my-command-name', # gets stored as self.name
'one-line help for what my-command-name does', # self.help
# self.description:
dedent('''
A multi-line description of my-command.

You can split this up into multiple paragraphs and they'll get
reflowed for you. You can also pass
formatter_class=argparse.RawDescriptionHelpFormatter when calling
parser_adder.add_parser() below if you want to keep your line
endings.'''))

def do_add_parser(self, parser_adder):


# This is a bit of boilerplate, which allows you full control over the
# type of argparse handling you want. The "parser_adder" argument is
# the return value of an argparse.ArgumentParser.add_subparsers() call.
parser = parser_adder.add_parser(self.name,
help=self.help,
description=self.description)

# Add some example options using the standard argparse module API.
parser.add_argument('-o', '--optional', help='an optional argument')
parser.add_argument('required', help='a required argument')

return parser # gets stored as self.parser

def do_run(self, args, unknown_args):


# This gets called when the user runs the command, e.g.:
#
# $ west my-command-name -o FOO BAR
# --optional is FOO
# required is BAR
log.inf('--optional is', args.optional)
log.inf('required is', args.required)

You can ignore the second argument to do_run() (unknown_args above), as WestCommand will reject
unknown arguments by default. If you want to be passed a list of unknown arguments instead, add
accepts_unknown_args=True to the super().__init__() arguments.

Step 2: Add or Update Your west-commands.yml You now need to add a west-commands.yml file to
your project which describes your extension to west.
Here is an example for the above class definition, assuming it’s in my_west_extension.py at the project
root directory:

156 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

west-commands:
- file: my_west_extension.py
commands:
- name: my-command-name
class: MyCommand
help: one-line help for what my-command-name does

The top level of this YAML file is a map with a west-commands key. The key’s value is a sequence
of “command descriptors”. Each command descriptor gives the location of a file implementing west
extensions, along with the names of those extensions, and optionally the names of the classes which
define them (if not given, the class value defaults to the same thing as name).
Some information in this file is redundant with definitions in the Python code. This is because west won’t
import my_west_extension.py until the user runs west my-command-name, since:
• It allows users to run west update with a manifest from an untrusted source, then use other west
commands without your code being imported along the way. Since importing a Python module is
shell-equivalent, this provides some peace of mind.
• It’s a small optimization, since your code will only be imported if it is needed.
So, unless your command is explicitly run, west will just load the west-commands.yml file to get the basic
information it needs to display information about your extension to the user in west --help output, etc.
If you have multiple extensions, or want to split your extensions across multiple files, your
west-commands.yml will look something like this:

west-commands:
- file: my_west_extension.py
commands:
- name: my-command-name
class: MyCommand
help: one-line help for what my-command-name does
- file: another_file.py
commands:
- name: command2
help: another cool west extension
- name: a-third-command
class: ThirdCommand
help: a third command in the same file as command2

Above:
• my_west_extension.py defines extension my-command-name with class MyCommand
• another_file.py defines two extensions:
1. command2 with class command2
2. a-third-command with class ThirdCommand
See the file west-commands-schema.yml in the west repository for a schema describing the contents of
a west-commands.yml.

Step 3: Update Your Manifest Finally, you need to specify the location of the west-commands.yml you
just edited in your west manifest. If your extension is in a project, add it like this:

manifest:
# [... other contents ...]

projects:
(continues on next page)

2.10. West (Zephyr’s meta-tool) 157


Zephyr Project Documentation, Release 3.4.0

(continued from previous page)


- name: your-project
west-commands: path/to/west-commands.yml
# [... other projects ...]

Where path/to/west-commands.yml is relative to the root of the project. Note that the name
west-commands.yml, while encouraged, is just a convention; you can name the file something else if
you need to.
Alternatively, if your extension is in the manifest repository, just do the same thing in the manifest’s self
section, like this:

manifest:
# [... other contents ...]

self:
west-commands: path/to/west-commands.yml

That’s it; you can now run west my-command-name. Your command’s name, help, and the project which
contains its code will now also show up in the west --help output. If you share the updated repositories
with others, they’ll be able to use it, too.

2.10.10 Building, Flashing and Debugging

Zephyr provides several west extension commands for building, flashing, and interacting with Zephyr
programs running on a board: build, flash, debug, debugserver and attach.
For information on adding board support for the flashing and debugging commands, see Flash and debug
support in the board porting guide.

Building: west build

Tip: Run west build -h for a quick overview.

The build command helps you build Zephyr applications from source. You can use west config to config-
ure its behavior.
Its default behavior tries to “do what you mean”:
• If there is a Zephyr build directory named build in your current working directory, it is incremen-
tally re-compiled. The same is true if you run west build from a Zephyr build directory.
• Otherwise, if you run west build from a Zephyr application’s source directory and no build direc-
tory is found, a new one is created and the application is compiled in it.

Basics The easiest way to use west build is to go to an application’s root directory (i.e. the folder
containing the application’s CMakeLists.txt) and then run:

west build -b <BOARD>

Where <BOARD> is the name of the board you want to build for. This is exactly the same name you would
supply to CMake if you were to invoke it with: cmake -DBOARD=<BOARD>.

Tip: You can use the west boards command to list all supported boards.

158 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

A build directory named build will be created, and the application will be compiled there after west
build runs CMake to create a build system in that directory. If west build finds an existing build
directory, the application is incrementally re-compiled there without re-running CMake. You can force
CMake to run again with --cmake.
You don’t need to use the --board option if you’ve already got an existing build directory; west build
can figure out the board from the CMake cache. For new builds, the --board option, BOARD environment
variable, or build.board configuration option are checked (in that order).

Sysbuild (multi-domain builds) Sysbuild (System build) can be used to create a multi-domain build
system combining multiple images for a single or multiple boards.
Use --sysbuild to select the Sysbuild (System build) build infrastructure with west build to build
multiple domains.
More detailed information regarding the use of sysbuild can be found in the Sysbuild (System build)
guide.

Tip: The build.sysbuild configuration option can be enabled to tell west build to default build using
sysbuild. --no-sysbuild can be used to disable sysbuild for a specific build.

west build will build all domains through the top-level build folder of the domains specified by sysbuild.
A single domain from a multi-domain project can be built by using --domain argument.

Examples Here are some west build usage examples, grouped by area.

Forcing CMake to Run Again To force a CMake re-run, use the --cmake (or -c) option:

west build -c

Setting a Default Board To configure west build to build for the reel_board by default:

west config build.board reel_board

(You can use any other board supported by Zephyr here; it doesn’t have to be reel_board.)

Setting Source and Build Directories To set the application source directory explicitly, give its path as
a positional argument:

west build -b <BOARD> path/to/source/directory

To set the build directory explicitly, use --build-dir (or -d):

west build -b <BOARD> --build-dir path/to/build/directory

To change the default build directory from build, use the build.dir-fmt configuration option. This lets
you name build directories using format strings, like this:

west config build.dir-fmt "build/{board} /{app} "

With the above, running west build -b reel_board samples/hello_world will use build directory
build/reel_board/hello_world. See Configuration Options for more details on this option.

2.10. West (Zephyr’s meta-tool) 159


Zephyr Project Documentation, Release 3.4.0

Setting the Build System Target To specify the build system target to run, use --target (or -t).
For example, on host platforms with QEMU, you can use the run target to build and run the hello_world
sample for the emulated qemu_x86 board in one command:

west build -b qemu_x86 -t run samples/hello_world

As another example, to use -t to list all build system targets:

west build -t help

As a final example, to use -t to run the pristine target, which deletes all the files in the build directory:

west build -t pristine

Pristine Builds A pristine build directory is essentially a new build directory. All byproducts from
previous builds have been removed.
To force west build make the build directory pristine before re-running CMake to generate a build
system, use the --pristine=always (or -p=always) option.
Giving --pristine or -p without a value has the same effect as giving it the value always. For example,
these commands are equivalent:

west build -p -b reel_board samples/hello_world


west build -p=always -b reel_board samples/hello_world

By default, west build applies a heuristic to detect if the build directory needs to be made pristine. This
is the same as using --pristine=auto.

Tip: You can run west config build.pristine always to always do a pristine build, or west config
build.pristine never to disable the heuristic. See the west build Configuration Options for details.

Verbose Builds To print the CMake and compiler commands run by west build, use the global west
verbosity option, -v:

west -v build -b reel_board samples/hello_world

One-Time CMake Arguments To pass additional arguments to the CMake invocation performed by
west build, pass them after a -- at the end of the command line.

Important: Passing additional CMake arguments like this forces west build to re-run the CMake build
configuration step, even if a build system has already been generated. This will make incremental builds
slower (but still much faster than building from scratch).
After using -- once to generate the build directory, use west build -d <build-dir> on subsequent
runs to do incremental builds.
Alternatively, make your CMake arguments permanent as described in the next section; it will not slow
down incremental builds.

For example, to use the Unix Makefiles CMake generator instead of Ninja (which west build uses by
default), run:

west build -b reel_board -- -G'Unix Makefiles'

160 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

To use Unix Makefiles and set CMAKE_VERBOSE_MAKEFILE to ON:

west build -b reel_board -- -G'Unix Makefiles' -DCMAKE_VERBOSE_MAKEFILE=ON

Notice how the -- only appears once, even though multiple CMake arguments are given. All command-
line arguments to west build after a -- are passed to CMake.
To set DTC_OVERLAY_FILE to enable-modem.overlay, using that file as a devicetree overlay:

west build -b reel_board -- -DDTC_OVERLAY_FILE=enable-modem.overlay

To merge the file.conf Kconfig fragment into your build’s .config:

west build -- -DEXTRA_CONF_FILE=file.conf

Permanent CMake Arguments The previous section describes how to add CMake arguments for a
single west build command. If you want to save CMake arguments for west build to use every time
it generates a new build system instead, you should use the build.cmake-args configuration option.
Whenever west build runs CMake to generate a build system, it splits this option’s value according to
shell rules and includes the results in the cmake command line.
Remember that, by default, west build tries to avoid generating a new build system if one is present
in your build directory. Therefore, you need to either delete any existing build directories or do a pristine
build after setting build.cmake-args to make sure it will take effect.
For example, to always enable CMAKE_EXPORT_COMPILE_COMMANDS, you can run:

west config build.cmake-args -- -DCMAKE_EXPORT_COMPILE_COMMANDS=ON

(The extra -- is used to force the rest of the command to be treated as a positional argument. Without
it, west config would treat the -DVAR=VAL syntax as a use of its -D option.)
To enable CMAKE_VERBOSE_MAKEFILE, so CMake always produces a verbose build system:

west config build.cmake-args -- -DCMAKE_VERBOSE_MAKEFILE=ON

To save more than one argument in build.cmake-args, use a single string whose value can be split into
distinct arguments (west build uses the Python function shlex.split() internally to split the value).
For example, to enable both CMAKE_EXPORT_COMPILE_COMMANDS and CMAKE_VERBOSE_MAKEFILE:

west config build.cmake-args -- "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_VERBOSE_


˓→MAKEFILE=ON"

If you want to save your CMake arguments in a separate file instead, you can combine CMake’s -C
<initial-cache> option with build.cmake-args. For instance, another way to set the options used in
the previous example is to create a file named ~/my-cache.cmake with the following contents:

set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE BOOL "")


set(CMAKE_VERBOSE_MAKEFILE ON CACHE BOOL "")

Then run:

west config build.cmake-args "-C ~/my-cache.cmake"

See the cmake(1) manual page and the set() command documentation for more details.

Build tool arguments Use -o to pass options to the underlying build tool.
This works with both ninja (the default) and make based build systems.
For example, to pass -dexplain to ninja:

2.10. West (Zephyr’s meta-tool) 161


Zephyr Project Documentation, Release 3.4.0

west build -o=-dexplain

As another example, to pass --keep-going to make:

west build -o=--keep-going

Note that using -o=--foo instead of -o --foo is required to prevent --foo from being treated as a west
build option.

Build parallelism By default, ninja uses all of your cores to build, while make uses only one. You can
control this explicitly with the -j option supported by both tools.
For example, to build with 4 cores:

west build -o=-j4

The -o option is described further in the previous section.

Build a single domain In a multi-domain build with hello_world and MCUboot, you can use --domain
hello_world to only build this domain:

west build --sysbuild --domain hello_world

The --domain argument can be combined with the --target argument to build the specific target for
the target, for example:

west build --sysbuild --domain hello_world --target help

Use a snippet See Using Snippets.

Configuration Options You can configure west build using these options.

162 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

Option Description
build.board String. If given, this the board used by west build when --board is not given
and BOARD is unset in the environment.
build.board_warn Boolean, default true. If false, disables warnings when west build can’t
figure out the target board.
build.cmake-args String. If present, the value will be split according to shell rules and passed
to CMake whenever a new build system is generated. See Permanent CMake
Arguments.
build.dir-fmt String, default build. The build folder format string, used by west when-
ever it needs to create or locate a build folder. The currently available
arguments are:
• board: The board name
• source_dir: The relative path from the current working directory to
the source directory. If the current working directory is inside the
source directory this will be set to an empty string.
• app: The name of the source directory.

build.generator String, default Ninja. The CMake Generator to use to create a build system.
(To set a generator for a single build, see the above example)
build.guess-dir String, instructs west whether to try to guess what build folder to use when
build.dir-fmt is in use and not enough information is available to resolve
the build folder name. Can take these values:
• never (default): Never try to guess, bail out instead and require the
user to provide a build folder with -d.
• runners: Try to guess the folder when using any of the ‘runner’ com-
mands. These are typically all commands that invoke an external tool,
such as flash and debug.

build.pristine String. Controls the way in which west build may clean the build folder
before building. Can take the following values:
• never (default): Never automatically make the build folder pristine.
• auto: west build will automatically make the build folder pristine
before building, if a build system is present and the build would fail
otherwise (e.g. the user has specified a different board or application
from the one previously used to make the build directory).
• always: Always make the build folder pristine before building, if a
build system is present.

build.sysbuild Boolean, default false. If true, build application using the sysbuild infras-
tructure.

Flashing: west flash

Tip: Run west flash -h for additional help.

Basics From a Zephyr build directory, re-build the binary and flash it to your board:

west flash

Without options, the behavior is the same as ninja flash (or make flash, etc.).
To specify the build directory, use --build-dir (or -d):

2.10. West (Zephyr’s meta-tool) 163


Zephyr Project Documentation, Release 3.4.0

west flash --build-dir path/to/build/directory

If you don’t specify the build directory, west flash searches for one in build, then the current working
directory. If you set the build.dir-fmt configuration option (see Setting Source and Build Directories),
west flash searches there instead of build.

Choosing a Runner If your board’s Zephyr integration supports flashing with multiple programs, you
can specify which one to use using the --runner (or -r) option. For example, if West flashes your board
with nrfjprog by default, but it also supports JLink, you can override the default with:

west flash --runner jlink

You can override the default flash runner at build time by using the BOARD_FLASH_RUNNER CMake vari-
able, and the debug runner with BOARD_DEBUG_RUNNER.
For example:

# Set the default runner to "jlink", overriding the board's


# usual default.
west build [...] -- -DBOARD_FLASH_RUNNER=jlink

See One-Time CMake Arguments and Permanent CMake Arguments for more information on setting CMake
arguments.
See Flash and debug runners below for more information on the runner library used by West. The list
of runners which support flashing can be obtained with west flash -H; if run from a build directory or
with --build-dir, this will print additional information on available runners for your board.

Configuration Overrides The CMake cache contains default values West uses while flashing, such as
where the board directory is on the file system, the path to the zephyr binaries to flash in several formats,
and more. You can override any of this configuration at runtime with additional options.
For example, to override the HEX file containing the Zephyr image to flash (assuming your runner expects
a HEX file), but keep other flash configuration at default values:

west flash --hex-file path/to/some/other.hex

The west flash -h output includes a complete list of overrides supported by all runners.

Runner-Specific Overrides Each runner may support additional options related to flashing. For exam-
ple, some runners support an --erase flag, which mass-erases the flash storage on your board before
flashing the Zephyr image.
To view all of the available options for the runners your board supports, as well as their usage informa-
tion, use --context (or -H):

west flash --context

Important: Note the capital H in the short option name. This re-runs the build in order to ensure the
information displayed is up to date!

When running West outside of a build directory, west flash -H just prints a list of runners. You can use
west flash -H -r <runner-name> to print usage information for options supported by that runner.
For example, to print usage information about the jlink runner:

164 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

west flash -H -r jlink

Multi-domain flashing When a Sysbuild (multi-domain builds) folder is detected, then west flash will
flash all domains in the order defined by sysbuild.
It is possible to flash the image from a single domain in a multi-domain project by using --domain.
For example, in a multi-domain build with hello_world and MCUboot, you can use the --domain
hello_world domain to only flash only the image from this domain:

west flash --domain hello_world

Debugging: west debug, west debugserver

Tip: Run west debug -h or west debugserver -h for additional help.

Basics From a Zephyr build directory, to attach a debugger to your board and open up a debug console
(e.g. a GDB session):

west debug

To attach a debugger to your board and open up a local network port you can connect a debugger to
(e.g. an IDE debugger):

west debugserver

Without options, the behavior is the same as ninja debug and ninja debugserver (or make debug,
etc.).
To specify the build directory, use --build-dir (or -d):

west debug --build-dir path/to/build/directory


west debugserver --build-dir path/to/build/directory

If you don’t specify the build directory, these commands search for one in build, then the current working
directory. If you set the build.dir-fmt configuration option (see Setting Source and Build Directories),
west debug searches there instead of build.

Choosing a Runner If your board’s Zephyr integration supports debugging with multiple programs,
you can specify which one to use using the --runner (or -r) option. For example, if West debugs your
board with pyocd-gdbserver by default, but it also supports JLink, you can override the default with:

west debug --runner jlink


west debugserver --runner jlink

See Flash and debug runners below for more information on the runner library used by West. The list of
runners which support debugging can be obtained with west debug -H; if run from a build directory or
with --build-dir, this will print additional information on available runners for your board.

Configuration Overrides The CMake cache contains default values West uses for debugging, such as
where the board directory is on the file system, the path to the zephyr binaries containing symbol tables,
and more. You can override any of this configuration at runtime with additional options.

2.10. West (Zephyr’s meta-tool) 165


Zephyr Project Documentation, Release 3.4.0

For example, to override the ELF file containing the Zephyr binary and symbol tables (assuming your
runner expects an ELF file), but keep other debug configuration at default values:
west debug --elf-file path/to/some/other.elf
west debugserver --elf-file path/to/some/other.elf

The west debug -h output includes a complete list of overrides supported by all runners.

Runner-Specific Overrides Each runner may support additional options related to debugging. For
example, some runners support flags which allow you to set the network ports used by debug servers.
To view all of the available options for the runners your board supports, as well as their usage informa-
tion, use --context (or -H):
west debug --context

(The command west debugserver --context will print the same output.)

Important: Note the capital H in the short option name. This re-runs the build in order to ensure the
information displayed is up to date!

When running West outside of a build directory, west debug -H just prints a list of runners. You can use
west debug -H -r <runner-name> to print usage information for options supported by that runner.
For example, to print usage information about the jlink runner:
west debug -H -r jlink

Multi-domain debugging west debug can only debug a single domain at a time. When a Sysbuild
(multi-domain builds) folder is detected, west debug will debug the default domain specified by sys-
build.
The default domain will be the application given as the source directory. See the following example:
west build --sysbuild path/to/source/directory

For example, when building hello_world with MCUboot using sysbuild, hello_world becomes the de-
fault domain:
west build --sysbuild samples/hello_world

So to debug hello_world you can do:


west debug

or:
west debug --domain hello_world

If you wish to debug MCUboot, you must explicitly specify MCUboot as the domain to debug:
west debug --domain mcuboot

Flash and debug runners

The flash and debug commands use Python wrappers around various Flash & Debug Host Tools. These
wrappers are all defined in a Python library at scripts/west_commands/runners. Each wrapper is called
a runner. Runners can flash and/or debug Zephyr programs.

166 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

The central abstraction within this library is ZephyrBinaryRunner, an abstract class which represents
runners. The set of available runners is determined by the imported subclasses of ZephyrBinaryRunner.
ZephyrBinaryRunner is available in the runners.core module; individual runner implementations are
in other submodules, such as runners.nrfjprog, runners.openocd, etc.

Hacking

This section documents the runners.core module used by the flash and debug commands. This is the
core abstraction used to implement support for these features.

Warning: These APIs are provided for reference, but they are more “shared code” used to implement
multiple extension commands than a stable API.

Developers can add support for new ways to flash and debug Zephyr programs by implementing addi-
tional runners. To get this support into upstream Zephyr, the runner should be added into a new or
existing runners module, and imported from runners/__init__.py.

Note: The test cases in scripts/west_commands/tests add unit test coverage for the runners package
and individual runner classes.
Please try to add tests when adding new runners. Note that if your changes break existing test cases, CI
testing on upstream pull requests will fail.

Zephyr binary runner core interfaces


This provides the core ZephyrBinaryRunner class meant for public use, as well as some other helpers for
concrete runner classes.
class runners.core.BuildConfiguration(build_dir: str)
This helper class provides access to build-time configuration.
Configuration options can be read as if the object were a dict, either object[‘CONFIG_FOO’] or
object.get(‘CONFIG_FOO’).
Kconfig configuration values are available (parsed from .config).
getboolean(option)
If a boolean option is explicitly set to y or n, returns its value. Otherwise, falls back to False.
class runners.core.DeprecatedAction(option_strings, dest, nargs=None, const=None,
default=None, type=None, choices=None, required=False,
help=None, metavar=None)

class runners.core.FileType(value, names=None, *, module=None, qualname=None, type=None,


start=1, boundary=None)

exception runners.core.MissingProgram(program)
FileNotFoundError subclass for missing program dependencies.
No significant changes from the parent FileNotFoundError; this is useful for explicitly signaling that
the file in question is a program that some class requires to proceed.
The filename attribute contains the missing program.
class runners.core.NetworkPortHelper
Helper class for dealing with local IP network ports.

2.10. West (Zephyr’s meta-tool) 167


Zephyr Project Documentation, Release 3.4.0

get_unused_ports(starting_from)
Find unused network ports, starting at given values.
starting_from is an iterable of ports the caller would like to use.
The return value is an iterable of ports, in the same order, using the given values if they were
unused, or the next sequentially available unused port otherwise.
Ports may be bound between this call’s check and actual usage, so callers still need to handle
errors involving returned ports.
class runners.core.RunnerCaps(commands: Set[str] = {'attach', 'debug', 'debugserver', 'flash'}, dev_id:
bool = False, flash_addr: bool = False, erase: bool = False, tool_opt:
bool = False, file: bool = False)
This class represents a runner class’s capabilities.
Each capability is represented as an attribute with the same name. Flag attributes are True or False.
Available capabilities:
• commands: set of supported commands; default is {‘flash’, ‘debug’, ‘debugserver’, ‘attach’}.
• dev_id: whether the runner supports device identifiers, in the form of an -i, –dev-id option.
This is useful when the user has multiple debuggers connected to a single computer, in order
to select which one will be used with the command provided.
• flash_addr: whether the runner supports flashing to an arbitrary address. Default is False. If
true, the runner must honor the –dt-flash option.
• erase: whether the runner supports an –erase option, which does a mass-erase of the entire
addressable flash on the target before flashing. On multi-core SoCs, this may only erase
portions of flash specific the actual target core. (This option can be useful for things like
clearing out old settings values or other subsystem state that may affect the behavior of the
zephyr image. It is also sometimes needed by SoCs which have flash-like areas that can’t be
sector erased by the underlying tool before flashing; UICR on nRF SoCs is one example.)
• tool_opt: whether the runner supports a –tool-opt (-O) option, which can be given multiple
times and is passed on to the underlying tool that the runner wraps.
class runners.core.RunnerConfig(build_dir: str, board_dir: str, elf_file: Optional[str], hex_file:
Optional[str], bin_file: Optional[str], uf2_file: Optional[str], file:
Optional[str], file_type: Optional[FileType] = FileType.OTHER,
gdb: Optional[str] = None, openocd: Optional[str] = None,
openocd_search: List[str] = [])
Runner execution-time configuration.
This is a common object shared by all runners. Individual runners can register specific configuration
options using their do_add_parser() hooks.
bin_file: Optional[str]
Alias for field number 4
board_dir: str
Alias for field number 1
build_dir: str
Alias for field number 0
elf_file: Optional[str]
Alias for field number 2
file: Optional[str]
Alias for field number 6

168 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

file_type: Optional[FileType]
Alias for field number 7
gdb: Optional[str]
Alias for field number 8
hex_file: Optional[str]
Alias for field number 3
openocd: Optional[str]
Alias for field number 9
openocd_search: List[str]
Alias for field number 10
uf2_file: Optional[str]
Alias for field number 5
class runners.core.ZephyrBinaryRunner(cfg: RunnerConfig)
Abstract superclass for binary runners (flashers, debuggers).
Note: this class’s API has changed relatively rarely since it as added, but it is not considered a
stable Zephyr API, and may change without notice.
With some exceptions, boards supported by Zephyr must provide generic means to be flashed (have
a Zephyr firmware binary permanently installed on the device for running) and debugged (have a
breakpoint debugger and program loader on a host workstation attached to a running target).
This is supported by four top-level commands managed by the Zephyr build system:
• ‘flash’: flash a previously configured binary to the board, start execution on the target, then
return.
• ‘debug’: connect to the board via a debugging protocol, program the flash, then drop the user
into a debugger interface with symbol tables loaded from the current binary, and block until
it exits.
• ‘debugserver’: connect via a board-specific debugging protocol, then reset and halt the target.
Ensure the user is now able to connect to a debug server with symbol tables loaded from the
binary.
• ‘attach’: connect to the board via a debugging protocol, then drop the user into a debugger
interface with symbol tables loaded from the current binary, and block until it exits. Unlike
‘debug’, this command does not program the flash.
This class provides an API for these commands. Every subclass is called a ‘runner’ for short. Each
runner has a name (like ‘pyocd’), and declares commands it can handle (like ‘flash’). Boards (like
‘nrf52dk_nrf52832’) declare which runner(s) are compatible with them to the Zephyr build system,
along with information on how to configure the runner to work with the board.
The build system will then place enough information in the build directory to create and use
runners with this class’s create() method, which provides a command line argument parsing API.
You can also create runners by instantiating subclasses directly.
In order to define your own runner, you need to:
1. Define a ZephyrBinaryRunner subclass, and implement its abstract methods. You may need to
override capabilities().
2. Make sure the Python module defining your runner class is imported, e.g. by editing this
package’s __init__.py (otherwise, get_runners() won’t work).
3. Give your runner’s name to the Zephyr build system in your board’s board.cmake.
Additional advice:

2.10. West (Zephyr’s meta-tool) 169


Zephyr Project Documentation, Release 3.4.0

• If you need to import any non-standard-library modules, make sure to catch ImportError and
defer complaints about it to a RuntimeError if one is missing. This avoids affecting users that
don’t require your runner, while still making it clear what went wrong to users that do require
it that don’t have the necessary modules installed.
• If you need to ask the user something (e.g. using input()), do it in your create() classmethod,
not do_run(). That ensures your __init__() really has everything it needs to call do_run(),
and also avoids calling input() when not instantiating within a command line application.
• Use self.logger to log messages using the standard library’s logging API; your logger is named
“runner.<your-runner-name()>”
For command-line invocation from the Zephyr build system, runners define their own argparse-
based interface through the common add_parser() (and runner-specific do_add_parser() it dele-
gates to), and provide a way to create instances of themselves from a RunnerConfig and parsed
runner-specific arguments via create().
Runners use a variety of host tools and configuration values, the user interface to which is ab-
stracted by this class. Each runner subclass should take any values it needs to execute one of these
commands in its constructor. The actual command execution is handled in the run() method.
classmethod add_parser(parser)
Adds a sub-command parser for this runner.
The given object, parser, is a sub-command parser from the argparse module. For more details,
refer to the documentation for argparse.ArgumentParser.add_subparsers().
The lone common optional argument is:
• –dt-flash (if the runner capabilities includes flash_addr)
Runner-specific options are added through the do_add_parser() hook.
property build_conf: BuildConfiguration
Get a BuildConfiguration for the build directory.
call(cmd: List[str], **kwargs) → int
Subclass subprocess.call() wrapper.
Subclasses should use this method to run command in a subprocess and get its return code,
rather than using subprocess directly, to keep accurate debug logs.
classmethod capabilities() → RunnerCaps
Returns a RunnerCaps representing this runner’s capabilities.
This implementation returns the default capabilities.
Subclasses should override appropriately if needed.
cfg
RunnerConfig for this instance.
check_call(cmd: List[str], **kwargs)
Subclass subprocess.check_call() wrapper.
Subclasses should use this method to run command in a subprocess and check that it executed
correctly, rather than using subprocess directly, to keep accurate debug logs.
check_output(cmd: List[str], **kwargs) → bytes
Subclass subprocess.check_output() wrapper.
Subclasses should use this method to run command in a subprocess and check that it executed
correctly, rather than using subprocess directly, to keep accurate debug logs.

170 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

classmethod create(cfg: RunnerConfig, args: Namespace) → ZephyrBinaryRunner


Create an instance from command-line arguments.
• cfg: runner configuration (pass to superclass __init__)
• args: arguments parsed from execution environment, as specified by add_parser().
classmethod dev_id_help() → str
Get the ArgParse help text for the –dev-id option.
abstract classmethod do_add_parser(parser)
Hook for adding runner-specific options.
abstract classmethod do_create(cfg: RunnerConfig, args: Namespace) → ZephyrBinaryRunner
Hook for instance creation from command line arguments.
abstract do_run(command: str, **kwargs)
Concrete runner; run() delegates to this. Implement in subclasses.
In case of an unsupported command, raise a ValueError.
ensure_output(output_type: str) → None
Ensure self.cfg has a particular output artifact.
For example, ensure_output(‘bin’) ensures that self.cfg.bin_file refers to an existing file. Errors
out if it’s missing or undefined.
Parameters
output_type – string naming the output type
static flash_address_from_build_conf(build_conf: BuildConfiguration)
If CONFIG_HAS_FLASH_LOAD_OFFSET is n in build_conf, return the CON-
FIG_FLASH_BASE_ADDRESS value. Otherwise, return CONFIG_FLASH_BASE_ADDRESS +
CONFIG_FLASH_LOAD_OFFSET.
static get_flash_address(args: Namespace, build_conf: BuildConfiguration, default: int = 0)
→ int
Helper method for extracting a flash address.
If args.dt_flash is true, returns the address obtained from ZephyrBinaryRun-
ner.flash_address_from_build_conf(build_conf).
Otherwise (when args.dt_flash is False), the default value is returned.
static get_runners() → List[Type[ZephyrBinaryRunner]]
Get a list of all currently defined runner classes.
logger
logging.Logger for this instance.
abstract classmethod name() → str
Return this runner’s user-visible name.
When choosing a name, pick something short and lowercase, based on the name of the tool
(like openocd, jlink, etc.) or the target architecture/board (like xtensa etc.).
popen_ignore_int(cmd: List[str], **kwargs) → Popen
Spawn a child command, ensuring it ignores SIGINT.
The returned subprocess.Popen object must be manually terminated.
static require(program: str) → str
Require that a program is installed before proceeding.
Parameters
program – name of the program that is required, or path to a program binary.

2.10. West (Zephyr’s meta-tool) 171


Zephyr Project Documentation, Release 3.4.0

If program is an absolute path to an existing program binary, this call succeeds. Otherwise,
try to find the program by name on the system PATH.
If the program can be found, its path is returned. Otherwise, raises MissingProgram.
run(command: str, **kwargs)
Runs command (‘flash’, ‘debug’, ‘debugserver’, ‘attach’).
This is the main entry point to this runner.
run_client(client)
Run a client that handles SIGINT.
run_server_and_client(server, client)
Run a server that ignores SIGINT, and a client that handles it.
This routine portably:
• creates a Popen object for the server command which ignores SIGINT
• runs client in a subprocess while temporarily ignoring SIGINT
• cleans up the server after the client exits.
It’s useful to e.g. open a GDB server and client.
property thread_info_enabled: bool
Returns True if self.build_conf has CONFIG_DEBUG_THREAD_INFO enabled.
classmethod tool_opt_help() → str
Get the ArgParse help text for the –tool-opt option.

Doing it By Hand

If you prefer not to use West to flash or debug your board, simply inspect the build directory for the
binaries output by the build system. These will be named something like zephyr/zephyr.elf, zephyr/
zephyr.hex, etc., depending on your board’s build system integration. These binaries may be flashed
to a board using alternative tools of your choice, or used for debugging as needed, e.g. as a source of
symbol tables.
By default, these West commands rebuild binaries before flashing and debugging. This can of course
also be accomplished using the usual targets provided by Zephyr’s build system (in fact, that’s how these
commands do it).

2.10.11 Signing Binaries

The west sign extension command can be used to sign a Zephyr application binary for consumption by
a bootloader using an external tool. Run west sign -h for command line help.

MCUboot / imgtool

The Zephyr build system has special support for signing binaries for use with the MCUboot bootloader
using the imgtool program provided by its developers. You can both build and sign this type of application
binary in one step by setting some Kconfig options. If you do, west flash will use the signed binaries.
If you use this feature, you don’t need to run west sign yourself; the build system will do it for you.
Here is an example workflow, which builds and flashes MCUboot, as well as the hello_world application
for chain-loading by MCUboot. Run these commands from the zephyrproject workspace you created
in the Getting Started Guide.

172 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

west build -b YOUR_BOARD bootloader/mcuboot/boot/zephyr -d build-mcuboot


west build -b YOUR_BOARD zephyr/samples/hello_world -d build-hello-signed -- \
-DCONFIG_BOOTLOADER_MCUBOOT=y \
-DCONFIG_MCUBOOT_SIGNATURE_KEY_FILE=\"bootloader/mcuboot/root-rsa-2048.pem\"

west flash -d build-mcuboot


west flash -d build-hello-signed

Notes on the above commands:


• YOUR_BOARD should be changed to match your board
• The CONFIG_MCUBOOT_SIGNATURE_KEY_FILE value is the insecure default provided and used by by
MCUboot for development and testing
• You can change the hello_world application directory to any other application that can be loaded
by MCUboot, such as the smp_svr_sample
For more information on these and other related configuration options, see:
• CONFIG_BOOTLOADER_MCUBOOT: build the application for loading by MCUboot
• CONFIG_MCUBOOT_SIGNATURE_KEY_FILE: the key file to use with west sign. If you have your own
key, change this appropriately
• CONFIG_MCUBOOT_EXTRA_IMGTOOL_ARGS: optional additional command line arguments for imgtool
• CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE: also generate a confirmed image, which may be
more useful for flashing in production environments than the OTA-able default image
• On Windows, if you get “Access denied” issues, the recommended fix is to run pip3 install
imgtool, then retry with a pristine build directory.
If your west flash runner uses an image format supported by imgtool, you should see something like
this on your device’s serial console when you run west flash -d build-mcuboot:

*** Booting Zephyr OS build zephyr-v2.3.0-2310-gcebac69c8ae1 ***


[00:00:00.004,669] <inf> mcuboot: Starting bootloader
[00:00:00.011,169] <inf> mcuboot: Primary image: magic=unset, swap_type=0x1, copy_
˓→done=0x3, image_ok=0x3

[00:00:00.021,636] <inf> mcuboot: Boot source: none


[00:00:00.027,313] <wrn> mcuboot: Failed reading image headers; Image=0
[00:00:00.035,064] <err> mcuboot: Unable to find bootable image

Then, you should see something like this when you run west flash -d build-hello-signed:

*** Booting Zephyr OS build zephyr-v2.3.0-2310-gcebac69c8ae1 ***


[00:00:00.004,669] <inf> mcuboot: Starting bootloader
[00:00:00.011,169] <inf> mcuboot: Primary image: magic=unset, swap_type=0x1, copy_
˓→done=0x3, image_ok=0x3

[00:00:00.021,636] <inf> mcuboot: Boot source: none


[00:00:00.027,374] <inf> mcuboot: Swap type: none
[00:00:00.115,142] <inf> mcuboot: Bootloader chainload address offset: 0xc000
[00:00:00.123,168] <inf> mcuboot: Jumping to the first image slot
*** Booting Zephyr OS build zephyr-v2.3.0-2310-gcebac69c8ae1 ***
Hello World! nrf52840dk_nrf52840

Whether west flash supports this feature depends on your runner. The nrfjprog and pyocd runners
work with the above flow. If your runner does not support this flow and you would like it to, please send
a patch or file an issue for adding support.

2.10. West (Zephyr’s meta-tool) 173


Zephyr Project Documentation, Release 3.4.0

Extending signing externally

The signing script used when running west flash can be extended or replaced to change features or
introduce different signing mechanisms. By default with MCUboot enabled, signing is setup by the
cmake/mcuboot.cmake file in Zephyr which adds extra post build commands for generating the signed
images. The file used for signing can be replaced by adjusting the SIGNING_SCRIPT property on the
zephyr_property_target, ideally done by a module using:

if(CONFIG_BOOTLOADER_MCUBOOT)
set_target_properties(zephyr_property_target PROPERTIES SIGNING_SCRIPT ${CMAKE_
˓→CURRENT_LIST_DIR}/custom_signing.cmake)

endif()

This will include the custom signing CMake file instead of the default Zephyr one when projects are
built with MCUboot signing support enabled. The base Zephyr MCUboot signing file can be used as a
reference for creating a new signing system or extending the default behaviour.

rimage

rimage configuration uses a different approach that does not rely on Kconfig or CMake but on west config
instead, similar to Permanent CMake Arguments.
Signing involves a number of “wrapper” scripts stacked on top of each other: west flash invokes west
build which invokes cmake and ninja which invokes west sign which invokes imgtool or rimage. As
long as the signing parameters desired are the default ones and fairly static, these indirections are not
a problem. On the other hand, passing imgtool or rimage options through all these layers can causes
issues typical when the layers don’t abstract anything. First, this usually requires boilerplate code in
each layer. Quoting whitespace or other special characters through all the wrappers can be difficult.
Reproducing a lower west sign command to debug some build-time issue can be very time-consuming:
it requires at least enabling and searching verbose build logs to find which exact options were used.
Copying these options from the build logs can be unreliable: it may produce different results because of
subtle environment differences. Last and worst: new signing feature and options are impossible to use
until more boilerplate code has been added in each layer.
To avoid these issues, rimage parameters can bet set in west config instead. Here’s a workspace/.
west/config example:

[sign]
# Not needed when invoked from CMake
tool = rimage

[rimage]
# Quoting is optional and works like in Unix shells
# Not needed when rimage can be found in the default PATH
path = "/home/me/zworkspace/build-rimage/rimage"

# Not needed when using the default development key


extra-args = -i 4 -k 'keys/key argument with space.pem'

In order to support quoting, values are parsed by Python’s shlex.split() like in One-Time CMake Argu-
ments.
The extra-args are passed directly to the rimage command. The example above has the same effect as
appending them on command line after -- like this: west sign --tool rimage -- -i 4 -k 'keys/
key argument with space.pem'. In case both are used, the command-line arguments go last.

174 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

2.10.12 Additional Zephyr extension commands

This page documents miscellaneous Zephyr Extensions.

Listing boards: west boards

The boards command can be used to list the boards that are supported by Zephyr without having to
resort to additional sources of information.
It can be run by typing:

west boards

This command lists all supported boards in a default format. If you prefer to specify the display format
yourself you can use the --format (or -f) flag:

west boards -f "{arch} :{name} "

Additional help about the formatting options can be found by running:

west boards -h

Shell completion scripts: west completion

The completion extension command outputs shell completion scripts that can then be used directly to
enable shell completion for the supported shells.
It currently supports the following shells:
• bash
• zsh
Additional instructions are available in the command’s help:

west help completion

Installing CMake packages: west zephyr-export

This command registers the current Zephyr installation as a CMake config package in the CMake user
package registry.
In Windows, the CMake user package registry is found in HKEY_CURRENT_USER\Software\Kitware\
CMake\Packages.
In Linux and MacOS, the CMake user package registry is found in. ~/.cmake/packages.
You may run this command when setting up a Zephyr workspace. If you do, application CMakeLists.txt
files that are outside of your workspace will be able to find the Zephyr repository with the following:

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})

See share/zephyr-package/cmake for details.

2.10. West (Zephyr’s meta-tool) 175


Zephyr Project Documentation, Release 3.4.0

Software bill of materials: west spdx

This command generates SPDX 2.2 tag-value documents, creating relationships from source files to the
corresponding generated build files. SPDX-License-Identifier comments in source files are scanned
and filled into the SPDX documents.
To use this command:
1. Pre-populate a build directory BUILD_DIR like this:

west spdx --init -d BUILD_DIR

This step ensures the build directory contains CMake metadata required for SPDX document gen-
eration.
2. Build your application using this pre-created build directory, like so:

west build -d BUILD_DIR [...]

3. Generate SPDX documents using this build directory:

west spdx -d BUILD_DIR

This generates the following SPDX bill-of-materials (BOM) documents in BUILD_DIR/spdx/:


• app.spdx: BOM for the application source files used for the build
• zephyr.spdx: BOM for the specific Zephyr source code files used for the build
• build.spdx: BOM for the built output files
Each file in the bill-of-materials is scanned, so that its hashes (SHA256 and SHA1) can be recorded,
along with any detected licenses if an SPDX-License-Identifier comment appears in the file.
SPDX Relationships are created to indicate dependencies between CMake build targets, build targets that
are linked together, and source files that are compiled to generate the built library files.
west spdx accepts these additional options:
• -n PREFIX: a prefix for the Document Namespaces that will be included in the generated SPDX
documents. See SPDX specification clause 6 for details. If -n is omitted, a default namespace will
be generated according to the default format described in section 2.5 using a random UUID.
• -s SPDX_DIR: specifies an alternate directory where the SPDX documents should be written instead
of BUILD_DIR/spdx/.
• --analyze-includes: in addition to recording the compiled source code files (e.g. .c, .S) in the
bills-of-materials, also attempt to determine the specific header files that are included for each .c
file.
This takes longer, as it performs a dry run using the C compiler for each .c file using the same
arguments that were passed to it for the actual build.
• --include-sdk: with --analyze-includes, also create a fourth SPDX document, sdk.spdx,
which lists header files included from the SDK.

Working with binary blobs: west blobs

The blobs command allows users to interact with binary blobs declared in one or more modules via their
module.yml file.
The blobs command has three sub-commands, used to list, fetch or clean (i.e. delete) the binary blobs
themselves.
You can list binary blobs while specifying the format of the output:

176 Chapter 2. Developing with Zephyr


Zephyr Project Documentation, Release 3.4.0

west blobs list -f '{module} : {type} {path} '

For the full set of variables available in -f/--format run west blobs -h.
Fetching blobs works in a similar manner:

west blobs fetch

Note that, as described in the modules section, fetched blobs are stored in a zephyr/blobs/ folder relative
to the root of the corresponding module repository.
As does deleting them:

west blobs clean

Additionally the tool allows you to specify the modules you want to list, fetch or clean blobs for by typing
the module names as a command-line parameter.

Twister wrapper: west twister

This command is a wrapper for twister.


Twister can then be invoked via west as follows:

west twister -help


west twister -T tests/ztest/base

2.10.13 History and Motivation

West was added to the Zephyr project to fulfill two fundamental requirements:
• The ability to work with multiple Git repositories
• The ability to provide an extensible and user-friendly command-line interface for basic Zephyr
workflows
During the development of west, a set of Design Constraints were identified to avoid the common pitfalls
of tools of this kind.

Requirements

Although the motivation behind splitting the Zephyr codebase into multiple repositories is outside of the
scope of this page, the fundamental requirements, along with a clear justification of the choice not to use
existing tools and instead develop a new one, do belong here.
The basic requirements are:
• R1: Keep externally maintained code in separately maintained repositories outside of the main
zephyr repository, without requiring users to manually clone each of the external repositories
• R2: Provide a tool that both Zephyr users and distributors can make use of to benefit from and
extend
• R3: Allow users and downstream distributions to override or remove repositories without having
to make changes to the zephyr repository
• R4: Support both continuous tracking and commit-based (bisectable) project updating

2.10. West (Zephyr’s meta-tool) 177


Zephyr Project Documentation, Release 3.4.0

Rationale for a custom tool

Some of west’s features are similar to those provided by Git Submodules and Google’s repo.
Existing tools were considered during west’s initial design and development. None were found suitable
for Zephyr’s requirements. In particular, these were examined in detail:
• Google repo
– Does not cleanly support using zephyr as the manifest repository (R4)
– Python 2 only
– Does not play well with Windows
– Assumes Gerrit is used for code review
• Git submodules
– Does not fully support R1, since the externally maintained repositories would still need to be
inside the main zephyr Git tree
– Does not support R3, since downstream copies would need to either delete or replace sub-
module definitions
– Does not support continuous tracking of the latest HEAD in external repositories (R4)
– Requires hardcoding of the paths/locations of the external repositories

Multiple Git Repositories

Zephyr intends to provide all required building blocks needed to deploy complex IoT applications. This
in turn means that the Zephyr project is much more than an RTOS kernel, and is instead a collection
of components that work together. In this context, there are a few reasons to work with multiple Git
repositories in a standardized manner within the project:
• Clean separation of Zephyr original code and imported projects and libraries
• Avoidance of license incompatibilities between original and imported code
• Reduction in size and scope of the core Zephyr codebase, with additional repositories containing
optional components instead of being imported directly into the tree
• Safety and security certifications
• Enforcement of modularization of the components
• Out-of-tree development based on subsets of the supported boards and SoCs
See Basics for information on how west workspaces manage multiple git repositories.

Design Constraints

West is:
• Optional: it is always possible to drop back to “raw” command-line tools, i.e. use Zephyr without
using west (although west itself might need to be installed and accessible to the build system). It
may not always be convenient to do so, however. (If all of west’s features were already conveniently
available, there would be no reason to develop it.)
• Compatible with CMake: building, flashing and debu