summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Markmann <tm@ayena.de>2017-06-12 13:52:24 (GMT)
committerTobias Markmann <tm@ayena.de>2017-06-13 14:39:25 (GMT)
commit3e6b1c914943d7d9b855bb144ad967fd285824fa (patch)
treeb624596e04c6aed5df99378924df28fd91b66f53
parentcf151bb5244858af53910f9486399f41103ebcc9 (diff)
downloadswift-3e6b1c914943d7d9b855bb144ad967fd285824fa.zip
swift-3e6b1c914943d7d9b855bb144ad967fd285824fa.tar.bz2
Add build_appimage.py for Linux packaging as AppImage
Run this script to generate a self-contained AppImage that will run on any Linux distribution that has the same or newer Linux kernel and the same or newer GLib. The script will generate an AppImage for the same architecture it is executed on. By default it will use Qt5. Specify --qt5=False to create an AppImage with Qt4. The resulting .appimage and .debug files are copied to ./Packages/Swift Test-Information: Latest iteration of the script was tested with building an AppImage on 64-bit Ubuntu 16.04 and running it on 64-bit Debian Sid. Earlier version of the script was tested on 32-bit SUSE Linux Enterprise 11. Change-Id: I14477ada3558109fe73a77f7e7fe1ee8ef629d5f
-rw-r--r--Swift/Packaging/appimage/build_appimage.py152
1 files changed, 152 insertions, 0 deletions
diff --git a/Swift/Packaging/appimage/build_appimage.py b/Swift/Packaging/appimage/build_appimage.py
new file mode 100644
index 0000000..e188c4f
--- /dev/null
+++ b/Swift/Packaging/appimage/build_appimage.py
@@ -0,0 +1,152 @@
+#!/usr/bin/env python2
+#
+# This Python script builds self-contained Linux packages, i.e. AppImages ( http://appimage.org/ ), of Swift.
+# It downloads required appimage tool that is executed at the end and an exculde list from the internet.
+#
+# Non-standard dependencies:
+# * plumbum ( https://plumbum.readthedocs.io/en/latest/ )
+# * click ( http://click.pocoo.org/5/ )
+#
+# They can be installed via `pip install plumbum click`.
+#
+# The script requires git, wget, readelf and objcopy to work and will fail if
+# they are not present.
+#
+# Just run ./Swift/Packaging/appimage/build_appimage.py and after it executed
+# there should be .appimage and .debug files in Packages/Swift.
+#
+# The appimage will be for the same architecture as the host architecture.
+# Pass `--qt5=False` to the tool to build against legacy Qt4.
+
+from plumbum import local, FG, BG, colors, commands
+import click
+import os
+import re
+import time
+import sys
+
+git = local['git']
+
+def git_working_dir():
+ working_dir = git('rev-parse', '--show-toplevel').strip()
+ if not os.path.exists(working_dir):
+ working_dir = os.path.dirname(os.path.abspath(git('rev-parse', '--git-dir').strip()))
+ return working_dir
+
+git_working_dir = git_working_dir()
+resources_dir = os.path.join(git_working_dir, "Swift/resources/")
+
+@click.command()
+@click.option('--qt5', default=True, type=bool, help='Build with Qt5.')
+def build_appimage(qt5):
+ print(colors.bold & colors.info | "Switch to git working directory root " + git_working_dir)
+ with local.cwd(git_working_dir):
+
+ def copy_dependencies_into_appdir(excludelist, binary_path, lib_path):
+ chain = local['ldd'][binary_path] | local['grep']["=> /"] | local['awk']['{print $3}']
+ for dynamic_lib in chain().strip().split('\n'):
+ if os.path.basename(dynamic_lib) in excludelist:
+ #print(colors.info | "Not including " + dynamic_lib + " as it is blacklisted.")
+ pass
+ else:
+ local['cp']('-v', '-L', dynamic_lib, lib_path)
+
+ scons = local['./scons']
+ print(colors.bold & colors.info | "Building Swift")
+ scons['qt5={}'.format("1" if qt5 else "0"), 'Swift'] & FG
+
+ swift = local['./Swift/QtUI/swift-im']
+ swift_version = swift('--version').strip()
+ print(colors.bold & colors.info | "Successfully built " + swift_version)
+
+ swift_architecture_string = ""
+ try:
+ readelf_on_swift_im_output = local['readelf']('-h', './Swift/QtUI/swift-im').strip()
+ swift_architecture = re.search(r'Class:\s+([^\s]+)', readelf_on_swift_im_output, flags=re.I).group(1)
+ if swift_architecture == "ELF32":
+ swift_architecture_string = ".i386"
+ elif swift_architecture == "ELF64":
+ swift_architecture_string = ".amd64"
+ except:
+ pass
+
+ appdir_path = os.path.join(git_working_dir, 'Swift/Packaging/AppImage/Swift.AppDir')
+ print(colors.bold & colors.info | "Prepare AppDir structure at " + appdir_path)
+ local['mkdir']('-p', appdir_path)
+
+ swift_install_dir = os.path.join(appdir_path, 'usr')
+ print(colors.bold & colors.info | "Install Swift to AppDir")
+ scons['qt5={}'.format("1" if qt5 else "0"), 'Swift', 'SWIFT_INSTALLDIR=' + swift_install_dir , swift_install_dir] & FG
+
+ print(colors.bold & colors.info | "Download dynamic lib exclude list from https://raw.githubusercontent.com/AppImage/AppImages/master/excludelist")
+ local['wget']['--no-check-certificate', '-O', '/tmp/excludelist', 'https://raw.githubusercontent.com/AppImage/AppImages/master/excludelist'] & FG
+
+ print(colors.bold & colors.info | "Load dynamic library exclude list")
+ excludelist = set()
+ with open('/tmp/excludelist') as f:
+ for line in f:
+ if line and "#" not in line:
+ excludelist.add(line.strip())
+
+ print(colors.bold & colors.info | "Copy dynamic library dependencies into AppDir")
+ local['mkdir']('-p', os.path.join(appdir_path, 'usr/lib'))
+ appdir_swift_im_binary = os.path.join(swift_install_dir, 'bin/swift-im')
+ copy_dependencies_into_appdir(excludelist, appdir_swift_im_binary, os.path.join(swift_install_dir, "lib"))
+
+ if qt5:
+ print(colors.bold & colors.info | "Analyze binary for Qt plugin paths")
+ # Run Swift binary and parse debug output to find plugin paths to copy.
+ swift_plugin_debug_output = ""
+ try:
+ process = local["env"]["QT_DEBUG_PLUGINS=1", './Swift/QtUI/swift-im'].popen()
+ time.sleep(2)
+ process.kill()
+ stdout, stderr = process.communicate()
+ swift_plugin_debug_output = stderr
+ except:
+ pass
+ if swift_plugin_debug_output:
+ matches = re.search(r"/.*/qt5/plugins", swift_plugin_debug_output)
+ if matches:
+ qt5_plugin_path = matches.group(0)
+ appdir_qt5_plugin_path = os.path.join(appdir_path, 'usr/lib/qt5')
+ local['mkdir']('-p', appdir_qt5_plugin_path)
+ local['cp']('-r', '-L', qt5_plugin_path, appdir_qt5_plugin_path)
+
+ print(colors.bold & colors.info | "Copy plugin dependencies into AppDir")
+ for plugin_path in local.path(appdir_qt5_plugin_path) // "plugins/*/*.so":
+ copy_dependencies_into_appdir(excludelist, plugin_path, os.path.join(swift_install_dir, "lib"))
+
+ print(colors.bold & colors.info | "Download https://github.com/AppImage/AppImageKit/raw/appimagetool/master/resources/AppRun to " + os.path.join(appdir_path, 'AppRun'))
+ local['wget']('--no-check-certificate', '-O', os.path.join(appdir_path, 'AppRun'), "https://github.com/AppImage/AppImageKit/raw/appimagetool/master/resources/AppRun")
+ local['chmod']('+x', os.path.join(appdir_path, 'AppRun'))
+
+ print(colors.bold & colors.info | "Copy swift.desktop file")
+ source_desktop_file = os.path.join(resources_dir, "swift.desktop")
+ target_desktop_file = os.path.join(appdir_path, 'swift.desktop')
+ local['cp']('-v', '-L', source_desktop_file, target_desktop_file)
+
+ print(colors.bold & colors.info | "Copy logos to Swift.AppDir")
+ local['cp']('-v', '-L', os.path.join(resources_dir, "logo/logo-icon-512.png"), os.path.join(appdir_path, "swift.png"))
+ local['cp']('-v', '-L', os.path.join(resources_dir, "logo/logo-icon.svg"), os.path.join(appdir_path, "swift.svg"))
+ local['cp']('-v', '-L', os.path.join(resources_dir, "logo/logo-icon-32.xpm"), os.path.join(appdir_path, "swift.xpm"))
+
+ print(colors.bold & colors.info | "Download appimagetool to /tmp/appimagetool and make it executable")
+ local['wget']['-O', '/tmp/appimagetool', 'https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-' + ("x86_64.AppImage" if swift_architecture_string == ".amd64": else "i686.AppImage")] & FG
+ local['chmod']['a+x', '/tmp/appimagetool']()
+
+ local['mkdir']('-p', os.path.join(git_working_dir, "Packages/Swift"))
+ appimage_path = os.path.join(git_working_dir, "Packages/Swift/" + swift_version.replace(" ", "-") + swift_architecture_string + ".appimage")
+ debug_symbol_path = os.path.join(git_working_dir, "Packages/Swift/" + swift_version.replace(" ", "-") + swift_architecture_string + ".debug")
+
+ print(colors.bold & colors.info | "Extract debug information from swift-im")
+ local['objcopy']('--only-keep-debug', appdir_swift_im_binary, debug_symbol_path)
+ local['strip']('-g', appdir_swift_im_binary)
+ local['objcopy']('--add-gnu-debuglink', debug_symbol_path, os.path.join(swift_install_dir, 'bin/swift-im'))
+
+ print(colors.bold & colors.info | "Generate AppImage from Swift.AppDir")
+ local['/tmp/appimagetool'][appdir_path, appimage_path] & FG
+
+
+if __name__ == '__main__':
+ build_appimage() \ No newline at end of file