blob: 4338a2764a094f29f4feb38cc3ccdd26336b1ba6 [file] [log] [blame]
#!/bin/sh -efu
# Copyright 2011-2012 Intel Corporation
# Author: Kirill Shutemov, Artem Bityutskiy
# License: GPLv2
srcdir="$(readlink -ev -- ${0%/*})"
export PATH="$srcdir:$srcdir/libshell:$PATH"
. shell-error
. shell-args
. shell-signal
. shell-quote
. aiaiai-sh-functions
PROG="${0##*/}"
message_time="yes"
# This is a small trick to make sure the script is portable - check if 'dash'
# is present, and if yes - use it.
if can_switch_to_dash; then
exec dash -euf -- "$srcdir/$PROG" "$@"
exit $?
fi
show_usage()
{
cat <<-EOF
Usage: $PROG [options] <kernel-tree> <targets...>
<kernel-tree> - directory with kernel sources
<targets...> - list of targets to make.
Options:
-o, --objdir=OBJDIR locate all output files in OBJDIR, including .config
(O=OBJDIR Kbuild feature); if undefined - use the
source directory (<kernel-tree>);
-D, --defconfig=CONF name of the defconfig to use for each target; if the
name contains a "/" character, it is interpreted as a
stand-alone defconfig file, otherwise it is assumed
that CONF is part of the <kernel-tree>;
-j, --jobs=N allow to run N jobs simultaneously (default is 1);
-O, --stdout=FILE redirect stdout of the build to FILE;
-E, --stderr=FILE redirect stderr of the build to FILE (note, if neither
-O nor -E are specified, everything is redirected to
stdout);
-k, --keep-going continue as much as possible after an error (see
-k GNU make option);
-a, --arch=A,[C] test for specified architecture (ARCH=) and the
cross-compiler prefix (CROSS_COMPILE=); Examples:
-a i386, -a arm,arm-eabi-, etc;
--sparse check with sparse while building;
--smatch check with smatch while building;
--cppcheck check with cppcheck while building;
--coccinelle=PATH check with coccinelle (spatch) using coccinelle
scripts from PATH; the scripts have to have ".cocci"
extention and may reside anywhere under PATH
--check-only=FILE check only files listed in FILE;
-M, --kmake-opts additional options to append to the final kernel
compilation 'make' command
(e.g., W=12 KALLSYMS_EXTRA_PASS=1)
defaults to "KCFLAGS='-Wno-missing-field-initializers
-Wno-sign-compare' W=1"
-v, --verbose be verbose;
-h, --help show this text and exit.
EOF
}
fail_usage()
{
[ -z "$1" ] || printf "%s\n" "$1"
show_usage
exit 1
}
# Strip useless stuff from the log and make it possible to compare it to
# another build log.
strip_log()
{
local logfile="$1"
sed -i -e "# Strip useless stuff
/^CRC [[:xdigit:]]\+$/d
/^System is [[:digit:]]\+ kB$/d
/^Setup is [[:digit:]]\+ bytes (padded to [[:digit:]]\+ bytes).$/d
/^Root device is ([[:digit:]]\+, [[:digit:]]\+)$/d
# Strip not very useful messages from modpost
/^To see full details build your kernel with:$/d
/^'make CONFIG_DEBUG_SECTION_MISMATCH=y'$/d
# Make all source paths relative to the kernel tree root
s/$(quote_sed_regexp "$kernel_tree/")//g" "$logfile"
# Strip objdir paths as well
[ -z "$objdir" ] || sed -i -e "s/$(quote_sed_regexp "$objdir/")//g" "$logfile"
}
make_target()
{
local target="$1"
if [ -n "$defconfig" ]; then
if printf "%s" "$defconfig" | grep -q '/'; then
# The defconfig is a path to a stand-alone defconfig file
# FIXME: ugly hack!
make -C $kernel_tree ${arch:+ARCH="$arch"} \
${cross:+CROSS_COMPILE="$cross"} \
${objdir:+O="$objdir"} \
KCONFIG_ALLCONFIG="$defconfig" -- alldefconfig
else
# The defconfig is part of the git tree
make -C $kernel_tree ${arch:+ARCH="$arch"} \
${cross:+CROSS_COMPILE="$cross"} \
${objdir:+O="$objdir"} -- "$defconfig"
fi
fi
aiaiai-locker $split -l "$lockfile" -c \
"make $keep_going -j $jobs -C $kernel_tree ${arch:+ARCH="$arch"} \
${cross:+CROSS_COMPILE="$cross"} ${objdir:+O="$objdir"} \
CHECK=\"aiaiai-checker $sparse $smatch $cppcheck $coccinelle $check_only --\" \
C=$check ${check:+CF="-D__CHECK_ENDIAN__"} SHELL=\"aiaiai-locker $split -l $lockfile\" \
$kmake_opts $target"
}
lockfile=
build_stdout=
build_stdout_given=
build_stderr=
build_stderr_given=
build_output=
cleanup_handler()
{
rm $verbose -f -- "$lockfile" >&2
[ -n "$build_stdout_given" ] || rm $verbose -f -- "$build_stdout" >&2
[ -n "$build_stderr_given" ] || rm $verbose -f -- "$build_stderr" >&2
rm $verbose -f -- "$build_output" >&2
}
set_cleanup_handler cleanup_handler
TEMP=`getopt -n $PROG -o o:,D:,j:,O:,E:,k:,a:,M:,v,h --long objdir:,defconfig:,jobs:,stdout:,stderr:,keep-going,arch:,sparse,smatch,cppcheck,coccinelle:,check-only:,kmake-opts:,verbose,help -- "$@"` ||
fail_usage ""
eval set -- "$TEMP"
objdir=
defconfig=
jobs=1
keep_going=
arch=
cross=
sparse=
smatch=
cppcheck=
coccinelle=
cocci_path=
check_only=
check=0
kmake_opts="KCFLAGS='-Wno-missing-field-initializers -Wno-sign-compare' W=1"
verbose=
while true; do
case "$1" in
-o|--objdir)
mkdir $verbose -p -- "$2" >&2
objdir="$(readlink -fv -- "$2")"
shift
;;
-D|--defconfig)
defconfig="$2"
shift
;;
-j|--jobs)
jobs="$(opt_check_number "$1" "$2")"
shift
;;
-O|--stdout)
touch "$2"
build_stdout="$(readlink -fv -- "$2")"
build_stdout_given="y"
shift
;;
-E|--stderr)
touch "$2"
build_stderr="$(readlink -fv -- "$2")"
build_stderr_given="y"
shift
;;
-k|--keep-going)
keep_going="--keep-going"
;;
-a|--arch)
arch="$(leave_first "$2")"
cross="$(leave_second "$2")"
shift
;;
--sparse)
sparse="--sparse"
check=1
;;
--smatch)
smatch="--smatch"
check=1
;;
--cppcheck)
cppcheck="--cppcheck"
check=1
;;
--coccinelle)
cocci_path="$(opt_check_dir "$1" "$2")"
coccinelle="--coccinelle=$cocci_path"
check=1
shift
;;
--check-only)
check_only="--check-only $(opt_check_read "$1" "$2")"
shift
;;
-M|--kmake-opts)
kmake_opts="$2"
shift
;;
-v|--verbose) verbose=-v
;;
-h|--help)
show_usage
exit 0
;;
--) shift; break
;;
*) fail_usage "Unrecognized option: $1"
;;
esac
shift
done
[ "$#" -ge 2 ] || fail_usage "Insufficient arguments"
compile_helpers "$srcdir"
program_required "aiaiai-locker" ""
program_required "${cross}gcc" ""
program_required "make" ""
kernel_tree="$(opt_check_dir "kernel-tree" "$1")"; shift
build_info="$kernel_tree${objdir:+ (O="$objdir")}"
if [ -n "$build_stdout_given" ] || [ -n "$build_stderr_given" ]; then
split="-s"
[ -n "$build_stdout_given" ] || build_stdout="$(mktemp -t "$PROG.stdout.XXXX")"
[ -n "$build_stderr_given" ] || build_stderr="$(mktemp -t "$PROG.stderr.XXXX")"
else
split=
build_output="$(mktemp -t "$PROG.output.XXXX")"
fi
lockfile="$(mktemp -t "$PROG.lock.XXXX")"
failed=
for target in $@; do
verbose "Making target \"$target\" for \"$build_info\""
if [ -z "$split" ]; then
make_target "$target" > "$build_output" || failed=1
[ -z "$failed" ] || echo "FAILURE" >> "$build_output"
else
make_target "$target" > "$build_stdout" 2> "$build_stderr" || failed=1
[ -z "$failed" ] || echo "FAILURE" >> "$build_stderr"
fi
if [ -n "$failed" ]; then
verbose "Failed to make target \"$target\" for \"$build_info\""
break
fi
done
[ -z "$build_stdout" ] || strip_log "$build_stdout"
[ -z "$build_stderr" ] || strip_log "$build_stderr"
[ -z "$build_output" ] || strip_log "$build_output"
if [ -n "$build_stdout_given" ] || [ -n "$build_stderr_given" ]; then
[ -n "$build_stdout_given" ] || cat "$build_stdout"
[ -n "$build_stderr_given" ] || cat "$build_stderr"
else
[ -z "$build_output" ] || cat "$build_output"
fi
if [ -z "$failed" ]; then
verbose "Successfully made all targets for \"$build_info\""
else
verbose "Failed to make a target, exiting"
fi