Skip to content

cmake: Do not link an executable to detect the compiler.#19507

Open
casaroli wants to merge 1 commit into
apache:masterfrom
casaroli:fix-cmake-try-compile
Open

cmake: Do not link an executable to detect the compiler.#19507
casaroli wants to merge 1 commit into
apache:masterfrom
casaroli:fix-cmake-try-compile

Conversation

@casaroli

@casaroli casaroli commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Summary

CMake validates a compiler by building and linking a small test program.
For a bare-metal cross toolchain that link cannot succeed on its own terms — no
start files, no default linker script, no libc — and the flags NuttX supplies
for it assume a toolchain shipped with newlib. arch/arm/src/cmake/gcc.cmake
sets:

set(CMAKE_EXE_LINKER_FLAGS_INIT "--specs=nosys.specs")

A perfectly usable arm-none-eabi-gcc built without those specs therefore
fails configuration before a single NuttX source file is considered.

Setting CMAKE_TRY_COMPILE_TARGET_TYPE to STATIC_LIBRARY makes the detection
step compile without linking. This is the approach CMake documents for
cross-compiling to bare metal, and NuttX does not currently set it anywhere in
the tree.

The issue is not ARM-specific, so the setting lives in the top-level
CMakeLists.txt, in the block that already selects CMAKE_TOOLCHAIN_FILE
before project() triggers detection. sim is excluded: it is hosted and
links real host executables, so it keeps the usual executable-based detection.
try_compile() reads the variable from the calling scope, so it takes effect
from there without having to live in a toolchain file — and
tools/toolchain.cmake.export already sets the same line for the exported
build, confirming it is generic rather than arch-specific.

Impact

  • Users: the CMake build becomes usable with any bare-metal cross toolchain
    that lacks nosys.specs, including the Homebrew arm-none-eabi-gcc and other
    newlib-less builds. Previously it could not configure at all.
  • Toolchains that do ship nosys.specs: unaffected. The setting applies
    only to CMake's own compiler-detection step, not to the NuttX link.
  • sim: unaffected — excluded by the CONFIG_ARCH guard, so hosted
    detection is exactly as before.
  • Other bare-metal arches: the setting is generic, so any arch that hits
    the same newlib-less detection failure benefits, not just ARM.
  • Build process: no change to any produced artifact.
  • Documentation / hardware / security / compatibility: unaffected.

Testing

Board: mps3-an547:picostest, CMake + Ninja generator.

Before (master 7df7c6ee):

$ cmake -B build -DBOARD_CONFIG=mps3-an547:picostest -GNinja
    arm-none-eabi-gcc: fatal error: cannot read spec file 'nosys.specs': No such file or directory
    compilation terminated.
    ninja: build stopped: subcommand failed.

  CMake will not be able to correctly generate this project.
Call Stack (most recent call first):
  CMakeLists.txt:481 (project)

-- Configuring incomplete, errors occurred!

After this patch, configuration succeeds:

$ cmake -B build -DBOARD_CONFIG=mps3-an547:picostest -GNinja
-- Check for working CXX compiler: /opt/homebrew/bin/arm-none-eabi-g++ - skipped
-- Detecting CXX compile features - done
-- Configuring done (2.5s)
-- Generating done (0.1s)
-- Build files have been written to: build

and the tree then compiles — 1248 objects built:

$ ninja -k 0
...
$ grep -c "Building C object" ninja.log
1248

The build stops at the final link, for a reason this patch does not address and
does not introduce:

FAILED: [code=1] nuttx
arm-none-eabi-g++: fatal error: cannot read spec file 'nosys.specs': No such file or directory

That is the NuttX link itself passing --specs=nosys.specs
(gcc.cmake:277), not CMake's detection step. With this patch the compile
phase is fully exercised on a newlib-less toolchain, where before nothing could
be configured.

(CONFIG_LIBM=y / CONFIG_LIBM_TOOLCHAIN=n was set for the run above, for the
same missing-newlib reason.)

Regression check on a toolchain that does ship newlib

The obvious question is whether this weakens compiler detection where it
currently works. Repeating the configure step with the Arm GNU Toolchain
15.2.Rel1:

Toolchain master with this patch
Arm GNU 15.2.Rel1 (has nosys.specs) configure OK configure OK
Homebrew 16.1.0 (no nosys.specs) configure FAILS configure OK

