#! /bin/bash -- # # build.sh -- compile StaticPython from sources # by pts@fazekas.hu at Wed Aug 11 16:49:32 CEST 2010 # Mac OS X support at Sat May 21 21:04:07 CEST 2011 # # Example invocation: ./build.sh # Example invocation: ./build.sh stackless # Example invocation: ./build.sh stacklessco # Example invocation: ./build.sh stacklessco usessl # Example invocation: ./build.sh python3.2 # Example invocation: ./build.sh stackless3.2 # Example invocation: ./build.sh stacklessxl3.2 # # This script has been tested on Ubuntu Hardy, should work on any Linux system. # # TODO(pts): Build linux libs from source as well. # TODO(pts): Run on FreeBSD in Linux. Does epoll in libevent mode? How to avoid it? # # To facilitate exit on error, # # (true; false; true; false) # # has to be changed to # # (true && false && true && false) || return "$?" # in bash-3.1.17 # (true && false && true && false) # in busybox sh # # for Mac OS X: # # TODO(pts): Add openssl-based AES encryption module (does it support XTS): https://wiki.openssl.org/index.php/EVP_Symmetric_Encryption_and_Decryption # ... or does alo-aes support XTS? # TODO(pts): Make binaries identical upon recompilation. # TODO(pts): Implement stacklessco. # TODO(pts): Configure -lz --> pyconfig.h HAVE_ZLIB_COPY=1 # TODO(pts): Verify `import sysconfig' on both Linux and Mac OS X. # TODO(pts): Get rid of -ldl. # TODO(pts): Get rid of -framework CoreFoundation. # TODO(pts): Use libintl.a, but without libiconv.a (too large, 1MB). # TODO(pts): Add -mtune=cpu-type and -march=cpu-type (with SSE). # TODO(pts): Test if hard switching works on both Linux and the Mac. # --enable-stacklessfewerregisters . # TODO(pts): Make zipimport keep the .zip file open. (it closes it in Python # 3.2.) if true { # Make the shell script editable while it's executing. test $(0%/*) != $0 && cd $(0%/*) setglobal UNAME = $[./busybox uname 2>/dev/null || uname || true] # To provide a uniform build environment unset PYTHONPATH PYTHONSTARTUP PYTHONHOME PYTHONCASEOK PYTHONIOENCODING if test $NO_BUSYBOX || test $UNAME = Darwin { # Darwin is Mac OS X setglobal BUSYBOX = '' setglobal PATCH = ''patch -t'' # -t to disable prompts. } elif test $BASH_VERSION || test -z $STATICPYTHON_IN_BUSYBOX { unset BASH_VERSION export STATICPYTHON_IN_BUSYBOX=1 exec ./busybox sh -- $0 @ARGV } else { setglobal BUSYBOX = './busybox' # Make sure we fail unless we use ./busybox for all non-built-in commands. export PATH=/dev/null set -e # Abort on error. test -d busybox.bin || ./busybox mkdir busybox.bin for F in [cp mv rm sleep touch mkdir tar expr sed awk ls pwd test cmp diff \ patch xz \ sort cat head tail chmod chown uname basename tr find grep ln] { ./busybox rm -f busybox.bin/"$F" ./busybox ln -s ../busybox busybox.bin/"$F" } setglobal PATCH = 'patch' # `busybox patch' doesn't have -t, but it disables prompts by default. ./busybox rm -f busybox.bin/make; ./busybox ln -s ../make busybox.bin/make ./busybox rm -f busybox.bin/perl; ./busybox ln -s ../perl busybox.bin/perl export PATH="$PWD/busybox.bin" export SHELL="$PWD/busybox.bin/sh" } set -e # Abort on error. # --- setglobal INSTS_BASE = '"bzip2-1.0.5.inst.tbz2 ncurses-5.6.inst.tbz2 readline-5.2.inst.tbz2 sqlite-3.7.0.1.inst.tbz2 zlib-1.2.3.3.inst.tbz2'" setglobal STEPS = '' setglobal USE_SSL = '' setglobal USE_TC = '' setglobal USE_LMDB = '' setglobal TARGET = 'python2.7-static' setglobal PYTHONTBZ2 = 'Python-2.7.12.tar.xz' setglobal IS_CO = '' setglobal IS_PY3 = '' for ARG in [@ARGV] { setglobal ARG = $(ARG%-static) # E.g. convert python2.7-static to python2.7 if test $ARG = stackless || test $ARG = stackless2.7 { setglobal TARGET = 'stackless2.7-static' setglobal PYTHONTBZ2 = 'stackless-2712-export.tar.xz' setglobal IS_CO = '' setglobal IS_XX = '' setglobal IS_PY3 = '' setglobal USE_SSL = '' } elif test $ARG = stacklessco || test $ARG = stacklessco2.7 { setglobal TARGET = 'stacklessco2.7-static' setglobal PYTHONTBZ2 = 'stackless-2712-export.tar.xz' setglobal IS_CO = '1' setglobal IS_XX = '' setglobal ISP_PY3 = '' setglobal USE_SSL = '1' } elif test $ARG = stacklessxx || test $ARG = stacklessxx2.7 { setglobal TARGET = 'stacklessxx2.7-static' setglobal PYTHONTBZ2 = 'stackless-2712-export.tar.xz' setglobal IS_CO = '1' setglobal IS_XX = '1' # IS_CO=1 must also be set. setglobal ISP_PY3 = '' setglobal USE_SSL = '1' setglobal USE_TC = '1' setglobal USE_LMDB = '1' } elif test $ARG = python || test $ARG = python2.7 { setglobal TARGET = 'python2.7-static' setglobal PYTHONTBZ2 = 'Python-2.7.12.tar.xz' setglobal IS_CO = '' setglobal IS_XX = '' setglobal IS_PY3 = '' setglobal USE_SSL = '' } elif test $ARG = python3.2 { setglobal TARGET = 'python3.2-static' setglobal PYTHONTBZ2 = 'Python-3.2.tar.bz2' setglobal IS_CO = '' setglobal IS_XX = '' setglobal IS_PY3 = '1' setglobal USE_SSL = '' } elif test $ARG = stackless3.2 { setglobal TARGET = 'stackless3.2-static' setglobal PYTHONTBZ2 = 'stackless-32-export.tar.bz2' setglobal IS_CO = '' setglobal IS_XX = '' setglobal IS_PY3 = '1' setglobal USE_SSL = '' } elif test $ARG = stacklessxl3.2 { setglobal TARGET = 'stacklessxl3.2-static' setglobal PYTHONTBZ2 = 'stackless-32-export.tar.bz2' setglobal IS_CO = '' setglobal IS_XX = '' setglobal IS_PY3 = '1' setglobal USE_SSL = '1' } elif test $ARG = usessl { setglobal USE_SSL = '1' } elif test $ARG = nossl { setglobal USE_SSL = '' } else { setglobal STEPS = ""$STEPS $ARG"" } } if test -z $STEPS { # Don't include betry here. # Please note that fixsetup appears multiple times here. This is intentional, # to get Modules/Setup right. setglobal STEPS = '"initbuilddir initdeps buildlibssl buildlibevent2 buildlibtc configure fixsemaphore patchsetup fixsetup patchimport patchgetpath patchsqlite patchssl patchlocale fixsetup makeminipython extractpyrex patchsyncless patchgevent patchgeventmysql patchmsgpack patchpythontokyocabinet patchpythonlmdb patchconcurrence patchpycrypto patchaloaes fixsetup makepython buildpythonlibzip buildtarget'" } setglobal INSTS = $INSTS_BASE setglobal BUILDDIR = ""$TARGET.build"" setglobal PBUILDDIR = ""$PWD/$BUILDDIR"" # GNU Autoconf's ./configure uses $CC, $LD, $AR, $LDFLAGS and $RANLIB to # generate the Makefile. if test $UNAME = Darwin { # -march=i386 wouldn't work, it would disable SSE. So we use -m32. export CC="gcc-mp-4.4 -m32 -static-libgcc -I$PBUILDDIR/build-include" export AR=ar export RANLIB=ranlib export LD=ld export LDFLAGS="-L$PBUILDDIR/build-lib" export STRIP=strip } else { export CC="$PBUILDDIR/cross-compiler-i686/bin/i686-gcc -static -fno-stack-protector" export AR="$PBUILDDIR/cross-compiler-i686/bin/i686-ar" export RANLIB="$PBUILDDIR/cross-compiler-i686/bin/i686-ranlib" export LD="$PBUILDDIR/cross-compiler-i686/bin/i686-ld" # The ./configure script of libevent2 fails without $LD being set. export LDFLAGS="" export STRIP="$PBUILDDIR/cross-compiler-i686/bin/i686-strip -s" } echo "Running in directory: $PWD" echo "Building target: $TARGET" echo "Building in directory: $BUILDDIR" echo "Using Python source distribution: $PYTHONTBZ2" echo "Will run steps: $STEPS" echo "Is adding coroutine libraries: $IS_CO" echo "Is using OpenSSL for SSL functionality: $USE_SSL" echo "Is using Tokyo Cabinet database: $USE_TC" echo "Is using LMDB (database): $USE_LMDB" echo "Operating system UNAME: $UNAME" echo proc initbuilddir { rm -rf $BUILDDIR || return "$?" mkdir $BUILDDIR || return "$?" if test $UNAME = Linux || test $UNAME = Darwin { : } else { set +x echo "fatal: unsupported operating system: $UNAME" >&2 return 2 } if test $UNAME = Darwin { mkdir "$BUILDDIR/build-include" || return "$?" mkdir "$BUILDDIR/build-lib" || return "$?" } else { shell { cd $BUILDDIR || return "$?" mkdir cross-compiler-i686 || return "$?" cd cross-compiler-i686 || return "$?" tar xjvf ../../gcxbase.inst.tbz2 || return "$?" tar xjvf ../../gcc.inst.tbz2 || return "$?" tar xjvf ../../gcxtool.inst.tbz2 || return "$?" } || return "$?" } # Set up a fake config.guess for operating system and architecture detection. # # This is to make sure that we have i686 even on an x86_64 host for Linux. if test $UNAME = Darwin { shell {echo '#!/bin/sh'; echo 'echo i386-apple-darwin9.8.0'} >"$BUILDDIR/config.guess.fake" || return "$?" } else { shell {echo '#!/bin/sh'; echo 'echo i686-pc-linux-gnu'} >"$BUILDDIR/config.guess.fake" || return "$?" } chmod +x "$BUILDDIR/config.guess.fake" || return "$?" # Check the C compiler. shell {echo '#include ' echo 'main() { return!printf("Hello, World!\n"); }' } >"$BUILDDIR/hello.c" || return "$?" if ! $CC -o "$BUILDDIR/hello" "$BUILDDIR/hello.c" { set +x echo "fatal: the C compiler doesn't work" >&2 if test $UNAME = Darwin { echo "info: did you install MacPorts and run: sudo port install gcc44" >&2 } exit 2 } $STRIP "$BUILDDIR/hello" || return "$?" local OUT="$["$BUILDDIR/hello]" test "$Status" = 0 test $OUT = "Hello, World!" shell { cd $BUILDDIR || return "$?" if test $(PYTHONTBZ2%.xz) != $(PYTHONTBZ2) { xz -d <../"$PYTHONTBZ2" | tar xv || return "$?" } else { tar xjvf ../"$PYTHONTBZ2" || return "$?" } } || return "$?" shell { cd $BUILDDIR || return "$?" if test -d Python-* { mv Python-*/* . || return "$?" } elif test -d python-* { mv python-*/* . || return "$?" } elif test -d stackless-* { mv stackless-*/* . || return "$?" } # Disabling this build rule is needed for python-2.7.12. perl -pi~ -e 's@^(Parser/pgenmain[.]o:)@disabled_$1@' Makefile.pre.in || return "$?" } || return "$?" shell { cd "$BUILDDIR/Modules" || return "$?" tar xzvf ../../greenlet-0.3.1.tar.gz || return "$?" if test $IS_PY3 { # TODO(pts): Copy patch(1) this to the Mac OS X chroot. $PATCH -p0 <../../greenlet-0.3.1-pycapsule.patch || return "$?" } } || return "$?" shell { cd $BUILDDIR || return "$?" mkdir -p advzip || return "$?" cd advzip || return "$?" if test $UNAME = Darwin { tar xjvf ../../advzip.darwin.inst.tbz2 || return "$?" } else { tar xjvf ../../advzip.inst.tbz2 || return "$?" } } || return "$?" cp -f "$BUILDDIR/config.guess.fake" "$BUILDDIR/config.guess" } proc initdeps { if test $UNAME = Darwin { # Mac OS X builddeps || return "$?" } else { # Linux extractinsts || return "$?" } # These are moved to $STEPS: #buildlibssl # Needs libz if enabled. #buildlibevent2 # Needs libssl if enabled. #buildlibtc # Needs libz and libbz2 if enabled. } proc builddeps { # The `|| return "$?"' clauses are needed by bash 3.2.17 on Mac OS X. # This is an alternative to extractinsts buildlibz || return "$?" buildlibbz2 || return "$?" buildlibreadline || return "$?" buildlibsqlite3 || return "$?" buildlibevent2 || return "$?" } proc buildlibbz2 { shell { cd $BUILDDIR || return "$?" rm -rf bzip2-1.0.6 || return "$?" tar xzvf ../bzip2-1.0.6.tar.gz || return "$?" cd bzip2-1.0.6 || return "$?" perl -pi~ -e 's@\s-g(?!\S)@@g, s@\s-O\d*(?!\S)@ -O3@g if s@^CFLAGS\s*=@CFLAGS = @' Makefile || return "$?" make CC="$CC" || return "$?" cp libbz2.a ../build-lib/libbz2-staticpython.a || return "$?" cp bzlib.h ../build-include/ || return "$?" } || return "$?" } proc buildlibtc { test $USE_TC || return 0 shell { cd $BUILDDIR || return "$?" rm -rf tokyocabinet-1.4.47 || return "$?" tar xzvf ../tokyocabinet-1.4.47.tar.gz || return "$?" cd tokyocabinet-1.4.47 || return "$?" #if test "$UNAME" = Darwin; then # : No support for xx on Darwin. # See below. # return 1 #fi # TODO(pts): Add -staticpython for libz and libbz2 on Darwin: # LIBS="-lbz2 $LIBS" # LIBS="-lz $LIBS" if test $UNAME = Darwin { # The configure script doesn't seem to care much. # This seems to work even on Linux. perl -pi~ -e 's@^ *(LIBS="-l(?:z|bz2))@$1-staticpython @' configure || return "$?" } # TODO(pts): Check perl -pi~ -e 's@nanl\([^()]*\)@NAN@g' *.c || return "$?" # There is no nanl(...) function in uClibc. ./configure --prefix=/dev/null/missing --disable-shared || return "$?" perl -pi~ -e 's@\s-g(?!\S)@@g, s@\s-O\d*(?!\S)@ -O2@g if s@^CFLAGS\s*=@CFLAGS = @; s@ -I\S+@ @g, s@=@= -I.@ if s@^CPPFLAGS\s*=\s*@CPPFLAGS = @' Makefile || return "$?" make libtokyocabinet.a || return "$?" $RANLIB libtokyocabinet.a || return "$?" cp libtokyocabinet.a ../build-lib/libtokyocabinet-staticpython.a || return "$?" # tcadb.h tcbdb.h tcfdb.h tchdb.h tctdb.h tcutil.h # Don't copy: md5.h myconf.h cp tc*.h ../build-include/ || return "$?" } || return "$?" } proc buildlibreadline { shell { cd $BUILDDIR || return "$?" rm -rf readline-5.2 || return "$?" tar xzvf ../readline-5.2.tar.gz || return "$?" cd readline-5.2 || return "$?" ./configure --disable-shared || return "$?" perl -pi~ -e 's@\s-g(?!\S)@@g, s@\s-O\d*(?!\S)@ -O2@g if s@^CFLAGS\s*=@CFLAGS = @' Makefile || return "$?" make || return "$?" # We could copy history.a, but Python doesn't need it. cp libreadline.a ../build-lib/libreadline-staticpython.a || return "$?" rm -rf ../build-include/readline || return "$?" mkdir ../build-include/readline || return "$?" cp rlstdc.h rltypedefs.h keymaps.h tilde.h readline.h history.h chardefs.h ../build-include/readline/ || return "$?" } || return "$?" } proc buildlibsqlite3 { shell { cd $BUILDDIR || return "$?" rm -rf sqlite-amalgamation-3070603 || return "$?" unzip ../sqlite-amalgamation-3070603.zip || return "$?" cd sqlite-amalgamation-3070603 || return "$?" $CC -c -O2 -DSQLITE_ENABLE_STAT2 -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE -W -Wall sqlite3.c || return "$?" $AR cr libsqlite3.a sqlite3.o || return "$?" $RANLIB libsqlite3.a || return "$?" cp libsqlite3.a ../build-lib/libsqlite3-staticpython.a || return "$?" cp sqlite3.h ../build-include/ || return "$?" } || return "$?" } proc buildlibz { shell { cd $BUILDDIR || return "$?" rm -rf zlib-1.2.5 || return "$?" tar xjvf ../zlib-1.2.5.tar.bz2 || return "$?" cd zlib-1.2.5 || return "$?" ./configure --static || return "$?" perl -pi~ -e 's@\s-g(?!\S)@@g, s@\s-O\d*(?!\S)@ -O3@g if s@^CFLAGS\s*=@CFLAGS = @' Makefile || return "$?" make || return "$?" cp libz.a ../build-lib/libz-staticpython.a || return "$?" cp zconf.h zlib.h ../build-include/ || return "$?" } || return "$?" } proc buildlibssl { test $USE_SSL || return 0 shell { cd $BUILDDIR || return "$?" rm -rf openssl-0.9.8zh.tar.gz || return "$?" tar xzvf ../openssl-0.9.8zh.tar.gz || return "$?" cd openssl-0.9.8zh || return "$?" if test $UNAME = Linux { ./Configure no-shared linux-elf no-dso || return "$?" } else { # This inserts `-arch i386', which we remove below. ./Configure no-shared darwin-i386-cc || return "$?" # TODO(pts): Test this. } # Doing -O3 instead of -O2 would increase the binary size by about 67 KiB # for openssl-0.9.8zh.tar.gz , and it would speed up hashlib.pbkdf2_hmac # by about 1.5% (most of the hash computation is already in assembly). Not # doing it. perl -pi~ -e 's@\s(?:-g|-arch\s+\S+)(?!\S)@@g, s@\s-O\d*(?!\S)@ -O2@g, s@\s-D(DSO_DLFCN|HAVE_DLFCN_H)(?!\S)@@g if s@^CFLAG\s*=\s*@CFLAG = @' Makefile || return "$?" # Workaround for our perl not supporting -I... and PERLINC=... ln -s . crypto/des/asm/perlasm || return "$?" make build_libs || return "$?" cp libssl.a ../build-lib/libssl-staticpython.a || return "$?" cp libcrypto.a ../build-lib/libcrypto-staticpython.a || return "$?" mkdir ../build-include/openssl || return "$?" cp include/openssl/*.h ../build-include/openssl/ || return "$?" } || return "$?" } proc buildlibevent2 { test $IS_CO || return 0 shell { cd $BUILDDIR || return "$?" rm -rf libevent-2.0.16-stable || return "$?" rm -rf build-include/event2 || return "$?" rm -rf build-lib/libevent* || return "$?" tar xzvf ../libevent-2.0.16-stable.tar.gz || return "$?" cd libevent-2.0.16-stable || return "$?" local SSL_FLAGS=--disable-openssl if test $USE_SSL { setglobal SSL_FLAGS = '--enable-openssl' perl -pi~ -e 's@^for ac_lib in \x27\x27 ssl;@for ac_lib in \x27\x27 \x27ssl-staticpython -lcrypto-staticpython\x27;@; s@ -lcrypto(?= )@ -lcrypto-staticpython@g' configure || return "$?" } ./configure $SSL_FLAGS --disable-debug-mode --disable-shared --disable-libevent-regress || return "$?" if test $USE_SSL { grep '^#define HAVE_OPENSSL 1$' config.h || return "$?" } cp -f ../config.guess.fake config.guess perl -pi~ -e 's@\s-g(?!\S)@@g, s@\s-O\d*(?!\S)@ -O2@g if s@^CFLAGS\s*=@CFLAGS = @' Makefile */Makefile || return "$?" make ./include/event2/event-config.h libevent_core.la libevent.la || return "$?" $AR cr libevent_evhttp.a bufferevent_sock.o http.o listener.o || return "$?" $RANLIB libevent_evhttp.a || return "$?" cp .libs/libevent_core.a ../build-lib/libevent_core-staticpython.a || return "$?" cp libevent_evhttp.a ../build-lib/libevent_evhttp-staticpython.a || return "$?" mkdir ../build-include/event2 || return "$?" cp include/event2/*.h ../build-include/event2/ || return "$?" } || return "$?" } proc extractinsts { for INSTTBZ2 in [$INSTS] { shell { cd "$BUILDDIR/cross-compiler-i686" || return "$?" tar xjvf ../../"$INSTTBZ2" || return "$?" } || return "$?" } # These symlinks are needed for the build commands below on Linux. if test $UNAME = Linux { ln -s cross-compiler-i686/lib "$BUILDDIR/build-lib" ln -s cross-compiler-i686/include "$BUILDDIR/build-include" } } proc configure { shell { cd $BUILDDIR || return "$?" # TODO(pts): Make sure x86 is detected (not x86_64). # This removal makes Python-ast.c not autogenerated. Autogeneration would # need a working Python binary, which we don't have yet. perl -pi -e '$_="" if /ASDLGEN/' Makefile.pre.in local REGSFLAGS= # Without --enable-stacklessfewerregisters, we'd get the error: # ./Stackless/platf/switch_x86_unix.h:37: error: PIC register 'ebx' clobbered in 'asm' test $UNAME = Darwin && setglobal REGSFLAGS = '--enable-stacklessfewerregisters' ./configure --disable-shared --disable-ipv6 $REGSFLAGS || return "$?" } || return "$?" fixmakefile } proc fixsemaphore { shell { cd $BUILDDIR || return "$?" if test $UNAME = Linux { # The ./configure script doesn't detect proper semaphores on Linux uClibc. # # It does detect on Darwin. perl -pi -e 's@^#define POSIX_SEMAPHORES_NOT_ENABLED 1$@/* #undef POSIX_SEMAPHORES_NOT_ENABLED */@' \ pyconfig.h || return "$?" } } || return "$?" } proc fixmakefile { shell { cd $BUILDDIR || return "$?" # `-framework CoreFoundation' is good to be removed on the Mac OS X, to # prevent additional .dylib dependencies on # /System//Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation # . perl -pi~ -e 's@\s-(?:ldl|framework\s+CoreFoundation)(?!\S)@@g if s@^LIBS\s*=@LIBS = @' Makefile || return "$?" # Remove -O... and -g from CFLAGS and OPT, and add -O2 to OPT. Please note # that Python 3.2 doesn't have CFLAGS at all. perl -pi~ -e 's@\s-(?:g|O\d*)(?!\S)@@g, s@$@ -O2@ if s@^OPT\s*=@OPT = @' Makefile || return "$?" perl -pi~ -e 's@\s-(?:g|O\d*)(?!\S)@@g, s@$@ -O2@ if s@^SLPFLAGS\s*=@SLPFLAGS = @' Makefile || return "$?" perl -pi~ -e 's@\s-g(?!\S)@@g, s@\s-O\d*(?!\S)@@g if s@^CFLAGS\s*=@CFLAGS = @' Makefile || return "$?" if test $IS_PY3 { if ! grep '@SLPFLAGS@' Makefile { : } elif test $UNAME = Darwin { # Fix for Stackless 3.2. # TODO(pts): Run all Stackless test to verify this. perl -pi~ -e 's~\@SLPFLAGS\@~-fomit-frame-pointer -DSTACKLESS_FRHACK=1 -O2~g' Makefile || return "$?" } else { perl -pi~ -e 's~\@SLPFLAGS\@~-fno-omit-frame-pointer -O2~g' Makefile || return "$?" } } } || return "$?" } proc patchsetup { # This must be run after the configure step, because configure overwrites # Modules/Setup if test $IS_PY3 { cp Modules.Setup.3.2.static "$BUILDDIR/Modules/Setup" || return "$?" } else { cp Modules.Setup.2.7.static "$BUILDDIR/Modules/Setup" || return "$?" } # Please note that fixsetup has to be called now, partially because of # fixing the Makefile. } proc fixsetup { if test $UNAME = Darwin { # * /usr/lib/libncurses.5.dylib # * _locale is disabled because -lintl needs -liconv, which is too large # (1MB) # * spwd is disabled because the Mac OS X doesn't contain # /usr/include/shadow.h . # * -lcrypt and -lm are not necessary in the Mac OS X, everything is in # the libc. # * -lz, -lsqlite3, -lreadline and -lbz2 have to be converted to # -l...-staticpython so that out lib*-staticpython.a would be selected. perl -pi~ -e ' s@\s-lncurses\S*@ -lncurses.5@g; s@^(?:_locale|spwd)(?!\S)@#@; s@\s-(?:lcrypt|lm)(?!\S)@@g; s@\s-(lz|lsqlite3|lreadline|lbz2)(?!\S)@ -$1-staticpython@g; ' "$BUILDDIR/Modules/Setup" || return "$?" } perl -pi~ -e 's@\s-(levent_core|levent_evhttp)(?!\S)@ -$1-staticpython@g' "$BUILDDIR/Modules/Setup" || return "$?" sleep 2 || return "$?" # Wait 2 seconds after the configure script creating Makefile. touch "$BUILDDIR/Modules/Setup" || return "$?" # We need to run `make Makefile' to rebuild it using our Modules/Setup shell { cd $BUILDDIR || return "$?" make Makefile || return "$?" } || return "$?" fixmakefile if test $IS_PY3 { shell { cd $BUILDDIR || return "$?" grep '^_thread ' Modules/Setup.config || return "$?" grep 'signal' Modules/Setup.config || return "$?" } || return "$?" } } proc patchimport { # This patch is idempotent. perl -pi~ -e 's@#ifdef HAVE_DYNAMIC_LOADING(?!_NOT)@#ifdef HAVE_DYNAMIC_LOADING_NOT /* StaticPython */@g' "$BUILDDIR"/Python/import.c "$BUILDDIR"/Python/importdl.c || return "$?" } proc patchgetpath { # This patch is idempotent. # TODO(pts): Make sure that the source string is there for patching. # TODO(pts): Make this repatch if calculate_path.*.c is modified. perl -pi~ -0777 -e 's@\s+static\s+void\s+calculate_path(?! )\s*\(\s*void\s*\)\s*{@\n\nstatic void calculate_path(void); /* StaticPython */\nstatic void calculate_path_not(void) {@g' "$BUILDDIR"/Modules/getpath.c || return "$?" if ! grep -q StaticPython-appended "$BUILDDIR/Modules/getpath.c" { if test $IS_PY3 { cat calculate_path.3.2.c >>"$BUILDDIR/Modules/getpath.c" || return "$?" } else { cat calculate_path.2.7.c >>"$BUILDDIR/Modules/getpath.c" || return "$?" } } } proc patchsqlite { # This patch is idempotent. if ! grep '^#define MODULE_NAME ' "$BUILDDIR/Modules/_sqlite/util.h" { perl -pi~ -0777 -e 's@\n#define PYSQLITE_UTIL_H\n@\n#define PYSQLITE_UTIL_H\n#define MODULE_NAME "_sqlite3" /* StaticPython */\n@' "$BUILDDIR/Modules/_sqlite/util.h" || return "$?" } for F in ["$BUILDDIR/Modules/_sqlite/"*.c] { if ! grep -q '^#include "util.h"' $F { perl -pi~ -0777 -e 's@\A@#include "util.h" /* StaticPython */\n@' $F || return "$?" } } } proc generate_loader_py { local CEXT_MODNAME="$1" local PY_MODNAME="$2" local PY_FILENAME="Lib/$(PY_MODNAME//.//).py" : Generating loader $PY_FILENAME echo "import sys; import $CEXT_MODNAME; sys.modules[__name__] = $CEXT_MODNAME" >"$PY_FILENAME" || return "$?" } proc patch_and_copy_cext { local SOURCE_C="$1" local TARGET_C="$2" local CEXT_MODNAME="$(TARGET_C%.c)" export CEXT_MODNAME="$(CEXT_MODNAME##*/)" export CEXT_MODNAME="$(CEXT_MODNAME//._/_)" export CEXT_MODNAME="$(CEXT_MODNAME//./_)" export CEXT_MODNAME=_"$(CEXT_MODNAME#_)" : Copying and patching $SOURCE_C to "$TARGET_C", CEXT_MODNAME="$CEXT_MODNAME" <"$SOURCE_C" >"$TARGET_C" perl -0777 -pe ' s@^(PyMODINIT_FUNC)\s+\w+\(@$1 init$ENV{CEXT_MODNAME}(@mg; s@( Py_InitModule\d*)\(\s*"\w[\w.]*",@$1("$ENV{CEXT_MODNAME}",@g; # Cython version of the one below. s@( Py_InitModule\d*\(\s*__Pyx_NAMESTR\()"\w[\w.]*"\),@$1"$ENV{CEXT_MODNAME}"),@g; # For PyCrypto. s@^[ \t]*(#[ \t]*define\s+MODULE_NAME\s+\S+)@#define MODULE_NAME $ENV{CEXT_MODNAME}@mg; s@^[ \t]*(#[ \t]*define\s+MODULE_NAME\s+\S+.*triple DES.*)@#define MODULE_NAME _Crypto_Cipher_DES3@mg; ' || return "$?" } proc enable_module { local CEXT_MODNAME="$1" export CEXT_MODNAME : Enabling module: $CEXT_MODNAME grep -qE "^#?$CEXT_MODNAME " Modules/Setup || return "$?" perl -0777 -pi -e 's@^#$ENV{CEXT_MODNAME} @$ENV{CEXT_MODNAME} @mg' Modules/Setup || return "$?" } proc patchssl { test $USE_SSL || return 0 shell { cd $BUILDDIR || return "$?" enable_module _ssl || return "$?" enable_module _hashlib || return "$?" } || return "$?" } proc patchsyncless { test $IS_CO || return 0 shell { cd $BUILDDIR || return "$?" rm -rf syncless-* syncless.dir Lib/syncless Modules/syncless || return "$?" tar xzvf ../syncless-0.25.tar.gz || return "$?" mv syncless-0.25 syncless.dir || return "$?" mkdir Lib/syncless Modules/syncless || return "$?" cp syncless.dir/syncless/*.py Lib/syncless/ || return "$?" generate_loader_py _syncless_coio syncless.coio || return "$?" patch_and_copy_cext syncless.dir/coio_src/coio.c Modules/syncless/_syncless_coio.c || return "$?" cp syncless.dir/coio_src/coio_minihdns.c \ syncless.dir/coio_src/coio_minihdns.h \ syncless.dir/coio_src/coio_c_*.h \ Modules/syncless/ || return "$?" enable_module _syncless_coio || return "$?" } || return "$?" } proc patchgevent { test $IS_CO || return 0 shell { cd $BUILDDIR || return "$?" rm -rf gevent-* gevent.dir Lib/gevent Modules/gevent || return "$?" tar xzvf ../gevent-0.13.6.tar.gz || return "$?" mv gevent-0.13.6 gevent.dir || return "$?" mkdir Lib/gevent Modules/gevent || return "$?" cp gevent.dir/gevent/*.py Lib/gevent/ || return "$?" rm -f gevent.dir/gevent/win32util.py || return "$?" generate_loader_py _gevent_core gevent.core || return "$?" patch_and_copy_cext gevent.dir/gevent/core.c Modules/gevent/_gevent_core.c || return "$?" cat >Modules/gevent/libevent.h <<'END' || return "$?" /**** pts ****/ #include "sys/queue.h" #define LIBEVENT_HTTP_MODERN #include "event2/event.h" #include "event2/event_struct.h" #include "event2/event_compat.h" #include "event2/http.h" #include "event2/http_compat.h" #include "event2/http_struct.h" #include "event2/buffer.h" #include "event2/buffer_compat.h" #include "event2/dns.h" #include "event2/dns_compat.h" #define EVBUFFER_DRAIN evbuffer_drain #define EVHTTP_SET_CB evhttp_set_cb #define EVBUFFER_PULLUP(BUF, SIZE) evbuffer_pullup(BUF, SIZE) #define current_base event_global_current_base_ #define TAILQ_GET_NEXT(X) TAILQ_NEXT((X), next) extern void *current_base; END enable_module _gevent_core || return "$?" } || return "$?" } proc patchgeventmysql { test $IS_CO || return 0 shell { cd $BUILDDIR || return "$?" rm -rf geventmysql-* geventmysql.dir Lib/geventmysql Modules/geventmysql || return "$?" tar xjvf ../geventmysql-20110201.tbz2 || return "$?" mv gevent-MySQL geventmysql.dir || return "$?" mkdir Lib/geventmysql Modules/geventmysql || return "$?" cp geventmysql.dir/lib/geventmysql/*.py Lib/geventmysql/ || return "$?" generate_loader_py _geventmysql_mysql geventmysql._mysql || return "$?" patch_and_copy_cext geventmysql.dir/lib/geventmysql/geventmysql._mysql.c Modules/geventmysql/geventmysql._mysql.c || return "$?" enable_module _geventmysql_mysql || return "$?" } || return "$?" } proc run_pyrexc { env PYTHONPATH="$PBUILDDIR/Lib:$PWD/pyrex.dir" "$PBUILDDIR"/minipython -S -W ignore::DeprecationWarning -c "from Pyrex.Compiler.Main import main; main(command_line=1)" @ARGV || return "$?" } #** Equivalent to zip -9r "$@" #** Usage: run_mkzip filename.zip file_or_dir ... proc run_mkzip { # advzip produces smaller files than `zip -9r', because advzip uses the # 7-Zip implementation of zip. rm -f $1 || return "$?" # The .zip file. "$PBUILDDIR/advzip/bin/advzip" -a -4 @ARGV || return "$?" } # Like run_mkzip, but uses Python instead of advzip. proc old_run_mkzip { local PYTHON="$PBUILDDIR"/python.exe test -f "$PBUILDDIR"/minipython && setglobal PYTHON = ""$PBUILDDIR"/minipython" # python.exe is for the Mac OS X (case insensitive, vs Python/) env PYTHONPATH="$PBUILDDIR/Lib" $PYTHON -S -c 'if 1: import os import os.path import stat import sys import zipfile def All(filename): s = os.lstat(filename) assert not stat.S_ISLNK(s.st_mode), filename if stat.S_ISDIR(s.st_mode): for entry in os.listdir(filename): for filename2 in All(os.path.join(filename, entry)): yield filename2 else: yield filename zip_filename = sys.argv[1] zipfile.zlib.Z_DEFAULT_COMPRESSION = 9 # Maximum effort. z = zipfile.ZipFile(zip_filename, "w", compression=zipfile.ZIP_DEFLATED) for filename in sys.argv[2:]: for filename2 in All(filename): z.write(filename2) z.close()' @ARGV || return "$?" } proc patchpythontokyocabinet { test $USE_TC || return 0 shell { cd $BUILDDIR || return "$?" rm -rf python-tokyocabinet-* tokyocabinet.dir Lib/tokyocabinet Modules/tokyocabinet || return "$?" tar xjvf ../python-tokyocabinet-20111221.tar.bz2 || return "$?" mv python-tokyocabinet-20111221 tokyocabinet.dir || return "$?" mkdir Lib/tokyocabinet Modules/tokyocabinet || return "$?" #cp tokyocabinet.dir/tokyocabinet/hash.c ../hash.c.orig shell {cd tokyocabinet.dir/tokyocabinet && $PATCH -p0 <../../../tokyocabinet_hash_c.patch} || return "$?" # This is just an empty __init__.py. cp tokyocabinet.dir/tokyocabinet/*.py Lib/tokyocabinet/ || return "$?" local M for M in [btree hash table] { patch_and_copy_cext tokyocabinet.dir/tokyocabinet/$M.c Modules/tokyocabinet/_tokyocabinet_$M.c || return "$?" generate_loader_py _tokyocabinet_$M tokyocabinet.$M || return "$?" enable_module _tokyocabinet_$M || return "$?" } } || return "$?" } proc patchpythonlmdb { test $USE_LMDB || return 0 shell { cd $BUILDDIR || return "$?" rm -rf lmdb-* lmdb.dir Lib/lmdb Modules/lmdb || return "$?" tar xzvf ../lmdb-0.92.tar.gz || return "$?" mv lmdb-0.92 lmdb.dir || return "$?" mkdir Lib/lmdb Modules/lmdb || return "$?" echo 'from _lmdb_cpython import * from _lmdb_cpython import open from _lmdb_cpython import __all__' >Lib/lmdb/__init__.py cp lmdb.dir/lmdb/tool.py Lib/lmdb/ || return "$?" cp lmdb.dir/lib/mdb.c Modules/lmdb/lmdb_mdb.c || return "$?" cp lmdb.dir/lib/midl.c Modules/lmdb/lmdb_midl.c || return "$?" # Our uClibc doesn't support pthread_mutexattr_setpshared, so we just skip the call. perl -pi~ -e 's@(pthread_mutexattr_setpshared\()@0&&$1@g' Modules/lmdb/lmdb_mdb.c || return "$?" patch_and_copy_cext lmdb.dir/lmdb/cpython.c Modules/lmdb/_lmdb_cpython.c || return "$?" #generate_loader_py _lmdb lmdb.btree || return "$?" enable_module _lmdb_cpython || return "$?" } || return "$?" } proc extractpyrex { test $IS_CO || return 0 shell { cd $BUILDDIR || return "$?" rm -rf pyrex.dir tar xzvf ../Pyrex-0.9.9.tar.gz || return "$?" mv Pyrex-0.9.9 pyrex.dir || return "$?" } || return "$?" } # Depends on extractpyrex. proc patchmsgpack { test $IS_XX || return 0 shell { cd $BUILDDIR || return "$?" rm -rf msgpack-* msgpack.dir Lib/msgpack Modules/msgpack || return "$?" tar xjvf ../msgpack-python-20111221.tar.bz2 || return "$?" mv msgpack-python-20111221 msgpack.dir || return "$?" local VERSION=$[grep '^version = ' msgpack.dir/setup.py] test $VERSION || return "$?" shell {cd msgpack.dir/msgpack && $PATCH -p0 <../../../msgpack_pyx.patch} || return "$?" mv msgpack.dir/msgpack/_msgpack.pyx msgpack.dir/msgpack/_msgpack_msgpack.pyx || return "$?" run_pyrexc msgpack.dir/msgpack/_msgpack_msgpack.pyx || return "$?" mkdir Lib/msgpack Modules/msgpack || return "$?" echo $VERSION >Lib/msgpack/__version__.py || return "$?" cp msgpack.dir/msgpack/__init__.py Lib/msgpack/ || return "$?" cp msgpack.dir/msgpack/_msgpack_msgpack.c msgpack.dir/msgpack/*.h Modules/msgpack/ || return "$?" generate_loader_py _msgpack_msgpack msgpack._msgpack || return "$?" enable_module _msgpack_msgpack || return "$?" } || return "$?" } # Depends on extractpyrex. proc patchconcurrence { test $IS_CO || return 0 shell { cd $BUILDDIR || return "$?" rm -rf concurrence-* concurrence.dir Lib/concurrence Modules/concurrence || return "$?" tar xzvf ../concurrence-0.3.1.tar.gz || return "$?" mv concurrence-0.3.1 concurrence.dir || return "$?" mkdir Lib/concurrence Modules/concurrence || return "$?" # TODO(pts): Fail if any of the pipe commands fail. shell {cd concurrence.dir/lib && tar c $[find concurrence -type f -iname '*.py]} | shell {cd Lib && tar x} || return "$?" generate_loader_py _concurrence_event concurrence._event || return "$?" cat >Modules/concurrence/event.h <<'END' /**** pts ****/ #include #include #include END run_pyrexc concurrence.dir/lib/concurrence/concurrence._event.pyx || return "$?" patch_and_copy_cext concurrence.dir/lib/concurrence/concurrence._event.c Modules/concurrence/concurrence._event.c || return "$?" enable_module _concurrence_event || return "$?" generate_loader_py _concurrence_io_io concurrence.io._io || return "$?" run_pyrexc concurrence.dir/lib/concurrence/io/concurrence.io._io.pyx || return "$?" patch_and_copy_cext concurrence.dir/lib/concurrence/io/concurrence.io._io.c Modules/concurrence/concurrence.io._io.c || return "$?" cp concurrence.dir/lib/concurrence/io/io_base.c \ concurrence.dir/lib/concurrence/io/io_base.h \ Modules/concurrence/ || return "$?" enable_module _concurrence_io_io || return "$?" generate_loader_py _concurrence_database_mysql_mysql concurrence.database.mysql._mysql || return "$?" run_pyrexc -I concurrence.dir/lib/concurrence/io concurrence.dir/lib/concurrence/database/mysql/concurrence.database.mysql._mysql.pyx || return "$?" patch_and_copy_cext concurrence.dir/lib/concurrence/database/mysql/concurrence.database.mysql._mysql.c Modules/concurrence/concurrence.database.mysql._mysql.c || return "$?" enable_module _concurrence_database_mysql_mysql || return "$?" } || return "$?" } proc patchpycrypto { test $IS_CO || return 0 shell { cd $BUILDDIR || return "$?" rm -rf pycrypto-* pycrypto.dir Lib/Crypto Modules/pycrypto || return "$?" tar xzvf ../pycrypto-2.3.tar.gz || return "$?" mv pycrypto-2.3 pycrypto.dir || return "$?" mkdir Lib/Crypto Modules/pycrypto Modules/pycrypto/libtom || return "$?" # TODO(pts): Fail if any of the pipe commands fail. shell {cd pycrypto.dir/lib && tar c $[find Crypto -type f -iname '*.py]} | shell {cd Lib && tar x} || return "$?" ln -s _Crypto_Cipher_DES.c Modules/pycrypto/DES.c || return "$?" cp pycrypto.dir/src/hash_template.c \ pycrypto.dir/src/block_template.c \ pycrypto.dir/src/stream_template.c \ pycrypto.dir/src/pycrypto_compat.h \ pycrypto.dir/src/_counter.h \ pycrypto.dir/src/Blowfish-tables.h \ pycrypto.dir/src/cast5.c \ Modules/pycrypto/ || return "$?" cp pycrypto.dir/src/libtom/tomcrypt_des.c \ pycrypto.dir/src/libtom/*.h \ Modules/pycrypto/libtom/ || return "$?" local M CEXT_MODNAME for M in [Crypto.Hash.MD2 Crypto.Hash.MD4 Crypto.Hash.SHA256 \ Crypto.Hash.RIPEMD160 \ Crypto.Cipher.AES Crypto.Cipher.ARC2 Crypto.Cipher.Blowfish \ Crypto.Cipher.CAST Crypto.Cipher.DES Crypto.Cipher.DES3 \ Crypto.Cipher.ARC4 Crypto.Cipher.XOR \ Crypto.Util.strxor Crypto.Util._counter] { \ setglobal CEXT_MODNAME = $(M##*/) setglobal CEXT_MODNAME = $(CEXT_MODNAME//._/_) setglobal CEXT_MODNAME = $(CEXT_MODNAME//./_) setglobal CEXT_MODNAME = "_"$(CEXT_MODNAME#_)"" generate_loader_py $CEXT_MODNAME $M || return "$?" patch_and_copy_cext "pycrypto.dir/src/$(M##*.).c" Modules/pycrypto/"$CEXT_MODNAME".c || return "$?" enable_module $CEXT_MODNAME || return "$?" } perl -0777 -pi -e 's@ Py_InitModule\("Crypto[.]\w+[.]"@ Py_InitModule(""@g' \ Modules/pycrypto/hash_template.c \ Modules/pycrypto/stream_template.c \ Modules/pycrypto/block_template.c || return "$?" } || return "$?" } proc patchaloaes { test $IS_CO || return 0 shell { cd $BUILDDIR || return "$?" rm -rf aloaes-* aloaes.dir Lib/aes Modules/aloaes || return "$?" tar xzvf ../alo-aes-0.3.tar.gz || return "$?" mv alo-aes-0.3 aloaes.dir || return "$?" mkdir Lib/aes Modules/aloaes || return "$?" cp aloaes.dir/aes/*.py Lib/aes/ || return "$?" generate_loader_py _aes_aes aes._aes || return "$?" patch_and_copy_cext aloaes.dir/aes/aesmodule.c Modules/aloaes/_aes_aes.c || return "$?" cp aloaes.dir/aes/rijndael-alg-fst.c \ aloaes.dir/aes/rijndael-alg-fst.h \ Modules/aloaes/ || return "$?" enable_module _aes_aes || return "$?" } || return "$?" } proc patchlocale { # TODO(pts): Make this idempotent. shell { cd $BUILDDIR || return "$?" if test $UNAME = Darwin { # To make Python able to start up with `export LC_CTYPE=utf-8', which # is a useful setting on the Mac OS X. if test $IS_PY3 { shell {cd Lib && $PATCH -p1 <../../locale.darwin.3.2.patch} || return "$?" } else { # Test it with: ./python2.7-static -c 'import locale; print locale.getpreferredencoding()' shell {cd Lib && $PATCH -p1 <../../locale.darwin.2.7.patch} || return "$?" } } } || return "$?" } proc makeminipython { test $IS_CO || return 0 shell { cd $BUILDDIR || return "$?" # TODO(pts): Disable co modules in Modules/Setup if test $UNAME = Darwin { make python.exe || return "$?" mv -f python.exe minipython || return "$?" } else { make python || return "$?" mv -f python minipython || return "$?" } $STRIP minipython || return "$?" } || return "$?" } proc makepython { shell { cd $BUILDDIR || return "$?" if test $UNAME = Darwin { make python.exe || return "$?" } else { make python || return "$?" rm -f python.exe || return "$?" ln -s python python.exe || return "$?" } } || return "$?" } proc buildpythonlibzip { # This step doesn't depend on makepython. shell { set -ex setglobal IFS = '' '' cd $BUILDDIR || shell {test -f xlib.zip && mv xlib.zip xlib.zip.old} || return "$?" rm -rf xlib || return "$?" # Compatibility note: `cp -a' works on Linux, but not on Mac OS X, so # we use `cp -R' here which works on both. cp -R Lib xlib || return "$?" rm -f $[find xlib -iname '*.pyc] || return "$?" rm -f xlib/plat-*/regen rm -rf xlib/email/test xlib/bdddb xlib/ctypes xlib/distutils \ xlib/idlelib xlib/lib-tk xlib/lib2to3 xlib/msilib \ xlib/plat-aix* xlib/plat-atheos xlib/plat-beos* \ xlib/plat-freebsd* xlib/plat-irix* xlib/plat-unixware* \ xlib/plat-mac xlib/plat-netbsd* xlib/plat-next* \ xlib/plat-os2* xlib/plat-riscos xlib/plat-sunos* \ xlib/site-packages* xlib/sqlite3/test/* xlib/turtle* xlib/tkinter \ xlib/bsddb/test \ xlib/test xlib/*.egg-info || return "$?" if test $UNAME = Darwin { rm -rf xlib/plat-linux2 || return "$?" } else { rm -rf xlib/plat-darwin || return "$?" } if test $IS_PY3 { cp ../site.3.2.py xlib/site.py || return "$?" # This is to make `import socket; socket.gethostbyname('www.google.com') # work. shell {cd xlib && $PATCH -p1 <../../encodings_idna_missing_unicodedata.3.2.patch} || return "$?" } else { cp ../site.2.7.py xlib/site.py || return "$?" } cd xlib || return "$?" rm -f *~ */*~ || return "$?" rm -f ../xlib.zip || return "$?" run_mkzip ../xlib.zip * || return "$?" } || return "$?" } # Fix ELF binaries to contain GNU/Linux as the operating system. This is # needed when running the program on FreeBSD in Linux mode. proc do_elfosfix { perl -e' use integer; use strict; #** ELF operating system codes from FreeBSDs /usr/share/misc/magic my %ELF_os_codes=qw{ SYSV 0 HP-UX 1 NetBSD 2 GNU/Linux 3 GNU/Hurd 4 86Open 5 Solaris 6 Monterey 7 IRIX 8 FreeBSD 9 Tru64 10 Novell 11 OpenBSD 12 ARM 97 embedded 255 }; my $from_oscode=$ELF_os_codes{"SYSV"}; my $to_oscode=$ELF_os_codes{"GNU/Linux"}; for my $fn (@ARGV) { my $f; if (!open $f, "+<", $fn) { print STDERR "$0: $fn: $!\n"; exit 2 # next } my $head; # vvv Imp: continue on next file instead of die()ing die if 8!=sysread($f,$head,8); if (substr($head,0,4)ne"\177ELF") { print STDERR "$0: $fn: not an ELF file\n"; close($f); next; } if (vec($head,7,8)==$to_oscode) { print STDERR "$0: info: $fn: already fixed\n"; } if ($from_oscode!=$to_oscode && vec($head,7,8)==$from_oscode) { vec($head,7,8)=$to_oscode; die if 0!=sysseek($f,0,0); die if length($head)!=syswrite($f,$head); } die "file error\n" if !close($f); }' -- @ARGV || return "$?" } proc buildtarget { cp "$BUILDDIR"/python.exe "$BUILDDIR/$TARGET" || return "$?" $STRIP "$BUILDDIR/$TARGET" || return "$?" if test $UNAME = Linux { do_elfosfix "$BUILDDIR/$TARGET" || return "$?" } cat "$BUILDDIR"/xlib.zip >>"$BUILDDIR/$TARGET" || return "$?" cp "$BUILDDIR/$TARGET" $TARGET || return "$?" ls -l $TARGET || return "$?" } proc betry { # This step is optional. It tries the freshly built binary. mkdir -p bch be/bardir || return "$?" echo "print 'FOO'" >be/foo.py || return "$?" echo "print 'BAR'" >be/bardir/bar.py || return "$?" cp $TARGET be/sp || return "$?" cp $TARGET bch/sp || return "$?" export PYTHONPATH=bardir unset PYTHONHOME #unset PYTHONPATH shell {cd be && ./sp} || return "$?" } proc fail_step { set +ex echo "Failed in step $2 with code $1" echo "Fix and retry with: $0 $(TARGET%-static) $2 $3" exit "$1" } setglobal XSTEPS = ""$[echo $STEPS] "" # Collapse whitespace etc. setglobal XSTEPS0 = $XSTEPS for STEP in [$XSTEPS] { echo "Running step: $STEP" setglobal XSTEPS = $(XSTEPS#* ) echo "Steps remaining: $XSTEPS" set -x # set -e (abort on error) has no effect in functions in busybox sh, so we # don't enable it. if ! $STEP { set +x fail_step "$Status" $STEP $XSTEPS } set +x } echo "OK running $0 $(TARGET%-static) $XSTEPS0" exit 0 }