Статьи

Linting с Eclipse и встроенным компилятором панели запуска GNU ARM

Для космического проекта мы должны убедиться, что все не выходит из строя, пока наше оборудование вращается вокруг Матери-Земли. Поэтому мы используем различные инструменты статического и динамического анализа, и один из них использует PC-lint от Gimpel для выявления как можно большего количества ошибок и ошибок. Для этого проекта мы используем Eclipse с компилятором ARM GNU ARM Embedded (launchpad) и Eclipse в качестве IDE с плагинами GNU ARM Eclipse . Существуют коммерческие плагины, доступные для линтинга с Eclipse (например, Linticator ), но с помощью нескольких настроек можно линковать с Eclipse бесплатно. Итак, эта статья о том, как линкнуть проект Eclipse с помощью PC-Lint.

Название изображения

Lint сообщения в Eclipse

PC-Lint

Если вы серьезно относитесь к разработке программного обеспечения, вы хотите проверить исходный код как можно раньше и как можно раньше. Инструмент, который я использовал очень давно, это PC-lint от Gimpel. Это не бесплатный инструмент (стоит около $ 390), но он сэкономил мне бесчисленные часы. Существуют альтернативы с открытым исходным кодом, которые я использую параллельно, но PC-lint для меня все еще своего рода справочник. Для пользователей Linux существует версия для этой операционной системы.

Задача полного использования PC-lint состоит в том, чтобы он знал обо всех путях и настройках библиотеки, а также во всех встроенных определениях компилятора для правильного связывания кода с библиотеками. Этот пост должен помочь вам решить эту проблему. 🙂

PC-Lint и Eclipse

Вы можете проверить одну из моих ранних статей о том, как линковать с Eclipse без плагина (см. Http://mcuoneclipse.com/2012/04/10/linting-without-a-plugin/ ). С тех пор все на стороне Eclipse немного изменилось. В этом посте улучшена обработка ошибок и показано, как использовать ее с инструментами GNU ARM Embedded (launchpad), включая правильное использование библиотек.

В следующих шагах я использую следующие инструменты:

  1. Eclipse Luna (Freescale (теперь NXP), Kinetis Design Studio V3.0.0) (устанавливается в C: \ Freescale \ KDS_3.0.0)
  2. GNU ARM Embedded (панель запуска) 4.9 2015 q2
  3. Подключаемые модули GNU ARM Eclipse C / C ++ (1.13.1.201504061754)
  4. PC-lint v9.0 (установлен в C: \ Freescale \ lint)

Подход, который я использую, заключается в следующем:

  1. На первом этапе создайте подходящие файлы конфигурации lint для использования с co-gcc.lnt.
  2. Создайте новую конфигурацию сборки (например, ‘lint’) для существующего проекта, который будет помечен
  3. В этой конфигурации сборки вызовите пакетный файл для запуска lint
  4. Пакетный файл вызовет lint с соответствующими операциями и файлами конфигурации.
  5. Список файлов для разметки будет указан в файлах конфигурации, указанных вручную

Конфигурационные файлы Lint для co-gcc.lnt

В моих ранее написанных проектах я использовал co-gnu.lnt.


Lint использует .lnt файлы для опций и конфигураций.
Многие файлы конфигурации поставляются с установкой lint в / lnt

Co-gnu.lnt является более старой версией и не очень хорошо работает с новыми компиляторами gcc. Вместо этого следует использовать co-gcc.lnt , который находится в подпапке ‘lnt’ установки PC-lint:


/* 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.

Однако, поскольку каждый gcc может иметь разные настройки, для этого co-gcc.lnt требуется несколько дополнительных сгенерированных файлов:

  1. gcc-include-path.lnt : список включаемых путей для поиска заголовков библиотеки.
  2. size-options.lnt : стандартные размеры шрифта.
  3. lint_cmac.h и lint-cppmac.h : файлы заголовков со всеми предопределенными компилятором C и C ++ определениями, используемые co-gcc.h.

Поскольку оба файла зависят от пути установки компилятора и параметров компилятора, эти файлы не являются частью установки PC-lint. Вместо этого они должны быть созданы.

В следующих разделах я опишу, как создать эти файлы. Вы можете пропустить этапы создания и напрямую использовать и принимать мои сгенерированные файлы вместо этого.

совместно gcc.mak

Для создания этих файлов в папке \ lnt есть файл make (co-gcc-mak). Он использует сам компилятор GNU для создания этих файлов. Это очень умный способ сделать это, однако он не очень хорошо работает для встроенных кросс-компиляторов (см. Позже). Файл make

Файл make зависит от нескольких инструментов, которые необходимо установить и представить в PATH:


Мне пришлось запустить установочную версию основных утилит GNU, так как в противном случае инструменты сообщали о некоторых отсутствующих файлах DLL в Windows :-(.

Файл make создаст следующие файлы (см. <Lint-installation-path> \ lnt \ gcc-readme.txt):

  1. lint_cmac.h
  2. lint_cppmac.h
  3. НКУ-включать-path.lnt
  4. Размер-options.lnt

Файл size-options.lint должен быть создан с небольшим исполняемым файлом (этот шаг не удастся, мы увидим).

Чтобы упростить запуск файла make и не изменять мою глобальную переменную PATH, я создал следующий пакетный файл co_gcc.bat внутри <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.

Вам нужно будет принять параметры пути в соответствии с утилитами make, awk, gnu core и установкой GNU gcc в вашей системе.

Другое соображение заключается в том, что gcc, вызываемый с этим файлом make, должен соответствовать настройкам компилятора, используемым в проекте Eclipse, который будет отображаться, поскольку создаваемые файлы .lnt должны соответствовать используемым настройкам компилятора.

На последнем шаге он вызывает утилиту make. На моей системе вывод выглядит так:


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&gt;

Обратите внимание, что на последнем шаге не удается создать исполняемый файл для выполнения. Ожидается, что это не удастся для кросс-компиляции (мы строим на хосте, но выполняем на встроенном процессоре ARM на другой плате). Но три других файла были созданы:

Название изображения

сгенерированные файлы от co_gcc.bat

Размер-options.lnt

Этот неудачный последний шаг должен создать файл size-options.lnt с таким кодом:


\
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) );\
}

Имея некоторые базовые знания о размерах типов, используемых компилятором, я могу создать этот файл size-options.lnt вручную, как показано ниже. Он сообщает lint с параметром -s о размере различных стандартных типов:


// 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

НКУ-включать-path.lnt

Он успешно создал gcc-include-path.lnt : он сообщает lint, где найти все включаемые файлы библиотеки GNU.


// 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"


Вы можете взять приведенный выше шаблон и легко перенести его на версию компилятора и путь установки.

lint_cmac.h и lint_cppmac.h

Сгенерированные lint_cmac.h и lint_cppmac.h содержат все предопределенные макросы компилятора gcc.


Я разместил свои файлы на GitHub здесь:
https://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/KDS/FRDM-K64F120M/FRDM-K64F_pc-lint/lint

Ниже приведен пример 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

Линтинг с затмением

Для линтинга проекта с Eclipse я рекомендую создать локальную папку «lint» и поместить в нее все необходимые файлы:


см. мой проект на GitHub:
https://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/KDS/FRDM-K64F120M/FRDM-K64F_pc-lint

Название изображения

Lint конфигурационные файлы внутри проекта

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.