views:

587

answers:

6

I am looking for a free static checker for C99 code (including GCC extensions) with the ability to explicitly say "these preprocessor macros are always defined."

I need that last part because I am compiling embedded code for a single target processor. The compiler (Microchip's C32, GCC based) sets a macro based on the selected processor, which is then used in the PIC32 header files to select a processor-specific header file to include. cppcheck therefore fails because it detects the 30 different #ifdefs used to select one of the many possible PIC32 processors, tries to analyse all possible combinations of these plus all other #defines, and fails.

For example, if splint could process C99 code, I would use

splint -D__PIC32_FEATURE_SET__=460 -D__32MX460F512L__ \
-D__LANGUAGE_C__ -I/path/to/my/includes source.c

An additional problem is that the PIC32 toolchain compiler is called pic32-gcc and not just gcc, although I haven't yet gotten to the point of needing to account for this.

Update #1 - One thing I'm interested in, but is orthogonal to this question, is Eclipse integration (it'd be nice not to have to write a makefile for 30+ compilation units). I asked about this on the Eclipse forums (although the discussion there is more about integration into Eclipse). Nothing groundbreaking.

Update #2 - just tried scan-build from clang, using:

scan-build --use-cc=/usr/local/bin/pic32-gcc make -B -k all

...(also without the --use-cc flag) but all I got was the typical build output, an example of which is:

Building file: ../src/MoreMath.c
Invoking: PIC C32 C Compiler
pic32-gcc -D__DEBUG -I/usr/local/pic32-libs/include -O0 -Wall -c -fmessage-length=0 -std=gnu99 -Werror-implicit-function-declaration -MMD -MP -MF"src/MoreMath.d" -MT"src/MoreMath.d" -mprocessor=32MX460F512L -D__DEBUG -g -o"src/MoreMath.o" "../src/MoreMath.c"
Finished building: ../src/MoreMath.c

...and at the end:

Building target: MyBinary.elf
Invoking: PIC C32 C Linker
pic32-gcc -Wl,-Map,MyBinary.map -mprocessor=32MX460F512L --defsym=__MPLAB_DEBUG=1 -o"MyBinary.elf" <<ALL OF MY *.o FILES HERE>>
Finished building target: MyBinary.elf

scan-build: Removing directory '/tmp/scan-build-2010-06-21-1' because it contains no reports.

So either my code is perfect according to scan-build, or it's not doing anything. I'm not sure what a good test might be to see if it is working.

+3  A: 

Clang's static analyzer should work.

Another option with the source code #defines is that you could run cpp over the source code with some of the preprocessor statements, and then run that resultant code through a static analyzer.

sharth
I think `scan-build` is about as good as I can get. I'm developing under Eclipse and using the internal builder (ie. no explicit makefile), and I don't think there's any clang integration for the Eclipse CDT. It might be worth switching to a makefile based project.
detly
Alas, I cannot see a way to get `scan-build` (or any Clang tools) to work with Eclipse.
detly
+3  A: 

You could just add some code like this to the top of your header that guarantees that it's defined:

#ifndef MACRO_I_NEED
#error "MACRO_I_NEED should be defined"
#define MACRO_I_NEED  // to appease cppcheck
#endif
Adam Rosenfield
Wouldn't I need to do that for every single source file though?
detly
@detly: Not necessarily -- if you have a header file that every file includes (such as a precompiled header), then you can put it at the top of that.
Adam Rosenfield
A: 

This might not directly give you the solution, but you might consider having a look to Coverity, which is a proprietary static syntax analyser, but that is free of charge for OS projects. It should do the job concerning your needs!

Cheers!

dcouscous
It's not an OSS project.
detly
A: 

You can use a tool like sunifdef to partially preprocess the source code according to the assumed defined macros. You'd have to make copies of system and library headers that are affected by those defines and process them as well. Then when doing the static analysis you would specify a different include path pointing to your already processed headers.

Geoff Reedy
+1  A: 

Instead of using scan-build with clang, consider swapping out gcc altogether! Clang's C support is stable (and does its best to emulate gcc), and should handle your code just fine.

Try something like make -j3 CC=clang and see what happens!

PS. That syntax might be totally wrong. Haven't used makefiles in ages (CMake is amazing btw).

Clark Gaebel
cmake is awful!
Matt Joiner
It doesn't support the `-MT` option, which means I have to rewrite a lot of makefiles. Currently the build uses autodependency files - `.d` files - which contain the header dependencies for each `.o` file. It'll be a while before I can test this.
detly
A: 

Depending on what actual analyses you want to run on your code, you might take a look at Frama-C. It uses whatever C preprocessor you tell it to, so you can use PIC32's CPP if you want.

Porges