build: allow application code to opt out of Zephyr stdint convention#104292
build: allow application code to opt out of Zephyr stdint convention#104292npitre wants to merge 1 commit intozephyrproject-rtos:mainfrom
Conversation
Zephyr enforces a particular mapping of C99 fixed-width integer types through zephyr_stdint.h, force-included via -imacros on all translation units when CONFIG_ENFORCE_ZEPHYR_STDINT=y (the default). This remaps the compiler's built-in type macros so that int32_t is always "int" and int64_t is always "long long", ensuring that printf format specifiers like %d and %lld work consistently without warnings across ILP32 and LP64 architectures. This convention, introduced by commit f32330b ("stdint.h: streamline type definitions"), remains desirable for Zephyr's own internals: it provides a coherent type system across all supported architectures, enables reliable printf format validation at compile time, and avoids the syntactic burden of PRIxN macros throughout the kernel and subsystem code. However, application code has different concerns. Some toolchains (notably arm-none-eabi-gcc) natively define int32_t as "long int" and uint32_t as "unsigned long int". Compiler-provided headers such as those implementing language extensions and intrinsics are designed around these native type mappings. When Zephyr's override is in effect, it can create type conflicts with such headers, for example through C11 _Generic associations that become ambiguous when the remapped types collapse distinct type entries into duplicates. This has been observed with CMSIS-DSP which already works around the issue by locally defining the zephyr_stdint.h include guard to bypass the override (commit 8d95c2c ("modules/cmsis-dsp: Don't use Zephyr stdint.h")). That per-library approach does not scale well for application code that may pull in various compiler- provided headers. Introduce CONFIG_OMIT_ZEPHYR_STDINT_FOR_APPS to provide a proper separation of concerns: Zephyr's own code continues to benefit from the enforced type convention, while application code is free to use the toolchain's native type definitions and whatever compiler-provided headers it needs without conflict. The mechanism is the same approach used by CMSIS-DSP: pre-defining the include guard macro (ZEPHYR_INCLUDE_TOOLCHAIN_STDINT_H_) so that the -imacros header becomes a no-op for the app target. This is safe at the linker level because Zephyr is C-only code where symbol names carry no type encoding. The affected types (e.g. "int" vs "long" on ILP32, or "long" vs "long long" for 64-bit quantities) are guaranteed to share the same size and ABI calling convention on all architectures that Zephyr supports, so object code compiled under either convention links and interoperates correctly. Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
|
nordicjm
left a comment
There was a problem hiding this comment.
I don't see any reason for this since out-of-tree applications can just do this in their CMake file, and nothing in the zephyr tree should make use of this
|
I beg to differ. The fact that issue #46032 has been open for over 3 years without resolution, and that people are still running into this problem today (most recently ARM's own engineers struggling with ACLE intrinsics), suggests that "just do it in your CMake file" is not an adequate answer. For an application developer hitting a cryptic The most frequent criticism leveled at Zephyr is its steep learning curve, especially around the build system. New users are already expected to absorb Kconfig, devicetree, west, and CMake simultaneously. Telling them to also reverse-engineer internal build plumbing to work around a type conflict they didn't cause is exactly the kind of thing that drives people away. We should be lowering barriers, not defending them. A Kconfig option is discoverable through Making things easier for application developers is not a reason to reject a feature — it's the point of one. |
Then that is an issue for you toolchain/company, it is not a zephyr problem
Sure, then you can add it through a module you provide for your company which allows adding it with a Kconfig, but that is not a module needed in zephyr. Nothing posted above has changed my mind on that. And there's nothing wrong with having generic options in a custom module, you can do whatever you want downstream in custom modules |
tejlmand
left a comment
There was a problem hiding this comment.
Thanks for opening this topic.
I'm not convinced that a Kconfig setting on just the app lib is the right path in this case, though I do understand and acknowledge the problem faced.
I beg to differ. The fact that issue #46032 has been open for over 3 years without resolution, and that people are still running into this problem today (most recently ARM's own engineers struggling with ACLE intrinsics), suggests that "just do it in your CMake file" is not an adequate answer.
Thanks for opening the discussion in #46032 again.
It's definitely an important one.
For an application developer hitting a cryptic Generic conflict or a pointer type mismatch from a compiler-provided header, the path from build error to "I need to pre-define ZEPHYR_INCLUDE_TOOLCHAIN_STDINT_H on the app target" is non-obvious.
Agree, we need something better / cleaner.
And documenting it wouldn't really help: a page explaining Zephyr's internal type override plumbing and how to undo it from CMake is rather arid knowledge that application developers shouldn't have to acquire when a simple Kconfig knob can solve their problem.
Kconfig sure has it's benefits in the help text rendered into documentation and menuconfig.
The problem with Kconfig in this case is that it's localized to app lib, but the problem is more general. Any Zephyr module developed downstream, for example integrating existing (legacy?) code included into Zephyr build through the use of Zephyr modules and using zephyr_library() will suffer this issue if the code relies on the toolchain's native int types.
I'm curious, in your use-case, is it required that the app lib is a Zephyr library ?
Libraries created using add_library() will not have have zephyr_stdint.h applied.
But of course also none of the other things inherited through zephyr_interface, including whole-archive.



Summary
CONFIG_OMIT_ZEPHYR_STDINT_FOR_APPSto let application code use the toolchain's native integer type definitions while keeping Zephyr's own kernel, drivers, and subsystem code under the enforcedzephyr_stdint.hconvention.zephyr_stdint.hinclude guard for theappbuild target, using the same approach as CMSIS-DSP (commit 8d95c2c).Motivation
Zephyr's
zephyr_stdint.hremaps compiler-provided type macros (e.g.__INT32_TYPE__fromlong inttoint) to ensure consistentprintfformat specifiers across architectures. This is valuable for Zephyr's internal code but creates conflicts for application code that includes compiler-provided headers designed around native type mappings, such as those implementing language extensions and intrinsics.The conflict manifests through C11
_Genericassociations becoming ambiguous when the remapped types collapse distinct type entries into duplicates, or through pointer type mismatches in intrinsic function signatures.Ref: #46032