10 changed files with 344 additions and 20 deletions
@ -0,0 +1,160 @@ |
|||||||
|
#!/usr/bin/env python |
||||||
|
# cerbero - a multi-platform build system for Open Source software |
||||||
|
# Copyright (C) 2012 Andoni Morales Alastruey <ylatuya@gmail.com> |
||||||
|
# |
||||||
|
# This library is free software; you can redistribute it and/or |
||||||
|
# modify it under the terms of the GNU Library General Public |
||||||
|
# License as published by the Free Software Foundation; either |
||||||
|
# version 2 of the License, or (at your option) any later version. |
||||||
|
# |
||||||
|
# This library is distributed in the hope that it will be useful, |
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||||
|
# Library General Public License for more details. |
||||||
|
# |
||||||
|
# You should have received a copy of the GNU Library General Public |
||||||
|
# License along with this library; if not, write to the |
||||||
|
# Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
||||||
|
# Boston, MA 02111-1307, USA. |
||||||
|
|
||||||
|
import os |
||||||
|
import subprocess |
||||||
|
|
||||||
|
|
||||||
|
INT_CMD = 'install_name_tool' |
||||||
|
OTOOL_CMD = 'otool' |
||||||
|
|
||||||
|
|
||||||
|
def shell_call(cmd, cmd_dir='.', fail=True): |
||||||
|
print "call", cmd |
||||||
|
try: |
||||||
|
ret = subprocess.check_call( |
||||||
|
cmd, cwd=cmd_dir, |
||||||
|
env=os.environ.copy()) |
||||||
|
except subprocess.CalledProcessError: |
||||||
|
if fail: |
||||||
|
raise SystemError("Error running command: {}".format(cmd)) |
||||||
|
else: |
||||||
|
ret = 0 |
||||||
|
return ret |
||||||
|
|
||||||
|
|
||||||
|
def shell_check_call(cmd): |
||||||
|
print "ccall", cmd |
||||||
|
try: |
||||||
|
process = subprocess.Popen( |
||||||
|
cmd, stdout=subprocess.PIPE) |
||||||
|
output, _ = process.communicate() |
||||||
|
except Exception: |
||||||
|
raise SystemError("Error running command: {}".format(cmd)) |
||||||
|
return output |
||||||
|
|
||||||
|
|
||||||
|
class OSXRelocator(object): |
||||||
|
''' |
||||||
|
Wrapper for OS X's install_name_tool and otool commands to help |
||||||
|
relocating shared libraries. |
||||||
|
It parses lib/ /libexec and bin/ directories, changes the prefix path of |
||||||
|
the shared libraries that an object file uses and changes it's library |
||||||
|
ID if the file is a shared library. |
||||||
|
''' |
||||||
|
|
||||||
|
def __init__(self, root, lib_prefix, new_lib_prefix, recursive): |
||||||
|
self.root = root |
||||||
|
self.lib_prefix = self._fix_path(lib_prefix) |
||||||
|
self.new_lib_prefix = self._fix_path(new_lib_prefix) |
||||||
|
self.recursive = recursive |
||||||
|
|
||||||
|
def relocate(self): |
||||||
|
self.parse_dir(self.root, filters=['', '.dylib', '.so', '0']) |
||||||
|
|
||||||
|
def relocate_file(self, object_file, id=None): |
||||||
|
self.change_libs_path(object_file) |
||||||
|
self.change_id(object_file, id) |
||||||
|
|
||||||
|
def change_id(self, object_file, id=None): |
||||||
|
id = id or object_file.replace(self.lib_prefix, self.new_lib_prefix) |
||||||
|
filename = os.path.basename(object_file) |
||||||
|
if not (filename.endswith('so') or filename.endswith('dylib')): |
||||||
|
return |
||||||
|
cmd = [INT_CMD, "-id", id, object_file] |
||||||
|
shell_call(cmd, fail=False) |
||||||
|
|
||||||
|
def change_libs_path(self, object_file): |
||||||
|
for lib in self.list_shared_libraries(object_file): |
||||||
|
if self.lib_prefix in lib: |
||||||
|
new_lib = lib.replace(self.lib_prefix, self.new_lib_prefix) |
||||||
|
cmd = [INT_CMD, "-change", lib, new_lib, object_file] |
||||||
|
shell_call(cmd) |
||||||
|
|
||||||
|
def parse_dir(self, dir_path, filters=None): |
||||||
|
for dirpath, dirnames, filenames in os.walk(dir_path): |
||||||
|
for f in filenames: |
||||||
|
if filters is not None and \ |
||||||
|
os.path.splitext(f)[1] not in filters: |
||||||
|
continue |
||||||
|
fn = os.path.join(dirpath, f) |
||||||
|
if os.path.islink(fn): |
||||||
|
continue |
||||||
|
if not os.path.isfile(fn): |
||||||
|
continue |
||||||
|
self.relocate_file(fn) |
||||||
|
if not self.recursive: |
||||||
|
break |
||||||
|
|
||||||
|
@staticmethod |
||||||
|
def list_shared_libraries(object_file): |
||||||
|
cmd = [OTOOL_CMD, "-L", object_file] |
||||||
|
res = shell_check_call(cmd).split('\n') |
||||||
|
# We don't use the first line |
||||||
|
libs = res[1:] |
||||||
|
# Remove the first character tabulation |
||||||
|
libs = [x[1:] for x in libs] |
||||||
|
# Remove the version info |
||||||
|
libs = [x.split(' ', 1)[0] for x in libs] |
||||||
|
return libs |
||||||
|
|
||||||
|
@staticmethod |
||||||
|
def library_id_name(object_file): |
||||||
|
cmd = [OTOOL_CMD, "-D", object_file] |
||||||
|
res = shell_check_call(cmd).split('\n')[0] |
||||||
|
# the library name ends with ':' |
||||||
|
lib_name = res[:-1] |
||||||
|
return lib_name |
||||||
|
|
||||||
|
def _fix_path(self, path): |
||||||
|
if path.endswith('/'): |
||||||
|
return path[:-1] |
||||||
|
return path |
||||||
|
|
||||||
|
|
||||||
|
class Main(object): |
||||||
|
|
||||||
|
def run(self): |
||||||
|
# We use OptionParser instead of ArgumentsParse because this script |
||||||
|
# might be run in OS X 10.6 or older, which do not provide the argparse |
||||||
|
# module |
||||||
|
import optparse |
||||||
|
usage = "usage: %prog [options] directory old_prefix new_prefix" |
||||||
|
description = 'Rellocates object files changing the dependant '\ |
||||||
|
' dynamic libraries location path with a new one' |
||||||
|
parser = optparse.OptionParser(usage=usage, description=description) |
||||||
|
parser.add_option('-r', '--recursive', action='store_true', |
||||||
|
default=False, dest='recursive', |
||||||
|
help='Scan directories recursively') |
||||||
|
|
||||||
|
options, args = parser.parse_args() |
||||||
|
if len(args) != 3: |
||||||
|
parser.print_usage() |
||||||
|
exit(1) |
||||||
|
relocator = OSXRelocator(args[0], args[1], args[2], options.recursive) |
||||||
|
relocator.relocate() |
||||||
|
exit(0) |
||||||
|
|
||||||
|
def main(): |
||||||
|
main = Main() |
||||||
|
main.run() |
||||||
|
|
||||||
|
if __name__ == "__main__": |
||||||
|
main() |
||||||
|
|
@ -0,0 +1,99 @@ |
|||||||
|
#!/bin/bash |
||||||
|
# |
||||||
|
# Author: Gus Grubba <mavlink@grubba.com> |
||||||
|
# |
||||||
|
# Copies the regular distribution of the gstreamer framework |
||||||
|
# into the libs directory (to be used for creating the Mac OS |
||||||
|
# bundle). It also prunes unnecessary files and relocates the |
||||||
|
# dynamic libraries. |
||||||
|
# |
||||||
|
# This script is run by the build process and should not be |
||||||
|
# executed manually. |
||||||
|
# |
||||||
|
# Usage: $script [framework destination path] [app bundle path] [qgc executable name] |
||||||
|
# |
||||||
|
# destination is usually: ../libs/lib/Frameworks/ |
||||||
|
# app bundle is something like: /path/qgroundcontrol.app |
||||||
|
# executable name is usually: qgroundcontrol |
||||||
|
|
||||||
|
die () { |
||||||
|
echo "$@" 1>&2 |
||||||
|
exit 1 |
||||||
|
} |
||||||
|
|
||||||
|
GST_VER=1.0 |
||||||
|
GST_ROOT=/Library/Frameworks/GStreamer.framework |
||||||
|
GST_BASE=$GST_ROOT/Versions/$GST_VER |
||||||
|
RELOC=$(dirname $0)/osxrelocator.py |
||||||
|
|
||||||
|
echo "GST Installer" |
||||||
|
[ "$#" -eq 3 ] || die "3 arguments required, $# provided" |
||||||
|
[ -d "$1" ] || die "Could not find $1" |
||||||
|
[ -d "$2" ] || die "Could not find $2" |
||||||
|
|
||||||
|
FMWORK_TARGET=$1 |
||||||
|
BUNDLE_TARGET=$2 |
||||||
|
GST_SOURCE=${1%/}/GStreamer.framework |
||||||
|
GST_TARGET=$GST_SOURCE/Versions/$GST_VER |
||||||
|
QGC_BINARY=$BUNDLE_TARGET/Contents/MacOS/$3 |
||||||
|
[ -e "$QGC_BINARY" ] || die "Could not find $QGC_BINARY" |
||||||
|
|
||||||
|
process_framework() { |
||||||
|
#-- Start looking for the source framework |
||||||
|
[ -d "$GST_ROOT" ] || die "Could not find gstreamer framework in $GST_ROOT" |
||||||
|
[ -d "$GST_BASE" ] || die "Wrong version of gstreamer framework found in $GST_ROOT" |
||||||
|
[ -e $RELOC ] || die "Cannot find $RELOC" |
||||||
|
echo "GST Installer: Copying $GST_ROOT to $FMWORK_TARGET" |
||||||
|
rsync -a --delete "$GST_ROOT" "$FMWORK_TARGET" || die "Error copying $GST_ROOT to $FMWORK_TARGET" |
||||||
|
#-- Prune unused stuff |
||||||
|
rm -rf $GST_TARGET/bin/* |
||||||
|
rm -rf $GST_TARGET/Headers/* |
||||||
|
rm -rf $GST_TARGET/include/* |
||||||
|
rm -rf $GST_TARGET/lib/*.a |
||||||
|
rm -rf $GST_TARGET/lib/*.la |
||||||
|
rm -rf $GST_TARGET/lib/gio/modules/static |
||||||
|
rm -rf $GST_TARGET/lib/glib-2.0 |
||||||
|
rm -rf $GST_TARGET/lib/gst-validate-launcher |
||||||
|
rm -rf $GST_TARGET/lib/gstreamer-1.0/static |
||||||
|
rm -rf $GST_TARGET/lib/libffi-3.0.13 |
||||||
|
rm -rf $GST_TARGET/lib/pkgconfig |
||||||
|
#-- Some dylibs are dupes instead of symlinks. |
||||||
|
#-- This will do a minimum job in trying to clean those. |
||||||
|
#-- Doesn't work. The stupid thing can't load a dlyb symlink. |
||||||
|
#for f in $GST_TARGET/lib/*.dylib |
||||||
|
#do |
||||||
|
# foo=$(basename "$f") |
||||||
|
# bar="${foo%.*}" |
||||||
|
# for i in `seq 0 9`; |
||||||
|
# do |
||||||
|
# if [ -e $GST_TARGET/lib/$bar.$i.dylib ]; then |
||||||
|
# DUPES="$DUPES |
||||||
|
#rm -f $GST_TARGET/lib/$bar.$i.dylib" |
||||||
|
# DUPES="$DUPES |
||||||
|
#ln -s $f $GST_TARGET/lib/$bar.$i.dylib" |
||||||
|
# fi |
||||||
|
# done |
||||||
|
#done |
||||||
|
#IFS=$'\n' |
||||||
|
#for c in $DUPES |
||||||
|
#do |
||||||
|
# eval $c |
||||||
|
#done |
||||||
|
#-- Now relocate the embeded paths |
||||||
|
echo "GST Installer: Relocating" |
||||||
|
python $RELOC -r $GST_TARGET/lib /Library/Frameworks/GStreamer.framework/ @executable_path/../Frameworks/GStreamer.framework/ > /dev/null || die "Error relocating binaries in $GST_TARGET/lib" |
||||||
|
python $RELOC -r $GST_TARGET/libexec /Library/Frameworks/GStreamer.framework/ @executable_path/../Frameworks/GStreamer.framework/ > /dev/null || die "Error relocating binaries in $GST_TARGET/libexec" |
||||||
|
} |
||||||
|
|
||||||
|
#-- Check and see if we've already processed the framework |
||||||
|
echo "GST Installer: Checking $GST_TARGET" |
||||||
|
[ -d $GST_TARGET ] || process_framework |
||||||
|
#-- Now copy the framework to the app bundle |
||||||
|
echo "GST Installer: Copying $GST_SOURCE to $BUNDLE_TARGET/Contents/Frameworks/" |
||||||
|
rsync -a --delete $GST_SOURCE $BUNDLE_TARGET/Contents/Frameworks/ || die "Error copying framework into app bundle" |
||||||
|
#-- Move this gst binary to MacOS |
||||||
|
mv $BUNDLE_TARGET/Contents/Frameworks/GStreamer.framework/Versions/1.0/libexec/gstreamer-1.0/gst-plugin-scanner $BUNDLE_TARGET/Contents/MacOS/ || die "Error moving gst-plugin-scanner" |
||||||
|
#-- Fix main binary |
||||||
|
python $RELOC $QGC_BINARY /Library/Frameworks/GStreamer.framework/ @executable_path/../Frameworks/GStreamer.framework/ > /dev/null || die "Error relocating $QGC_BINARY" |
||||||
|
|
||||||
|
|
Loading…
Reference in new issue