10 changed files with 344 additions and 20 deletions
@ -0,0 +1,160 @@
@@ -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 @@
@@ -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