Tuesday, April 14, 2015

Configuring PC-Lint to use with Atmel Studio and GCC Toolchain.

Generation of macro definition headers, --i options and size options for Lint when using Atmel GCC toolchain.

In theory this is done by using co-gcc.mak file provided with PC-Lint intallation (see C:/lint/lnt folder). I guess this works with standalone GCC installation. But when GCC is provided as part of Atmel Studio, invoking GNU make from C:\Program Files (x86)\Atmel\Atmel Studio 6.2\shellUtils folder doesn't work.
Instead, I just did manually all that makefile does.
Here's step-by-step instructions.

1) Makefile must provide a lot of options to Make utility to get correct output. These options are:
- GCC_BIN='name of gcc binary'
- GXX_BIN='name of g++ binary'
- CFLAGS='[usual C compile switches here]'
- CXXFLAGS='[usual C++ compile switches here]'
- CPPFLAGS='[usual common preprocessor switches here]'
- COMMON_FLAGS='[usual C & C++ compile switches here]'
In case of only C program we don't need all these C++ options, so we'll get only what we need.

2) Get COMMON_FLAGS options from Atmel Studio.
Open Project Properties (press Alt+F7), then get your options from Toolchain->ARM/GNU Common tab:

In our case it's -mthumb -D__SAMD21J17A__.

3) Get CFLAGS from Toolchain->ARM/GNU C Compiler tab. It's a huge list of options:
Here's full list: 
-x c -mthumb -D__SAMD21J17A__ -DDEBUG -DBOARD=SAMD21_XPLAINED_PRO -D__SAMD21J18A__ -DARM_MATH_CM0=true -DSPI_CALLBACK_MODE=false -DEXTINT_CALLBACK_MODE=true -DEVENTS_INTERRUPT_HOOKS_MODE=true  -I"../sam0/drivers/sercom/spi/quick_start_master/samd21_xplained_pro" -I"../src/ASF/sam0/utils/header_files" -I"../src/ASF/sam0/drivers/system/power/power_sam_d_r" -I"../src/ASF/common/utils" -I"../src/ASF/sam0/drivers/system/pinmux" -I"../src/ASF/sam0/drivers/system/power" -I"../src/ASF/sam0/drivers/system/reset/reset_sam_d_r" -I"../src/ASF/common/boards" -I"../src/ASF/sam0/drivers/sercom/spi" -I"../src/ASF/sam0/drivers/port" -I"../src/ASF/sam0/drivers/system/clock/clock_samd21_r21" -I"../src/ASF/sam0/boards" -I"../src/ASF/sam0/utils" -I"../src/ASF/thirdparty/CMSIS/Include" -I"../src/config" -I"../src/ASF/thirdparty/CMSIS/Lib/GCC" -I"../src/ASF/sam0/drivers/system/reset" -I"../src/ASF/sam0/drivers/system/interrupt/system_interrupt_samd21" -I"../src/ASF/sam0/boards/samd21_xplained_pro" -I"../src" -I"../src/ASF/sam0/drivers/sercom" -I"../src/ASF/sam0/utils/preprocessor" -I"../src/ASF/sam0/utils/cmsis/samd21/include" -I"../src/ASF/sam0/drivers/system" -I"../src/ASF/sam0/utils/cmsis/samd21/source" -I"../src/ASF/sam0/drivers/system/clock" -I"../src/ASF/sam0/drivers/system/interrupt" -I"../inc" -I"../src/ASF/common2/services/delay" -I"../src/ASF/common2/services/delay/sam0" -I"../src/ASF/sam0/drivers/extint" -I"../src/ASF/sam0/drivers/extint/extint_sam_d_r" -I"../src/ASF/common/services/ioport" -I"../src/ASF/sam0/drivers/events/events_sam_d_r" -I"../src/ASF/sam0/drivers/events"  -O3 -fdata-sections -ffunction-sections -g3 -Wall -mcpu=cortex-m0plus -c -pipe -fno-strict-aliasing -Wall -Wstrict-prototypes -Wmissing-prototypes -Werror-implicit-function-declaration -Wpointer-arith -std=gnu99 -ffunction-sections -fdata-sections -Wchar-subscripts -Wcomment -Wformat=2 -Wimplicit-int -Wmain -Wparentheses -Wsequence-point -Wreturn-type -Wswitch -Wtrigraphs -Wunused -Wuninitialized -Wunknown-pragmas -Wfloat-equal -Wundef -Wshadow -Wbad-function-cast -Wwrite-strings -Wsign-compare -Waggregate-return  -Wmissing-declarations -Wformat -Wmissing-format-attribute -Wno-deprecated-declarations -Wpacked -Wredundant-decls -Wnested-externs -Wunreachable-code -Wcast-align --param max-inline-insns-single=500  -Wno-long-long -MD -MP -MF "$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -MT"$(@:%.o=%.o)"

