utility/rtos_compatibility_layers/FreeRTOS/FreeRTOS.h chooses the interrupt primitives by compiler rather than by target:
#ifndef portDISABLE_INTERRUPTS
#if defined(__IAR_SYSTEMS_ICC__)
#define portDISABLE_INTERRUPTS() __disable_interrupt()
#elif defined(__GNUC__ )
#define portDISABLE_INTERRUPTS() __disable_interrupts()
#elif defined(__ARMCC_VERSION)
#define portDISABLE_INTERRUPTS() __disable_irq()
#else
UINT _tx_thread_interrupt_disable(VOID);
#define portDISABLE_INTERRUPTS() _tx_thread_interrupt_disable()
#endif
#endif
portENABLE_INTERRUPTS is structured the same way.
__disable_interrupts() is a bare metal intrinsic. GCC hosted on Linux does not provide it, so any GCC build that is not for a bare metal target selects a symbol that does not exist. The failure is at link time, in vPortEnterCritical() and vPortExitCritical():
undefined reference to `__disable_interrupts'
undefined reference to `__enable_interrupts'
The #else branch already carries a portable fallback built on the ThreadX primitives, _tx_thread_interrupt_disable() and _tx_thread_interrupt_restore(), which would work here. It is simply unreachable for any GNU build.
Impact
The compatibility layer cannot be built with GCC for a hosted target without the application defining both macros itself. That includes the Linux port, which is what the regression suites use, so it is the first thing anyone hits when testing the layer on a host.
Workaround in place
The suite added in #583 defines both macros in its own FreeRTOSConfig.h, pointing them at the ThreadX primitives from the header's own #else branch. Both macros are #ifndef guarded, so a configuration file can pre-empt the choice. That is a fixture level workaround, not a fix.
Suggested fix
Gate the compiler branches on the target as well, so that a GNU build only selects __disable_interrupts() when the target actually provides it, and otherwise falls through to the ThreadX based branch. The ThreadX fallback is correct everywhere ThreadX runs, so it is a reasonable default with the intrinsics as the special case rather than the other way round.
Notes
Found while building the regression suite in #583.
utility/rtos_compatibility_layers/FreeRTOS/FreeRTOS.hchooses the interrupt primitives by compiler rather than by target:portENABLE_INTERRUPTSis structured the same way.__disable_interrupts()is a bare metal intrinsic. GCC hosted on Linux does not provide it, so any GCC build that is not for a bare metal target selects a symbol that does not exist. The failure is at link time, invPortEnterCritical()andvPortExitCritical():The
#elsebranch already carries a portable fallback built on the ThreadX primitives,_tx_thread_interrupt_disable()and_tx_thread_interrupt_restore(), which would work here. It is simply unreachable for any GNU build.Impact
The compatibility layer cannot be built with GCC for a hosted target without the application defining both macros itself. That includes the Linux port, which is what the regression suites use, so it is the first thing anyone hits when testing the layer on a host.
Workaround in place
The suite added in #583 defines both macros in its own
FreeRTOSConfig.h, pointing them at the ThreadX primitives from the header's own#elsebranch. Both macros are#ifndefguarded, so a configuration file can pre-empt the choice. That is a fixture level workaround, not a fix.Suggested fix
Gate the compiler branches on the target as well, so that a GNU build only selects
__disable_interrupts()when the target actually provides it, and otherwise falls through to the ThreadX based branch. The ThreadX fallback is correct everywhere ThreadX runs, so it is a reasonable default with the intrinsics as the special case rather than the other way round.Notes
Found while building the regression suite in #583.