From 9a5845365bdcbca0c4dea36342e81bdb3e417c46 Mon Sep 17 00:00:00 2001
From: Vicki Pfau <vi@endrift.com>
Date: Wed, 22 Mar 2017 14:26:02 -0700
Subject: [PATCH] Tools: Replace deploy-mac with BundleUtilities

---
 src/platform/qt/CMakeLists.txt |  23 ++---
 tools/deploy-mac.py            | 170 ---------------------------------
 2 files changed, 12 insertions(+), 181 deletions(-)
 delete mode 100755 tools/deploy-mac.py

diff --git a/src/platform/qt/CMakeLists.txt b/src/platform/qt/CMakeLists.txt
index cb98d95e9..485a6d6f5 100644
--- a/src/platform/qt/CMakeLists.txt
+++ b/src/platform/qt/CMakeLists.txt
@@ -245,15 +245,16 @@ if(APPLE OR WIN32)
 	set_target_properties(${BINARY_NAME}-qt PROPERTIES OUTPUT_NAME ${PROJECT_NAME})
 endif()
 if(APPLE)
-	set(DEPLOY_OPTIONS -p platforms/libqcocoa.dylib,audio/libqtaudio_coreaudio.dylib)
-	if(NOT CMAKE_INSTALL_NAME_TOOL EQUAL "install_name_tool")
-		set(DEPLOY_OPTIONS ${DEPLOY_OPTIONS} -I ${CMAKE_INSTALL_NAME_TOOL})
-	endif()
-	if(DEFINED CMAKE_OTOOL AND NOT CMAKE_OTOOL EQUAL "otool")
-		set(DEPLOY_OPTIONS ${DEPLOY_OPTIONS} -O ${CMAKE_OTOOL})
-	endif()
-	if(DEFINED CROSS_ROOT)
-		set(DEPLOY_OPTIONS ${DEPLOY_OPTIONS} -R ${CROSS_ROOT})
-	endif()
-	add_custom_command(TARGET ${BINARY_NAME}-qt POST_BUILD COMMAND ${CMAKE_SOURCE_DIR}/tools/deploy-mac.py ${DEPLOY_OPTIONS} ${PROJECT_NAME}.app)
+	get_target_property(QTCOCOA Qt5::QCocoaIntegrationPlugin LOCATION)
+	get_target_property(COREAUDIO Qt5::CoreAudioPlugin LOCATION)
+	get_target_property(BUNDLE_PATH ${BINARY_NAME}-qt LOCATION)
+	target_sources(${BINARY_NAME}-qt PRIVATE "${PLUGINS}")
+	set_source_files_properties("${QTCOCOA}" PROPERTIES MACOSX_PACKAGE_LOCATION Contents/PlugIns)
+	set_source_files_properties("${COREAUDIO}" PROPERTIES MACOSX_PACKAGE_LOCATION Contents/PlugIns)
+	install(CODE "
+	   include(BundleUtilities)
+	   set(BU_CHMOD_BUNDLE_ITEMS ON)
+	   file(GLOB_RECURSE PLUGINS \"${BUNDLE_PATH}/Contents/PlugIns/*${CMAKE_SHARED_LIBRARY_SUFFIX}\")
+	   fixup_bundle(\"${BUNDLE_PATH}\"   \"${PLUGINS}\"   \"\")
+	   " COMPONENT ${BINARY_NAME}-qt)
 endif()
diff --git a/tools/deploy-mac.py b/tools/deploy-mac.py
deleted file mode 100755
index e525e3012..000000000
--- a/tools/deploy-mac.py
+++ /dev/null
@@ -1,170 +0,0 @@
-#!/usr/bin/env python
-from __future__ import print_function
-import argparse
-import errno
-import os
-import re
-import shutil
-import subprocess
-
-qtPath = None
-verbose = False
-
-def splitPath(path):
-	folders = []
-	while True:
-		path, folder = os.path.split(path)
-		if folder != '':
-			folders.append(folder)
-		else:
-			if path != '':
-				folders.append(path)
-			break
-	folders.reverse()
-	return folders
-
-def joinPath(path):
-	return reduce(os.path.join, path, '')
-
-def findFramework(path):
-	child = []
-	while path and not path[-1].endswith('.framework'):
-		child.append(path.pop())
-	child.reverse()
-	return path, child
-
-def findQtPath(path):
-	parent, child = findFramework(splitPath(path))
-	return joinPath(parent[:-2])
-
-def makedirs(path):
-	split = splitPath(path)
-	accum = []
-	split.reverse()
-	while split:
-		accum.append(split.pop())
-		newPath = joinPath(accum)
-		if newPath == '/':
-			continue
-		try:
-			os.mkdir(newPath)
-		except OSError as e:
-			if e.errno != errno.EEXIST:
-				raise
-
-
-def parseOtoolLine(line, execPath, root):
-	if not line.startswith('\t'):
-		return None, None, None, None
-	line = line[1:]
-	match = re.match('([@/].*) \(compatibility version.*\)', line)
-	path = match.group(1)
-	split = splitPath(path)
-	newExecPath = ['@executable_path', '..', 'Frameworks']
-	newPath = execPath[:-1]
-	newPath.append('Frameworks')
-	if split[:3] == ['/', 'usr', 'lib'] or split[:2] == ['/', 'System']:
-		return None, None, None, None
-	if split[0] == '@executable_path':
-		split[:1] = execPath
-	if split[0] == '/' and not os.access(joinPath(split), os.F_OK):
-		split[:1] = root
-	oldPath = os.path.realpath(joinPath(split))
-	split = splitPath(oldPath)
-	isFramework = False
-	if not split[-1].endswith('.dylib'):
-		isFramework = True
-		split, framework = findFramework(split)
-	newPath.append(split[-1])
-	newExecPath.append(split[-1])
-	if isFramework:
-		newPath.extend(framework)
-		newExecPath.extend(framework)
-		split.extend(framework)
-	newPath = joinPath(newPath)
-	newExecPath = joinPath(newExecPath)
-	return joinPath(split), newPath, path, newExecPath
-
-def updateMachO(bin, execPath, root):
-	global qtPath
-	otoolOutput = subprocess.check_output([otool, '-L', bin])
-	toUpdate = []
-	for line in otoolOutput.split('\n'):
-		oldPath, newPath, oldExecPath, newExecPath = parseOtoolLine(line, execPath, root)
-		if not newPath:
-			continue
-		if os.access(newPath, os.F_OK):
-			if verbose:
-				print('Skipping copying {}, already done.'.format(oldPath))
-			newPath = None
-		elif os.path.abspath(oldPath) != os.path.abspath(newPath):
-			if verbose:
-				print('Copying {} to {}...'.format(oldPath, newPath))
-			parent, child = os.path.split(newPath)
-			makedirs(parent)
-			shutil.copy2(oldPath, newPath)
-			os.chmod(newPath, 0o644)
-		toUpdate.append((newPath, oldExecPath, newExecPath))
-		if not qtPath and 'Qt' in oldPath:
-			qtPath = findQtPath(oldPath)
-			if verbose:
-				print('Found Qt path at {}.'.format(qtPath))
-	args = [installNameTool]
-	for path, oldExecPath, newExecPath in toUpdate:
-		if path != bin:
-			if path:
-				updateMachO(path, execPath, root)
-			if verbose:
-				print('Updating Mach-O load from {} to {}...'.format(oldExecPath, newExecPath))
-			args.extend(['-change', oldExecPath, newExecPath])
-		else:
-			if verbose:
-				print('Updating Mach-O id from {} to {}...'.format(oldExecPath, newExecPath))
-			args.extend(['-id', newExecPath])
-	args.append(bin)
-	subprocess.check_call(args)
-
-if __name__ == '__main__':
-	parser = argparse.ArgumentParser()
-	parser.add_argument('-R', '--root', metavar='ROOT', default='/', help='root directory to search')
-	parser.add_argument('-I', '--install-name-tool', metavar='INSTALL_NAME_TOOL', default='install_name_tool', help='path to install_name_tool')
-	parser.add_argument('-O', '--otool', metavar='OTOOL', default='otool', help='path to otool')
-	parser.add_argument('-p', '--qt-plugins', metavar='PLUGINS', default='', help='Qt plugins to include (comma-separated)')
-	parser.add_argument('-v', '--verbose', action='store_true', default=False, help='output more information')
-	parser.add_argument('bundle', help='application bundle to deploy')
-	args = parser.parse_args()
-
-	otool = args.otool
-	installNameTool = args.install_name_tool
-	verbose = args.verbose
-
-	try:
-		shutil.rmtree(os.path.join(args.bundle, 'Contents/Frameworks/'))
-	except OSError as e:
-		if e.errno != errno.ENOENT:
-			raise
-
-	for executable in os.listdir(os.path.join(args.bundle, 'Contents/MacOS')):
-		if executable.endswith('.dSYM'):
-			continue
-		fullPath = os.path.join(args.bundle, 'Contents/MacOS/', executable)
-		updateMachO(fullPath, splitPath(os.path.join(args.bundle, 'Contents/MacOS')), splitPath(args.root))
-	if args.qt_plugins:
-		try:
-			shutil.rmtree(os.path.join(args.bundle, 'Contents/PlugIns/'))
-		except OSError as e:
-			if e.errno != errno.ENOENT:
-				raise
-		makedirs(os.path.join(args.bundle, 'Contents/PlugIns'))
-		makedirs(os.path.join(args.bundle, 'Contents/Resources'))
-		with open(os.path.join(args.bundle, 'Contents/Resources/qt.conf'), 'w') as conf:
-			conf.write('[Paths]\nPlugins = PlugIns\n')
-		plugins = args.qt_plugins.split(',')
-		for plugin in plugins:
-			plugin = plugin.strip()
-			kind, plug = os.path.split(plugin)
-			newDir = os.path.join(args.bundle, 'Contents/PlugIns/', kind)
-			makedirs(newDir)
-			newPath = os.path.join(newDir, plug)
-			shutil.copy2(os.path.join(qtPath, 'plugins', plugin), newPath)
-			updateMachO(newPath, splitPath(os.path.join(args.bundle, 'Contents/MacOS')), splitPath(args.root))