--- a/configure +++ b/configure @@ -1,10 +1,10 @@ -#!/bin/bash +#!/bin/sh # set environment variables used by scripts/make.sh # People run ./configure out of habit, so do "defconfig" for them. -if [ "$(basename "$0")" == configure ] +if [ "$(basename "$0")" = configure ] then echo "Assuming you want 'make defconfig', but you should probably check the README." make defconfig @@ -12,8 +12,12 @@ fi # Warn about stuff, disable stupid warnings, be 8-bit clean for utf8. -[ "${CFLAGS/-funsigned-char//}" == "$CFLAGS" ] && - CFLAGS+=" -Wall -Wundef -Werror=implicit-function-declaration -Wno-char-subscripts -Wno-pointer-sign -funsigned-char" +case " ${CFLAGS-} " in + *" -funsigned-char "*) ;; + *) + CFLAGS="${CFLAGS-} -Wall -Wundef -Werror=implicit-function-declaration -Wno-char-subscripts -Wno-pointer-sign -funsigned-char" + ;; +esac # Set default values if variable not already set : ${CC:=cc} ${HOSTCC:=cc} ${GENDIR:=generated} ${KCONFIG_CONFIG:=.config} --- a/scripts/portability.sh +++ b/scripts/portability.sh @@ -1,6 +1,6 @@ # sourced to find alternate names for things -source ./configure +. ./configure if [ -z "$(command -v "$CROSS_COMPILE$CC")" ] then @@ -8,15 +8,20 @@ exit 1 fi -if [ -z "$SED" ] +if [ -z "${SED:-}" ] then - [ ! -z "$(command -v gsed 2>/dev/null)" ] && SED=gsed || SED=sed + if command -v gsed >/dev/null 2>&1 + then + SED=gsed + else + SED=sed + fi fi # Tell linker to do dead code elimination at function level -if [ "$(uname)" == "Darwin" ] +if [ "$(uname)" = "Darwin" ] then - CFLAGS+=" -Wno-deprecated-declarations" + CFLAGS="${CFLAGS} -Wno-deprecated-declarations" : ${LDOPTIMIZE:=-Wl,-dead_strip} ${STRIP:=strip} else : ${LDOPTIMIZE:=-Wl,--gc-sections -Wl,--as-needed} ${STRIP:=strip -s -R .note* -R .comment} @@ -24,9 +29,9 @@ # Disable pointless warnings only clang produces [ -n "$("$CROSS_COMPILE$CC" --version | grep -w clang)" ] && - CFLAGS+=" -Wno-string-plus-int -Wno-invalid-source-encoding" || + CFLAGS="${CFLAGS} -Wno-string-plus-int -Wno-invalid-source-encoding" || # And ones only gcc produces - CFLAGS+=" -Wno-restrict -Wno-format-overflow" + CFLAGS="${CFLAGS} -Wno-restrict -Wno-format-overflow" # Address Sanitizer if [ -n "$ASAN" ]; then @@ -55,9 +60,10 @@ # Run a C file from scripts/*.c using $HOSTCC as necessary brun() { - [ ! -e "$UNSTRIPPED"/$1 -o "$UNSTRIPPED"/$1 -ot scripts/$1.c ] && + tool=$1 + shift + [ ! -e "$UNSTRIPPED"/$tool -o "$UNSTRIPPED"/$tool -ot scripts/$tool.c ] && { mkdir -p "$UNSTRIPPED" && - do_loudly $HOSTCC scripts/$1.c -o "$UNSTRIPPED"/$1 || exit 1; } - do_loudly "$UNSTRIPPED"/$1 "${@:2}" + do_loudly $HOSTCC scripts/$tool.c -o "$UNSTRIPPED"/$tool || exit 1; } + do_loudly "$UNSTRIPPED"/$tool "$@" } - --- a/scripts/genconfig.sh +++ b/scripts/genconfig.sh @@ -1,9 +1,9 @@ -#!/bin/bash +#!/bin/sh # This has to be a separate file from scripts/make.sh so it can be called # before menuconfig. (It's called again from scripts/make.sh just to be sure.) -source scripts/portability.sh +. scripts/portability.sh mkdir -p "$GENDIR" @@ -16,9 +16,11 @@ # Symbol name is first argument, flags second, feed C file to stdin probesymbol() { - probecc "${@:2}" 2>/dev/null && DEFAULT=y || DEFAULT=n + symbol=$1 + shift + probecc "$@" 2>/dev/null && DEFAULT=y || DEFAULT=n rm a.out 2>/dev/null - echo -e "config $1\n\tbool\n\tdefault $DEFAULT\n" || exit 1 + printf 'config %s\n\tbool\n\tdefault %s\n\n' "$symbol" "$DEFAULT" || exit 1 } probeconfig() @@ -35,7 +37,7 @@ #include int main(int argc, char *argv[]) { return fork(); } EOF - echo -e '\tdepends on !TOYBOX_FORCE_NOMMU' + printf '\tdepends on !TOYBOX_FORCE_NOMMU\n' } genconfig() @@ -77,20 +79,22 @@ toys toys/*/*.c | ( while IFS=":" read FILE NAME do - echo -e "test_$NAME:\n\tscripts/test.sh $NAME\n" - [ "$NAME" == help ] && continue - [ "$NAME" == install ] && continue - [ "$NAME" == sh ] && FILE="toys/*/*.c" - echo -e "$NAME: $FILE *.[ch] lib/*.[ch]\n\tscripts/single.sh $NAME\n" - [ "${FILE/example//}" != "$FILE" ] && EXAMPLE="$EXAMPLE $NAME" || - [ "${FILE/pending//}" != "$FILE" ] && PENDING="$PENDING $NAME" || - WORKING="$WORKING $NAME" + printf 'test_%s:\n\tscripts/test.sh %s\n\n' "$NAME" "$NAME" + [ "$NAME" = help ] && continue + [ "$NAME" = install ] && continue + [ "$NAME" = sh ] && FILE="toys/*/*.c" + printf '%s: %s *.[ch] lib/*.[ch]\n\tscripts/single.sh %s\n\n' "$NAME" "$FILE" "$NAME" + case $FILE in + *example*) EXAMPLE="$EXAMPLE $NAME" ;; + *pending*) PENDING="$PENDING $NAME" ;; + *) WORKING="$WORKING $NAME" ;; + esac done && -echo -e "clean::\n\t@rm -f $WORKING $PENDING" && -echo -e "list:\n\t@echo $(echo $WORKING | tr ' ' '\n' | sort | xargs)" && -echo -e "list_example:\n\t@echo $(echo $EXAMPLE | tr ' ' '\n' | sort | xargs)"&& -echo -e "list_pending:\n\t@echo $(echo $PENDING | tr ' ' '\n' | sort | xargs)"&& -echo -e ".PHONY: $WORKING $PENDING" | $SED 's/ \([^ ]\)/ test_\1/g' +printf 'clean::\n\t@rm -f%s%s\n' "$WORKING" "$PENDING" && +printf 'list:\n\t@echo %s\n' "$(echo "$WORKING" | tr ' ' '\n' | sort | xargs)" && +printf 'list_example:\n\t@echo %s\n' "$(echo "$EXAMPLE" | tr ' ' '\n' | sort | xargs)" && +printf 'list_pending:\n\t@echo %s\n' "$(echo "$PENDING" | tr ' ' '\n' | sort | xargs)" && +printf '.PHONY:%s%s\n' "$WORKING" "$PENDING" | $SED 's/ \([^ ]\)/ test_\1/g' ) > .singlemake brun kconfig -h > "$GENDIR"/help.h || exit 1 --- a/scripts/make.sh +++ b/scripts/make.sh @@ -1,50 +1,16 @@ -#!/bin/bash +#!/bin/sh # Grab default values for $CFLAGS and such. -set -o pipefail -source scripts/portability.sh - -# Shell functions called by the build - -DASHN=-n -true & wait -n 2>/dev/null || { wait; unset DASHN; } -ratelimit() -{ - if [ "$#" -eq 0 ] - then - [ -z "$DASHN" ] && PIDS="$PIDS$! " - [ $((++COUNT)) -lt $CPUS ] && return 0 - fi - ((--COUNT)) - if [ -n "$DASHN" ] - then - wait -n - DONE=$(($DONE+$?)) - else - # MacOS uses an ancient version of bash which hasn't got "wait -n", and - # wait without arguments always returns 0 instead of process exit code. - # This keeps $CPUS less busy when jobs finish out of order. - wait ${PIDS%% *} - DONE=$(($DONE+$?)) - PIDS=${PIDS#* } - fi - - return $DONE -} - -# Respond to V= by echoing command lines as well as running them -do_loudly() -{ - { [ -n "$V" ] && echo "$@" || echo -n "$DOTPROG" ; } >&2 - "$@" -} +. scripts/portability.sh # Is anything under directory $2 newer than generated/$1 (or does it not exist)? isnewer() { - [ -e "$GENDIR/$1" ] && [ -z "$(find "${@:2}" -newer "$GENDIR/$1")" ] && + target=$1 + shift + [ -e "$GENDIR/$target" ] && [ -z "$(find "$@" -newer "$GENDIR/$target")" ] && return 1 - echo -n "${DIDNEWER:-$GENDIR/{}$1" + printf '%s' "${DIDNEWER:-$GENDIR/{}}$target" DIDNEWER=, } @@ -64,16 +30,18 @@ [ -z "$V" ] && X=/dev/null || X=/dev/stderr for i in util crypt m resolv selinux smack attr crypto z log iconv tls ssl do - do_loudly ${CROSS_COMPILE}${CC} $CFLAGS $LDFLAGS -xc - -l$i >>$X 2>&1 \ - -o /dev/null <<<"int main(int argc,char*argv[]){return 0;}" && - echo -l$i & + printf '%s\n' 'int main(int argc,char*argv[]){return 0;}' | + do_loudly ${CROSS_COMPILE}${CC} $CFLAGS $LDFLAGS -xc - -l$i >>$X 2>&1 \ + -o /dev/null && echo -l$i & done | sort | xargs ) # Actually resolve dangling dependencies in extra libraries when static linking -[ -n "$LIBRARIES" ] && [ "$LDFLAGS" != "${LDFLAGS/-static/}" ] && - LIBRARIES="-Wl,--start-group $LIBRARIES -Wl,--end-group" +[ -n "$LIBRARIES" ] && +case $LDFLAGS in + *-static*) LIBRARIES="-Wl,--start-group $LIBRARIES -Wl,--end-group" ;; +esac -[ -z "$VERSION" ] && [ -d ".git" ] && [ -n "$(which git 2>/dev/null)" ] && +[ -z "$VERSION" ] && [ -d ".git" ] && command -v git >/dev/null 2>&1 && VERSION="$(git describe --tags --abbrev=12 2>/dev/null)" # Set/record build environment information @@ -93,33 +61,42 @@ # Make sure rm -rf isn't gonna go funny B="$(readlink -f "$PWD")/" A="$(readlink -f "$GENDIR")" A="${A%/}"/ -[ "$A" == "${B::${#A}}" ] && - { echo "\$GENDIR=$GENDIR cannot include \$PWD=$PWD"; exit 1; } +case $B in + "$A"*) + echo "\$GENDIR=$GENDIR cannot include \$PWD=$PWD" + exit 1 + ;; +esac unset A B DOTPROG DIDNEWER # Force full rebuild if our compiler/linker options changed -cmp -s <(compflags | grep '#d') <(grep '%d' "$GENDIR"/build.sh 2>/dev/null) || - rm -rf "$GENDIR"/* # Keep symlink, delete contents +new_build=$(mktemp) +old_build=$(mktemp) +compflags | grep '#d' > "$new_build" +grep '#d' "$GENDIR"/build.sh 2>/dev/null > "$old_build" || : +cmp -s "$new_build" "$old_build" || rm -rf "$GENDIR"/* # Keep symlink, delete contents +rm -f "$new_build" "$old_build" mkdir -p "$UNSTRIPPED" "$(dirname $OUTNAME)" || exit 1 # Extract a list of toys/*/*.c files to compile from the data in $KCONFIG_CONFIG # (First command names, then filenames with relevant {NEW,OLD}TOY() macro.) -[ -n "$V" ] && echo -e "\nWhich C files to build..." +[ -n "$V" ] && printf '\nWhich C files to build...\n' TOYFILES="$($SED -n 's/^CONFIG_\([^=]*\)=.*/\1/p' "$KCONFIG_CONFIG" | xargs | tr ' ' '|')" TOYFILES="main.c $(egrep -l "^USE_($TOYFILES)[(]...TOY[(]" toys/*/*.c | xargs)" -if [ "${TOYFILES/pending//}" != "$TOYFILES" ] -then - echo -e "\n\033[1;31mwarning: using unfinished code from toys/pending\033[0m" -fi +case $TOYFILES in + *pending*) + printf '\n\033[1;31mwarning: using unfinished code from toys/pending\033[0m\n' + ;; +esac # Write build variables (and set them locally), then append build invocation. -compflags > "$GENDIR"/build.sh && source "$GENDIR/build.sh" && +compflags > "$GENDIR"/build.sh && . "$GENDIR"/build.sh && { - echo FILES=$'"\n'"$(fold -s <<<"$TOYFILES")"$'\n"' && + printf 'FILES="\n%s\n"\n' "$(printf '%s\n' "$TOYFILES" | fold -s)" && echo && - echo -e "\$BUILD lib/*.c \$FILES \$LINK -o $OUTNAME" + printf '%s\n' "\$BUILD lib/*.c \$FILES \$LINK -o $OUTNAME" } >> "$GENDIR"/build.sh && chmod +x "$GENDIR"/build.sh || exit 1 @@ -133,7 +110,7 @@ B="$(egrep "^CONFIG_($(echo "$A" | sed 's/=[yn]//' | xargs | tr ' ' '|'))=" "$KCONFIG_CONFIG" | $SED 's/^CONFIG_//' | sort)" A="$(echo "$A" | grep -v =n)" [ "$A" != "$B" ] && - { echo -e "\nWarning: Config.probed changed, run 'make oldconfig'" >&2; } + { printf "\nWarning: Config.probed changed, run 'make oldconfig'\n" >&2; } unset A B # Create a list of all the commands toybox can provide. @@ -171,7 +148,7 @@ echo "#define NEWTOY(aa,bb,cc) aa $I bb" echo '#define OLDTOY(...)' - if [ "$I" == A ] + if [ "$I" = A ] then cat "$GENDIR"/config.h else @@ -207,8 +184,8 @@ $TOYFILES)" echo "$STRUX" && echo "extern union global_union {" && - $SED -n 's/^struct \(.*\)_data .*/\1/;T;s/.*/\tstruct &_data &;/p' \ - <<<"$STRUX" && + printf '%s\n' "$STRUX" | \ + $SED -n 's/^struct \(.*\)_data .*/\1/;T;s/.*/\tstruct &_data &;/p' && echo "} this;" } > "$GENDIR"/globals.h || exit 1 @@ -220,8 +197,10 @@ for j in $i; do [ $X -eq 31 ] && LL=LL NAME="$HEAD$j" + VALUE="(1$LL<<$X)" printf "#define $NAME %*s%s\n#define _$NAME %*s%s\n" \ - $((32-${#NAME})) "" "$X" $((31-${#NAME})) "" "(1$LL<<$((X++)))" || exit 1 + $((32-${#NAME})) "" "$X" $((31-${#NAME})) "" "$VALUE" || exit 1 + X=$((X+1)) done done > "$GENDIR"/tags.h || exit 1 @@ -240,7 +219,7 @@ rm -f "$GENDIR"/zhelp.h fi -[ -z "$DIDNEWER" ] || echo } +[ -z "$DIDNEWER" ] || echo '}' [ -n "$NOBUILD" ] && exit 0 echo "Compile $OUTNAME" @@ -260,12 +239,16 @@ # build each generated/obj/*.o file in parallel -PENDING= LNKFILES= CLICK= DONE=0 COUNT=0 +LNKFILES= +CLICK= for i in lib/*.c click $TOYFILES do - [ "$i" == click ] && CLICK=1 && continue + [ "$i" = click ] && CLICK=1 && continue - X=${i/lib\//lib_} + X=$i + case $X in + lib/*) X=lib_${X#lib/} ;; + esac X=${X##*/} OUT="$GENDIR/obj/${X%%.c}.o" LNKFILES="$LNKFILES $OUT" @@ -274,19 +257,10 @@ [ "$OUT" -nt "$i" ] && [ -z "$CLICK" -o "$OUT" -nt "$KCONFIG_CONFIG" ] && continue - do_loudly $BUILD -c $i -o $OUT & - - ratelimit || break -done - -# wait for all background jobs, detecting errors -while [ "$COUNT" -gt 0 ] -do - ratelimit done + do_loudly $BUILD -c $i -o $OUT || exit 1 done -[ $DONE -ne 0 ] && exit 1 -UNSTRIPPED="$UNSTRIPPED/${OUTNAME/*\//}" +UNSTRIPPED="$UNSTRIPPED/${OUTNAME##*/}" do_loudly $BUILD $LNKFILES $LINK -o "$UNSTRIPPED" || exit 1 if [ -n "$NOSTRIP" ] || ! do_loudly ${CROSS_COMPILE}${STRIP} "$UNSTRIPPED" -o "$OUTNAME" --- a/scripts/install.sh +++ b/scripts/install.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # usage: PREFIX=/target/path scripts/install.sh [--options] @@ -12,29 +12,29 @@ # Grab default values for $CFLAGS and such (to build scripts/install.c) -source scripts/portability.sh +. scripts/portability.sh [ -z "$PREFIX" ] && PREFIX="$PWD/install" # Parse command line arguments. LONG_PATH="" -while [ ! -z "$1" ] +while [ -n "${1:-}" ] do # Create symlinks instead of hardlinks? - [ "$1" == "--symlink" ] && TYPE="-s" + [ "$1" = "--symlink" ] && TYPE="-s" # Uninstall? - [ "$1" == "--uninstall" ] && UNINSTALL=Uninstall + [ "$1" = "--uninstall" ] && UNINSTALL=Uninstall # Delete destination command if it exists? - [ "$1" == "--force" ] && FORCE="-f" + [ "$1" = "--force" ] && FORCE="-f" # Use {,usr}/{bin,sbin} paths instead of all files in one directory? - [ "$1" == "--long" ] && LONG_PATH="bin/" + [ "$1" = "--long" ] && LONG_PATH="bin/" # Symlink host toolchain binaries to destination to create cross compile $PATH - [ "$1" == "--airlock" ] && AIRLOCK=1 + [ "$1" = "--airlock" ] && AIRLOCK=1 shift done @@ -52,7 +52,7 @@ then mkdir -p "${PREFIX}/${LONG_PATH}" && rm -f "${PREFIX}/${LONG_PATH}/toybox" && - cp toybox"${TARGET:+-$TARGET}" ${PREFIX}/${LONG_PATH} || exit 1 + cp toybox"${TARGET:+-$TARGET}" "${PREFIX}/${LONG_PATH}/" || exit 1 else rm -f "${PREFIX}/${LONG_PATH}/toybox" 2>/dev/null fi @@ -107,7 +107,7 @@ # python and deciding to #include Python.h). # mkroot has patches to remove the need for "bc" and "gcc" -TOOLCHAIN="${TOOLCHAIN//,/ } as cc ld objdump bc gcc" +TOOLCHAIN="$(printf '%s' "${TOOLCHAIN:-}" | tr ',' ' ') as cc ld objdump bc gcc" # The following are commands toybox should provide, but doesn't yet. # For now symlink the host version. This list must go away by 1.0. @@ -134,7 +134,7 @@ ln -sf "$j" "$FALLBACK/$i" || exit 1 fi - X=$[$X+1] + X=$((X+1)) FALLBACK="$PREFIX/fallback-$X" done