diff --git a/CMakeLists.txt b/CMakeLists.txt
index 10fa0f481..22f97965b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -16,7 +16,14 @@ project(${XSTUDIO_GLOBAL_NAME} VERSION ${XSTUDIO_GLOBAL_VERSION} LANGUAGES CXX)
# Pre-create the target so Qt's FindWrapOpenGL early-returns and never hits the
# broken AGL block. Can be removed once the minimum supported Qt is >= 6.9.
if(APPLE AND NOT TARGET WrapOpenGL::WrapOpenGL)
- find_package(OpenGL REQUIRED)
+ # Force the system framework to be found, otherwise
+ # xstudio crashes under Tahoe and it prevents codesigning.
+ # Note that vcpkg's glew port needs to be patched similarly.
+ block(SCOPE_FOR VARIABLES)
+ set(CMAKE_FIND_FRAMEWORK ONLY)
+ find_package(OpenGL REQUIRED)
+ endblock()
+
add_library(WrapOpenGL::WrapOpenGL INTERFACE IMPORTED)
target_link_libraries(WrapOpenGL::WrapOpenGL INTERFACE OpenGL::GL)
endif()
@@ -312,6 +319,11 @@ if (USE_VCPKG)
add_subdirectory("scripts/qt_install")
endif()
+if (APPLE)
+ # Finalize the bundle by removing any absolute rpaths from and codesigning any binaries
+ add_subdirectory("scripts/macos_finalize_bundle")
+endif()
+
if (WIN32)
include(InstallRequiredSystemLibraries)
diff --git a/cmake/macros.cmake b/cmake/macros.cmake
index 920bcfcb9..378101da0 100644
--- a/cmake/macros.cmake
+++ b/cmake/macros.cmake
@@ -225,7 +225,7 @@ macro(add_plugin_qml name _dir)
cmake_path(GET DIR FILENAME dirname)
add_custom_command(TARGET ${name}_COPY_QML POST_BUILD
COMMAND ${CMAKE_COMMAND} -E
- copy_directory ${DIR} ${CMAKE_BINARY_DIR}/xSTUDIO.app/Contents/PlugIns/xstudio/qml/${dirname})
+ copy_directory ${DIR} ${CMAKE_BINARY_DIR}/xSTUDIO.app/Contents/Resources/qml/${dirname})
endif()
endforeach()
else()
diff --git a/cmake/vcpkg_overlay_ports/glew/fix-LNK2019.patch b/cmake/vcpkg_overlay_ports/glew/fix-LNK2019.patch
new file mode 100644
index 000000000..bfb58ade7
--- /dev/null
+++ b/cmake/vcpkg_overlay_ports/glew/fix-LNK2019.patch
@@ -0,0 +1,14 @@
+diff --git a/build/cmake/CMakeLists.txt b/build/cmake/CMakeLists.txt
+index 5649972..c0252ec 100644
+--- a/build/cmake/CMakeLists.txt
++++ b/build/cmake/CMakeLists.txt
+@@ -129,9 +129,6 @@ if (MSVC)
+ target_compile_options (glew PRIVATE -GS-)
+ target_compile_options (glew_s PRIVATE -GS-)
+ # remove stdlib dependency
+- target_link_libraries (glew LINK_PRIVATE -nodefaultlib -noentry)
+- target_link_libraries (glew LINK_PRIVATE libvcruntime.lib)
+- target_link_libraries (glew LINK_PRIVATE msvcrt.lib )
+ string(REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_C_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG})
+ elseif (WIN32 AND ((CMAKE_C_COMPILER_ID MATCHES "GNU") OR (CMAKE_C_COMPILER_ID MATCHES "Clang")))
+ # remove stdlib dependency on windows with GCC and Clang (for similar reasons
diff --git a/cmake/vcpkg_overlay_ports/glew/opengl.patch b/cmake/vcpkg_overlay_ports/glew/opengl.patch
new file mode 100644
index 000000000..9e47e1d7f
--- /dev/null
+++ b/cmake/vcpkg_overlay_ports/glew/opengl.patch
@@ -0,0 +1,17 @@
+--- a/build/cmake/CMakeLists.txt
++++ b/build/cmake/CMakeLists.txt
+@@ -36,7 +36,13 @@
+ set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
+ endif()
+
+-find_package (OpenGL REQUIRED)
++if (APPLE)
++ set(CMAKE_FIND_FRAMEWORK ONLY)
++ find_package (OpenGL REQUIRED)
++ unset(CMAKE_FIND_FRAMEWORK)
++else()
++ find_package (OpenGL REQUIRED)
++endif()
+
+ # prefer GLVND
+ if (OPENGL_opengl_LIBRARY)
diff --git a/cmake/vcpkg_overlay_ports/glew/portfile.cmake b/cmake/vcpkg_overlay_ports/glew/portfile.cmake
new file mode 100644
index 000000000..40005dff1
--- /dev/null
+++ b/cmake/vcpkg_overlay_ports/glew/portfile.cmake
@@ -0,0 +1,62 @@
+if("x11" IN_LIST FEATURES)
+ message(WARNING "${PORT} requires the following libraries from the system package manager:\n libxmu-dev\n libxi-dev\n libgl-dev\n\nThese can be installed on Ubuntu systems via apt-get install libxmu-dev libxi-dev libgl-dev.")
+endif()
+
+# Don't change to vcpkg_from_github! The sources in the git repository (archives) are missing some files that are distributed inside releases.
+# More info: https://github.com/nigels-com/glew/issues/31 and https://github.com/nigels-com/glew/issues/13
+vcpkg_download_distfile(ARCHIVE
+ URLS "https://github.com/nigels-com/glew/releases/download/glew-${VERSION}/glew-${VERSION}.tgz"
+ FILENAME "glew-${VERSION}.tgz"
+ SHA512 cb4caecf32ec0f180c2691dc7769ffc99571c64f259a2663a2b80e788f1c2fd5362c59e0caaeefed6fb78a4070366d244666a657358049b09071b59fae2377e0
+)
+
+vcpkg_extract_source_archive(
+ SOURCE_PATH
+ ARCHIVE "${ARCHIVE}"
+ SOURCE_BASE glew
+ PATCHES
+ fix-LNK2019.patch
+ trim-build.diff
+ opengl.patch
+)
+
+set(options "")
+if(VCPKG_TARGET_IS_ANDROID)
+ list(APPEND options "-DGLEW_X11=OFF")
+endif()
+
+vcpkg_cmake_configure(
+ SOURCE_PATH "${SOURCE_PATH}/build/cmake"
+ OPTIONS
+ ${options}
+ -DBUILD_UTILS=OFF
+)
+
+vcpkg_cmake_install()
+vcpkg_copy_pdbs()
+vcpkg_cmake_config_fixup(CONFIG_PATH lib/cmake/glew)
+vcpkg_fixup_pkgconfig()
+
+# Burn-in CMake build config
+vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/include/GL/glew.h" "ifndef GLEW_NO_GLU" "if 0")
+
+if(NOT VCPKG_BUILD_TYPE)
+ set(libname GLEW)
+ if(VCPKG_TARGET_IS_WINDOWS)
+ set(libname glew32)
+ endif()
+ vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/glew.pc" " -l${libname}" " -l${libname}d")
+endif()
+
+if(VCPKG_LIBRARY_LINKAGE STREQUAL "static")
+ vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/include/GL/glew.h" "#ifdef GLEW_STATIC" "#if 1")
+ vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/include/GL/wglew.h" "#ifdef GLEW_STATIC" "#if 1")
+endif()
+
+file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include")
+file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/share")
+
+file(INSTALL "${CMAKE_CURRENT_LIST_DIR}/vcpkg-cmake-wrapper.cmake" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}")
+file(COPY "${CMAKE_CURRENT_LIST_DIR}/usage" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}")
+
+vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE.txt")
diff --git a/cmake/vcpkg_overlay_ports/glew/trim-build.diff b/cmake/vcpkg_overlay_ports/glew/trim-build.diff
new file mode 100644
index 000000000..6a1b358b4
--- /dev/null
+++ b/cmake/vcpkg_overlay_ports/glew/trim-build.diff
@@ -0,0 +1,23 @@
+diff --git a/build/cmake/CMakeLists.txt b/build/cmake/CMakeLists.txt
+index c5c1fb8..b1f41bf 100644
+--- a/build/cmake/CMakeLists.txt
++++ b/build/cmake/CMakeLists.txt
+@@ -162,8 +162,10 @@ endforeach()
+ set(targets_to_install "")
+ if(BUILD_SHARED_LIBS)
+ list(APPEND targets_to_install glew)
++ set_target_properties(glew_s PROPERTIES EXCLUDE_FROM_ALL 1)
+ else ()
+ list(APPEND targets_to_install glew_s)
++ set_target_properties(glew PROPERTIES EXCLUDE_FROM_ALL 1)
+ endif()
+
+ install ( TARGETS ${targets_to_install}
+@@ -235,6 +237,7 @@ if(WIN32 AND MSVC AND (NOT MSVC_VERSION LESS 1600))
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ CONFIGURATIONS Debug RelWithDebInfo
+ COMPONENT Runtime
++ OPTIONAL # subject to BUILD_SHARED_LIBS
+ )
+ endif()
+
diff --git a/cmake/vcpkg_overlay_ports/glew/usage b/cmake/vcpkg_overlay_ports/glew/usage
new file mode 100644
index 000000000..8eebb4b3b
--- /dev/null
+++ b/cmake/vcpkg_overlay_ports/glew/usage
@@ -0,0 +1,14 @@
+glew provides CMake targets:
+
+ # Legacy CMake find module
+ find_package(GLEW REQUIRED)
+ target_link_libraries(main PRIVATE GLEW::GLEW)
+
+ # Modern CMake config package
+ find_package(GLEW CONFIG REQUIRED)
+ target_link_libraries(main PRIVATE GLEW::GLEW)
+
+glew provides pkg-config modules:
+
+ # The OpenGL Extension Wrangler library
+ glew
diff --git a/cmake/vcpkg_overlay_ports/glew/vcpkg-cmake-wrapper.cmake b/cmake/vcpkg_overlay_ports/glew/vcpkg-cmake-wrapper.cmake
new file mode 100644
index 000000000..909a63540
--- /dev/null
+++ b/cmake/vcpkg_overlay_ports/glew/vcpkg-cmake-wrapper.cmake
@@ -0,0 +1,25 @@
+include(SelectLibraryConfigurations)
+_find_package(GLEW CONFIG)
+if(GLEW_FOUND AND TARGET GLEW::GLEW AND NOT DEFINED GLEW_INCLUDE_DIRS)
+ get_target_property(GLEW_INCLUDE_DIRS GLEW::GLEW INTERFACE_INCLUDE_DIRECTORIES)
+ set(GLEW_INCLUDE_DIR ${GLEW_INCLUDE_DIRS})
+ get_target_property(_GLEW_DEFS GLEW::GLEW INTERFACE_COMPILE_DEFINITIONS)
+ if("${_GLEW_DEFS}" MATCHES "GLEW_STATIC")
+ get_target_property(GLEW_LIBRARY_DEBUG GLEW::GLEW IMPORTED_LOCATION_DEBUG)
+ get_target_property(GLEW_LIBRARY_RELEASE GLEW::GLEW IMPORTED_LOCATION_RELEASE)
+ else()
+ get_target_property(GLEW_LIBRARY_DEBUG GLEW::GLEW IMPORTED_IMPLIB_DEBUG)
+ get_target_property(GLEW_LIBRARY_RELEASE GLEW::GLEW IMPORTED_IMPLIB_RELEASE)
+ endif()
+ get_target_property(_GLEW_LINK_INTERFACE GLEW::GLEW IMPORTED_LINK_INTERFACE_LIBRARIES_RELEASE) # same for debug and release
+ list(APPEND GLEW_LIBRARIES ${_GLEW_LINK_INTERFACE})
+ list(APPEND GLEW_LIBRARY ${_GLEW_LINK_INTERFACE})
+ select_library_configurations(GLEW)
+ if("${_GLEW_DEFS}" MATCHES "GLEW_STATIC")
+ set(GLEW_STATIC_LIBRARIES ${GLEW_LIBRARIES})
+ else()
+ set(GLEW_SHARED_LIBRARIES ${GLEW_LIBRARIES})
+ endif()
+ unset(_GLEW_DEFS)
+ unset(_GLEW_LINK_INTERFACE)
+endif()
\ No newline at end of file
diff --git a/cmake/vcpkg_overlay_ports/glew/vcpkg.json b/cmake/vcpkg_overlay_ports/glew/vcpkg.json
new file mode 100644
index 000000000..a448a8179
--- /dev/null
+++ b/cmake/vcpkg_overlay_ports/glew/vcpkg.json
@@ -0,0 +1,18 @@
+{
+ "name": "glew",
+ "version": "2.3.1",
+ "description": "The OpenGL Extension Wrangler Library (GLEW) is a cross-platform open-source C/C++ extension loading library.",
+ "homepage": "https://github.com/nigels-com/glew",
+ "supports": "!android",
+ "dependencies": [
+ "opengl",
+ {
+ "name": "vcpkg-cmake",
+ "host": true
+ },
+ {
+ "name": "vcpkg-cmake-config",
+ "host": true
+ }
+ ]
+}
diff --git a/extern/quickfuture/CMakeLists.txt b/extern/quickfuture/CMakeLists.txt
index 1e3176484..90b36c099 100644
--- a/extern/quickfuture/CMakeLists.txt
+++ b/extern/quickfuture/CMakeLists.txt
@@ -22,7 +22,7 @@ set(QML_FILES
if(APPLE)
set_target_properties(quickfuture
PROPERTIES
- LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/xSTUDIO.app/Contents/PlugIns/xstudio/qml/QuickFuture"
+ LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/xSTUDIO.app/Contents/Resources/qml/QuickFuture"
)
else()
set_target_properties(quickfuture
@@ -49,7 +49,7 @@ set(QML_FUTURE_FILES
)
if (APPLE)
- set(QML_DEST_DIR ${CMAKE_BINARY_DIR}/xSTUDIO.app/Contents/PlugIns/xstudio/qml/QuickFuture)
+ set(QML_DEST_DIR ${CMAKE_BINARY_DIR}/xSTUDIO.app/Contents/Resources/qml/QuickFuture)
else()
set(QML_DEST_DIR ${CMAKE_BINARY_DIR}/bin/plugin/qml/QuickFuture)
endif()
diff --git a/extern/quickpromise/CMakeLists.txt b/extern/quickpromise/CMakeLists.txt
index 975068f77..4af7b8574 100644
--- a/extern/quickpromise/CMakeLists.txt
+++ b/extern/quickpromise/CMakeLists.txt
@@ -38,11 +38,15 @@ else()
add_library(quickpromise SHARED)
endif()
-# On Windows the DLL must be next to the QML files for Qt to load the plugin.
-# (Install puts it at bin/ separately, see below.)
-if(WIN32)
+if(APPLE)
+ set_target_properties(quickpromise
+ PROPERTIES
+ LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/plugin/qml/QuickPromise"
+ )
+else()
set_target_properties(quickpromise
PROPERTIES
+ LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/plugin/qml/QuickPromise"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/plugin/qml/QuickPromise")
endif()
@@ -68,7 +72,7 @@ endif()
add_custom_target(COPY_PROMISE_QML)
if (APPLE)
- set(QML_DEST_DIR ${CMAKE_BINARY_DIR}/xSTUDIO.app/Contents/PlugIns/xstudio/qml/QuickPromise)
+ set(QML_DEST_DIR ${CMAKE_BINARY_DIR}/xSTUDIO.app/Contents/Resources/qml/QuickPromise)
else()
set(QML_DEST_DIR ${CMAKE_BINARY_DIR}/bin/plugin/qml/QuickPromise)
endif()
diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
index f7cdfa3da..188dbf71a 100644
--- a/python/CMakeLists.txt
+++ b/python/CMakeLists.txt
@@ -26,8 +26,8 @@ if(APPLE)
add_custom_target(python_module ALL DEPENDS __pybind_xstudio ${VCPKG_LOCATION}/xstudio/api)
- # Here we copy the entire python installation into Frameworks
- install(DIRECTORY ${VCPKG_LOCATION}/lib/${PYTHONVP} DESTINATION ${CMAKE_BINARY_DIR}/xSTUDIO.app/Contents/Frameworks/lib/)
+ # Here we copy the entire python installation into Resources
+ install(DIRECTORY ${VCPKG_LOCATION}/lib/${PYTHONVP} DESTINATION ${CMAKE_BINARY_DIR}/xSTUDIO.app/Contents/Resources/python/lib)
elseif(WIN32)
diff --git a/scripts/macos_finalize_bundle/CMakeLists.txt b/scripts/macos_finalize_bundle/CMakeLists.txt
new file mode 100644
index 000000000..e4fc64025
--- /dev/null
+++ b/scripts/macos_finalize_bundle/CMakeLists.txt
@@ -0,0 +1,10 @@
+# After macdeployqt has done its thing to the bundle, it still needs
+# some cleanup by removing absolute rpath's from and codesigning
+# all the binaries.
+
+find_package(Python COMPONENTS Interpreter REQUIRED)
+
+set(_cmd "${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/macos_finalize_bundle.py ${CMAKE_BINARY_DIR}/xSTUDIO.app")
+
+install(CODE "message(\"Running: ${_cmd}\")")
+install(CODE "execute_process(COMMAND ${_cmd})")
diff --git a/scripts/macos_finalize_bundle/macos_finalize_bundle.py b/scripts/macos_finalize_bundle/macos_finalize_bundle.py
new file mode 100755
index 000000000..ae4872fc7
--- /dev/null
+++ b/scripts/macos_finalize_bundle/macos_finalize_bundle.py
@@ -0,0 +1,206 @@
+#!/usr/bin/env python3
+
+import abc
+import argparse
+import os
+import plistlib
+import re
+import subprocess
+import sys
+import shutil
+import logging
+
+
+logging.basicConfig(
+ level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
+)
+
+CODESIGN_IDENTITY = os.environ.get("CODESIGN_IDENTITY", "-")
+KEYCHAIN_PASSWORD = os.environ.get("KEYCHAIN_PASSWORD")
+
+def fatal_error(msg):
+ """Print error to stderr and exit with code 1"""
+ logging.critical(msg)
+ sys.exit(1)
+
+
+def finalize_framework(path):
+ name = os.path.basename(path)
+ lib_name, _ = os.path.splitext(name)
+ lib_path = os.path.join(path, "Versions", "Current", lib_name)
+ remove_absolute_rpaths(lib_path)
+ sign_path(lib_path)
+
+
+def unlock_keychain():
+
+ if not CODESIGN_IDENTITY:
+ logging.warning("No identity given. Skipping unlock_keychain")
+ return
+ if CODESIGN_IDENTITY == "-":
+ logging.info("ad-hoc identity given. Skipping unlock_keychain")
+
+ if not KEYCHAIN_PASSWORD:
+ return
+
+ try:
+ subprocess.check_call(
+ ["security", "unlock-keychain", "-p",
+ KEYCHAIN_PASSWORD, "login.keychain"]
+ )
+ except subprocess.CalledProcessError as error:
+ fatal_error(f"Error unlocking keychain: {error}")
+
+
+def finalize_app(path):
+ exe_path = os.path.join(path, "Contents", "MacOS")
+ app_name = os.path.basename(path)
+ info_plist_path = os.path.join(path, "Contents", "Info.plist")
+ info = plistlib.load(open(info_plist_path, "rb"))
+ app_name = info.get("CFBundleExecutable")
+ # sign any extra exes but skip the bundle exe
+ for name in os.listdir(exe_path):
+ if name == app_name:
+ continue
+ exe = os.path.join(exe_path, name)
+ remove_absolute_rpaths(exe)
+ sign_path(exe)
+ remove_absolute_rpaths(os.path.join(exe_path, app_name))
+ sign_path(path)
+
+
+def sign_path(path):
+ if not CODESIGN_IDENTITY:
+ logging.warning(
+ f"No identity given. Skipping code sign step for {path}")
+ return
+ code_sign = "/usr/bin/codesign"
+ logging.info(f"Signing {path} with identity {CODESIGN_IDENTITY}")
+ try:
+ subprocess.check_output(
+ [
+ code_sign,
+ "--force",
+ "--sign",
+ CODESIGN_IDENTITY,
+ path,
+ ]
+ )
+ except subprocess.CalledProcessError as error:
+ fatal_error(
+ f"Error signing {path}. stderr: {error.stderr}, stdout: {error.stdout}"
+ )
+
+
+def finalize_dir(full_path, name):
+ if name.endswith(".framework"):
+ finalize_framework(full_path)
+ if name.endswith(".app"):
+ finalize_app(full_path)
+
+
+def finalize_bundle(output_path):
+ unlock_keychain()
+ for root, dirs, files in os.walk(output_path, topdown=False):
+ for name in files:
+ _, ext = os.path.splitext(name)
+ if ext in (".dylib", ".so"):
+ lib = os.path.join(root, name)
+ remove_absolute_rpaths(lib)
+ sign_path(lib)
+ for name in dirs:
+ full_path = os.path.join(root, name)
+ finalize_dir(full_path, name)
+ finalize_dir(output_path, os.path.basename(output_path))
+
+
+def get_rpaths(binary_path):
+ """
+ Run otool -l on a binary and return list of rpaths.
+
+ Args:
+ binary_path: Path to the binary/framework/dylib
+
+ Returns:
+ List of rpath strings (e.g., ['@executable_path/../Frameworks'])
+ """
+ try:
+ # Run otool -l
+ result = subprocess.run(
+ ["otool", "-l", binary_path], capture_output=True, text=True, check=True
+ )
+
+ rpaths = []
+ lines = result.stdout.split("\n")
+
+ # Look for LC_RPATH sections
+ for i, line in enumerate(lines):
+ if "cmd LC_RPATH" in line:
+ # The path is typically 2 lines after LC_RPATH
+ if i + 2 < len(lines):
+ path_line = lines[i + 2].strip()
+ # Extract path using regex
+ match = re.search(r"path\s+(.+?)\s+\(offset", path_line)
+ if match:
+ rpaths.append(match.group(1))
+
+ return rpaths
+
+ except subprocess.CalledProcessError as e:
+ fatal_error(f"Error running otool: {e}")
+ except FileNotFoundError:
+ fatal_error("otool not found")
+
+
+def delete_rpath(binary_path, rpath):
+ """
+ Delete an rpath from a binary using install_name_tool.
+
+ Args:
+ binary_path: Path to the binary/framework/dylib
+ rpath: The rpath to delete (e.g., '@executable_path/../Frameworks')
+
+ Raises:
+ RuntimeError: If install_name_tool fails
+ """
+ try:
+ subprocess.run(
+ ["install_name_tool", "-delete_rpath", rpath, binary_path],
+ capture_output=True,
+ text=True,
+ check=True,
+ )
+ except subprocess.CalledProcessError as e:
+ fatal_error(f"install_name_tool failed: {e.stderr}")
+ except FileNotFoundError:
+ fatal_error("install_name_tool not found")
+
+
+def remove_absolute_rpaths(binary_path):
+ """
+ Remove all absolute rpaths from a binary, keeping only relative ones (@-prefixed).
+
+ Args:
+ binary_path: Path to the binary/framework/dylib
+ """
+ rpaths = get_rpaths(binary_path)
+
+ for rpath in rpaths:
+ if not rpath.startswith("@"):
+ logging.info(
+ f"Deleting absolute rpath '{rpath}' from '{binary_path}'")
+ delete_rpath(binary_path, rpath)
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ "finalize_macos_bundle",
+ description="rpath fixer and codesign tool for MacOS build"
+ )
+ parser.add_argument("bundle")
+
+ args = parser.parse_args()
+ finalize_bundle(args.bundle)
+
+if __name__ == "__main__":
+ main()
diff --git a/scripts/qt_install/CMakeLists.txt b/scripts/qt_install/CMakeLists.txt
index 7c59a03c3..bd51bc968 100644
--- a/scripts/qt_install/CMakeLists.txt
+++ b/scripts/qt_install/CMakeLists.txt
@@ -1,8 +1,17 @@
-# After everything else is installed, windeployqt will scan the contents and package up Qt dependencies.
+# After everything else is installed, windeployqt/macdeployqt will scan the contents and package up Qt dependencies.
get_target_property(_qmake_executable Qt6::qmake IMPORTED_LOCATION)
get_filename_component(_qt_bin_dir "${_qmake_executable}" DIRECTORY)
-find_program(windeployqt_exe windeployqt HINTS "${_qt_bin_dir}")
-configure_file(qt_install.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/qt_install.cmake @ONLY)
-install(SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/qt_install.cmake)
+if(APPLE)
+ find_program(macdeployqt_exe macdeployqt HINTS "${_qt_bin_dir}")
+ set(_cmd "${macdeployqt_exe} ${CMAKE_BINARY_DIR}/xSTUDIO.app -qmldir=${CMAKE_SOURCE_DIR}/ui")
+elseif(WIN32)
+ find_program(windeployqt_exe windeployqt HINTS "${_qt_bin_dir}")
+ set(_cmd "${windeployqt_exe} ${CMAKE_INSTALL_PREFIX}/bin/xstudio.exe --qmldir ${CMAKE_SOURCE_DIR}/ui)")
+endif()
+
+if(NOT "${_cmd}" STREQUAL "")
+ install(CODE "message(\"Running: ${_cmd}\")")
+ install(CODE "execute_process(COMMAND ${_cmd})")
+endif()
diff --git a/scripts/qt_install/qt_install.cmake.in b/scripts/qt_install/qt_install.cmake.in
deleted file mode 100644
index 53aa5e9f8..000000000
--- a/scripts/qt_install/qt_install.cmake.in
+++ /dev/null
@@ -1,3 +0,0 @@
-message("Running windeployqt... with args: ${CMAKE_INSTALL_PREFIX}/bin/xstudio.exe --qmldir @CMAKE_SOURCE_DIR@/ui")
-execute_process(COMMAND "@windeployqt_exe@" "${CMAKE_INSTALL_PREFIX}/bin/xstudio.exe" --qmldir "@CMAKE_SOURCE_DIR@/ui"
- WORKING_DIRECTORY "${CMAKE_INSTALL_PREFIX}")
diff --git a/src/embedded_python/src/embedded_python.cpp b/src/embedded_python/src/embedded_python.cpp
index 32f84db54..8768f3507 100644
--- a/src/embedded_python/src/embedded_python.cpp
+++ b/src/embedded_python/src/embedded_python.cpp
@@ -56,8 +56,8 @@ void EmbeddedPython::setup() {
std::string python_home;
if (p.string().find("Contents/Frameworks") != std::string::npos) {
// String match will happen On MacOS install, here python
- // installation is in Frameworks colder in the app bundle
- python_home = p.parent_path();
+ // installation is in Resources folder in the app bundle
+ python_home = p.parent_path().parent_path() / "Resources/python";
} else {
// Otherwise, we jump up twice to get above the 'lib' folder
// where python310.so is installed, as python home should
diff --git a/src/launch/xstudio/src/CMakeLists.txt b/src/launch/xstudio/src/CMakeLists.txt
index aa460f563..b66245a36 100644
--- a/src/launch/xstudio/src/CMakeLists.txt
+++ b/src/launch/xstudio/src/CMakeLists.txt
@@ -130,10 +130,6 @@ elseif(APPLE)
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/xSTUDIO.app/Contents/Resources")
- add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy
- ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist "${CMAKE_BINARY_DIR}/xSTUDIO.app/Contents/")
-
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/xstudio_app.ico "${CMAKE_BINARY_DIR}/xSTUDIO.app/Contents/Resources/")
@@ -144,17 +140,19 @@ elseif(APPLE)
COMMAND ${CMAKE_COMMAND} -E copy
${FFMPEG_APP} "${CMAKE_BINARY_DIR}/xSTUDIO.app/Contents/MacOS/ffmpeg")
- get_target_property(_qmake_executable Qt6::qmake IMPORTED_LOCATION)
- get_filename_component(_qt_bin_dir "${_qmake_executable}" DIRECTORY)
- find_program(macdeployqt_exe macdeployqt HINTS "${_qt_bin_dir}")
- configure_file(macdeploy.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/macdeploy.cmake @ONLY)
- install(SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/macdeploy.cmake)
-
- # Add custom command to fix library paths after build
- add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
- COMMAND ${CMAKE_COMMAND} -DAPP_BUNDLE_DIR=${CMAKE_BINARY_DIR}/xSTUDIO.app
- -P ${CMAKE_CURRENT_SOURCE_DIR}/fixup_macos_bundle.cmake
- )
+ # change its rpath so it can find its libraries in their build location so it and can be run in-place
+ # (this gets cleaned up during the install by macdeployqt)
+ add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
+ COMMAND install_name_tool -rpath "@loader_path/../../lib" "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib"
+ "${CMAKE_BINARY_DIR}/xSTUDIO.app/Contents/MacOS/ffmpeg")
+ add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
+ COMMAND install_name_tool -add_rpath "@executable_path/../Frameworks"
+ "${CMAKE_BINARY_DIR}/xSTUDIO.app/Contents/MacOS/ffmpeg")
+
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/Info.plist" "${CMAKE_CURRENT_BINARY_DIR}/Info.plist")
+ add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy
+ "${CMAKE_CURRENT_BINARY_DIR}/Info.plist" "${CMAKE_BINARY_DIR}/xSTUDIO.app/Contents/Info.plist")
else()
diff --git a/src/launch/xstudio/src/Info.plist b/src/launch/xstudio/src/Info.plist
index 57dc1e23c..a9a61f038 100644
--- a/src/launch/xstudio/src/Info.plist
+++ b/src/launch/xstudio/src/Info.plist
@@ -9,7 +9,7 @@
CFBundleIconFile
xstudio_app.ico
CFBundleIdentifier
- com.googlecode.skia.${PRODUCT_NAME:rfc1034identifier}
+ com.dneg.xSTUDIO
CFBundleInfoDictionaryVersion
6.0
CFBundleName
@@ -17,16 +17,14 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 1.0
- CFBundleSignature
- ????
+ ${XSTUDIO_GLOBAL_VERSION}
CFBundleVersion
1
LSMinimumSystemVersion
- ${MACOSX_DEPLOYMENT_TARGET}
+ ${CMAKE_OSX_DEPLOYMENT_TARGET}
NSMainNibFile
- HelloWorld
+ MainMenu
NSPrincipalClass
NSApplication
-
\ No newline at end of file
+
diff --git a/src/launch/xstudio/src/fixup_macos_bundle.cmake b/src/launch/xstudio/src/fixup_macos_bundle.cmake
deleted file mode 100644
index 4766332a6..000000000
--- a/src/launch/xstudio/src/fixup_macos_bundle.cmake
+++ /dev/null
@@ -1,15 +0,0 @@
-# Fix library paths in the app bundle to ensure they're relative
-file(GLOB_RECURSE LIBRARIES "${APP_BUNDLE_DIR}/Contents/Frameworks/*.dylib")
-foreach(LIB ${LIBRARIES})
- get_filename_component(LIB_NAME ${LIB} NAME)
- execute_process(COMMAND install_name_tool -id "@rpath/${LIB_NAME}" ${LIB})
-endforeach()
-
-# Fix executable references to libraries
-execute_process(
- COMMAND
- install_name_tool
- -add_rpath
- "@executable_path/../Frameworks"
- ${APP_BUNDLE_DIR}/Contents/MacOS/xstudio.bin
-)
diff --git a/src/launch/xstudio/src/macdeploy.cmake.in b/src/launch/xstudio/src/macdeploy.cmake.in
deleted file mode 100644
index 4a7b59b7e..000000000
--- a/src/launch/xstudio/src/macdeploy.cmake.in
+++ /dev/null
@@ -1,26 +0,0 @@
-
-# This command manipulates the rpath in ffmpeg so it can find the ffmpeg libs in the Frameworks
-# folder in the app bundle
-execute_process(COMMAND install_name_tool ${CMAKE_BINARY_DIR}/xSTUDIO.app/Contents/MacOS/ffmpeg -rpath @loader_path/../../lib @loader_path/../Frameworks WORKING_DIRECTORY "${CMAKE_INSTALL_PREFIX}")
-
-# macdeployqt finds xSTUDIO's library dependencies and adds them to the app bundle, as well as
-# making necessary rpath manipulations
-message("Running @macdeployqt_exe@ with args: ${CMAKE_BINARY_DIR}/xSTUDIO.app -qmldir=@CMAKE_SOURCE_DIR@/ui")
-execute_process(COMMAND "@macdeployqt_exe@" ${CMAKE_BINARY_DIR}/xSTUDIO.app -qmldir=@CMAKE_SOURCE_DIR@/ui
- WORKING_DIRECTORY "${CMAKE_INSTALL_PREFIX}")
-
-# Fix library paths to ensure they're relative to the bundle
-execute_process(
- COMMAND
- install_name_tool -id
- "@rpath/libglobal.dylib"
- ${CMAKE_BINARY_DIR}/xSTUDIO.app/Contents/Frameworks/libglobal.dylib
-)
-execute_process(
- COMMAND
- install_name_tool
- -change
- "@rpath/libglobal.dylib"
- "@executable_path/../Frameworks/libglobal.dylib"
- ${CMAKE_BINARY_DIR}/xSTUDIO.app/Contents/MacOS/xstudio.bin
-)
diff --git a/vcpkg.json b/vcpkg.json
index 77b7eec24..430dc6236 100644
--- a/vcpkg.json
+++ b/vcpkg.json
@@ -74,6 +74,10 @@
"name": "freetype",
"version": "2.10.1-6#0"
},
+ {
+ "name": "glew",
+ "version": "2.3.1"
+ },
{
"name": "boost-modular-build-helper",
"version": "1.84.0#3"