Integrating OCLint in XCode

OCLint is well know tool doing static code analyzing, for c, c++ and objc. It’s not only stylistic analysis, but also some metrics based, complicated analysis able to detect too complicated logics in code (the simpler the code – the better it is) which is far most useful then XCode’s native static analyzer which is mostly about memory management. Since ARC was applied to you project – it became useless.

It appears to be not so easy and obvious when it comes to using OCLint for real-world project. Here’s my experience integrating this tool in regular XCode project.

Prerequisites

OCLint has pretty much good documentation on how to start with it. The only thing worth noting is that I wasn’t able to run oclint executable from their binary distribution. On OSX10.7 it says something like “incorrect instruction”. Googling a bit I found out that something wrong with installation and I have to recompile it. So I dropped out package I downloaded first time and built OCLint from sources. This time everything was OK. I installed OCLint by adding it’s path to my ~/.bash_profile.

Giving a try

Typically you run OCLint against one file giving it all the same arguments you provide to compiler when compiling this file. To analyze the whole project you have to create some script invoking oclit for every file. Boilerplate, isn’t it? Good news – OCLint package already such script – called oclint-json-compilation-database which reads file with json-formatted list of the files to analyze along with it’s compile parameters. There is also a helpful script which can read xcodebuild generated output and produce this json formatted database – oclint-xcodebuild. So, typically you have to do the following:

$ xcodebuild | tee xcodebuild.log
$ oclint-xcodebuild xcodebuild.log
$ oclint-json-compilation-database

You can provide oclint modifying flags by adding separator – -, like this:

$ oclint-json-compilation-database -- -o=report.html -html

This command will generate report.html file with all the output from oclint. It’s good to have this report, it’ll be much better to be able to see exact line of code the warning was generated from. It’ll great to have oclint behaving similar to XCode’s own static analyzer.

Integrating in XCode

Well, here’s my solution.
I added new target to the project, let’s call it OCLint. It should be aggregate target. Then add new build phase for running custom script and put following script in editor:


source ~/.bash_profile
hash oclint &> /dev/null
if [ $? -eq 1 ]; then
echo &>2 "oclint not found, analyzing stopped"
exit 1
fi

cd ${TARGET_TEMP_DIR}

if [ ! -f compile_commands.json ]; then
echo "[*] compile_commands.json not found, possibly clean was performed"
echo "[*] starting xcodebuild to rebuild the project.."
# clean previous output
if [ -f xcodebuild.log ]; then
rm xcodebuild.log
fi

cd ${SRCROOT}

xcodebuild clean

#build xcodebuild.log
xcodebuild | tee ${TARGET_TEMP_DIR}/xcodebuild.log

echo "[*] transforming xcodebuild.log into compile_commands.json..."
cd ${TARGET_TEMP_DIR}
#transform it into compile_commands.json
oclint-xcodebuild

fi

#if [-d report.html]; then
#rm report.html
#fi

#run static analyzer
#oclint-json-compilation-database -- -o=./report.html -html

echo "[*] starting analyzing"
cd ${TARGET_TEMP_DIR}
oclint-json-compilation-database | sed 's/\(.*\.\m\{1,2\}:[0-9]*:[0-9]*:\)/\1 warning:/

Some things to notice in this script. First, as you see I first apply ~/.bash_profile to current session. The thing is, if you installed oclint by adding it’s path to your bash_profile file, it won’t be visible during build, as technically build is done in separate user’s session. If you installed oclint by copying it into one of the system’s path – this command is not required.
Second, all the files are being created in build’s temp dir. Before analyzing oclint needs the whole project to be build by xcodebuild, but this process may require a lot of time and it’s output tends to be constant (until you add new file to project or change some file’s compilation parameters) so we need to build only once. If you however do require to rebuild json database – simply perform clean. As I mentioned, all the files are crated in temp directory which is totally removed when cleaning the target.
And the last thing to notice. oclint generates output in form:

/path/to/file.m:123:2: warning message

This output can be easily read by XCode but it treats this message as error by default. To force it treat this message as warning, the output should be modified to following form:

/path/to/file.m:123:2: warning: <warning message>

This is performed by redirecting oclint’s output to sed with neat regex.
That’s it! Now you can see all the warning generated by oclint exactly where it was generated! As usual, XCode only shows first 200 messages during build. Even if you perform ‘Analyze’ instead of ‘Build’ it will behave the same way. If you can find the way to force XCode show all the errors – let me know!

I post main script on gist so you guys can fork it and improve for your own needs.

7 comments on “Integrating OCLint in XCode

  1. Pingback: Last months iOS resources (March 4 2013) | E.V.I.C.T. B.V.

  2. Very nice article..

    Trying to achieve same in my project.

    But running in xcode 5.1.1 with ios 7.1 sdk is giving

    Could not build module ‘QuartzCore’
    Could not build module ‘UIKit’
    .
    .
    .
    .

    Any solution for this

    • Based on the error message you get I’m pretty sure your problem is in something different. Also, the solution I described was targeted for XCode 4 and I have no guarantee that it works on newer XCode. I suggest you refer to official oclint documentation as they took my original idea and improved it, keeping solution up-to-date.

Leave a comment