Notice, that CFLAGS does contain both COMMON_FLAGS options. There's no need to use them twice, so we can drop COMMON_FLAGS and stick with CFLAGS only.

4) This is optional, but it lets to run GCC executable by only printing it's name without the full (and very long) path to it every time.
Add path to GCC binaries to PATH system variable. The path is "C:\Program Files (x86)\Atmel\Atmel Toolchain\ARM GCC\Native\4.8.1429\arm-gnu-toolchain\bin".

5) Create empty C file, for example D:\empty.c.
Get  macro definitions and redirect them to file by running GCC command with all that CFLAGS as arguments plus "-E -dM empty.c >lint_cmac.h" assuming you run command line from drive D:.

To have fully prepared command at hand, I created file D:\gcc_get_lint_cmac.txt with such contents:
arm-none-eabi-gcc -x c -mthumb -D__SAMD21J17A__ -DDEBUG -DBOARD=SAMD21_XPLAINED_PRO -D__SAMD21J18A__ -DARM_MATH_CM0=true -DSPI_CALLBACK_MODE=false -DEXTINT_CALLBACK_MODE=true -DEVENTS_INTERRUPT_HOOKS_MODE=true  -I"../sam0/drivers/sercom/spi/quick_start_master/samd21_xplained_pro" -I"../src/ASF/sam0/utils/header_files" -I"../src/ASF/sam0/drivers/system/power/power_sam_d_r" -I"../src/ASF/common/utils" -I"../src/ASF/sam0/drivers/system/pinmux" -I"../src/ASF/sam0/drivers/system/power" -I"../src/ASF/sam0/drivers/system/reset/reset_sam_d_r" -I"../src/ASF/common/boards" -I"../src/ASF/sam0/drivers/sercom/spi" -I"../src/ASF/sam0/drivers/port" -I"../src/ASF/sam0/drivers/system/clock/clock_samd21_r21" -I"../src/ASF/sam0/boards" -I"../src/ASF/sam0/utils" -I"../src/ASF/thirdparty/CMSIS/Include" -I"../src/config" -I"../src/ASF/thirdparty/CMSIS/Lib/GCC" -I"../src/ASF/sam0/drivers/system/reset" -I"../src/ASF/sam0/drivers/system/interrupt/system_interrupt_samd21" -I"../src/ASF/sam0/boards/samd21_xplained_pro" -I"../src" -I"../src/ASF/sam0/drivers/sercom" -I"../src/ASF/sam0/utils/preprocessor" -I"../src/ASF/sam0/utils/cmsis/samd21/include" -I"../src/ASF/sam0/drivers/system" -I"../src/ASF/sam0/utils/cmsis/samd21/source" -I"../src/ASF/sam0/drivers/system/clock" -I"../src/ASF/sam0/drivers/system/interrupt" -I"../inc" -I"../src/ASF/common2/services/delay" -I"../src/ASF/common2/services/delay/sam0" -I"../src/ASF/sam0/drivers/extint" -I"../src/ASF/sam0/drivers/extint/extint_sam_d_r" -I"../src/ASF/common/services/ioport" -I"../src/ASF/sam0/drivers/events/events_sam_d_r" -I"../src/ASF/sam0/drivers/events"  -O3 -fdata-sections -ffunction-sections -g3 -Wall -mcpu=cortex-m0plus -c -pipe -fno-strict-aliasing -Wall -Wstrict-prototypes -Wmissing-prototypes -Werror-implicit-function-declaration -Wpointer-arith -std=gnu99 -ffunction-sections -fdata-sections -Wchar-subscripts -Wcomment -Wformat=2 -Wimplicit-int -Wmain -Wparentheses -Wsequence-point -Wreturn-type -Wswitch -Wtrigraphs -Wunused -Wuninitialized -Wunknown-pragmas -Wfloat-equal -Wundef -Wshadow -Wbad-function-cast -Wwrite-strings -Wsign-compare -Waggregate-return  -Wmissing-declarations -Wformat -Wmissing-format-attribute -Wno-deprecated-declarations -Wpacked -Wredundant-decls -Wnested-externs -Wunreachable-code -Wcast-align --param max-inline-insns-single=500  -Wno-long-long -MD -MP -MF "$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -MT"$(@:%.o=%.o)" -E -dM empty.c >lint_cmac.h

