Determine Compiler Version

From Nutwiki
Jump to: navigation, search

Test Environments

Hardware Comments Nut/OS
4.6.3
Nut/OS
4.6.4
Nut/OS
4.7.4
Nut/OS
4.8.0
Nut/OS
4.8.7
Ethernut 1.3 H OK OK
Binaries
OK
Binaries
OK
Binaries
OK
Binaries
Compiler: AVR-GCC 4.3.2
Ethernut 2.1 B OK OK
Binaries
OK
Binaries
OK
Binaries
OK
Binaries
Compiler: AVR-GCC 4.3.2
Ethernut 3.0 E OK OK
Binaries
OK
Binaries
OK
Binaries
OK
Binaries
Compiler: AVR-GCC 4.3.2
EIR 1.0 C Set jumper JP1 to DEBUG mode. OK OK
Binaries
OK
Binaries
OK
Binaries
Compiler: ARM-GCC 4.2.2 ; AVR-GCC 4.3.0

Description

This example demonstrates how to determine which compiler was used to compile a program and in the case of the GNU C compiler how to display its version.

Source Code

<source lang="c">

  1. include <dev/board.h>
  2. include <stdio.h>
  1. define STRINGIFY_(x) #x
  2. define STRINGIFY(x) STRINGIFY_(x)
  1. if defined(__AVR__)
  2. define CPUTYPE "AVR"
  3. elif defined (__arm__)
  4. define CPUTYPE "ARM"
  5. else
  6. define CPUTYPE ""
  7. endif
  1. if defined(__GNUC__)
  2. if defined(__GNUC_PATCHLEVEL__)
  3. define COMPILER CPUTYPE "-" "GCC" " " STRINGIFY(__GNUC__) "." STRINGIFY(__GNUC_MINOR__) "." STRINGIFY(__GNUC_PATCHLEVEL__)
  4. else
  5. define COMPILER CPUTYPE "-" "GCC" " " STRINGIFY(__GNUC__) "." STRINGIFY(__GNUC_MINOR__)
  6. endif
  7. elif defined (__IMAGECRAFT__)
  8. define COMPILER "ICCAVR"
  9. else
  10. define COMPILER "Unknown"
  11. endif

int main(void) {

   u_long baud = 115200;
   NutRegisterDevice(&DEV_DEBUG, 0, 0);
   freopen(DEV_DEBUG_NAME, "w", stdout);
   _ioctl(_fileno(stdout), UART_SETSPEED, &baud);
   printf("Compiler: %s\n", COMPILER);
   for(;;);
   return 0;

} </source>

Output

Compiler: ARM-GCC 4.2.2

Details

The main action takes place in the preprocessor commands as you can see.

<source lang="c">

  1. define STRINGIFY_(x) #x
  2. define STRINGIFY(x) STRINGIFY_(x)

</source>

These lines are required to store an integer value in a string.

<source lang="c">

  1. if defined(__AVR__)
  2. define CPUTYPE "AVR"
  3. elif defined (__arm__)
  4. define CPUTYPE "ARM"
  5. else
  6. define CPUTYPE ""
  7. endif

</source>

This block of code checks if the current board uses an AVR or an ARM processor. It makes use of the macros __AVR__ and __arm__ , which are defined, if the corresponding CPU is installed. The new macro CPUTYPE now is defined as ARM or AVR. Before calling the main() function, the preprocessor substitutes CPUTYPE by ARM or AVR So, whenever we use CPUTYPE in our program we get either an "ARM" or an "AVR" string.

<source lang="c">

  1. if defined(__GNUC__)
  2. if defined(__GNUC_PATCHLEVEL__)
  3. define COMPILER CPUTYPE "-" "GCC" " " STRINGIFY(__GNUC__) "." STRINGIFY(__GNUC_MINOR__) "." STRINGIFY(__GNUC_PATCHLEVEL__)
  4. else
  5. define COMPILER CPUTYPE "-" "GCC" " " STRINGIFY(__GNUC__) "." STRINGIFY(__GNUC_MINOR__)
  6. endif
  7. elif defined (__IMAGECRAFT__)
  8. define COMPILER "ICCAVR"
  9. else
  10. define COMPILER "Unknown"
  11. endif

</source> This segment of code consists of 2 nested if statements, to determine, which compiler was used. Aditionally, if GNUC (GCC) was used, which version was used.

To do so, these 4 predefined macros are used.

  • __GNUC__ - Gets replaced by the major version number. (here: 4) Only defined if GCC was used as compiler.
  • __GNUC_MINOR__ - Gets replaced by the minor version number. (here: 2)
  • __GNUC_PATCHLEVEL__ - Gets replaced by the patchlevel (thrid position) version number (here: 2)
  • __IMAGECRAFT__ - Is defined if ICCAVR was used to compile.

So macros are not only used to be replaced by certain values, but also just to check if they were defined or not.

With

<source lang="c">

  1. define STRINGIFY_(x) #x
  2. define STRINGIFY(x) STRINGIFY_(x)

</source>

defined

<source lang="c">

  1. define COMPILER CPUTYPE "-" "GCC" " " STRINGIFY(__GNUC__) "." STRINGIFY(__GNUC_MINOR__) "." STRINGIFY(__GNUC_PATCHLEVEL__)

</source>

we can now use a macro "function" (STRINGIFY) to define a macro (COMPILER) as a string to contain integer values like __GNUC__ or (_GNUC_MINOR__ do.

In other words, STRINGIFY turns its parameter into a string value. These string values as well as some dots and the CPUTYPE macro (which "holds" a string already) replace COMPILER.

<source lang="c"> printf("Compiler: %s\n", COMPILER); </source>

So everytime we use COMPILER in our program, we get a string instead, which holds the compiler name and version.

See also