From a4d4d233b0de84223ad77272b1b034a5b0c0400f Mon Sep 17 00:00:00 2001 From: Jonathan Springer Date: Fri, 13 Jun 2014 23:40:12 -0400 Subject: [PATCH] Link mudraw binary to bundled libraries on Mac OS X --- osx/macosx-builder.py | 57 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/osx/macosx-builder.py b/osx/macosx-builder.py index 6c442dc..04affdc 100644 --- a/osx/macosx-builder.py +++ b/osx/macosx-builder.py @@ -93,6 +93,11 @@ MuPDF Required for PDF support in OpenLP. Install using macports, or use the '--mudraw-bin' option of this script to point to the mudraw binary. +MachOLib + Python library to analyze and edit Mach-O headers, the executable format + used by Mac OS X. Used to relink the mudraw binary from MuPDF to the bundled + libraries. Install using macports or pip. + config.ini.default The configuration file contains settings of the version string to include in the bundle as well as directory and file settings for different @@ -126,6 +131,9 @@ from subprocess import Popen, PIPE from configparser import ConfigParser from argparse import ArgumentParser +from macholib.MachO import MachO +from macholib.util import flipwritable, in_system_path + def _which(command): """ @@ -451,9 +459,58 @@ class MacosxBuilder(object): self._print_verbose('... mudraw') if self.mudraw_bin and os.path.isfile(self.mudraw_bin): copy(os.path.join(self.mudraw_bin), os.path.join(self.dist_path, 'mudraw')) + self.relink_mudraw() else: self._print('... WARNING: mudraw not found') + def relink_mudraw(self): + """ + Relink mudraw to bundled libraries + """ + self._print('Linking mudraw with bundled libraries...') + libname = os.path.join(self.dist_path, 'mudraw') + distname = os.path.relpath(self.dist_path, libname) + self._print_verbose('... mudraw path %s', libname) + + # Determine how many directories up is the directory with shared + # dynamic libraries. '../' + # E.g. ./qt4_plugins/images/ -> ./../../ + parent_dir = '' + # Check if distname is not only base filename. + if os.path.dirname(distname): + parent_level = len(os.path.dirname(distname).split(os.sep)) + parent_dir = parent_level * (os.pardir + os.sep) + + def match_func(pth): + """ + For system libraries leave path unchanged. + """ + # Match non system dynamic libraries. + if not in_system_path(pth): + # Use relative path to dependend dynamic libraries bases on + # location of the executable. + pth = os.path.join('@loader_path', parent_dir, os.path.basename(pth)) + self._print_verbose('... %s', pth) + return pth + + # Rewrite mach headers with @loader_path. + dll = MachO(libname) + dll.rewriteLoadCommands(match_func) + + # Write changes into file. + # Write code is based on macholib example. + try: + self._print_verbose('... writing new library paths') + f = open(dll.filename, 'rb+') + for header in dll.headers: + f.seek(0) + dll.write(f) + f.seek(0, 2) + f.flush() + f.close() + except Exception: + pass + def update_translations(self): """ Update the translations.