If you followed stage 4 and added path to system variable, you can copy it in command line nad run it as it is. If not, instead of just arm-none-eabi-gcc provide full path to .exe
As a result of running this command we now have file D:\lint_cmac.h with all the macros from compiler set to our project build options. The list is pretty long, so here's only part of it, so you could understand how does it look like:
#define __DBL_MIN_EXP__ (-1021)
#define __HQ_FBIT__ 15
#define __UINT_LEAST16_MAX__ 65535
#define __ARM_SIZEOF_WCHAR_T 32
#define __ATOMIC_ACQUIRE 2
#define __SFRACT_IBIT__ 0
#define __FLT_MIN__ 1.1754943508222875e-38F
#define BOARD SAMD21_XPLAINED_PRO
......................................

6) Now we need to specify the list of directories with system headers, so Lint would know where to get them.
Run arm-none-eabi-gcc -c -v empty.c. You get a lot of output. Find the section which starts with "#include "..." search starts here" and ends with "End of search list". Copy that paths to a file named gcc-include-path.lnt (create that file first, of course).
There's more simple way to do this. Just go to Project options in Atmel Studio and copy these paths from ARM/GNU Common->General->Default Include Paths.
gcc-include-path.lnt file provides this paths to PC-Lint as parameters, so it must include paths in form of --i parameter as follows:
--i"c:\program files (x86)\atmel\atmel toolchain\arm gcc\native\4.8.1429\arm-gnu-toolchain\bin\../lib/gcc/arm-none-eabi/4.8.3/include"
Each path should be on a separate line.

7) Copy files lint_cmac.h and gcc-include-path.lnt to PC-Lint folder C:\lint.

Running PC-Lint for GCC compiled projects.

Use provided with install co-gcc.lnt as your Lint configuration file or as a template for your own such file.
You will invoke Lint in form of
lint std.lnt source-files-to-be-linted
That std.lnt file could include that macro and directories files we got earlier. It also can include a list of source files, so you'll be able to lint your project with just 
lint std.lnt

I use PC-Lint with Visual Lint embedded in Atmel Studio and Visual Lint invokes Lint with custom std.lnt file. This file includes following:

// Author recommendations and checks recommended by industry bodies
au-barr10.lnt                   //
au-misra3.lnt                   //

// Compiler configuration
co-gcc.lnt                   // AVR/ARM GCC compiler

// PC-lint warning level (0 through 4). Recommended levels are -w1 (Basic), -w2 (Thorough), -w1 -w3 (Aggressive), or -w3 (Very Aggressive)
-w1 -w3                             // Aggressive

Here we turn on Michael Barr's 10 rules check and MISRA-2012 checks, set warning level to Aggressive and use co-gcc.lnt as compiler configuration.

co-gcc.lnt is used as it was provided with PC-Lint installation and it contains the calls to our gcc-include-path.lnt and lint_cmac.h files (see the contents of your co-gcc.lnt and how it calls this files and other options useful for GCC).

So now any time we run PC-Lint it takes in consideration all the include files paths and all macros that are actually used in our GCC project compilation.


4 comments:

  1. Hi Alex, Thanks so much for sharing this, it's really helpful! Can you share the .mak file so I can try see what I'm doing wrong?

    ReplyDelete
    Replies
    1. Hi! Just saw your question, only because I needed to refresh in memory how the hell did I get PC-Lint working with Atmel Studio :) The .mak file should be provided with Visual Lint nstallation.
      I can't show it here, at least not full file at one time as it's too long for posting (longer than 4096 symbols). If you didn't find it in Visual Lint folder, let me know, I'll post it in several messages.

      Delete
  2. Alex ...thank you so much for posting this blog ! I was struggling to make sense of the official user guide shipped with PCLintPlus and getting it to work with Atmel Studio 7. You saved me a day or two !! Cheers and keep going !!!

    ReplyDelete
  3. Glad it helped!
    BTW, using PC Lint "as is" is not very user friendly, so I always recommend to use Visual Lint along with it.
    VL is a great tool that visualizes PC Lint messages and provides some interactivity. Check it if you're having any trouble parsing PC Lint warnings and errors.

    ReplyDelete