So the patch strictly widens the set of usable toolchains.

With the newlib toolchain the build then proceeds through 1120 objects and
stops at the final link — again identically with and without this patch:

ld: libs/libc/builtin/lib_builtin_forindex.c:62: undefined reference to `g_builtins'
sched/init/nx_bringup.c:391: undefined reference to `nsh_main'

That is this board config not linking its applications, which reproduces on
unmodified master and is unrelated to this change. I mention it only so the
absence of a nuttx binary in these logs is not mistaken for a regression.

Re-verified from the top-level location

With the setting moved to CMakeLists.txt, mps3-an547:picostest configures
identically — Check for working C compiler … skipped confirms
CMAKE_TRY_COMPILE_TARGET_TYPE takes effect from the top-level scope, so it
does not need to reside in a toolchain file. tools/checkpatch.sh -c -u -m -g
passes on the change.

@github-actions github-actions Bot added Arch: arm Issues related to ARM (32-bit) architecture Size: S The size of the change in this PR is small labels Jul 23, 2026
@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown

MemBrowse Memory Report

No memory changes detected for:

@casaroli
casaroli force-pushed the fix-cmake-try-compile branch 2 times, most recently from 6cfd507 to 22f8bf8 Compare July 23, 2026 06:55
jerpelea
jerpelea previously approved these changes Jul 23, 2026
Comment thread arch/arm/src/cmake/Toolchain.cmake Outdated
# Building a static library instead exercises the compiler and stops short of
# the link, which is the documented approach for this case.

set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we move to a more common places? since it isn't specific to arm.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe this is valid for x86 as well, on bare-metal only architectures I think it might not make sense.

I am ok with moving this to somewhere more generic. Where do you suggest?

I think we would need to make sure this is not included in the sim target. Right? WDYT?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or move to each arch's cmake file

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved to top level CMakeLists and guarded against simmoved to top level CMakeLists and guarded against sim

acassis
acassis previously approved these changes Jul 23, 2026
@casaroli
casaroli force-pushed the fix-cmake-try-compile branch from 22f8bf8 to c4c8b32 Compare July 23, 2026 17:03
@casaroli casaroli changed the title arch/arm/cmake: do not link an executable to detect the compiler arch/arm/cmake: Do not link an executable to detect the compiler. Jul 23, 2026
CMake validates a compiler by building and linking a test program.  For a
bare metal cross toolchain that link cannot succeed on its own terms, and
the flags NuttX supplies for it assume a toolchain shipped with newlib:
gcc.cmake sets

  set(CMAKE_EXE_LINKER_FLAGS_INIT "--specs=nosys.specs")

A perfectly usable arm-none-eabi-gcc built without those specs therefore
fails configuration before a single NuttX source file is considered:

  arm-none-eabi-gcc: fatal error: cannot read spec file 'nosys.specs':
  No such file or directory
  CMake Error: ... CMake will not be able to correctly generate this
  project.

Setting CMAKE_TRY_COMPILE_TARGET_TYPE to STATIC_LIBRARY makes the
detection step compile without linking, which is the documented approach
for cross compiling to a bare metal target.  Toolchains that do ship
nosys.specs are unaffected: the flag only applies to CMake's own
detection, not to the NuttX link.

This is not arch specific, so it is set once in the top level CMakeLists.txt
alongside the toolchain-file selection, before project() triggers detection.
sim is excluded: it is hosted and links real host executables, so it keeps
the usual executable-based detection.  try_compile() reads the variable from
the calling scope, so it takes effect without living in a toolchain file;
tools/toolchain.cmake.export already sets the same for the exported build.

Assisted-by: Claude Code:claude-opus-4-8
Assisted-by: Claude Code:claude-fable-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
@casaroli
casaroli dismissed stale reviews from acassis, jerpelea, and xiaoxiang781216 via 2de8b47 July 24, 2026 11:39
@casaroli
casaroli force-pushed the fix-cmake-try-compile branch from c4c8b32 to 2de8b47 Compare July 24, 2026 11:39
@github-actions github-actions Bot added Area: Build system and removed Arch: arm Issues related to ARM (32-bit) architecture labels Jul 24, 2026
@casaroli casaroli changed the title arch/arm/cmake: Do not link an executable to detect the compiler. cmake: Do not link an executable to detect the compiler. Jul 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: Build system Size: S The size of the change in this PR is small

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants