commit 87142112db32e1999de9ab2a213f5521d37a1e94 Author: David Fifield david@bamsoftware.com Date: Fri Nov 22 17:22:42 2013 +0000
Add gcc, dllwrap, and swig wrappers for Wine.
Python distutils, with the "mingw32" compiler profile, is inflexible. It hardcodes the names "gcc.exe" and "dllwrap.exe", and passes them fixed options. It's not possible to control it with environment variables like CC and CFLAGS.
Before Python 2.7.6, distutils always passes the option -mno-cygwin to gcc, which causes an error. Additionally, when distutils is run under Wine, it passes Windows-style paths with backslashes to our unsuspecting i686-w64-mingw32-gcc.
These wrapper programs strip -mno-cygwin, and convert Windows paths to Unix paths. They also set LD_PRELOAD and FAKETIME, because those can't be set for the outer Wine process.
Doing a subprocess.Popen of a Unix program from within Wine mostly works. For example, subprocess.Popen(["/usr/bin/i686-w64-mingw32-gcc"]) starts a new compiler process. However, if you .wait() on the process object, you get a "WindowsError: [Error 6] Invalid handle". The same goes for the implicit wait in subprocess.call and subprocess.check_output. The .pid of such processes is 0.
What you can do, however, is read from one of the process's output streams--it will be closed when the process terminates. Because we know we are dealing with gcc subprocesses, we read its stderr and look for the string " error: ". If it appears, we return a non-zero status code. We don't return non-zero merely on a non-empty stderr, because warnings don't usually cause that.
The difficulty doesn't exist when running native Windows binaries. That's why we can do subprocess.call(["winepath", ...]): because winepath.exe is a native binary that comes with Wine. --- gitian/build-helpers/wine-wrappers/common.py | 27 ++++++++++++++++++ gitian/build-helpers/wine-wrappers/dllwrap.py | 36 ++++++++++++++++++++++++ gitian/build-helpers/wine-wrappers/gcc.py | 36 ++++++++++++++++++++++++ gitian/build-helpers/wine-wrappers/settings.py | 2 ++ gitian/build-helpers/wine-wrappers/setup.py | 7 +++++ gitian/build-helpers/wine-wrappers/swig.py | 33 ++++++++++++++++++++++ gitian/mkbundle-linux.sh | 2 +- gitian/mkbundle-mac.sh | 2 +- gitian/mkbundle-windows.sh | 2 +- 9 files changed, 144 insertions(+), 3 deletions(-)
diff --git a/gitian/build-helpers/wine-wrappers/common.py b/gitian/build-helpers/wine-wrappers/common.py new file mode 100644 index 0000000..19e994b --- /dev/null +++ b/gitian/build-helpers/wine-wrappers/common.py @@ -0,0 +1,27 @@ +import os +import subprocess + +import settings + +def winepath(windowspath): + """Convert a Windows path to a Unix path.""" + return subprocess.check_output(["winepath", "-u", windowspath])[:-1] + +def search_startswith(a, elems): + """Search for the first element of the array a that startswith any of the + members of elems, and return it. Return None if no match was found.""" + for e in elems: + if a.startswith(e): + return e + return None + +def popen_faketime(*args, **kwargs): + """Does subprocess.Popen after setting faketime environment variables.""" + ld_preload = os.getenv("LD_PRELOAD") + if ld_preload: + # ld.so(8): "The items of [LD_PRELOAD] can be separated by spaces or colons." + ld_preload += ":" + ld_preload += settings.LD_PRELOAD + os.putenv("LD_PRELOAD", ld_preload) + os.putenv("FAKETIME", settings.FAKETIME) + return subprocess.Popen(*args, **kwargs) diff --git a/gitian/build-helpers/wine-wrappers/dllwrap.py b/gitian/build-helpers/wine-wrappers/dllwrap.py new file mode 100755 index 0000000..fdff035 --- /dev/null +++ b/gitian/build-helpers/wine-wrappers/dllwrap.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python + +# A wrapper for i686-w64-mingw32-dllwrap that removes -mno-cygwin and converts +# Windows paths to Unix paths, so that the w64-mingw32 dllwrap can be called by +# Python distutils. + +import os +import subprocess +import sys + +import common + +args = ["/usr/bin/i686-w64-mingw32-dllwrap"] +sys.argv.pop(0) +while sys.argv: + a = sys.argv.pop(0) + if not a.startswith("-"): + args.append(common.winepath(a)) + continue + if a == "-mno-cygwin": + continue + if a in ("-I", "-L", "-s", "--def", "--output-lib"): + args.append(a) + args.append(common.winepath(sys.argv.pop(0))) + continue + o = common.search_startswith(a, ("-I", "-L", "--def=", "--output-lib=")) + if o is not None: + path = a[len(o):] + args.append("%s%s" % (o, common.winepath(path))) + continue + args.append(a) +p = common.popen_faketime(args, stderr=subprocess.PIPE) +stderr = p.stderr.read() +sys.stderr.write(stderr) +if " error: " in stderr: + sys.exit(1) diff --git a/gitian/build-helpers/wine-wrappers/gcc.py b/gitian/build-helpers/wine-wrappers/gcc.py new file mode 100755 index 0000000..493b27b --- /dev/null +++ b/gitian/build-helpers/wine-wrappers/gcc.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python + +# A wrapper for i686-w64-mingw32-gcc that removes -mno-cygwin and converts +# Windows paths to Unix paths, so that the w64-mingw32 gcc can be called by +# Python distutils. + +import os +import subprocess +import sys + +import common + +args = ["/usr/bin/i686-w64-mingw32-gcc"] +sys.argv.pop(0) +while sys.argv: + a = sys.argv.pop(0) + if not a.startswith("-"): + args.append(common.winepath(a)) + continue + if a == "-mno-cygwin": + continue + if a in ("-I", "-L"): + args.append(a) + args.append(common.winepath(sys.argv.pop(0))) + continue + o = common.search_startswith(a, ("-I", "-L")) + if o is not None: + path = a[len(o):] + args.append("%s%s" % (o, common.winepath(path))) + continue + args.append(a) +p = common.popen_faketime(args, stderr=subprocess.PIPE) +stderr = p.stderr.read() +sys.stderr.write(stderr) +if " error: " in stderr: + sys.exit(1) diff --git a/gitian/build-helpers/wine-wrappers/settings.py b/gitian/build-helpers/wine-wrappers/settings.py new file mode 100644 index 0000000..f395433 --- /dev/null +++ b/gitian/build-helpers/wine-wrappers/settings.py @@ -0,0 +1,2 @@ +LD_PRELOAD = "/usr/lib/faketime/libfaketime.so.1" +FAKETIME = "2000-01-01 00:00:00" diff --git a/gitian/build-helpers/wine-wrappers/setup.py b/gitian/build-helpers/wine-wrappers/setup.py new file mode 100644 index 0000000..797015e --- /dev/null +++ b/gitian/build-helpers/wine-wrappers/setup.py @@ -0,0 +1,7 @@ +from distutils.core import setup +import py2exe +setup( + console=["gcc.py", "dllwrap.py", "swig.py"], + zipfile=None, + options={"py2exe": {"bundle_files": 1, "compressed": True}} +) diff --git a/gitian/build-helpers/wine-wrappers/swig.py b/gitian/build-helpers/wine-wrappers/swig.py new file mode 100755 index 0000000..45941f4 --- /dev/null +++ b/gitian/build-helpers/wine-wrappers/swig.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python + +# A wrapper for swig that converts Windows paths to Unix paths, so that swig can +# be called by Python distutils. + +import os +import subprocess +import sys + +import common + +args = ["/usr/bin/swig"] +sys.argv.pop(0) +while sys.argv: + a = sys.argv.pop(0) + if not a.startswith("-"): + args.append(common.winepath(a)) + continue + if a in ("-I",): + args.append(a) + args.append(common.winepath(sys.argv.pop(0))) + continue + o = common.search_startswith(a, ("-I",)) + if o is not None: + path = a[len(o):] + args.append("%s%s" % (o, common.winepath(path))) + continue + args.append(a) +p = common.popen_faketime(args, stderr=subprocess.PIPE) +stderr = p.stderr.read() +sys.stderr.write(stderr) +if " Error: " in stderr: + sys.exit(1) diff --git a/gitian/mkbundle-linux.sh b/gitian/mkbundle-linux.sh index 9ef0910..3b92216 100755 --- a/gitian/mkbundle-linux.sh +++ b/gitian/mkbundle-linux.sh @@ -41,7 +41,7 @@ echo "pref("torbrowser.version", "$TORBROWSER_VERSION-Linux");" > $GITIAN_DI echo "$TORBROWSER_VERSION" > $GITIAN_DIR/inputs/bare-version cp -a $WRAPPER_DIR/$VERSIONS_FILE $GITIAN_DIR/inputs/versions
-cp $WRAPPER_DIR/build-helpers/* $GITIAN_DIR/inputs/ +cp -r $WRAPPER_DIR/build-helpers/* $GITIAN_DIR/inputs/
cd $WRAPPER_DIR/.. rm -f $GITIAN_DIR/inputs/relativelink-src.zip diff --git a/gitian/mkbundle-mac.sh b/gitian/mkbundle-mac.sh index 8e4da79..69ef3ed 100755 --- a/gitian/mkbundle-mac.sh +++ b/gitian/mkbundle-mac.sh @@ -41,7 +41,7 @@ echo "pref("torbrowser.version", "$TORBROWSER_VERSION-MacOS");" > $GITIAN_DI echo "$TORBROWSER_VERSION" > $GITIAN_DIR/inputs/bare-version cp -a $WRAPPER_DIR/$VERSIONS_FILE $GITIAN_DIR/inputs/versions
-cp $WRAPPER_DIR/build-helpers/* $GITIAN_DIR/inputs/ +cp -r $WRAPPER_DIR/build-helpers/* $GITIAN_DIR/inputs/
cd $WRAPPER_DIR/.. rm -f $GITIAN_DIR/inputs/relativelink-src.zip diff --git a/gitian/mkbundle-windows.sh b/gitian/mkbundle-windows.sh index 33e8a2b..9542604 100755 --- a/gitian/mkbundle-windows.sh +++ b/gitian/mkbundle-windows.sh @@ -42,7 +42,7 @@ echo "pref("torbrowser.version", "$TORBROWSER_VERSION-Windows");" > $GITIAN_ echo "$TORBROWSER_VERSION" > $GITIAN_DIR/inputs/bare-version cp -a $WRAPPER_DIR/$VERSIONS_FILE $GITIAN_DIR/inputs/versions
-cp $WRAPPER_DIR/build-helpers/* $GITIAN_DIR/inputs/ +cp -r $WRAPPER_DIR/build-helpers/* $GITIAN_DIR/inputs/ cp $WRAPPER_DIR/gpg/ubuntu-wine.gpg $GITIAN_DIR/inputs/
cd $WRAPPER_DIR/..
tor-commits@lists.torproject.org