Using Nordic's SDKs with the GNU G++ Compiler

A persistant problem that people using the C++ compiler from the "GNU Tools for ARM Embedded Processors" toolchain has been the way that G++ handles the inline-assembly for the SVC instruction.

Specifically, you get an impossible constraint in 'asm' error when trying to use any softdevice header.

There have been a few questions about this here on the Nordic Developer Zone, here for example, with putative answers on StackOverflow.

However, myself and others have found that the "insert a cast" answer on StackOverflow does not work with the latest (4.9) G++ under the -Os optimization mode. Digging into the issue, it appears that different code generation and optimization options make it hit-and-miss with being able to use the GNU G++ compiler.

Note that often GCC will work even though G++ does not because the rules of type-inference for enumdiffer substantially between C and C++. For the current GNU compilers, even explicitly setting the type via enum : unsigned char { ... } does not work (and might be a compiler bug).

Therefore, I've created a tool on GitHub that automagically translates Nordic's enum header files into Keil-compatible #define constants.

Since I can't release the modified Nordic SDKs, I've opted to release the tool, enum2define.py and just the patch files under the MIT license.

Comments and suggestions (and better yet, patches) are gratefully accepted.

  • I got through all this and the application compiles and can be downloaded. BUT, when I use g++ to compile the application, the bootloader (compiled by gcc or Keil) starts and it appears that the application never gets to line 1 of main(). When I simply switch to gcc and add -std=gnu99, compile, download, it downloads, and the bootloader starts, and then vectors nicely to the app which runs.

    Why would simply changing gcc to g++ cause the app to not run? It compiles just fine (and yes, I did a few things to get compile success such as reorder some initializers and the stuff above). To be clear, the same exact code compiles fine on both g++, gcc, and Keil, but will not run when compiled by g++.

    BTW, I'm using the hrs_with_dfu example app.

  • Hi Andrew,

    I changed the line:

    	"bx r14" : : "I" (number) : "r0" \
    

    into:

    	"bx r14" : : "I" (static_cast<int>(number)) : "r0" \
    

    with an #ifdef __cplusplus around it.

    Cheers, Marcel

  • Hi, Carles!

    I'm sorry that I didn't reply earlier, but I did not get mail notification that your comment was here!

    The issue is only with the SVC enumerations due to the way the SVC call is defined in the nrf_svc.h header file. Specifically, it has something to do with the __asm( "svc %0\n" "bx r14" : : "I" (number) : "r0" ); call.

    The "I" (number) constraint requires a compile-time integer constant. In C, enums are just aliases to integers, the compiler has no problem with it. However, C++ does not equate integers with enums; they are a distinct type, even under C++03. You can technically set a typed enum storage class in C++11 via the enum name_t : short { ... syntax, but this does not work for some reason.

    I am not sure if this is a gcc bug or not; I suspect that inline assembly always plays poorly with standards.

    I'm using the official arm-none-eabi-gcc distribution on launchpad, BTW.

    Cheers, -Andrew.

    (BTW, enums that are not used in the SVC calls compile without issue, so the problem is only with enums passed to the inline assembler.)

  • Hi Andrew,

    Thanks for the great tool. Is this an issue only for SVC enumerations, or is it also a problem with the rest of enums present in SoftDevice header files? (i.e. events, options, etc)

    Thanks!