Linting With Eclipse and the GNU ARM Embedded Launchpad Compiler
For mission critical software, the more information about potential bugs, the better. This article describes using PC-lint to perform analyis of an application destined for space.
Join the DZone community and get the full member experience.
Join For FreeFor a space project we have to make sure that things are not failing while our hardware orbits around Mother Earth. Therefore, we are using different static and dynamic analysis tools, and one of them is using PC-lint from Gimpel to catch as many errors and bugs as possible. For that project, we are using Eclipse with the GNU ARM Embedded (launchpad) ARM compiler and Eclipse as IDE with the GNU ARM Eclipse plugins. There are commercial plugins available for linting with Eclipse (e.g. Linticator), but with a few tweaks it is possible to lint with Eclipse free-of-charge. So this article is about how to lint an Eclipse project with PC-Lint.
Lint messages in Eclipse
PC-Lint
If you are serious about software development, you want to check your source code as much and as early as possible. A tool I have used for a very long time is PC-lint from Gimpel. It is not a free tool (costs around $390) but it has saved me countless hours so far. There are open source alternatives which I’m using in parallel, but PC-lint is still a kind of reference for me. For Linux users there is a version for that hosts the operating system too.
The challenge with fully using PC-lint is to make it aware of all the library include path and settings, plus to make it aware of all the compiler built-in defines to properly lint code with libraries. This post should help you to solve that challenge. :-)
PC-Lint and Eclipse
You might check out one of my early articles about how to lint with Eclipse without a plugin (see http://mcuoneclipse.com/2012/04/10/linting-without-a-plugin/). Since then, things on the Eclipse side has been changed a bit. This post has improved error handling and shows how to use it with the GNU ARM Embedded (launchpad) tools including properly including the libraries.
In the steps below I’m using the following tools:
- Eclipse Luna (Freescale (now NXP) Kinetis Design Studio V3.0.0) (Installed in C:\Freescale\KDS_3.0.0)
- GNU ARM Embedded (launchpad) 4.9 2015 q2
- GNU ARM Eclipse C/C++ plugins (1.13.1.201504061754)
- PC-lint v9.0 (installed in C:\Freescale\lint)
The approach I’m using is this:
- In a first step, create the proper lint configuration files to be used with co-gcc.lnt
- Create a new build configuration (e.g. ‘lint’) for the existing project to be linted
- In that build configuration, call a batch file to run lint
- The batch file will call lint with the proper operations and configuration files
- The list of files to be linted will be specified in a configuration files, specified manually
Lint Configuration Files for co-gcc.lnt
In my earlier linted projects, I have used co-gnu.lnt.
Lint uses .lnt files for options and configurations. Many configurations files are delivered with the lint installation in /lnt
The co-gnu.lnt is an older version and does not play well with newer gcc compilers. Instead, the co-gcc.lnt should be used which is located in the ‘lnt’ subfolder of the PC-lint installation:
/* Date Stamp */ -d"_lint_co_gcc_lnt=co-gcc.lnt modified 4-Jan-2012"
/* To document usage use: -message( "Using " _lint_co_gcc_lnt ) */
/* co-gcc.lnt: This is the seed file for configuring Lint for use with
GCC versions 2.95.3 and later.
Like all compiler options files this file is intended to be used
as follows:
lint co-gcc.lnt source-files-to-be-linted
Some of the information that co-gcc.lnt requires needs to be furnished
with the help of the gcc system itself. The easiest way to generate
this information is to use the makefile co-gcc.mak (supplied with the
Lint distribution) in an invocation of GNU Make; for details, see the
commentary at the top of co-gcc.mak.
*/
-cgnu // Notifies FlexeLint that gcc is being used.
// ===========================
// Preprocessor Configuration:
+fdi // GCC starts its #include search in the directory of the including
// file.
++fln // Allow:
// # digit-sequence " [s-char-sequence] " new-line
// as a synonym for:
// # line digit-sequence " [s-char-sequence] " new-line
// GCC additionally allows flag values to follow the
// s-char-sequence, but currently Lint ignores them.
-header(co-gcc.h) // Includes headers generated by GCC (bringing in
// predefined macros).
+libh(co-gcc.h) // Marks that header as library code.
gcc-include-path.lnt // This .lnt file should contain --i options
// and should be generated by invoking gcc with its '-v' option.
// (GCC's implicit #include search path is presented in the output.)
// This happens automatically when 'make -f co-gcc.mak' is invoked.
// Assertion directives (a feature of GCC's preprocessor) have been
// considered obsolete in GCC's documentation since version 3.0, so we do
// not use them here. If support for #assert is needed in the form of a
// lint option, one may use '-a#' like so:
// -a#machine(i386) // #assert's machine(i386) (SVR4 facility).
+cpp(.cc,.C) // extensions for C++ that are commonly used in addition
// to the default extensions of .cpp and .cxx
// =============
// Size Options:
// +fwc // wchar_t might be builtin; if so, uncomment this option. (NOTE:
// // this option needs to be set before a size option is given for
// // wchar_t; see the documentation for -sw# in the Lint manual.)
size-options.lnt // This .lnt file should be generated (preferrably
// by a program created by invoking GCC with the compile options that
// are used in the compilation of the project to be linted). This
// happens automatically when 'make -f co-gcc.mak' is invoked.
// ===========================================
// +rw and -d options to cope with GNU syntax:
+ppw(ident) // Tolerate #ident
+ppw(warning)
// GCC provides alternative spellings of certain keywords:
-rw_asgn(__inline,inline)
-rw_asgn(__inline__,inline)
-rw_asgn(__signed__,signed)
-rw_asgn(__signed,signed)
-rw_asgn( __volatile__, volatile )
-rw_asgn( __volatile, volatile )
++d__const=const // gconv.h uses __const rather than const
++dconst=const // ensure const expands to const.
-rw_asgn( asm, _up_to_brackets )
-rw_asgn( __asm, _up_to_brackets )
-rw_asgn( __asm__, _up_to_brackets )
// This re-definition of the various spellings of the asm keyword enables
// Lint to pass gracefully over expression-statements like:
// __asm __volatile ("fsqrt" : "=t" (__result) : "0" (__x));
// But it may be necessary to suppress certain error messages that are
// triggered by tokens that are part of an assembly declaration or
// statement. For example:
-d"__asm__(p...)=/*lint -e{19}*/ __asm__(p)"
// ...causes Lint to be quiet about the semicolon that follows an
// __asm__() declaration. Note, the -e{N} form of suppression takes
// effect only for the forward-declaration, definition or
// [possibly-compound] statement that immediately follows. Because a
// semicolon is seen as a declaration-terminator, Error 19 will be
// re-enabled immediately after the semicolon in '__asm__(...);'.
// (The elipsis after the macro parameter p allows zero or more commas to
// appear in the operand.)
//
// If you encounter other diagnostics that appear to need suppression in
// or near assembly regions, please let us know!
//
-esym(123,__asm__)
-rw_asgn(__alignof__,__alignof)
// "__extension__" is GCC's way of allowing the use of non-standard
// constructs in a strict Standard-conforming mode. We don't currently
// have explicit support for it, but we can use local suppressions. For
// example, we can use -e(160) so that we will not see any Errors about
// GNU statement-expressions wrapped in __extension__().
++d"__extension__=/*lint -e(160) */"
++d__builtin_va_list=void* // used by stdarg.h
++d__builtin_stdarg_start()=_to_semi // ditto
++d__builtin_va_end()=_to_semi // ditto
++d"__builtin_va_arg(a,b)=(*( (b *) ( ((a) += sizeof(b)) - sizeof(b) )))"
++d__null=0
+rw(_to_semi) // needed for the two macros above.
+rw(__typeof__) // activate __typeof__ keyword
-d__typeof=__typeof__ // an alternative to using __typeof__
+rw( __restrict )
+rw( __restrict__ )
-rw(__except) // This MS reserved word is used as an identifier
+rw( __complex__, __real__, __imag__ ) // reserved words that can be ignored.
++d__builtin_strchr=(char*) // permits the inline definition ...
++d__builtin_strpbrk=(char*) // of these functions to be linted ...
++d__builtin_strrchr=(char*) // without drawing a complaint
++d__builtin_strstr=(char*) // about the use of a non-standard name
++d__PRETTY_FUNCTION__=___function___ // lint defines ___function___ internally
++d__FUNCTION__=___function___ // lint defines ___function___ internally
++d__func__=___function___ // Some C++ modes suport the implicit __func__
// identifier.
// =========================================================
// Other options supporting GNU C/C++ syntax:
+fld // enables the processing of _L_abel _D_esignators E.g.:
// union { double d; int i; } u = { d: 3.141 };
// =========================================================
// Generally useful suppressions:
-wlib(1) // sets the warning level within library headers to 1
// (no warnings, just syntax errors). Comment out if you
// are actually linting library headers.
-elib(123) // 123 is really a warning, but it's in the "Error" range.
-elib(93) // allow newlines within quoted string arguments to macros
-elib(46) // allow bit fields to have integral types other than
// '_Bool' and 'int'.
-elibsym(628) // Suppress 628 for __builtin symbols.
-esym(528,__huge_val,__nan,__qnan,__qnanf,__snan,__snanf)
// We don't care if we don't reference some GNU functions
-esym(528,__gnu_malloc,__gnu_calloc)
// The following functions exhibit variable return modes.
// That is, they may equally-usefully be called for a value
// as called just for their effects. Accordingly we inhibit
// Warning 534 for these functions.
// Feel free to add to or subtract from this list.
-esym(534,close,creat,fclose,fprintf,fputc)
-esym(534,fputs,fscanf,fseek,fwrite,lseek,memcpy,memmove,memset)
-esym(534,printf,puts,scanf,sprintf,sscanf,strcat,strcpy)
-esym(534,strncat,strncpy,unlink,write)
// For non-ANSI compilers we suppress messages 515 and 516
// for functions known to have variable argument lists.
// For ANSI compilers, header files should take care of this.
-esym(515,fprintf,printf,sprintf,fscanf,scanf,sscanf)
-esym(516,fprintf,printf,sprintf,fscanf,scanf,sscanf)
-esym(1702,*operator<<,*operator>>)
-esym(534,*operator<<,*operator>>)
-esym(1055,*__builtin*)
-esym(718,*__builtin*) // The compiler does not need these ...
-esym(746,*__builtin*) // declared and it knows their prototypes.
However, as every gcc might have different settings, this co-gcc.lnt requires several extra generated files:
- gcc-include-path.lnt: list of include paths to find the library headers.
- size-options.lnt: standard type sizes.
- lint_cmac.h and lint-cppmac.h: header files with all compiler predefined C and C++ defines, used by co-gcc.h.
As both files depend on the compiler installation path and compiler options, these files are not part of the PC-lint installation. Instead, they have to be created.
In the next sections I describe how to create these to files. You might skip the creation steps and directly use and adopt my generated files instead.
co-gcc.mak
To create these files, there is a make file (co-gcc-mak) inside the \lnt folder. It uses the GNU compiler itself to create these files. This is a very smart way to do this, however it does not work well for embedded cross compilers (will see later). The make file
The make file depends on several tools which need to be installed and present in the PATH:
- GNU awk: http://gnuwin32.sourceforge.net/packages/gawk.htm
- GNU make: e.g. from https://sourceforge.net/projects/gnuarmeclipse/files/Build%20Tools/
- GNU core utilities (touch, rm, …): http://gnuwin32.sourceforge.net/packages/coreutils.htm
- GNU compiler toolchain with gcc and g++ (GNU ARM Embedded (launchpad))
I had to run the setup version of the GNU core utilities, as otherwise the tools reported some missing DLL files on Windows :-(.
The make file will create the following files (see <lint-installation-path>\lnt\gcc-readme.txt):
- lint_cmac.h
- lint_cppmac.h
- gcc-include-path.lnt
- size-options.lnt
The size-options.lint file shall be created with a small executable (that step will fail, we will see).
To simplify running the make file, and in order not to change my global PATH variable, I have created the following batch file co_gcc.bat inside <lint-installation-path>\lnt:
@REM make sure that make, awk, gcc, g++, touch are in PATH
@REM Path to make
SET MAKE_PATH=C:\Freescale\KDS_3.0.0\bin
@REM Path to GNU awk
SET AWK_PATH=C:\GNU\gawk-3.1.6-1\bin
@REM Path to GNU core utilities (touch)
SET CORE_PATH=C:\Program Files (x86)\GnuWin32\bin
@REM Path to GNU ARM Embedded
SET GNU_PATH=C:\Freescale\KDS_3.0.0\toolchain\bin
@REM append GNU path to PATH
SET PATH=%PATH%;%MAKE_PATH%;%GNU_PATH%;%AWK_PATH%;%CORE_PATH%
@REM call make file
make -f co-gcc.mak GCC_BIN=arm-none-eabi-gcc GXX_BIN=arm-none-eabi-g++
@REM note that the last step will fail (to link and execute the file for the type sizes). This is expected.
You will need to adopt the path settings to match make, awk, gnu core utilities, and GNU gcc installation on your system.
The other consideration is that the gcc called with that make file should match the compiler settings used in the Eclipse project to be linted, as the .lnt files produced need to match the compiler settings used.
In the last step, it calls the make utility. On my system, the output is as below:
C:\Freescale\lint\lnt>co_gcc.bat
C:\Freescale\lint\lnt>SET MAKE_PATH=C:\Freescale\KDS_3.0.0\bin
C:\Freescale\lint\lnt>SET AWK_PATH=C:\GNU\gawk-3.1.6-1\bin
C:\Freescale\lint\lnt>SET CORE_PATH=C:\Program Files (x86)\GnuWin32\bin
C:\Freescale\lint\lnt>SET GNU_PATH=C:\Freescale\KDS_3.0.0\toolchain\bin
C:\Freescale\lint\lnt>make -f co-gcc.mak GCC_BIN=arm-none-eabi-gcc GXX_BIN=arm-n
one-eabi-g++
rm -f \
lint_cppmac.h \
lint_cmac.h \
gcc-include-path.lnt \
size-options.lnt
rm -f co-gcc.mak.temp-empty*
touch co-gcc.mak.temp-empty.cpp co-gcc.mak.temp-empty.c
arm-none-eabi-gcc -Wno-long-long -E -dM co-gcc.mak.temp-empty.c -o lint_cma
c.h
arm-none-eabi-g++ -Wno-long-long -E -dM co-gcc.mak.temp-empty.cpp -o lint_cpp
mac.h
arm-none-eabi-g++ -Wno-long-long -v -c co-gcc.mak.temp-empty.cpp 2>&1 \
| awk ' \
BEGIN {S=0} \
/search starts here:/ {S=1;next;} \
S >> /Library\/Frameworks/ {next;} \
S >> /^ / { \
sub("^ ",""); \
gsub("//*","/"); \
sub("\xd$",""); \
sub("/$",""); \
printf("--i\"%s\"\n", $0); \
next; \
} \
S {exit;} \
' >gcc-include-path.lnt
rm -f co-gcc.mak.temp-generate-size-options*
arm-none-eabi-g++ -Wno-long-long co-gcc.mak.temp-generate-size-options.cc -o
co-gcc.mak.temp-generate-size-options
c:/freescale/kds_3.0.0/toolchain/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../
arm-none-eabi/lib\libc.a(lib_a-exit.o): In function `exit':
exit.c:(.text.exit+0x2c): undefined reference to `_exit'
c:/freescale/kds_3.0.0/toolchain/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../
arm-none-eabi/lib\libc.a(lib_a-abort.o): In function `abort':
abort.c:(.text.abort+0x10): undefined reference to `_exit'
c:/freescale/kds_3.0.0/toolchain/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../
arm-none-eabi/lib\libc.a(lib_a-signalr.o): In function `_kill_r':
signalr.c:(.text._kill_r+0x1c): undefined reference to `_kill'
c:/freescale/kds_3.0.0/toolchain/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../
arm-none-eabi/lib\libc.a(lib_a-signalr.o): In function `_getpid_r':
signalr.c:(.text._getpid_r+0x4): undefined reference to `_getpid'
c:/freescale/kds_3.0.0/toolchain/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../
arm-none-eabi/lib\libc.a(lib_a-sbrkr.o): In function `_sbrk_r':
sbrkr.c:(.text._sbrk_r+0x18): undefined reference to `_sbrk'
c:/freescale/kds_3.0.0/toolchain/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../
arm-none-eabi/lib\libc.a(lib_a-writer.o): In function `_write_r':
writer.c:(.text._write_r+0x20): undefined reference to `_write'
c:/freescale/kds_3.0.0/toolchain/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../
arm-none-eabi/lib\libc.a(lib_a-closer.o): In function `_close_r':
closer.c:(.text._close_r+0x18): undefined reference to `_close'
c:/freescale/kds_3.0.0/toolchain/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../
arm-none-eabi/lib\libc.a(lib_a-fstatr.o): In function `_fstat_r':
fstatr.c:(.text._fstat_r+0x1c): undefined reference to `_fstat'
c:/freescale/kds_3.0.0/toolchain/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../
arm-none-eabi/lib\libc.a(lib_a-isattyr.o): In function `_isatty_r':
isattyr.c:(.text._isatty_r+0x18): undefined reference to `_isatty'
c:/freescale/kds_3.0.0/toolchain/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../
arm-none-eabi/lib\libc.a(lib_a-lseekr.o): In function `_lseek_r':
lseekr.c:(.text._lseek_r+0x20): undefined reference to `_lseek'
c:/freescale/kds_3.0.0/toolchain/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../
arm-none-eabi/lib\libc.a(lib_a-readr.o): In function `_read_r':
readr.c:(.text._read_r+0x20): undefined reference to `_read'
collect2.exe: error: ld returned 1 exit status
co-gcc.mak:132: recipe for target 'sizes' failed
make: *** [sizes] Error 1
C:\Freescale\lint\lnt>
Notice that it fails in the last step to build an executable to be executed. This is expected to fail for a cross-compilation toolchain (we build on the host, but execute on an embedded ARM processor on another board). But the three other files have been generated:
generated files by co_gcc.bat
size-options.lnt
This failing last step is supposed to create the size-options.lnt file with this code:
\
extern "C" int printf(const char*, ...);\
int main() {\
printf( "-ss%u ", sizeof(short) );\
printf( "-si%u ", sizeof(int) );\
printf( "-sl%u ", sizeof(long) );\
printf( "-sll%u ", sizeof(long long) );\
printf( "-sf%u ", sizeof(float) );\
printf( "-sd%u ", sizeof(double) );\
printf( "-sld%u ", sizeof(long double) );\
printf( "-sp%u ", sizeof(void*) );\
printf( "-sw%u ", sizeof(wchar_t) );\
}
With some basic knowledge about the type sizes used by the compiler, I can create that size-options.lnt file by hand as below. It tells lint with the -s option about the size of the different standard types:
// size_options.lnt
// type sizes
-ss2 // short
-si4 // int
-sl4 // long
-sll4 // long long
-sf4 // float
-sd8 // double
-sld8 // long double
-sp4 // void*
-sw4 // wchar_t
gcc-include-path.lnt
What it has sucessfully created is the gcc-include-path.lnt: It tells lint where to find all the GNU library include files
// gcc-include-path.lnt
--i"c:\freescale\kds_3.0.0\toolchain\bin\../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/include/c++/4.9.3"
--i"c:\freescale\kds_3.0.0\toolchain\bin\../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/include/c++/4.9.3/arm-none-eabi"
--i"c:\freescale\kds_3.0.0\toolchain\bin\../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/include/c++/4.9.3/backward"
--i"c:\freescale\kds_3.0.0\toolchain\bin\../lib/gcc/arm-none-eabi/4.9.3/include"
--i"c:\freescale\kds_3.0.0\toolchain\bin\../lib/gcc/arm-none-eabi/4.9.3/include-fixed"
--i"c:\freescale\kds_3.0.0\toolchain\bin\../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/include"
You can take above template and easily adopt to your compiler version and installation path.
lint_cmac.h and lint_cppmac.h
The generated lint_cmac.h and lint_cppmac.h contain all the predefined macros of the gcc compiler.
I have posted my files on GitHub here: https://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/KDS/FRDM-K64F120M/FRDM-K64F_pc-lint/lint
Below is an example of lint_cmac.h:
#define __DBL_MIN_EXP__ (-1021)
#define __HQ_FBIT__ 15
#define __UINT_LEAST16_MAX__ 65535
#define __ARM_SIZEOF_WCHAR_T 4
#define __ATOMIC_ACQUIRE 2
#define __SFRACT_IBIT__ 0
#define __FLT_MIN__ 1.1754943508222875e-38F
#define __GCC_IEC_559_COMPLEX 0
#define __UFRACT_MAX__ 0XFFFFP-16UR
#define __UINT_LEAST8_TYPE__ unsigned char
#define __DQ_FBIT__ 63
#define __INTMAX_C(c) c ## LL
#define __ULFRACT_FBIT__ 32
#define __SACCUM_EPSILON__ 0x1P-7HK
#define __CHAR_BIT__ 8
#define __USQ_IBIT__ 0
#define __UINT8_MAX__ 255
#define __ACCUM_FBIT__ 15
#define __WINT_MAX__ 4294967295U
#define __USFRACT_FBIT__ 8
#define __ORDER_LITTLE_ENDIAN__ 1234
#define __SIZE_MAX__ 4294967295U
#define __ARM_ARCH_ISA_ARM 1
#define __WCHAR_MAX__ 4294967295U
#define __LACCUM_IBIT__ 32
#define __DBL_DENORM_MIN__ ((double)4.9406564584124654e-324L)
#define __GCC_ATOMIC_CHAR_LOCK_FREE 1
#define __GCC_IEC_559 0
#define __FLT_EVAL_METHOD__ 0
#define __LLACCUM_MAX__ 0X7FFFFFFFFFFFFFFFP-31LLK
#define __GCC_ATOMIC_CHAR32_T_LOCK_FREE 1
#define __FRACT_FBIT__ 15
#define __UINT_FAST64_MAX__ 18446744073709551615ULL
#define __SIG_ATOMIC_TYPE__ int
#define __UACCUM_FBIT__ 16
#define __DBL_MIN_10_EXP__ (-307)
#define __FINITE_MATH_ONLY__ 0
#define __ARMEL__ 1
#define __LFRACT_IBIT__ 0
#define __GNUC_PATCHLEVEL__ 3
#define __LFRACT_MAX__ 0X7FFFFFFFP-31LR
#define __UINT_FAST8_MAX__ 4294967295U
#define __has_include(STR) __has_include__(STR)
#define __DEC64_MAX_EXP__ 385
#define __INT8_C(c) c
#define __UINT_LEAST64_MAX__ 18446744073709551615ULL
#define __SA_FBIT__ 15
#define __SHRT_MAX__ 32767
#define __LDBL_MAX__ 1.7976931348623157e+308L
#define __FRACT_MAX__ 0X7FFFP-15R
#define __UFRACT_FBIT__ 16
#define __ARM_FP 12
#define __UFRACT_MIN__ 0.0UR
#define __UINT_LEAST8_MAX__ 255
#define __GCC_ATOMIC_BOOL_LOCK_FREE 1
#define __UINTMAX_TYPE__ long long unsigned int
#define __LLFRACT_EPSILON__ 0x1P-63LLR
#define __DEC32_EPSILON__ 1E-6DF
#define __CHAR_UNSIGNED__ 1
#define __UINT32_MAX__ 4294967295UL
#define __ULFRACT_MAX__ 0XFFFFFFFFP-32ULR
#define __TA_IBIT__ 64
#define __LDBL_MAX_EXP__ 1024
#define __WINT_MIN__ 0U
#define __ULLFRACT_MIN__ 0.0ULLR
#define __SCHAR_MAX__ 127
#define __WCHAR_MIN__ 0U
#define __INT64_C(c) c ## LL
#define __DBL_DIG__ 15
#define __ARM_NEON_FP 4
#define __GCC_ATOMIC_POINTER_LOCK_FREE 1
#define __LLACCUM_MIN__ (-0X1P31LLK-0X1P31LLK)
#define __SIZEOF_INT__ 4
#define __SIZEOF_POINTER__ 4
#define __USACCUM_IBIT__ 8
#define __USER_LABEL_PREFIX__
#define __STDC_HOSTED__ 1
#define __LDBL_HAS_INFINITY__ 1
#define __LFRACT_MIN__ (-0.5LR-0.5LR)
#define __HA_IBIT__ 8
#define __TQ_IBIT__ 0
#define __FLT_EPSILON__ 1.1920928955078125e-7F
#define __APCS_32__ 1
#define __USFRACT_IBIT__ 0
#define __LDBL_MIN__ 2.2250738585072014e-308L
#define __FRACT_MIN__ (-0.5R-0.5R)
#define __DEC32_MAX__ 9.999999E96DF
#define __DA_IBIT__ 32
#define __ARM_SIZEOF_MINIMAL_ENUM 1
#define __INT32_MAX__ 2147483647L
#define __UQQ_FBIT__ 8
#define __SIZEOF_LONG__ 4
#define __UACCUM_MAX__ 0XFFFFFFFFP-16UK
#define __UINT16_C(c) c
#define __DECIMAL_DIG__ 17
#define __LFRACT_EPSILON__ 0x1P-31LR
#define __ULFRACT_MIN__ 0.0ULR
#define __has_include_next(STR) __has_include_next__(STR)
#define __LDBL_HAS_QUIET_NAN__ 1
#define __ULACCUM_IBIT__ 32
#define __UACCUM_EPSILON__ 0x1P-16UK
#define __GNUC__ 4
#define __ULLACCUM_MAX__ 0XFFFFFFFFFFFFFFFFP-32ULLK
#define __HQ_IBIT__ 0
#define __FLT_HAS_DENORM__ 1
#define __SIZEOF_LONG_DOUBLE__ 8
#define __BIGGEST_ALIGNMENT__ 8
#define __DQ_IBIT__ 0
#define __DBL_MAX__ ((double)1.7976931348623157e+308L)
#define __ULFRACT_IBIT__ 0
#define __INT_FAST32_MAX__ 2147483647
#define __DBL_HAS_INFINITY__ 1
#define __ACCUM_IBIT__ 16
#define __DEC32_MIN_EXP__ (-94)
#define __THUMB_INTERWORK__ 1
#define __LACCUM_MAX__ 0X7FFFFFFFFFFFFFFFP-31LK
#define __INT_FAST16_TYPE__ int
#define __LDBL_HAS_DENORM__ 1
#define __DEC128_MAX__ 9.999999999999999999999999999999999E6144DL
#define __INT_LEAST32_MAX__ 2147483647L
#define __ARM_PCS 1
#define __DEC32_MIN__ 1E-95DF
#define __ACCUM_MAX__ 0X7FFFFFFFP-15K
#define __DBL_MAX_EXP__ 1024
#define __USACCUM_EPSILON__ 0x1P-8UHK
#define __DEC128_EPSILON__ 1E-33DL
#define __SFRACT_MAX__ 0X7FP-7HR
#define __FRACT_IBIT__ 0
#define __PTRDIFF_MAX__ 2147483647
#define __UACCUM_MIN__ 0.0UK
#define __UACCUM_IBIT__ 16
#define __LONG_LONG_MAX__ 9223372036854775807LL
#define __SIZEOF_SIZE_T__ 4
#define __ULACCUM_MAX__ 0XFFFFFFFFFFFFFFFFP-32ULK
#define __SIZEOF_WINT_T__ 4
#define __SA_IBIT__ 16
#define __ULLACCUM_MIN__ 0.0ULLK
#define __GXX_ABI_VERSION 1002
#define __UTA_FBIT__ 64
#define __SOFTFP__ 1
#define __FLT_MIN_EXP__ (-125)
#define __USFRACT_MAX__ 0XFFP-8UHR
#define __UFRACT_IBIT__ 0
#define __INT_FAST64_TYPE__ long long int
#define __DBL_MIN__ ((double)2.2250738585072014e-308L)
#define __LACCUM_MIN__ (-0X1P31LK-0X1P31LK)
#define __ULLACCUM_FBIT__ 32
#define __GXX_TYPEINFO_EQUALITY_INLINE 0
#define __ULLFRACT_EPSILON__ 0x1P-64ULLR
#define __USES_INITFINI__ 1
#define __DEC128_MIN__ 1E-6143DL
#define __REGISTER_PREFIX__
#define __UINT16_MAX__ 65535
#define __DBL_HAS_DENORM__ 1
#define __ACCUM_MIN__ (-0X1P15K-0X1P15K)
#define __SQ_IBIT__ 0
#define __UINT8_TYPE__ unsigned char
#define __UHA_FBIT__ 8
#define __NO_INLINE__ 1
#define __SFRACT_MIN__ (-0.5HR-0.5HR)
#define __UTQ_FBIT__ 128
#define __FLT_MANT_DIG__ 24
#define __VERSION__ "4.9.3 20150529 (release) [ARM/embedded-4_9-branch revision 224288]"
#define __UINT64_C(c) c ## ULL
#define __ULLFRACT_FBIT__ 64
#define __FRACT_EPSILON__ 0x1P-15R
#define __ULACCUM_MIN__ 0.0ULK
#define __UDA_FBIT__ 32
#define __LLACCUM_EPSILON__ 0x1P-31LLK
#define __GCC_ATOMIC_INT_LOCK_FREE 1
#define __FLOAT_WORD_ORDER__ __ORDER_LITTLE_ENDIAN__
#define __USFRACT_MIN__ 0.0UHR
#define __UQQ_IBIT__ 0
#define __INT32_C(c) c ## L
#define __DEC64_EPSILON__ 1E-15DD
#define __ORDER_PDP_ENDIAN__ 3412
#define __DEC128_MIN_EXP__ (-6142)
#define __UHQ_FBIT__ 16
#define __LLACCUM_FBIT__ 31
#define __INT_FAST32_TYPE__ int
#define __UINT_LEAST16_TYPE__ short unsigned int
#define __INT16_MAX__ 32767
#define __SIZE_TYPE__ unsigned int
#define __UINT64_MAX__ 18446744073709551615ULL
#define __UDQ_FBIT__ 64
#define __INT8_TYPE__ signed char
#define __ELF__ 1
#define __ULFRACT_EPSILON__ 0x1P-32ULR
#define __LLFRACT_FBIT__ 63
#define __FLT_RADIX__ 2
#define __INT_LEAST16_TYPE__ short int
#define __LDBL_EPSILON__ 2.2204460492503131e-16L
#define __UINTMAX_C(c) c ## ULL
#define __SACCUM_MAX__ 0X7FFFP-7HK
#define __SIG_ATOMIC_MAX__ 2147483647
#define __GCC_ATOMIC_WCHAR_T_LOCK_FREE 1
#define __VFP_FP__ 1
#define __SIZEOF_PTRDIFF_T__ 4
#define __LACCUM_EPSILON__ 0x1P-31LK
#define __DEC32_SUBNORMAL_MIN__ 0.000001E-95DF
#define __INT_FAST16_MAX__ 2147483647
#define __UINT_FAST32_MAX__ 4294967295U
#define __UINT_LEAST64_TYPE__ long long unsigned int
#define __USACCUM_MAX__ 0XFFFFP-8UHK
#define __SFRACT_EPSILON__ 0x1P-7HR
#define __FLT_HAS_QUIET_NAN__ 1
#define __FLT_MAX_10_EXP__ 38
#define __LONG_MAX__ 2147483647L
#define __DEC128_SUBNORMAL_MIN__ 0.000000000000000000000000000000001E-6143DL
#define __FLT_HAS_INFINITY__ 1
#define __USA_FBIT__ 16
#define __UINT_FAST16_TYPE__ unsigned int
#define __DEC64_MAX__ 9.999999999999999E384DD
#define __ARM_32BIT_STATE 1
#define __CHAR16_TYPE__ short unsigned int
#define __PRAGMA_REDEFINE_EXTNAME 1
#define __INT_LEAST16_MAX__ 32767
#define __DEC64_MANT_DIG__ 16
#define __INT64_MAX__ 9223372036854775807LL
#define __UINT_LEAST32_MAX__ 4294967295UL
#define __SACCUM_FBIT__ 7
#define __GCC_ATOMIC_LONG_LOCK_FREE 1
#define __INT_LEAST64_TYPE__ long long int
#define __INT16_TYPE__ short int
#define __INT_LEAST8_TYPE__ signed char
#define __SQ_FBIT__ 31
#define __DEC32_MAX_EXP__ 97
#define __ARM_ARCH_ISA_THUMB 1
#define __INT_FAST8_MAX__ 2147483647
#define __ARM_ARCH 4
#define __INTPTR_MAX__ 2147483647
#define __QQ_FBIT__ 7
#define __UTA_IBIT__ 64
#define __LDBL_MANT_DIG__ 53
#define __SFRACT_FBIT__ 7
#define __SACCUM_MIN__ (-0X1P7HK-0X1P7HK)
#define __DBL_HAS_QUIET_NAN__ 1
#define __SIG_ATOMIC_MIN__ (-__SIG_ATOMIC_MAX__ - 1)
#define __INTPTR_TYPE__ int
#define __UINT16_TYPE__ short unsigned int
#define __WCHAR_TYPE__ unsigned int
#define __SIZEOF_FLOAT__ 4
#define __USQ_FBIT__ 32
#define __UINTPTR_MAX__ 4294967295U
#define __DEC64_MIN_EXP__ (-382)
#define __ULLACCUM_IBIT__ 32
#define __INT_FAST64_MAX__ 9223372036854775807LL
#define __GCC_ATOMIC_TEST_AND_SET_TRUEVAL 1
#define __FLT_DIG__ 6
#define __UINT_FAST64_TYPE__ long long unsigned int
#define __INT_MAX__ 2147483647
#define __LACCUM_FBIT__ 31
#define __USACCUM_MIN__ 0.0UHK
#define __UHA_IBIT__ 8
#define __INT64_TYPE__ long long int
#define __FLT_MAX_EXP__ 128
#define __UTQ_IBIT__ 0
#define __DBL_MANT_DIG__ 53
#define __INT_LEAST64_MAX__ 9223372036854775807LL
#define __GCC_ATOMIC_CHAR16_T_LOCK_FREE 1
#define __DEC64_MIN__ 1E-383DD
#define __WINT_TYPE__ unsigned int
#define __UINT_LEAST32_TYPE__ long unsigned int
#define __SIZEOF_SHORT__ 2
#define __ULLFRACT_IBIT__ 0
#define __LDBL_MIN_EXP__ (-1021)
#define __arm__ 1
#define __UDA_IBIT__ 32
#define __INT_LEAST8_MAX__ 127
#define __LFRACT_FBIT__ 31
#define __LDBL_MAX_10_EXP__ 308
#define __ATOMIC_RELAXED 0
#define __DBL_EPSILON__ ((double)2.2204460492503131e-16L)
#define __UINT8_C(c) c
#define __INT_LEAST32_TYPE__ long int
#define __SIZEOF_WCHAR_T__ 4
#define __UINT64_TYPE__ long long unsigned int
#define __LLFRACT_MAX__ 0X7FFFFFFFFFFFFFFFP-63LLR
#define __TQ_FBIT__ 127
#define __INT_FAST8_TYPE__ int
#define __ULLACCUM_EPSILON__ 0x1P-32ULLK
#define __UHQ_IBIT__ 0
#define __LLACCUM_IBIT__ 32
#define __DBL_DECIMAL_DIG__ 17
#define __DEC_EVAL_METHOD__ 2
#define __TA_FBIT__ 63
#define __UDQ_IBIT__ 0
#define __ORDER_BIG_ENDIAN__ 4321
#define __ACCUM_EPSILON__ 0x1P-15K
#define __UINT32_C(c) c ## UL
#define __INTMAX_MAX__ 9223372036854775807LL
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
#define __FLT_DENORM_MIN__ 1.4012984643248171e-45F
#define __LLFRACT_IBIT__ 0
#define __INT8_MAX__ 127
#define __UINT_FAST32_TYPE__ unsigned int
#define __CHAR32_TYPE__ long unsigned int
#define __FLT_MAX__ 3.4028234663852886e+38F
#define __USACCUM_FBIT__ 8
#define __INT32_TYPE__ long int
#define __SIZEOF_DOUBLE__ 8
#define __FLT_MIN_10_EXP__ (-37)
#define __UFRACT_EPSILON__ 0x1P-16UR
#define __INTMAX_TYPE__ long long int
#define __DEC128_MAX_EXP__ 6145
#define __ATOMIC_CONSUME 1
#define __GNUC_MINOR__ 9
#define __UINTMAX_MAX__ 18446744073709551615ULL
#define __DEC32_MANT_DIG__ 7
#define __HA_FBIT__ 7
#define __DBL_MAX_10_EXP__ 308
#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324L
#define __INT16_C(c) c
#define __STDC__ 1
#define __ARM_ARCH_4T__ 1
#define __PTRDIFF_TYPE__ int
#define __LLFRACT_MIN__ (-0.5LLR-0.5LLR)
#define __ATOMIC_SEQ_CST 5
#define __DA_FBIT__ 31
#define __UINT32_TYPE__ long unsigned int
#define __UINTPTR_TYPE__ unsigned int
#define __USA_IBIT__ 16
#define __DEC64_SUBNORMAL_MIN__ 0.000000000000001E-383DD
#define __ARM_EABI__ 1
#define __DEC128_MANT_DIG__ 34
#define __LDBL_MIN_10_EXP__ (-307)
#define __SIZEOF_LONG_LONG__ 8
#define __ULACCUM_EPSILON__ 0x1P-32ULK
#define __SACCUM_IBIT__ 8
#define __GCC_ATOMIC_LLONG_LOCK_FREE 1
#define __LDBL_DIG__ 15
#define __FLT_DECIMAL_DIG__ 9
#define __UINT_FAST16_MAX__ 4294967295U
#define __GNUC_GNU_INLINE__ 1
#define __GCC_ATOMIC_SHORT_LOCK_FREE 1
#define __ULLFRACT_MAX__ 0XFFFFFFFFFFFFFFFFP-64ULLR
#define __UINT_FAST8_TYPE__ unsigned int
#define __USFRACT_EPSILON__ 0x1P-8UHR
#define __ULACCUM_FBIT__ 32
#define __QQ_IBIT__ 0
#define __ATOMIC_ACQ_REL 4
#define __ATOMIC_RELEASE 3
Linting With Eclipse
To lint a project with Eclipse, I recommend to create a local "lint" folder and place all needed files into it:
see my project on GitHub: https://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/KDS/FRDM-K64F120M/FRDM-K64F_pc-lint
lint configuration files inside project
lint_cmac.h, lint_cppmac.h, gcc-include-path.lnt and size-options.lnt are the files from the previous step.
do_lint.bat and Related Files
do_lint.bat is a batch file I will call from the build configuration (later more about this):
@rem call this batch file from the Eclipse project settings
@rem The arguments for this batch file:
@rem %1: The path to the project root folder
@rem ------------------------------------------------------
@rem Path to the project folder
SET PROJ_PATH=%1
@rem Path to lint-nt.exe (NO SPACES!!!)
SET LINT_EXE=C:\Freescale\lint\lint-nt.exe
@rem Path to my lint configuration files
SET LOCAL_LNT_FILES=C:\Freescale\lint\lnt
@rem Path to my local lint folder inside the project with the lint files
SET PROJ_LINT_PATH=%PROJ_PATH%\lint
@rem Lint configuration files and includes
SET LNT_INCLUDES=-i"%PROJ_LINT_PATH%" -i%LOCAL_LNT_FILES%
@rem --------------- Run PC-lint ---------------------------
%LINT_EXE% %LNT_INCLUDES% %PROJ_LINT_PATH%\eclipse_msg.lnt %PROJ_LINT_PATH%\proj_options.lnt %PROJ_LINT_PATH%\proj_files.lnt -vf
It configures the path/tool settings and then it calls the PC-lint executables. It needs the following files which are explained below:
- eclipse_msg.lnt: this configures the messages so the Eclipse Problems view can parse it
- proj_options.lnt: has the project specific options used e.g. to disable/enable warnings/errors
- proj_files.lnt: has the source files to be linted
In eclipse_msg.lnt the message format is defined:
// Configure PC-lint messages so they show up in the Eclipse 'Problems' view
-hF1
+ffn
// Normally my format is defined as follows:
//-"format=%(\q%f\q %l %C%) %t %n: %m"
// For eclipse-usage, the GCC error format is necessary,
// since we have only the default eclipse error parser available.
-"format=%(%f:%l:%C:%) %t: [%n] %m"
// Enable warning 831 if you are interested.
-frl
// Do not break lines
-width(0)
// And make sure no foreign includes change the format
+flm
In proj_options.lnt it uses the co-gcc.lnt as configuration files. Additionally list here all your include paths of the project sources, plus any other options (e.g. to inhibit messages):
-fff
// Include standard GNU options
co-gcc.lnt
// Include paths used
-i%PROJ_PATH%\Includes
-i%PROJ_PATH%\Sources
// inhibit messages for Processor Expert libraries
-elib(19, 10)
-e766
+libh(Events.h, Cpu.h)
In proj_files.lnt I list all the source files to be linted:
%PROJ_PATH%\Sources\test.c
%PROJ_PATH%\Sources\main.c
I was thinking about an extra step to generate the list of files automatically. But at the end it was simpler and easier to maintain that list by hand, and I can simply comment lines to only do a partial lint run.
Eclipse Build Configuration
To lint a project in Eclipse, I create a new build configuration for it. I select the project in the Project Explorer view and use the menu Project > Build Configuration > Manage to create a new configuration with the ‘New’ button:
New Configuration to Lint
Then change the newly created configuration (lint in my case), deselect 'Use default build command', deselect 'Generate Makefiles automatically', and enter the following build command to launch the batch file:
${ProjDirPath}\lint\do_lint.bat "${ProjDirPath}"
Build Command for PC-Lint
With that build command I’m calling the batch file (do_lint.bat) from the previous step. As argument I pass the project path to it with the Eclipse $ProjDirPath variable.
Now I can lint (aka compile) the project with that build configuration:
Linting Project
And it will show all the lint messages in the Eclipse problem view:
Lint messages in Eclipse
That’s it. :-). Everything else will depend on your project: add new files to be linted, adopt the settings, and happy linting. :-)
Summary
Linting project files is a valuable way for me to increase software quality (lint early and often). I have been deliquent for a while not doing it often recently, but that space project reminded me to start this good habit again, even if it takes some time to do it. To use lint with Eclipse projects is not straight-forward at the beginning, but with some infrastructure and getting used to it, it is very easy. And I hope this article motivates others to use lint more. PC-lint is not free, but it might be very worthwile. Otherwise I hope the above setup can help as well with other similiar tools.
Published at DZone with permission of Erich Styger, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments