[Analysis] CMake vs. Make Build-System Gap Analysis
- Dominant language
- C
- Stars
- 4k
- Forks
- 1.7k
- Avg merge
- 1d 17h
- Merged PRs (30d)
- 237
Description
### Description
# NuttX CMake vs. Make Build-System Gap Analysis
Keeping this here for visibility and so that we can AI-fix this quickly soon.
## Scope
This document records a static comparison of the NuttX CMake and GNU Make build systems in this workspace.
- **Make** is treated as the compatibility-complete reference implementation.
- **CMake** has a substantial working core, but is not feature- or coverage-complete.
- No files were changed while conducting the analysis.
- No configuration-specific build was run: `nuttx/.config` was absent in this checkout. Findings are based on the build graph, configuration code, and mechanical directory inventory.
## What CMake already supports
The CMake implementation has an established core:
- Out-of-source configuration from a board `defconfig`.
- Kconfig value export into CMake.
- Architecture toolchain selection before `project()`.
- Kernel, system, and application library graphs with link grouping.
- Flat and protected build handling, including `nuttx_user`.
- Standard firmware output formats (`bin`, `hex`, `srec`, disassembly).
- Linker-script preprocessing, maps, manifest generation, and board-specific post-build hooks.
- CMake configuration targets including `menuconfig`, `qconfig`, `olddefconfig`, `resetconfig`, `distcleanconfig`, and `savedefconfig`.
The principal issue is not the absence of a CMake foundation; it is incomplete compatibility coverage compared with Make.
## Confirmed gaps
| Priority | Gap | Evidence and impact |
|---|---|---|
| P0 | **11 architectures are Make-only** | `nuttx/arch/CMakeLists.txt:41` always enters `arch/${CONFIG_ARCH}`. The following architectures have `src/Makefile` but no `CMakeLists.txt`: `avr`, `ceva`, `hc`, `mips`, `misoc`, `or1k`, `renesas`, `sparc`, `x86`, `z16`, and `z80`. `arch/avr` has no CMake toolchain implementation either. Those configurations cannot be built through CMake. |
| P0 | **Board coverage is incomplete** | The CMake top level rejects a selected board when neither the board directory nor its `../common` directory has a `CMakeLists.txt` (`nuttx/CMakeLists.txt:269-272`). For example, `boards/arm/at32/at32f437-mini` has 12 Make-supported defconfigs and no CMake files; its parent has no `common/CMakeLists.txt`. Its configurations cannot be configured via CMake. |
| P0 | **119 application directories have Make rules but no CMake counterpart** | Inventory: `apps` has 643 Makefile directories, 535 CMake directories, and 119 Make-only directories. `nuttx_add_subdirectory()` only descends into child directories that contain `CMakeLists.txt` (`nuttx/cmake/nuttx_add_subdirectory.cmake:31-49`), so those apps are not visible to CMake. |
| P0 | **Database/SQLite is absent from CMake** | Make supports `apps/database` through `Directory.mk` (`apps/database/Makefile:23-25`). `apps/CMakeLists.txt:49-81` does not add `database`, and neither `apps/database` nor `apps/database/sqlite` contains a `CMakeLists.txt`. SQLite cannot be selected or built through CMake. |
| P0 | **External-tree Kconfig integration is disabled** | CMake hard-codes `EXTERNALDIR=dummy` and `DRIVERS_PLATFORM_DIR=dummy` (`nuttx/CMakeLists.txt:223-228`; `nuttx/cmake/menuconfig.cmake:26-29`). Make detects `external/Kconfig` and uses `EXTERNALDIR=external` when present (`nuttx/tools/Unix.mk:78-86`). External Kconfig/source integration has no equivalent in CMake. |
| P1 | **Custom board/chip support is unfinished** | CMake explicitly labels the current behavior “Unsupported custom board/chips yet, workaround” (`nuttx/CMakeLists.txt:344-349`). `boards/CMakeLists.txt:23-33` leaves custom-board Kconfig handling as TODO/commented logic. |
| P1 | **No generic CMake equivalent of deployment/export targets** | Make provides generic `flash`/`download`, `bootloader`, `clean_bootloader`, and `export` targets (`nuttx/tools/Unix.mk:606-637`, `:810-819`). Some individual CMake ports define similar board-specific targets, but no generic extension mechanism matches Make’s `FLASH` abstraction, and no general export target exists. Kernel export is explicitly TODO (`nuttx/CMakeLists.txt:940-943`). |
| P1 | **Configuration target coverage is smaller** | Make supports `config`, `oldconfig`, `olddefconfig`, `menuconfig`, `nconfig`, `qconfig`, `gconfig`, and `savedefconfig` (`nuttx/tools/Unix.mk:732-807`). CMake has `menuconfig`, `qconfig`, `olddefconfig`, reset/clean helpers, and `savedefconfig`, but no equivalents for `config`, `oldconfig`, `nconfig`, or `gconfig`. |
| P1 | **Protected combined HEX is known broken** | CMake states that `nuttx_combined.hex` “does not seem to be generating a functional hex file” (`nuttx/CMakeLists.txt:926-935`). This needs repair and a regression test. |
| P2 | **U-Boot deployment behavior differs** | Both systems generate `uImage`; Make optionally copies it to writable `/tftpboot` (`nuttx/tools/Unix.mk:590-597`). CMake leaves this as a TODO (`nuttx/CMakeLists.txt:740-752`). An explicit opt-in deployment target would preserve out-of-tree safety while restoring functionality. |
| P2 | **CMake documentation is effectively absent** | `Documentation/components/cmake.rst:5-6` says CMake documentation will be added “in the future.” There is no support matrix, target reference, known-incompatibilities list, or migration guide. |
| P2 | **Known configurations are documented as Make-only** | `rv-virt:python` is documented as not working with CMake (`Documentation/applications/interpreters/python/index.rst:29-36`), as is `sim/wamr` (`Documentation/applications/interpreters/wamr/index.rst:17-24`). |
## Application coverage details
The 119 Make-only application directories include notable groups such as:
- Audio / benchmarks / crypto: `audioutils/morsey`, `audioutils/rtttl-c`, `benchmarks/sd_bench`, `crypto/wolfssl`.
- Database: `database`, `database/sqlite`.
- Games: `NXDoom`, `brickmatch`, `match4`, `snake`.
- Graphics: `ft80x`, `libjpeg`, `nxglyphs`, `nxwidgets`, `nxwm`, `pdcurs34`, `screenshot`, `slcd`, `tiff`, `twm4nx`.
- Interpreters: `duktape`, `ficl`, `luajit`, Python, `toywasm`, `wasm3`, and Lua modules.
- ML / DSP: CMSIS, Darknet, NNabla Runtime, Liquid DSP.
- Networking: `bare`, `cwebsocket`, `mdns`, `nanopb`, `thttpd/cgi-src`, and `xedge`.
- System: `libffi`, `psmq`, `settings`, and `smf`.
- Wireless: `gs2200m` and `iwpan`.
- Language-specific examples: several Rust, Zig, Swift, D, and Nim examples.
Some entries are nested tests or helpers. Each should be triaged before being declared unsupported, but all have Make build metadata without a CMake equivalent.
## Root cause: different discovery models
Make discovers applications dynamically through `apps/Make.defs` and per-directory `Make.defs`/`Kconfig` metadata. CMake uses a fixed category list in `apps/CMakeLists.txt:49-81`, then descends only into directories with a `CMakeLists.txt`.
Consequences:
1. Adding a Make app is often sufficient for Make discovery.
2. Adding a CMake app requires a `CMakeLists.txt` at every necessary level.
3. Parent CMake lists must include the subtree.
4. Kconfig generation must include the subtree.
5. Special behavior must be ported: generated code, ROMFS, builtins, modules, external dependencies, or non-C language compilation.
This is the primary cause of continuing CMake coverage drift.
## Recommended remediation sequence
### 1. Establish a support contract and coverage reporting
- Define CMake support levels: configure, compile, link, artifact creation, deployment, and export.
- Add an automated report for selectable architectures, boards, and applications that have Make metadata but no CMake path.
- Publish a CMake support matrix and classify intentionally unsupported configurations.
### 2. Restore configuration/discovery parity
- Implement `EXTERNALDIR` and platform-driver discovery.
- Complete custom board/chip Kconfig and source integration.
- Add missing top-level app categories, beginning with `database`.
### 3. Close architecture and board coverage incrementally
- Port complete vertical slices: toolchain, architecture sources, chip selection, linker scripts, a representative board, and a build test.
- Prioritize actively maintained hardware rather than attempting every historical port at once.
- For intentionally unsupported targets, fail early with a precise message and a Make fallback instruction.
### 4. Port applications by reusable feature family
- Start with high-value components: SQLite, WolfSSL, Python/WAMR, popular graphics stacks, and language-specific application support.
- Create reusable CMake abstractions for recurring Make-only behavior before porting each individual application.
### 5. Restore operational parity
- Define a generic board extension API for `flash`, `download`, bootloader build/clean, and post-build packaging.
- Implement export packaging or document its supported replacement.
- Repair `nuttx_combined.hex` and add a regression test.
### 6. Add Make-vs-CMake parity tests
For each supported `board:config`, compare:
- successful configuration and final link;
- final artifact set;
- enabled builtin registrations and modules;
- Kconfig visibility;
- flat, protected, and kernel build modes where applicable.
## Best first deliverable
The highest-value initial project is an automated **board / architecture / application CMake coverage report**, paired with a maintained support matrix. This gives the project an objective baseline, allows prioritization, and prevents new Make-only additions from silently expanding the gap.
### Verification
- [x] I have verified before submitting the report.
Contributor guide
Research direction
Start by reading nuttx/arch/CMakeLists.txt, nuttx/CMakeLists.txt, apps/CMakeLists.txt, and nuttx/cmake/nuttx_add_subdirectory.cmake, then compare them with the Make metadata and discovery paths named in the issue. Define the support levels and generate an automated report of architectures, boards, and applications with Make metadata but no CMake path. Done means the report and a maintained support matrix are available.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c, cmake
- Domain
- build-system, embedded-iot
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100