Skip to content

Instantly share code, notes, and snippets.

@pamaury
Last active August 29, 2015 14:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pamaury/3fa6ff03ecc26387b977 to your computer and use it in GitHub Desktop.
Save pamaury/3fa6ff03ecc26387b977 to your computer and use it in GitHub Desktop.
#/bin/bash
TMPDIR="./tmp-check-defines"
SEARCH_DIRS="apps/ firmware/ uisimulator/"
function usage()
{
echo "Usage: $0 <build file> <define 1> [<define 2>...]"
echo "If the define name is suffixed with @ or ~, the tool will also print its value"
echo "Furthermore, if a regex follows the @, the tool will try to list all defines"
echo "matching this regex to pretty print the output"
echo "If the define name is suffixed with ~, the tool will try to list all definitions"
echo "of the macro and compare the right hand side value with the actual value"
echo "to pretty print the value"
echo ""
echo "Examples:"
echo "$0 ../www/buildserver/builds HAVE_USBSTACK "
echo "$0 ../www/buildserver/builds 'CONFIG_LCD@LCD_[[:alnum:]_]*'"
echo "$0 ../www/buildserver/builds CONFIG_CPU~"
exit 1
}
# pattern_check define file
function pattern_check()
{
cat >>"$2" <<EOF
#ifdef $1
#pragma message "cafebabe-$1"
#else
#pragma message "deadbeef-$1"
#endif
EOF
}
# pattern_check define file
function pattern_value()
{
cat >>"$2" <<EOF
#ifdef $1
#pragma message "cafebabe-$1@"MYEVAL($1)"@"
#else
#pragma message "deadbeef-$1"
#endif
EOF
}
# pattern_check define regex file
function pattern_regex()
{
# not implemented yet
cat >>"$3" <<EOF
#ifdef $1
#pragma message "cafebabe-$1@"MYEVAL($1)"@"
#else
#pragma message "deadbeef-$1"
#endif
EOF
}
# pattern_list define file
function pattern_list()
{
cat >>"$2" <<EOF
#if !defined($1)
#pragma message "deadbeef-$1"
EOF
# find all occurences
grep -REh "^#define[[:space:]]+$1[[:space:]]+" $SEARCH_DIRS |
awk -v "DEF=$1" '{ match($0,/#define[[:space:]]+[[:alnum:]_]+[[:space:]]+(.*)/,arr);
print("#elif "DEF" == ("arr[1]")");
print("#pragma message \"cafebabe-"DEF"@"arr[1]"@\""); }' >> $2
cat >>"$2" <<EOF
#else
#pragma message "cafebabe-$1@"MYEVAL($1)"@"
#endif
EOF
}
# check number of arguments
if [ $# -le 1 ]; then
usage
fi
# print invocation, for reference
echo "#invocation $0 $*"
# build file
BUILD_FILE="$1"
shift
# check build file
if [ ! -f $BUILD_FILE ]; then
echo "ERROR: build file doesn't exist"
exit 2
fi
# fill template test file
TMPLFILE=template.c
cat > "$TMPLFILE" <<EOF
/* Automatically generated. http://www.rockbox.org/ */
#include "system.h"
#include "usb.h"
#include "usb_ch9.h"
/* add more includes here if needed */
#define MYEVAL_(x) #x
#define MYEVAL(x) MYEVAL_(x)
EOF
# generate test pattern for each define
for DEFINE in "$@"
do
# check if define must be printed (named suffixed by @)
if [[ "$DEFINE" =~ "@" ]]; then
REGEX=`echo "$DEFINE" | awk '{ match($0,/@(.*)$/,arr); print(arr[1]); }'`
DEFINE=`echo "$DEFINE" | awk '{ match($0,/([^@]*)@/,arr); print(arr[1]); }'`
# if regex is empty, it's simple
if [ "$REGEX" = "" ]; then
pattern_value "$DEFINE" "$TMPLFILE"
else
pattern_regex "$DEFINE" "$REGEX" "$TMPLFILE"
fi
elif [[ "$DEFINE" =~ "~" ]]; then
DEFINE=`echo "$DEFINE" | awk '{ match($0,/([^~]*)~/,arr); print(arr[1]); }'`
pattern_list "$DEFINE" "$TMPLFILE"
else
pattern_check "$DEFINE" "$TMPLFILE"
fi
done
# process lines in the build
while read line
do
# ignore wps and manual lines, also sim
if `echo "$line" | grep -E "(wps)|(manual)|(sim)" &> /dev/null`; then
continue
fi
# format of each line: compiler:x:name:title:file:hint:command
NAME=`echo "$line" | awk 'BEGIN { FS=":" } { print $3 }'`
CMD=`echo "$line" | awk 'BEGIN { FS=":" } { print $7 }'`
# remove temporary directory
rm -rf "$TMPDIR"
# create temporary directory and cd into it
mkdir "$TMPDIR"
cd "$TMPDIR"
# create a fake generated file
TESTFILE=mytest
cp "../$TMPLFILE" "$TESTFILE.c"
# the command extract is of the form
# ../tools/configure <options> && make <blabla>
# extract the part before && and replace the whole thing with:
# ../tools/configure <options> && make $TESTFILE.o
CFGCMD=`echo "$CMD" | awk '{ i=index($0, "&&"); print(substr($0,1,i-1)); }'`
# try to run configure
# it might error if the target compiler is not installed for example
if eval $CFGCMD &>/dev/null; then
# pretend dependencies were generated (because it's very long)
touch make.dep
# try to build our test file
OUTPUT=out.txt
ERROR=err.txt
if ! make $TESTFILE.o >$OUTPUT 2>$ERROR; then
# print make error
echo "$NAME: <make error>"
else
# print defines
echo "$NAME:" `cat "$ERROR" | awk 'BEGIN { list="" }
{ if(match($0,/cafebabe-([[:alnum:]_]+)/,arr) != 0) list = list " " arr[1];
if(match($0,/@([^@]*)@/,arr)) list = list "=" arr[1]; }
END { print(list); }'`
fi
else
# print config error
echo "$NAME: <config error>"
fi
# cd back to root
cd ..
done < "$BUILD_FILE"
# remove everything
rm -rf "$TMPDIR"
rm -f "$TMPLFILE"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment