macOS: Use macdeployqt instead of the old admin/osx/macdeployqt.py
authorMichael Schuster <michael@schuster.ms>
Wed, 22 Jan 2020 03:53:03 +0000 (04:53 +0100)
committerMichael Schuster <michael@schuster.ms>
Sun, 7 Jun 2020 12:39:42 +0000 (14:39 +0200)
In order to build the new 2.7 releases (new QML dependencies) without manually
modifying the old Python script each time, rely on Qt's standard tool instead.

This should streamline the build systems for upcoming dependency changes.

Signed-off-by: Michael Schuster <michael@schuster.ms>
admin/osx/macdeployqt.py [deleted file]
src/cmd/CMakeLists.txt
src/crashreporter/CMakeLists.txt
src/gui/CMakeLists.txt

diff --git a/admin/osx/macdeployqt.py b/admin/osx/macdeployqt.py
deleted file mode 100755 (executable)
index fbf4a19..0000000
+++ /dev/null
@@ -1,366 +0,0 @@
-#!/usr/bin/python
-#  This file is part of ownCloud.
-#  It was inspired in large part by the macdeploy script in Clementine
-#  and Tomahawk
-#
-#  ownCloud is free software: you can redistribute it and/or modify
-#  it under the terms of the GNU General Public License as published by
-#  the Free Software Foundation; either version 2 of the License, or
-#  (at your option) any later version.
-#
-#  ownCLoud 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 General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with ownCloud.  If not, see <http://www.gnu.org/licenses/>.
-
-from __future__ import print_function
-import os
-import re
-import subprocess
-import commands
-import sys
-from glob import glob
-from distutils.version import LooseVersion
-
-def QueryQMake(attrib):
-    return subprocess.check_output([qmake_path, '-query', attrib]).rstrip('\n')
-
-FRAMEWORK_SEARCH_PATH=[
-    '/Library/Frameworks',
-    os.path.join(os.environ['HOME'], 'Library/Frameworks')
-]
-
-LIBRARY_SEARCH_PATH=['/usr/local/lib', '/usr/local/Qt-5.12.5/lib', '.']
-
-QT_PLUGINS = [
-    'sqldrivers/libqsqlite.dylib',
-    'platforms/libqcocoa.dylib',
-    'styles/libqmacstyle.dylib',
-    'imageformats/libqgif.dylib',
-    'imageformats/libqico.dylib',
-    'imageformats/libqjpeg.dylib',
-    'imageformats/libqsvg.dylib',
-]
-
-QT_PLUGINS_SEARCH_PATH=[
-#    os.path.join(os.environ['QTDIR'], 'plugins'),
-#    '/usr/local/Cellar/qt/5.2.1/plugins',
-    '/usr/local/Qt-5.12.5/plugins',
-]
-
-
-class Error(Exception):
-  pass
-
-
-class CouldNotFindQtPluginErrorFindFrameworkError(Error):
-  pass
-
-
-class InstallNameToolError(Error):
-  pass
-
-
-class CouldNotFindQtPluginError(Error):
-  pass
-
-
-class CouldNotFindScriptPluginError(Error):
-  pass
-
-class CouldNotFindFrameworkError(Error):
-  pass
-
-if len(sys.argv) < 3:
-  print('Usage: %s <bundle.app> <path-to-qmake>' % sys.argv[0])
-  exit()
-
-def is_exe(fpath):
-  return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
-
-bundle_dir = sys.argv[1]
-qmake_path = sys.argv[2]
-
-bundle_name = os.path.basename(bundle_dir).split('.')[0]
-
-commands = []
-
-binary_dir = os.path.join(bundle_dir, 'Contents', 'MacOS')
-frameworks_dir = os.path.join(bundle_dir, 'Contents', 'Frameworks')
-commands.append(['mkdir', '-p', frameworks_dir])
-resources_dir = os.path.join(bundle_dir, 'Contents', 'Resources')
-commands.append(['mkdir', '-p', resources_dir])
-plugins_dir = os.path.join(bundle_dir, 'Contents', 'PlugIns')
-binaries = [i for i in glob(os.path.join(bundle_dir, 'Contents', 'MacOS', "*")) if is_exe(i)];
-
-qt_version = QueryQMake('QT_VERSION')
-print("Using Qt", qt_version)
-
-fixed_libraries = []
-fixed_frameworks = []
-
-def WriteQtConf():
-  print("Writing qt.conf...")
-  with open(os.path.join(resources_dir, 'qt.conf'), 'w') as f:
-    f.write("[Paths]\nPlugins = PlugIns\n");
-    f.close()
-
-def GetBrokenLibraries(binary):
-  #print "Checking libs for binary: %s" % binary
-  output = subprocess.Popen(['otool', '-L', binary], stdout=subprocess.PIPE).communicate()[0]
-  broken_libs = {
-      'frameworks': [],
-      'libs': []}
-  for line in [x.split(' ')[0].lstrip() for x in output.split('\n')[1:]]:
-    #print "Checking line: %s" % line
-    if not line:  # skip empty lines
-      continue
-    if os.path.basename(binary) == os.path.basename(line):
-      #print "mnope %s-%s" % (os.path.basename(binary), os.path.basename(line))
-      continue
-    if re.match(r'^\s*/System/', line):
-      continue  # System framework
-    elif re.match(r'^\s*/usr/lib/', line):
-      #print "unix style system lib"
-      continue  # unix style system library
-    elif re.match(r'Breakpad', line):
-      continue  # Manually added by cmake.
-    elif re.match(r'^\s*@executable_path', line) or re.match(r'^\s*@loader_path', line):
-      # Potentially already fixed library
-      if '.framework' in line:
-        relative_path = os.path.join(*line.split('/')[3:])
-        if not os.path.exists(os.path.join(frameworks_dir, relative_path)):
-          broken_libs['frameworks'].append(relative_path)
-      else:
-        relative_path = os.path.join(*line.split('/')[1:])
-        #print "RELPATH %s %s" % (relative_path, os.path.join(binary_dir, relative_path))
-        if not os.path.exists(os.path.join(binary_dir, relative_path)):
-          broken_libs['libs'].append(relative_path)
-    elif re.search(r'\w+\.framework', line):
-      broken_libs['frameworks'].append(line)
-    else:
-      broken_libs['libs'].append(line)
-
-  return broken_libs
-
-def FindFramework(path):
-  search_pathes = FRAMEWORK_SEARCH_PATH
-  search_pathes.insert(0, QueryQMake('QT_INSTALL_LIBS'))
-  for search_path in search_pathes:
-    # The following two lines are needed for a custom built Qt from version 5.5 on, possibly not for the one from the Qt SDK.
-    # Looks like the upstream macdeployqt also had an issue there https://bugreports.qt.io/browse/QTBUG-47868
-    if path.find( "\@rpath/"):
-      path = path.replace("@rpath/", "")
-    abs_path = os.path.join(search_path, path)
-    if os.path.exists(abs_path):
-      return abs_path
-
-  raise CouldNotFindFrameworkError(path)
-
-def FindLibrary(path):
-  if os.path.exists(path):
-    return path
-  search_pathes = LIBRARY_SEARCH_PATH
-  search_pathes.insert(0, QueryQMake('QT_INSTALL_LIBS'))
-  for search_path in search_pathes:
-    abs_path = os.path.join(search_path, path)
-    if os.path.exists(abs_path):
-      return abs_path
-    else: # try harder---look for lib name in library folders
-      newpath = os.path.join(search_path,os.path.basename(path))
-      if os.path.exists(newpath):
-        return newpath
-
-  return ""
-  #raise CouldNotFindFrameworkError(path)
-
-def FixAllLibraries(broken_libs):
-  for framework in broken_libs['frameworks']:
-    FixFramework(framework)
-  for lib in broken_libs['libs']:
-    FixLibrary(lib)
-
-def FixFramework(path):
-  if path in fixed_libraries:
-    return
-  else:
-    fixed_libraries.append(path)
-  abs_path = FindFramework(path)
-  broken_libs = GetBrokenLibraries(abs_path)
-  FixAllLibraries(broken_libs)
-
-  new_path = CopyFramework(abs_path)
-  id = os.sep.join(new_path.split(os.sep)[3:])
-  FixFrameworkId(new_path, id)
-  for framework in broken_libs['frameworks']:
-    FixFrameworkInstallPath(framework, new_path)
-  for library in broken_libs['libs']:
-    FixLibraryInstallPath(library, new_path)
-
-def FixLibrary(path):
-  if path in fixed_libraries or FindSystemLibrary(os.path.basename(path)) is not None:
-    return
-  else:
-    fixed_libraries.append(path)
-  abs_path = FindLibrary(path)
-  if abs_path == "":
-    print("Could not resolve %s, not fixing!" % path)
-    return
-  broken_libs = GetBrokenLibraries(abs_path)
-  FixAllLibraries(broken_libs)
-
-  new_path = CopyLibrary(abs_path)
-  FixLibraryId(new_path)
-  for framework in broken_libs['frameworks']:
-    FixFrameworkInstallPath(framework, new_path)
-  for library in broken_libs['libs']:
-    FixLibraryInstallPath(library, new_path)
-
-def FixPlugin(abs_path, subdir):
-  broken_libs = GetBrokenLibraries(abs_path)
-  FixAllLibraries(broken_libs)
-
-  new_path = CopyPlugin(abs_path, subdir)
-  for framework in broken_libs['frameworks']:
-    FixFrameworkInstallPath(framework, new_path)
-  for library in broken_libs['libs']:
-    FixLibraryInstallPath(library, new_path)
-
-def FixBinary(path):
-  broken_libs = GetBrokenLibraries(path)
-  FixAllLibraries(broken_libs)
-  for framework in broken_libs['frameworks']:
-    FixFrameworkInstallPath(framework, path)
-  for library in broken_libs['libs']:
-    FixLibraryInstallPath(library, path)
-
-def CopyLibrary(path):
-  new_path = os.path.join(binary_dir, os.path.basename(path))
-  args = ['ditto', '--arch=x86_64', path, new_path]
-  commands.append(args)
-  args = ['chmod', 'u+w', new_path]
-  commands.append(args)
-  return new_path
-
-def CopyPlugin(path, subdir):
-  new_path = os.path.join(plugins_dir, subdir, os.path.basename(path))
-  args = ['mkdir', '-p', os.path.dirname(new_path)]
-  commands.append(args)
-  args = ['ditto', '--arch=x86_64', path, new_path]
-  commands.append(args)
-  args = ['chmod', 'u+w', new_path]
-  commands.append(args)
-  return new_path
-
-def CopyFramework(source_dylib):
-  parts = source_dylib.split(os.sep)
-  print("CopyFramework:", source_dylib)
-  for i, part in enumerate(parts):
-    matchObj = re.match(r'(\w+\.framework)', part)
-    if matchObj:
-      framework = matchObj.group(1)
-      dylib_name = parts[-1]
-      source_path = os.path.join('/', *parts[:i+1])
-      dest_path = os.path.join(frameworks_dir, framework)
-      dest_dylib_path = os.path.join(frameworks_dir, *parts[i:-1])
-      break
-#  if os.path.exists(dest_path):
-#    print dest_path, "already exists, skipping copy..."
-#    return os.path.join(dest_dylib_path, dylib_name)
-
-  args = ['mkdir', '-p', dest_dylib_path]
-  commands.append(args)
-  args = ['ditto', '--arch=x86_64', source_dylib, dest_dylib_path]
-  commands.append(args)
-  args = ['chmod', 'u+w', os.path.join(dest_dylib_path, parts[-1])]
-  commands.append(args)
-  args = ['ln', '-s', '5', os.path.join(dest_path, 'Versions', 'Current')]
-  commands.append(args)
-  args = ['ln', '-s', os.path.join('Versions', 'Current', dylib_name), os.path.join(dest_path, dylib_name)]
-  commands.append(args)
-  args = ['ln', '-s', os.path.join('Versions', 'Current', 'Resources'), os.path.join(dest_path, 'Resources')]
-  commands.append(args)
-  args = ['cp', '-r', os.path.join(source_path, 'Versions', '5', 'Resources'), os.path.join(dest_path, 'Versions', '5')]
-  commands.append(args)
-  args = ['ln', '-s', os.path.join('Versions', 'Current', 'Helpers'), os.path.join(dest_path, 'Helpers')]
-  commands.append(args)
-  args = ['cp', '-r', os.path.join(source_path, 'Versions', '5', 'Helpers'), os.path.join(dest_path, 'Versions', '5')]
-  commands.append(args)
-
-  return os.path.join(dest_dylib_path, dylib_name)
-
-def FixId(path, library_name):
-  id = '@executable_path/../Frameworks/%s' % library_name
-  args = ['install_name_tool', '-id', id, path]
-  commands.append(args)
-
-def FixLibraryId(path):
-  library_name = os.path.basename(path)
-  FixId(path, library_name)
-
-def FixFrameworkId(path, id):
-  FixId(path, id)
-
-def FixInstallPath(library_path, library, new_path):
-  args = ['install_name_tool', '-change', library_path, new_path, library]
-  commands.append(args)
-
-def FindSystemLibrary(library_name):
-  for path in ['/lib', '/usr/lib']:
-    full_path = os.path.join(path, library_name)
-    if os.path.exists(full_path):
-      return full_path
-  return None
-
-def FixLibraryInstallPath(library_path, library):
-  system_library = FindSystemLibrary(os.path.basename(library_path))
-  if system_library is None:
-    new_path = '@executable_path/../MacOS/%s' % os.path.basename(library_path)
-    FixInstallPath(library_path, library, new_path)
-  else:
-    FixInstallPath(library_path, library, system_library)
-
-def FixFrameworkInstallPath(library_path, library):
-  parts = library_path.split(os.sep)
-  for i, part in enumerate(parts):
-    if re.match(r'\w+\.framework', part):
-      full_path = os.path.join(*parts[i:])
-      break
-  new_path = '@executable_path/../Frameworks/%s' % full_path
-  FixInstallPath(library_path, library, new_path)
-
-def FindQtPlugin(name):
-  search_path = QT_PLUGINS_SEARCH_PATH
-  search_path.insert(0, QueryQMake('QT_INSTALL_PLUGINS'))
-  for path in search_path:
-    if os.path.exists(path):
-      if os.path.exists(os.path.join(path, name)):
-        return os.path.join(path, name)
-  raise CouldNotFindQtPluginError(name)
-
-for binary in binaries:
-  FixBinary(binary)
-
-for plugin in QT_PLUGINS:
-  FixPlugin(FindQtPlugin(plugin), os.path.dirname(plugin))
-
-if LooseVersion(qt_version) >= LooseVersion("5.10.0"):
-  args = ['plutil', '-insert', 'LSMinimumSystemVersion', '-string', '10.10.0', os.path.join(bundle_dir, 'Contents', 'Info.plist')]
-  commands.append(args)
-else:
-  args = ['plutil', '-insert', 'LSMinimumSystemVersion', '-string', '10.7.0', os.path.join(bundle_dir, 'Contents', 'Info.plist')]
-  commands.append(args)
-
-if len(sys.argv) <= 2:
-  print('Will run %d commands:' % len(commands))
-  for command in commands:
-    print(' '.join(command))
-
-for command in commands:
-  p = subprocess.Popen(command)
-  os.waitpid(p.pid, 0)
-
-WriteQtConf()
index 6b0d0b0dcc9a80d400d2308a508157e44df3440f..722fc1284c196ef1080d2a592edde1a172f6f3e5 100644 (file)
@@ -46,10 +46,15 @@ endif()
 # currently it needs to be done because the code right above needs to be executed no matter
 # if building a bundle or not and the install_qt4_executable needs to be called afterwards
 if(BUILD_OWNCLOUD_OSX_BUNDLE AND NOT BUILD_LIBRARIES_ONLY)
-   get_target_property (QT_QMAKE_EXECUTABLE Qt5::qmake IMPORTED_LOCATION)
-   install(CODE "
-    message(STATUS \"Deploying (Qt) dependencies and fixing library paths...\")
-    execute_process(COMMAND \"${CMAKE_SOURCE_DIR}/admin/osx/macdeployqt.py\" ${CMAKE_INSTALL_PREFIX}/${OWNCLOUD_OSX_BUNDLE} ${QT_QMAKE_EXECUTABLE})
-    execute_process(COMMAND \"${CMAKE_SOURCE_DIR}/admin/osx/macdeployqt.py\" ${CMAKE_INSTALL_PREFIX}/${OWNCLOUD_OSX_BUNDLE}/Contents/Frameworks/QtWebEngineCore.framework/Helpers/QtWebEngineProcess.app ${QT_QMAKE_EXECUTABLE})
-    " COMPONENT RUNTIME)
+    get_target_property (QT_QMAKE_EXECUTABLE Qt5::qmake IMPORTED_LOCATION)
+    get_filename_component(QT_BIN_DIR "${QT_QMAKE_EXECUTABLE}" DIRECTORY)
+    find_program(MACDEPLOYQT_EXECUTABLE macdeployqt HINTS "${QT_BIN_DIR}")
+
+    add_custom_command(TARGET ${cmd_NAME} POST_BUILD
+        COMMAND "${MACDEPLOYQT_EXECUTABLE}"
+            "$<TARGET_FILE_DIR:${cmd_NAME}>/../.."
+            -qmldir=${CMAKE_SOURCE_DIR}/src/gui
+            -always-overwrite
+        COMMENT "Running macdeployqt..."
+    )
 endif()
index 57043f6ff2bac8af2f9cfd2fb4077933bd70391a..eb68418dcb87cc8defb20b6a1970d2f0ba1850bc 100644 (file)
@@ -49,11 +49,16 @@ if(NOT BUILD_LIBRARIES_ONLY)
     # currently it needs to be done because the code right above needs to be executed no matter
     # if building a bundle or not and the install_qt4_executable needs to be called afterwards
     if(BUILD_OWNCLOUD_OSX_BUNDLE)
-       get_target_property (QT_QMAKE_EXECUTABLE Qt5::qmake IMPORTED_LOCATION)
-       install(CODE "
-        message(STATUS \"Deploying (Qt) dependencies and fixing library paths...\")
-        execute_process(COMMAND \"${CMAKE_SOURCE_DIR}/admin/osx/macdeployqt.py\" ${CMAKE_INSTALL_PREFIX}/${OWNCLOUD_OSX_BUNDLE} ${QT_QMAKE_EXECUTABLE})
-        execute_process(COMMAND \"${CMAKE_SOURCE_DIR}/admin/osx/macdeployqt.py\" ${CMAKE_INSTALL_PREFIX}/${OWNCLOUD_OSX_BUNDLE}/Contents/Frameworks/QtWebEngineCore.framework/Helpers/QtWebEngineProcess.app ${QT_QMAKE_EXECUTABLE})
-        " COMPONENT RUNTIME)
+        get_target_property (QT_QMAKE_EXECUTABLE Qt5::qmake IMPORTED_LOCATION)
+        get_filename_component(QT_BIN_DIR "${QT_QMAKE_EXECUTABLE}" DIRECTORY)
+        find_program(MACDEPLOYQT_EXECUTABLE macdeployqt HINTS "${QT_BIN_DIR}")
+
+        add_custom_command(TARGET ${CRASHREPORTER_EXECUTABLE} POST_BUILD
+            COMMAND "${MACDEPLOYQT_EXECUTABLE}"
+                "$<TARGET_FILE_DIR:${CRASHREPORTER_EXECUTABLE}>/../.."
+                -qmldir=${CMAKE_SOURCE_DIR}/src/gui
+                -always-overwrite
+            COMMENT "Running macdeployqt..."
+        )
     endif()
 endif()
index 93f63450e9d094ffe01a7b6d32ca1f2f5406e2c8..ed17270cbd7effbbce6fd5f3fa17d8e1a90e5e6f 100644 (file)
@@ -389,12 +389,17 @@ install(TARGETS ${APPLICATION_EXECUTABLE}
 # currently it needs to be done because the code right above needs to be executed no matter
 # if building a bundle or not and the install_qt4_executable needs to be called afterwards
 if(BUILD_OWNCLOUD_OSX_BUNDLE AND NOT BUILD_LIBRARIES_ONLY)
-   get_target_property (QT_QMAKE_EXECUTABLE Qt5::qmake IMPORTED_LOCATION)
-   install(CODE "
-    message(STATUS \"Deploying (Qt) dependencies and fixing library paths...\")
-    execute_process(COMMAND \"${CMAKE_SOURCE_DIR}/admin/osx/macdeployqt.py\" ${CMAKE_INSTALL_PREFIX}/${OWNCLOUD_OSX_BUNDLE} ${QT_QMAKE_EXECUTABLE})
-    execute_process(COMMAND \"${CMAKE_SOURCE_DIR}/admin/osx/macdeployqt.py\" ${CMAKE_INSTALL_PREFIX}/${OWNCLOUD_OSX_BUNDLE}/Contents/Frameworks/QtWebEngineCore.framework/Helpers/QtWebEngineProcess.app ${QT_QMAKE_EXECUTABLE})
-    " COMPONENT RUNTIME)
+    get_target_property (QT_QMAKE_EXECUTABLE Qt5::qmake IMPORTED_LOCATION)
+    get_filename_component(QT_BIN_DIR "${QT_QMAKE_EXECUTABLE}" DIRECTORY)
+    find_program(MACDEPLOYQT_EXECUTABLE macdeployqt HINTS "${QT_BIN_DIR}")
+
+    add_custom_command(TARGET ${APPLICATION_EXECUTABLE} POST_BUILD
+        COMMAND "${MACDEPLOYQT_EXECUTABLE}"
+            "$<TARGET_FILE_DIR:${APPLICATION_EXECUTABLE}>/../.."
+            -qmldir=${CMAKE_SOURCE_DIR}/src/gui
+            -always-overwrite
+        COMMENT "Running macdeployqt..."
+    )
 endif()
 
 if(NOT BUILD_OWNCLOUD_OSX_BUNDLE AND NOT WIN32)