Kernel 11.2.0 Linker Error

Hi,

I work with Kernel 11.2.0 R5 port. My project is cpp but I compile Kernel with gcc. Before Kernel 11.2.0 (such as 11.1.0) I can work without any problem but with Kernel 11.2.0, I have linker error that undefined reference to vAssertCalled function. The reason of this problem is, FreeRTOSConfig.h that define vAssertCalled function is defined after extern “C”

/* *INDENT-OFF* */
#ifdef __cplusplus
    extern "C" {
#endif
/* *INDENT-ON* */

/* Acceptable values for configTICK_TYPE_WIDTH_IN_BITS. */
#define TICK_TYPE_WIDTH_16_BITS    0
#define TICK_TYPE_WIDTH_32_BITS    1
#define TICK_TYPE_WIDTH_64_BITS    2

/* Application specific configuration options. */
#include "FreeRTOSConfig.h"

But in Kernel 11.2.0 FreeRTOSConfig.h is defined before extern “C”. I solved this problem with added extern “C” in the beginning of the FreeRTOSConfig.h.

Normal coding conventions say that “external” header, like FreeRTOSConfig.h shouldn’t normally be included inside an extern “C” block.

FreeRTOSConfig.h should declare for itself the function vAssertCalled inside a small extern “C” block (with the appropriate C++ check guards).

1 Like

I do not see any #ifdef __cplusplus in FreeRTOS.h: FreeRTOS-Kernel/include/FreeRTOS.h at main · FreeRTOS/FreeRTOS-Kernel · GitHub. Which file are you talking about and where did you get that?

Adding extern “C” to your FreeRTOSConfig.h to a function for which you need C linkage seems correct to me.

#include <stdint.h> /* READ COMMENT ABOVE. */

/* *INDENT-OFF* */
#ifdef __cplusplus
    extern "C" {
#endif
/* *INDENT-ON* */

/* Acceptable values for configTICK_TYPE_WIDTH_IN_BITS. */
#define TICK_TYPE_WIDTH_16_BITS    0
#define TICK_TYPE_WIDTH_32_BITS    1
#define TICK_TYPE_WIDTH_64_BITS    2

/* Application specific configuration options. */
#include "FreeRTOSConfig.h"

This code belongs to FreeRTOS.h in Kernel 11.1.0 release. extern “C” includes the FreeRTOSConfig.h.
In 11.2.0 release,

#include <stdint.h> /* READ COMMENT ABOVE. */

/* Acceptable values for configTICK_TYPE_WIDTH_IN_BITS. */
#define TICK_TYPE_WIDTH_16_BITS    0
#define TICK_TYPE_WIDTH_32_BITS    1
#define TICK_TYPE_WIDTH_64_BITS    2

/* Application specific configuration options. */
#include "FreeRTOSConfig.h"

There is no extern “C” that cover FreeRTOSConfig.h.

extern “C” in 11.2.0, added after the include FreeRTOSConfig.h. line.

/* *INDENT-OFF* */
#ifdef __cplusplus
    extern "C" {
#endif
/* *INDENT-ON* */

#ifndef configUSE_C_RUNTIME_TLS_SUPPORT
    #define configUSE_C_RUNTIME_TLS_SUPPORT    0
#endif

#if ( configUSE_C_RUNTIME_TLS_SUPPORT == 1 )

    #ifndef configTLS_BLOCK_TYPE
        #error Missing definition:  configTLS_BLOCK_TYPE must be defined in FreeRTOSConfig.h when configUSE_C_RUNTIME_TLS_SUPPORT is set to 1.
    #endif

@emrecntz Thank you for sharing that. I see that it was changed in this PR - Move Header Includes Before Extern C by HTRamsey · Pull Request #1047 · FreeRTOS/FreeRTOS-Kernel · GitHub.

As I said before, your solution of adding extern “C” to your FreeRTOSConfig.h seems correct to me.

Thanks.

1 Like

@aggarg @richard-damon

thank you for your interest.

Its in line 147 and 3354, and have been there for ages. I think I might have been one of the causes of it, with a request many years ago.

The fix for bug 1064 moved it to where it should have been.

Note, the adding of them to FreeRTOSConfig.h is only needed if you only implement vAssertCalled in a C++ file (which is likely the normal case for C++ develepment). If you implement it as a normal C++ function in a C++ file, and also as a C function in a C file (perhaps with different operations) you don’t need it, and C code will call the C version, and C++ the C++ version.

Yes, it was a miss on my part which I realized later. Thank you for pointing it!