diff --git a/distribute.sh b/distribute.sh index e33404e4ed..9a8da04bef 100755 --- a/distribute.sh +++ b/distribute.sh @@ -63,6 +63,8 @@ export BIGLINK="$ROOT_PATH/src/tools/biglink" export PIP=$PIP_NAME export VIRTUALENV=$VIRTUALENV_NAME +export COPYLIBS=0 + MD5SUM=$(which md5sum) if [ "X$MD5SUM" == "X" ]; then MD5SUM=$(which md5) @@ -217,6 +219,7 @@ function push_arm() { export LD="$TOOLCHAIN_PREFIX-ld" export STRIP="$TOOLCHAIN_PREFIX-strip --strip-unneeded" export MAKE="make -j5" + export READELF="$TOOLCHAIN_PREFIX-readelf" # Use ccache ? which ccache &>/dev/null @@ -253,6 +256,10 @@ function usage() { echo " -f Restart from scratch (remove the current build)" echo " -x display expanded values (execute 'set -x')" echo + echo "Advanced:" + echo " -C Copy libraries instead of using biglink" + echo " (may not work before Android 4.3)" + echo echo "For developers:" echo " -u 'mod1 mod2' Modules to update (if already compiled)" echo @@ -345,6 +352,15 @@ function run_prepare() { fi done + if [ "$COPYLIBS" == "1" ]; then + info "Library files will be copied to the distribution (no biglink)" + error "NOTICE: This option is still beta!" + error "\tIf you encounter an error 'Failed to locate needed libraries!' and" + error "\tthe libraries listed are not supposed to be provided by your app or" + error "\tits dependencies, please submit a bug report at" + error "\thttps://github.com/kivy/python-for-android/issues" + fi + info "Distribution will be located at $DIST_PATH" if [ -e "$DIST_PATH" ]; then error "The distribution $DIST_PATH already exist" @@ -760,7 +776,14 @@ function run_distribute() { debug "Fill private directory" try cp -a python-install/lib private/ try mkdir -p private/include/python2.7 - try mv libs/$ARCH/libpymodules.so private/ + + if [ "$COPYLIBS" == "1" ]; then + if [ -s "libs/$ARCH/copylibs" ]; then + try sh -c "cat libs/$ARCH/copylibs | xargs -d'\n' cp -t private/" + fi + else + try mv libs/$ARCH/libpymodules.so private/ + fi try cp python-install/include/python2.7/pyconfig.h private/include/python2.7/ debug "Reduce private directory from unwanted files" @@ -787,7 +810,11 @@ function run_distribute() { function run_biglink() { push_arm - try $BIGLINK $LIBS_PATH/libpymodules.so $LIBLINK_PATH + if [ "$COPYLIBS" == "0" ]; then + try $BIGLINK $LIBS_PATH/libpymodules.so $LIBLINK_PATH + else + try $BIGLINK $LIBS_PATH/copylibs $LIBLINK_PATH + fi pop_arm } @@ -829,11 +856,16 @@ function arm_deduplicate() { # Do the build -while getopts ":hvlfxm:u:d:s" opt; do +while getopts ":hCvlfxm:u:d:s" opt; do case $opt in h) usage ;; + C) + COPYLIBS=1 + LIBLINK=${LIBLINK}-jb + BIGLINK=${BIGLINK}-jb + ;; l) list_modules ;; diff --git a/src/tools/biglink-jb b/src/tools/biglink-jb new file mode 100755 index 0000000000..ef3004f5bc --- /dev/null +++ b/src/tools/biglink-jb @@ -0,0 +1,111 @@ +#!/usr/bin/env python + +from __future__ import print_function +import os +import sys +import subprocess +import re + +re_needso = re.compile(r'^.*\(NEEDED\)\s+Shared library: \[lib(.*)\.so\]\s*$') + +blacklist_libs = ( + 'c', + 'stdc++', + 'dl', + 'python2.7', + 'sdl', + 'sdl_image', + 'sdl_ttf', + 'z', + 'm', + 'GLESv2', + 'jpeg', + 'png', + 'log', +) + +found_libs = [] +sofiles = [ ] + +for directory in sys.argv[2:]: + + for fn in os.listdir(directory): + fn = os.path.join(directory, fn) + + if not fn.endswith(".libs"): + continue + + dirfn = fn[:-1] + 'dirs' + if not os.path.exists(dirfn): + continue + + with open(fn) as f: + needed_libs = [lib for lib in {ln.strip() for ln in f} if lib not in blacklist_libs and lib not in found_libs] + + while needed_libs: + print('need libs:\n\t' + '\n\t'.join(needed_libs)) + + start_needed_libs = needed_libs[:] + found_sofiles = [] + + with open(dirfn) as f: + for libdir in f: + if not needed_libs: + break + + libdir = libdir.strip() + print('scanning %s' % libdir) + for lib in needed_libs[:]: + if lib in found_libs: + continue + + if lib.endswith('.a'): + needed_libs.remove(lib) + found_libs.append(lib) + continue + + lib_a = 'lib' + lib + '.a' + libpath_a = os.path.join(libdir, lib_a) + lib_so = 'lib' + lib + '.so' + libpath_so = os.path.join(libdir, lib_so) + plain_so = lib + '.so' + plainpath_so = os.path.join(libdir, plain_so) + + sopath = None + if os.path.exists(libpath_so): + sopath = libpath_so + elif os.path.exists(plainpath_so): + sopath = plainpath_so + + if sopath: + print('found %s in %s' % (lib, libdir)) + found_sofiles.append(sopath) + needed_libs.remove(lib) + found_libs.append(lib) + continue + + if os.path.exists(libpath_a): + print('found %s (static) in %s' % (lib, libdir)) + needed_libs.remove(lib) + found_libs.append(lib) + continue + + for sofile in found_sofiles: + print('scanning dependencies for %s' % sofile) + out = subprocess.check_output([os.environ['READELF'], '-d', sofile]) + for line in out.splitlines(): + needso = re_needso.match(line) + if needso: + lib = needso.group(1) + if lib not in needed_libs and lib not in found_libs and lib not in blacklist_libs: + needed_libs.append(needso.group(1)) + + sofiles += found_sofiles + + if needed_libs == start_needed_libs: + raise RuntimeError('Failed to locate needed libraries!\n\t' + '\n\t'.join(needed_libs)) + +output = sys.argv[1] + +with open(output, 'w') as f: + f.write('\n'.join(sofiles)) diff --git a/src/tools/liblink-jb b/src/tools/liblink-jb new file mode 100755 index 0000000000..46dc1ca325 --- /dev/null +++ b/src/tools/liblink-jb @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +from __future__ import print_function +import sys +import subprocess +from os import environ +from os.path import basename, join + +libs = [ ] +libdirs = [ ] +output = None + + +i = 1 +while i < len(sys.argv): + opt = sys.argv[i] + i += 1 + + if opt == "-o": + output = sys.argv[i] + i ++ 1 + continue + + if opt.startswith("-l"): + libs.append(opt[2:]) + continue + + if opt.startswith("-L"): + libdirs.append(opt[2:]) + continue + +output = join(environ.get('LIBLINK_PATH'), basename(output)) + +with open(output + ".libs", "w") as f: + f.write("\n".join(libs)) + +with open(output + ".libdirs", "w") as f: + f.write("\n".join(libdirs)) + + +libargs = ' '.join(["'%s'" % arg for arg in sys.argv[1:]]) +cmd = '%s -shared %s %s' % (environ['CC'], environ['LDFLAGS'], libargs) +sys.exit(subprocess.call(cmd, shell=True))