ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Zephyr BSP: 32-CMake构建系统

Zephyr BSP: 32-CMake构建系统 摘要:本文是 Zephyr BSP 系列第 33 篇,聚焦 CMake 构建系统。讲解zephyr_library()等构建宏、Devicetree/Kconfig/CMake 三角关系、SoC 与 Driver 的 CMake 层级差异,以及"Kconfig 开了但代码没编译"等常见坑的排查思路,并串联第 20~32 篇形成完整 BSP 闭环。关键词:Zephyr;CMake;BSP;构建系统;KconfigCMake / Build System:Zephyr BSP 最后是怎么"编译起来"的到第 31 篇,你已经把Company SoC 的 Kconfig 配置体系建立起来了。现在进入一个非常关键、也很容易混淆的部分:Devicetree 告诉 Zephyr「硬件是什么」,Kconfig 告诉 Zephyr「启用什么」,CMake 则负责告诉编译系统「到底编译哪些代码、去哪里找这些代码、怎么链接成最终 firmware」。所以可以把前面的几篇串起来:Zephyr BSP │ ┌──────────────┼──────────────┐ │ │ │ Devicetree Kconfig CMake │ │ │ 描述硬件结构 决定功能配置 决定构建过程 │ │ │ └──────────────┼──────────────┘ ↓ C / C++ Source ↓ Compiler ↓ Linker ↓ zephyr.elf / bin1. 为什么 BSP 需要 CMake?假设你的 Company SoC 有:Company SoC ├── UART ├── GPIO ├── SPI ├── I2C ├── TIMER ├── CLOCK └── IRQ对应 Zephyr source:soc/company/xyz/ ├── CMakeLists.txt ├── Kconfig ├── Kconfig.defconfig ├── soc.c ├── clock.c └── startup.c drivers/serial/ ├── uart_company.c drivers/gpio/ ├── gpio_company.c drivers/spi/ ├── spi_company.c问题来了:Zephyr 怎么知道这些 .c 文件应该被编译?答案就是:CMake例如:zephyr_library()zephyr_library_sources(soc.c clock.c startup.c)这实际上是在告诉 Zephyr:把这些 source 加入当前 build。2. Zephyr 的 CMake 不是普通 CMake这是非常重要的一点。你当然可以看到:add_library(...)add_executable(...)target_sources(...)target_include_directories(...)但 Zephyr BSP 通常大量使用自己的 CMake helper:zephyr_library()zephyr_library_sources()zephyr_library_sources_ifdef()zephyr_include_directories()例如:zephyr_library_sources(uart_company.c uart_company_dma.c)或者:zephyr_library_sources_ifdef(CONFIG_UART_COMPANY_DMA uart_company_dma.c)后者非常重要。它把:Kconfig ↓ CONFIG_UART_COMPANY_DMA ↓ CMake ↓ uart_company_dma.c连接起来。3. Kconfig 和 CMake 到底是什么关系?假设:Kconfig定义:CONFIG_COMPANY_UART CONFIG_COMPANY_UART_DMA CONFIG_COMPANY_SPI用户:CONFIG_COMPANY_UART=yCONFIG_COMPANY_UART_DMA=yCONFIG_COMPANY_SPI=n那么 CMake 可以:zephyr_library()zephyr_library_sources_ifdef(CONFIG_COMPANY_UART uart_company.c)zephyr_library_sources_ifdef(CONFIG_COMPANY_UART_DMA uart_company_dma.c)zephyr_library_sources_ifdef(CONFIG_COMPANY_SPI spi_company.c)最终:编译 ├── uart_company.c ├── uart_company_dma.c └── spi_company.c ❌所以:Kconfig 决定「有没有这个功能」,CMake 决定「这个功能对应哪些 source 被编译」。4. 最小 Company SoC CMakeLists.txt假设你的 SoC:soc/company/mychip/结构:soc/company/mychip/ ├── CMakeLists.txt ├── Kconfig ├── Kconfig.defconfig ├── soc.c ├── clock.c └── irq.c最简单:zephyr_library()zephyr_library_sources(soc.c clock.c irq.c)意思就是:创建 Zephyr library │ ├── soc.c ├── clock.c └── irq.c5. 如果代码依赖 CONFIG 呢?例如:CONFIG_SOC_COMPANY_MYCHIP=yCONFIG_COMPANY_CLOCK=y那么:zephyr_library()zephyr_library_sources(soc.c)zephyr_library_sources_ifdef(CONFIG_COMPANY_CLOCK clock.c)如果:CONFIG_COMPANY_CLOCK=y那么:clock.c加入 build。如果:CONFIG_COMPANY_CLOCK=n则:clock.c不会被编译。6. Driver 的 CMake 又在哪里?这里是 BSP 初学者非常容易迷糊的地方。你可能会认为:soc/company/mychip/ CMakeLists.txt会自动编译:drivers/serial/uart_company.c不会。SoC CMake 和 Driver CMake 是不同层级。例如:└── mychip/ └── CMakeLists.txt drivers/ └── serial/ └── CMakeLists.txtDriver 自己负责:zephyr_library()zephyr_library_sources_ifdef(CONFIG_UART_COMPANY uart_company.c)所以最终:SoC CMake │ ├── soc.c ├── clock.c └── irq.c │ ↓ Driver CMake │ ├── uart_company.c ├── gpio_company.c └── spi_company.c7. CMake 是怎么被 Zephyr 找到的?这是理解 Zephyr build system 的关键。用户执行:west build-bcompany_board app大致发生:LinkerCompilerNinjaApplication CMakeDriver CMakeSoC CMakeBoard CMakeCMakewest用户LinkerCompilerNinjaApplication CMakeDriver CMakeSoC CMakeBoard CMakeCMakewest用户
返回列表