From 335e3cf6203327b3ce1ee6e47c09a8139232317c Mon Sep 17 00:00:00 2001 From: Marcus Eggenberger Date: Fri, 27 Jun 2008 17:14:41 +0200 Subject: [PATCH] Mac OS X only: added deployment scripts. Finally managed to cope with 10.4 SDK and cmake... -.- --- CMakeLists.txt | 19 +++-- scripts/build/macosx_DeployApp.py | 113 ++++++++++++++++++++++++++++ scripts/build/macosx_makePackage.sh | 59 +++++++++++++++ scripts/build/macosx_makebundle.py | 9 +++ 4 files changed, 193 insertions(+), 7 deletions(-) create mode 100755 scripts/build/macosx_DeployApp.py create mode 100755 scripts/build/macosx_makePackage.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f074e84..16dac306 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,7 @@ # -DQT=/path/to/qt : Choose a Qt4 installation to use instead of the system Qt4 # -DSTATIC=ON : Enable static building of Quassel. Use with care. # -DSPUTDEV=ON : Do not use. +# -DDEPLOY=ON : Mac OS X only. Use only fore redistribution Quassel Packages!! # # NOTE: You need to remove CMakeCache.txt if you plan to change any of these values! @@ -27,6 +28,7 @@ option(WANT_QTCLIENT "Build the Qt4 GUI client binary" ON) option(WANT_MONO "Build the monolithic (all-in-one) binary" OFF) option(STATIC "Enable static building (might not be portable)" OFF) +option(DEPLOY "Mac OS X only! Adds required libs to bundle resources and create a dmg. Note: requires Qt to be built with 10.4u SDK" OFF) option(SPUTDEV "Do not use!" OFF) set(QT "" CACHE STRING "Path to a Qt installation to use instead of the system Qt") @@ -54,10 +56,11 @@ endif(CMAKE_COMPILER_IS_GNUCXX) set(QT_MIN_VERSION "4.3.0") -if(APPLE) +if(APPLE AND DEPLOY) set(CMAKE_OSX_ARCHITECTURES "i386;ppc") -# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.4") -endif(APPLE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.4") + set(CMAKE_OSX_SYSROOT "/Developer/SDKs/MacOSX10.4u.sdk/") +endif(APPLE AND DEPLOY) # Enable mostly b0rked stuff (new ChatView), do not enable this unless you know what you do... if(SPUTDEV) @@ -83,10 +86,6 @@ include_directories(${QT_INCLUDES}) # We need to create a version.gen # For this, we create our genversion binary and make sure it is run every time. add_executable(genversion ${CMAKE_SOURCE_DIR}/src/common/genversion.cpp) -#set_target_properties(genversion PROPERTIES -# LINK_FLAGS "-mmacosx-version-min=10.4") -# COMPILE_FLAGS "-mmacosx-version-min=10.4" - target_link_libraries(genversion ${QT_LIBRARIES} ${QT_CORE_LIB_DEPENDENCIES}) add_custom_target(genversion_run ALL ${CMAKE_BINARY_DIR}/genversion @@ -195,6 +194,12 @@ if(APPLE) add_custom_command(TARGET quassel POST_BUILD COMMAND ${CMAKE_SOURCE_DIR}/scripts/build/macosx_makebundle.py ${CMAKE_SOURCE_DIR} "Quassel" quassel) + if(DEPLOY) + add_custom_command(TARGET quasselclient POST_BUILD + COMMAND ${CMAKE_SOURCE_DIR}/scripts/build/macosx_makePackage.sh Client) + add_custom_command(TARGET quasselcore POST_BUILD + COMMAND ${CMAKE_SOURCE_DIR}/scripts/build/macosx_makePackage.sh Core) + endif(DEPLOY) endif(APPLE) # Install rules diff --git a/scripts/build/macosx_DeployApp.py b/scripts/build/macosx_DeployApp.py new file mode 100755 index 00000000..4be32f7f --- /dev/null +++ b/scripts/build/macosx_DeployApp.py @@ -0,0 +1,113 @@ +#!/usr/bin/python +# -*- coding: iso-8859-1 -*- + +################################################################################ +# # +# 2008 June 27th by Marcus 'EgS' Eggenberger # +# # +# The author disclaims copyright to this source code. # +# This Python Script is in the PUBLIC DOMAIN. # +# # +################################################################################ + +# ============================== +# Imports +# ============================== +import sys +import os + +class InstallQt(object): + def __init__(self, appdir, bundle = True): + self.appDir = appdir + self.bundle = bundle + self.executableDir = self.appDir + if bundle: + self.executableDir += "/MacOS" + + if bundle: + self.frameworkDir = self.appDir + "/Frameworks" + else: + self.frameworkDir = self.executableDir + "/Frameworks" + + self.needFrameworks = [] + + executables = [self.executableDir + "/" + executable for executable in os.listdir(self.executableDir)] + + for executable in executables: + for framework,lib in self.determineDependancies(executable): + if framework not in self.needFrameworks: + self.needFrameworks.append(framework) + self.installFramework(framework) + self.changeDylPath(executable) + + def installFramework(self, framework): + try: + os.mkdir(self.frameworkDir) + except: + pass + + # Copy Framework + os.system('cp -R "%s" "%s"' % (framework, self.frameworkDir)) + + frameworkname = framework.split('/')[-1] + localframework = self.frameworkDir + "/" + frameworkname + + # De-Myllify + os.system('find "%s" -name *debug* -exec rm -f {} \;' % localframework) + os.system('find "%s" -name Headers -exec rm -rf {} \; 2>/dev/null' % localframework) + + # Install new Lib ID and Change Path to Frameworks for the Dynamic linker + for lib in os.listdir(localframework + "/Versions/Current"): + lib = "%s/Versions/Current/%s" % (localframework, lib) + otoolpipe = os.popen('otool -D "%s"' % lib) + libname = [line for line in otoolpipe][1].strip() + otoolpipe.close() + frameworkpath, libpath = libname.split(frameworkname) + if self.bundle: + newlibname = "@executable_path/../%s%s" % (frameworkname, libpath) + else: + newlibname = "@executable_path/%s%s" % (frameworkname, libpath) + #print 'install_name_tool -id "%s" "%s"' % (newlibname, lib) + os.system('install_name_tool -id "%s" "%s"' % (newlibname, lib)) + self.changeDylPath(lib) + + def determineDependancies(self, app): + otoolPipe = os.popen('otool -L "%s"' % app) + otoolOutput = [line for line in otoolPipe] + otoolPipe.close() + libs = [line.split()[0] for line in otoolOutput[1:] if "Qt" in line and not "@executable_path" in line] + frameworks = [lib[:lib.find(".framework")+len(".framework")] for lib in libs] + return zip(frameworks, libs) + + def changeDylPath(self, obj): + for framework, lib in self.determineDependancies(obj): + frameworkname = framework.split('/')[-1] + frameworkpath, libpath = lib.split(frameworkname) + if self.bundle: + newlibname = "@executable_path/../Frameworks/%s%s" % (frameworkname, libpath) + else: + newlibname = "@executable_path/Frameworks/%s%s" % (frameworkname, libpath) + + #print 'install_name_tool -change "%s" "%s" "%s"' % (lib, newlibname, obj) + os.system('install_name_tool -change "%s" "%s" "%s"' % (lib, newlibname, obj)) + +if __name__ == "__main__": + if len(sys.argv) < 2: + print "Wrong Argument Count (Syntax: %s [--nobundle] $TARGET_APP)" % sys.argv[0] + sys.exit(1) + else: + bundle = True + offset = 1 + + if sys.argv[1].startswith("--"): + offset = 2 + if sys.argv[1] == "--nobundle": + bundle = False + + targetDir = sys.argv[offset] + if bundle: + targetDir += "/Contents" + + InstallQt(targetDir, bundle) + + diff --git a/scripts/build/macosx_makePackage.sh b/scripts/build/macosx_makePackage.sh new file mode 100755 index 00000000..35b4f884 --- /dev/null +++ b/scripts/build/macosx_makePackage.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +myname=$0 +if [ -s "$myname" ] && [ -x "$myname" ]; then + # $myname is already a valid file name + + mypath=$myname +else + case "$myname" in + /*) exit 1;; # absolute path - do not search PATH + *) + # Search all directories from the PATH variable. Take + # care to interpret leading and trailing ":" as meaning + # the current directory; the same is true for "::" within + # the PATH. + + # Replace leading : with . in PATH, store in p + p=${PATH/#:/.:} + # Replace trailing : with . + p=${p//%:/:.} + # Replace :: with :.: + p=${p//::/:.:} + # Temporary input field separator, see FAQ #1 + OFS=$IFS IFS=: + # Split the path on colons and loop through each of them + for dir in $p; do + [ -f "$dir/$myname" ] || continue # no file + [ -x "$dir/$myname" ] || continue # not executable + mypath=$dir/$myname + break # only return first matching file + done + # Restore old input field separator + IFS=$OFS + ;; + esac +fi + +if [ ! -f "$mypath" ]; then + echo >&2 "cannot find full path name: $myname" + exit 1 +fi + +SCRIPTDIR=$(dirname $mypath) +QUASSEL_VERSION=$(git-describe) +BUILDTYPE=$1 +if [[ $BUILDTYPE = "Core" ]] || [[ $BUILDTYPE = "Client" ]]; then + QUASSEL_DMG="Quassel${BUILDTYPE}_MacOSX-universal_${QUASSEL_VERSION}.dmg" + mkdir $BUILDTYPE + if [[ $BUILDTYPE = "Client" ]]; then + cp -r Quassel\ Client.app Client/ + ${SCRIPTDIR}/macosx_DeployApp.py "Client/Quassel Client.app" + else + cp quasselcore Core/ + ${SCRIPTDIR}/macosx_DeployApp.py --nobundle Core + fi + hdiutil create -srcfolder ${BUILDTYPE} -format UDBZ -volname "Quassel ${BUILDTYPE} - ${QUASSEL_VERSION}" "Quassel${BUILDTYPE}_MacOSX-universal_${QUASSEL_VERSION}.dmg" >/dev/null +else + echo >&2 "Valid parameters are \"Client\" or \"Core\"" +fi diff --git a/scripts/build/macosx_makebundle.py b/scripts/build/macosx_makebundle.py index 821ce74e..72e73793 100755 --- a/scripts/build/macosx_makebundle.py +++ b/scripts/build/macosx_makebundle.py @@ -1,6 +1,15 @@ #!/usr/bin/python # -*- coding: iso-8859-1 -*- +################################################################################ +# # +# 2008 June 27th by Marcus 'EgS' Eggenberger # +# # +# The author disclaims copyright to this source code. # +# This Python Script is in the PUBLIC DOMAIN. # +# # +################################################################################ + # ============================== # Imports # ============================== -- 2.20.1