Resolve Qt framework path with install_name_tool (#7379)
* Add comment about EXC_BAD_ACCESS * Optional certificate install * Improve log output * Move team ID arg * Change position of arg * Set PATH in .zshrc and use bash command substitution * Simplified macdeployqt find logic * Formatting * Minor tweaks to Qt cmake config * Resolve framework path with install_name_tool * Update ChangeLog
This commit is contained in:
parent
16c0472d4d
commit
d8acb36e8d
6 changed files with 117 additions and 58 deletions
26
.env.example
26
.env.example
|
|
@ -25,22 +25,22 @@
|
||||||
# [Windows] Password for the PFX code signing certificate
|
# [Windows] Password for the PFX code signing certificate
|
||||||
# WINDOWS_PFX_PASSWORD="super-secret-password"
|
# WINDOWS_PFX_PASSWORD="super-secret-password"
|
||||||
|
|
||||||
|
# [macOS] Certificate ID for the Developer ID Application code signing certificate
|
||||||
|
# APPLE_CODESIGN_ID="Developer ID Application: Acme Inc (ABC123XYZ9)"
|
||||||
|
|
||||||
|
# [macOS] Base64 encoded P12 code signing certificate
|
||||||
|
# APPLE_P12_CERTIFICATE="very-long-base64-encoded-string"
|
||||||
|
|
||||||
|
# [macOS] Password for the P12 code signing certificate
|
||||||
|
# APPLE_P12_PASSWORD="super-secret-password"
|
||||||
|
|
||||||
|
# [macOS] Apple Team ID
|
||||||
|
# https://developer.apple.com/account/#/membership
|
||||||
|
# APPLE_TEAM_ID="ABC123XYZ9"
|
||||||
|
|
||||||
# [macOS] Apple ID used to notarize the app
|
# [macOS] Apple ID used to notarize the app
|
||||||
# APPLE_NOTARY_USER="example@example.com"
|
# APPLE_NOTARY_USER="example@example.com"
|
||||||
|
|
||||||
# [macOS] App-specific password for the Apple ID
|
# [macOS] App-specific password for the Apple ID
|
||||||
# https://support.apple.com/en-gb/102654
|
# https://support.apple.com/en-gb/102654
|
||||||
# APPLE_NOTARY_PASSWORD="super-secret-password"
|
# APPLE_NOTARY_PASSWORD="super-secret-password"
|
||||||
|
|
||||||
# [macOS] Apple Team ID
|
|
||||||
# https://developer.apple.com/account/#/membership
|
|
||||||
# APPLE_TEAM_ID="ABC123XYZ9"
|
|
||||||
|
|
||||||
# [macOS] Certificate ID for the Developer ID Application code signing certificate
|
|
||||||
# APPLE_CODESIGN_ID="Developer ID Application: Acme Inc (ABC123XYZ9)"
|
|
||||||
|
|
||||||
# [macOS] Password for the P12 code signing certificate
|
|
||||||
# APPLE_P12_PASSWORD="super-secret-password"
|
|
||||||
|
|
||||||
# [macOS] Base64 encoded P12 code signing certificate
|
|
||||||
# APPLE_P12_CERTIFICATE="very-long-base64-encoded-string"
|
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ Enhancements:
|
||||||
- #7374 Add missing DEB and RPM dependencies
|
- #7374 Add missing DEB and RPM dependencies
|
||||||
- #7376 Automated weekly build of Docker images for Linux runners
|
- #7376 Automated weekly build of Docker images for Linux runners
|
||||||
- #7378 Improve workflow triggers to ensure correct run time
|
- #7378 Improve workflow triggers to ensure correct run time
|
||||||
|
- #7379 Resolve Qt framework path with `install_name_tool`
|
||||||
- #7380 Add `qt6-qpa-plugins` Qt dependency for Debian
|
- #7380 Add `qt6-qpa-plugins` Qt dependency for Debian
|
||||||
|
|
||||||
# 1.14.6
|
# 1.14.6
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,14 @@
|
||||||
"aqtinstall",
|
"aqtinstall",
|
||||||
"codesign",
|
"codesign",
|
||||||
"codesigning",
|
"codesigning",
|
||||||
|
"contribs",
|
||||||
"distros",
|
"distros",
|
||||||
"dmgbuild",
|
"dmgbuild",
|
||||||
"dotenv",
|
"dotenv",
|
||||||
"gdrive",
|
"gdrive",
|
||||||
"keychain",
|
"keychain",
|
||||||
"Keychains",
|
"Keychains",
|
||||||
|
"LLDB",
|
||||||
"macdeployqt",
|
"macdeployqt",
|
||||||
"msvc",
|
"msvc",
|
||||||
"notarytool",
|
"notarytool",
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@ class Dependencies:
|
||||||
cmd_utils.run(command, shell=True, print_cmd=True)
|
cmd_utils.run(command, shell=True, print_cmd=True)
|
||||||
|
|
||||||
if not self.ci_env:
|
if not self.ci_env:
|
||||||
mac.set_cmake_prefix_env_var(self.config.get_os_value("qt-prefix-command"))
|
mac.set_env_vars(self.config.get_os_value("qt-prefix-command"))
|
||||||
|
|
||||||
def linux(self):
|
def linux(self):
|
||||||
"""Installs dependencies on Linux."""
|
"""Installs dependencies on Linux."""
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,10 @@ import lib.cmd_utils as cmd_utils
|
||||||
import lib.env as env
|
import lib.env as env
|
||||||
from lib.certificate import Certificate
|
from lib.certificate import Certificate
|
||||||
|
|
||||||
cmake_env_var = "CMAKE_PREFIX_PATH"
|
path_env = "PATH"
|
||||||
|
cmake_env = "CMAKE_PREFIX_PATH"
|
||||||
|
cert_p12_env = "APPLE_P12_CERTIFICATE"
|
||||||
|
notary_user_env = "APPLE_NOTARY_USER"
|
||||||
shell_rc = "~/.zshrc"
|
shell_rc = "~/.zshrc"
|
||||||
dist_dir = "dist"
|
dist_dir = "dist"
|
||||||
product_name = "Synergy 1"
|
product_name = "Synergy 1"
|
||||||
|
|
@ -21,35 +24,80 @@ keychain_path = "/Library/Keychains/System.keychain"
|
||||||
def set_env_var(name, value):
|
def set_env_var(name, value):
|
||||||
text = f'export {name}="${name}:{value}"'
|
text = f'export {name}="${name}:{value}"'
|
||||||
file = os.path.expanduser(shell_rc)
|
file = os.path.expanduser(shell_rc)
|
||||||
with open(file, "r") as f:
|
if os.path.exists(file):
|
||||||
if text in f.read():
|
with open(file, "r") as f:
|
||||||
return
|
if text in f.read():
|
||||||
|
return
|
||||||
|
|
||||||
print(f"Setting environment variable: {name}={name}")
|
print(f"Setting environment variable: {name}={name}")
|
||||||
with open(file, "a") as f:
|
with open(file, "a") as f:
|
||||||
f.write(f"\n{text}")
|
f.write(f"\n{text}\n")
|
||||||
print(f"Appended to {shell_rc}: {text}")
|
print(f"Appended to {shell_rc}: {text}")
|
||||||
|
|
||||||
|
|
||||||
def set_cmake_prefix_env_var(cmake_prefix_command):
|
def set_env_vars(cmake_prefix_command):
|
||||||
result = cmd_utils.run(
|
cmd_sub = f"$({cmake_prefix_command})"
|
||||||
cmake_prefix_command, get_output=True, shell=True, print_cmd=True
|
set_env_var(path_env, cmd_sub)
|
||||||
)
|
set_env_var(cmake_env, cmd_sub)
|
||||||
cmake_prefix = result.stdout.strip()
|
|
||||||
set_env_var(cmake_env_var, cmake_prefix)
|
|
||||||
|
|
||||||
|
|
||||||
def package(filename_base):
|
def package(filename_base):
|
||||||
codesign_id = env.get_env("APPLE_CODESIGN_ID")
|
"""
|
||||||
cert_base64 = env.get_env("APPLE_P12_CERTIFICATE")
|
Package the application for macOS.
|
||||||
cert_password = env.get_env("APPLE_P12_PASSWORD")
|
The app bundle must be signed, or an error will occur:
|
||||||
|
> EXC_BAD_ACCESS (SIGKILL (Code Signature Invalid))
|
||||||
|
An "Apple Development" certificate is sufficient for local development.
|
||||||
|
"""
|
||||||
|
|
||||||
|
(
|
||||||
|
codesign_id,
|
||||||
|
cert_base64,
|
||||||
|
cert_password,
|
||||||
|
notary_user,
|
||||||
|
notary_password,
|
||||||
|
notary_team_id,
|
||||||
|
) = package_env_vars()
|
||||||
|
|
||||||
|
if cert_base64:
|
||||||
|
install_certificate(cert_base64, cert_password)
|
||||||
|
else:
|
||||||
|
print(f"Skipped certificate installation, env var {cert_p12_env} not set")
|
||||||
|
|
||||||
build_bundle()
|
build_bundle()
|
||||||
install_certificate(cert_base64, cert_password)
|
|
||||||
assert_certificate_installed(codesign_id)
|
|
||||||
sign_bundle(codesign_id)
|
sign_bundle(codesign_id)
|
||||||
dmg_path = build_dmg(filename_base)
|
dmg_path = build_dmg(filename_base)
|
||||||
notarize_package(dmg_path)
|
|
||||||
|
if notary_user:
|
||||||
|
notarize_package(dmg_path, notary_user, notary_password, notary_team_id)
|
||||||
|
else:
|
||||||
|
print(f"Skipped notarization, env var {notary_user_env} not set")
|
||||||
|
|
||||||
|
|
||||||
|
def package_env_vars():
|
||||||
|
codesign_id = env.get_env("APPLE_CODESIGN_ID")
|
||||||
|
cert_base64 = env.get_env(cert_p12_env, required=False)
|
||||||
|
notary_user = env.get_env(notary_user_env, required=False)
|
||||||
|
|
||||||
|
if notary_user:
|
||||||
|
notary_password = env.get_env("APPLE_NOTARY_PASSWORD")
|
||||||
|
notary_team_id = env.get_env("APPLE_TEAM_ID")
|
||||||
|
else:
|
||||||
|
notary_password = None
|
||||||
|
notary_team_id = None
|
||||||
|
|
||||||
|
if cert_base64:
|
||||||
|
cert_password = env.get_env("APPLE_P12_PASSWORD")
|
||||||
|
else:
|
||||||
|
cert_password = None
|
||||||
|
|
||||||
|
return (
|
||||||
|
codesign_id,
|
||||||
|
cert_base64,
|
||||||
|
cert_password,
|
||||||
|
notary_user,
|
||||||
|
notary_password,
|
||||||
|
notary_team_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def build_bundle():
|
def build_bundle():
|
||||||
|
|
@ -57,9 +105,19 @@ def build_bundle():
|
||||||
# cmake build install target should run macdeployqt
|
# cmake build install target should run macdeployqt
|
||||||
cmd_utils.run("cmake --build build --target install", shell=True, print_cmd=True)
|
cmd_utils.run("cmake --build build --target install", shell=True, print_cmd=True)
|
||||||
|
|
||||||
|
bundle_bin_path = "Contents/MacOS/synergy"
|
||||||
|
cmd_utils.run(
|
||||||
|
'install_name_tool -add_rpath "@executable_path/../Frameworks" '
|
||||||
|
f"{app_path}/{bundle_bin_path}",
|
||||||
|
shell=True,
|
||||||
|
print_cmd=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def sign_bundle(codesign_id):
|
def sign_bundle(codesign_id):
|
||||||
print(f"Signing bundle {app_path}...")
|
print(f"Signing bundle {app_path}...")
|
||||||
|
|
||||||
|
assert_certificate_installed(codesign_id)
|
||||||
cmd_utils.run(
|
cmd_utils.run(
|
||||||
[
|
[
|
||||||
codesign_path,
|
codesign_path,
|
||||||
|
|
@ -75,6 +133,8 @@ def sign_bundle(codesign_id):
|
||||||
|
|
||||||
|
|
||||||
def assert_certificate_installed(codesign_id):
|
def assert_certificate_installed(codesign_id):
|
||||||
|
print(f"Checking certificate: {codesign_id}")
|
||||||
|
|
||||||
installed = cmd_utils.run(
|
installed = cmd_utils.run(
|
||||||
"security find-identity -v -p codesigning",
|
"security find-identity -v -p codesigning",
|
||||||
get_output=True,
|
get_output=True,
|
||||||
|
|
@ -146,15 +206,10 @@ def install_certificate(cert_base64, cert_password):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def notarize_package(dmg_path):
|
def notarize_package(dmg_path, user, password, team_id):
|
||||||
print(f"Notarizing package {dmg_path}...")
|
print(f"Notarizing package {dmg_path}...")
|
||||||
notary_tool = NotaryTool()
|
notary_tool = NotaryTool()
|
||||||
notary_tool.store_credentials(
|
notary_tool.store_credentials(user, password, team_id)
|
||||||
env.get_env("APPLE_NOTARY_USER"),
|
|
||||||
env.get_env("APPLE_NOTARY_PASSWORD"),
|
|
||||||
env.get_env("APPLE_TEAM_ID"),
|
|
||||||
)
|
|
||||||
|
|
||||||
notary_tool.submit_and_wait(dmg_path)
|
notary_tool.submit_and_wait(dmg_path)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -186,10 +241,10 @@ class NotaryTool:
|
||||||
notarytool_path,
|
notarytool_path,
|
||||||
"store-credentials",
|
"store-credentials",
|
||||||
"notarytool-password",
|
"notarytool-password",
|
||||||
"--apple-id",
|
|
||||||
user,
|
|
||||||
"--team-id",
|
"--team-id",
|
||||||
team_id,
|
team_id,
|
||||||
|
"--apple-id",
|
||||||
|
user,
|
||||||
"--password",
|
"--password",
|
||||||
password,
|
password,
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
find_package(
|
find_package(
|
||||||
Qt6
|
Qt6
|
||||||
COMPONENTS Core Widgets Network Core5Compat
|
COMPONENTS Core5Compat Core Widgets Network
|
||||||
REQUIRED)
|
REQUIRED)
|
||||||
|
|
||||||
set(CMAKE_AUTOMOC ON)
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
|
@ -17,13 +17,6 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||||
list(APPEND GUI_SOURCE_FILES ${GUI_MAC_SOURCE_FILES})
|
list(APPEND GUI_SOURCE_FILES ${GUI_MAC_SOURCE_FILES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Retrieve the absolute path to qmake and then use that path to find the
|
|
||||||
# binaries
|
|
||||||
get_target_property(_qmake_executable Qt6::qmake IMPORTED_LOCATION)
|
|
||||||
get_filename_component(_qt_bin_dir "${_qmake_executable}" DIRECTORY)
|
|
||||||
find_program(WINDEPLOYQT_EXECUTABLE windeployqt HINTS "${_qt_bin_dir}")
|
|
||||||
find_program(MACDEPLOYQT_EXECUTABLE macdeployqt HINTS "${_qt_bin_dir}")
|
|
||||||
|
|
||||||
if(NOT ENABLE_LICENSING)
|
if(NOT ENABLE_LICENSING)
|
||||||
list(REMOVE_ITEM GUI_SOURCE_FILES ${ACTIVATION_FILES})
|
list(REMOVE_ITEM GUI_SOURCE_FILES ${ACTIVATION_FILES})
|
||||||
list(REMOVE_ITEM GUI_UI_FILES ${ACTIVATION_FILES})
|
list(REMOVE_ITEM GUI_UI_FILES ${ACTIVATION_FILES})
|
||||||
|
|
@ -51,17 +44,23 @@ if(WIN32)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||||
install(TARGETS synergy DESTINATION ${SYNERGY_BUNDLE_BINARY_DIR})
|
|
||||||
install(
|
|
||||||
CODE "MESSAGE (\"Running macdeployqt to install frameworks in bundle\")")
|
|
||||||
install(
|
|
||||||
CODE "execute_process(COMMAND ${MACDEPLOYQT_EXECUTABLE} ${SYNERGY_BUNDLE_APP_DIR} -always-overwrite)"
|
|
||||||
)
|
|
||||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
|
||||||
install(TARGETS synergy DESTINATION bin)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WIN32)
|
find_program(MACDEPLOYQT_BIN macdeployqt6)
|
||||||
|
message(STATUS "Found macdeployqt6: ${MACDEPLOYQT_BIN}")
|
||||||
|
|
||||||
|
set(MACDEPLOYQT_CMD
|
||||||
|
"${MACDEPLOYQT_BIN} ${SYNERGY_BUNDLE_APP_DIR} -always-overwrite")
|
||||||
|
|
||||||
|
install(TARGETS synergy DESTINATION ${SYNERGY_BUNDLE_BINARY_DIR})
|
||||||
|
install(CODE "MESSAGE (\"Running: ${MACDEPLOYQT_CMD}\")")
|
||||||
|
install(CODE "execute_process(COMMAND ${MACDEPLOYQT_CMD})")
|
||||||
|
|
||||||
|
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||||
|
|
||||||
|
install(TARGETS synergy DESTINATION bin)
|
||||||
|
|
||||||
|
elseif(WIN32)
|
||||||
|
|
||||||
if(Qt6_FOUND
|
if(Qt6_FOUND
|
||||||
AND WIN32
|
AND WIN32
|
||||||
AND TARGET Qt6::qmake
|
AND TARGET Qt6::qmake
|
||||||
|
|
@ -83,6 +82,7 @@ if(WIN32)
|
||||||
${imported_location})
|
${imported_location})
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(TARGET Qt6::windeployqt)
|
if(TARGET Qt6::windeployqt)
|
||||||
# execute windeployqt in a tmp directory after build
|
# execute windeployqt in a tmp directory after build
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
|
|
@ -92,4 +92,5 @@ if(WIN32)
|
||||||
COMMAND Qt6::windeployqt
|
COMMAND Qt6::windeployqt
|
||||||
"$<TARGET_FILE_DIR:synergy>/$<TARGET_FILE_NAME:synergy>")
|
"$<TARGET_FILE_DIR:synergy>/$<TARGET_FILE_NAME:synergy>")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue