Question
The RUN_CLANG_STATIC_ANALYZER ("Run Static Analyzer") project setting has found important issues in our project. We have addressed them and we want to prevent future issues from creeping in.
We're trying to get clang analysis warnings to be treated as errors to break our build. So far no success despite having -Werror ("Treat Warnings as Errors") enabled.
Example of Problem
The following analysis call generated within Xcode:
/Developer/usr/bin/clang -x objective-c [...] --analyze [...]/TroubledCode.m -o [...]/TroubledTarget.build/StaticAnalyzer/normal/i386/TroubledCode.plist
produces a static code analysis warning:
[...]/TroubledCode.m:38:34: warning: Potential leak of an object allocated on line 38 and stored into 'leakingManager'
Manager *leakingManager = [[Manager alloc] init];
^
1 warning generated.
but Xcode reports "Build Succeeded ... 1 analyzer result". The solution we're looking for would make the example above generate a "Build Failed".
Solution
I took Jim's advice and created a build script.
To avoid false alarms, I went through the trouble of making sure it ignores extraneous analysis residue. This solution should work when building from the Xcode IDE and when building your project using xcodebuild
.
To turn Xcode 3 analysis warnings into build errors:
- Double click the project or target in question.
- Under the Build tab, check the box under Settings > Linking > Write Link Map File
That setting is also known as LD_GENERATE_MAP_FILE
.
- Under "Groups & Files" > "Targets", click the disclosure triangle of the target you'd like to add this feature to.
- Right-click the "Link Binary With Libraries" phase.
- select Add > New Build Phase > New Run Script Build Phase
- optional: Rename the "Run Script" phase you just added to "Treat Clang Warnings as Errors".
- Double-click the new script phase if it's not already open.
Copy the content below and paste it into the "Script" section.
error_count=0
##
function verify_clang_analysis_at_path()
{
local analysis_path=$1
local plist_tool=/usr/libexec/PlistBuddy
local diagnostics=$($plist_tool -c "print diagnostics" $analysis_path)
if [[ $diagnostics != $'Array {\n}' ]]
then
((error_count++))
fi
}
function verify_clang_analysis_for_object_file()
{
local object_file=$1
local analysis_directory=$TARGET_TEMP_DIR/StaticAnalyzer/$CURRENT_VARIANT/$CURRENT_ARCH
local analysis_path=$analysis_directory/${object_file%.*}.plist
# if this object file corresponds to a source file that clang analyzed...
if [ -e $analysis_path ]
then
verify_clang_analysis_at_path $analysis_path
fi
}
##
object_directory=$OBJECT_FILE_DIR-$CURRENT_VARIANT/$CURRENT_ARCH
object_path_pattern=${object_directory}'/\(.\)\+\.o$'
index_pattern='\[[[:space:]0-9]*\][[:space:]]'
object_paths=$(
grep $object_path_pattern $LD_MAP_FILE_PATH | sed s/$index_pattern//
)
##
for object_path in $object_paths
do
object_file=${object_path##*/}
verify_clang_analysis_for_object_file $object_file
done
if [ $error_count -gt 0 ]
then
echo "Clang static code analysis failed for" $error_count "source file(s)."
fi
exit $error_count
Update
Mike Vosseller has an upgraded version of this script for Xcode 5.