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_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
|
||||
# APPLE_NOTARY_USER="example@example.com"
|
||||
|
||||
# [macOS] App-specific password for the Apple ID
|
||||
# https://support.apple.com/en-gb/102654
|
||||
# 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
|
||||
- #7376 Automated weekly build of Docker images for Linux runners
|
||||
- #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
|
||||
|
||||
# 1.14.6
|
||||
|
|
|
|||
|
|
@ -7,12 +7,14 @@
|
|||
"aqtinstall",
|
||||
"codesign",
|
||||
"codesigning",
|
||||
"contribs",
|
||||
"distros",
|
||||
"dmgbuild",
|
||||
"dotenv",
|
||||
"gdrive",
|
||||
"keychain",
|
||||
"Keychains",
|
||||
"LLDB",
|
||||
"macdeployqt",
|
||||
"msvc",
|
||||
"notarytool",
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ class Dependencies:
|
|||
cmd_utils.run(command, shell=True, print_cmd=True)
|
||||
|
||||
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):
|
||||
"""Installs dependencies on Linux."""
|
||||
|
|
|
|||
|
|
@ -4,7 +4,10 @@ import lib.cmd_utils as cmd_utils
|
|||
import lib.env as env
|
||||
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"
|
||||
dist_dir = "dist"
|
||||
product_name = "Synergy 1"
|
||||
|
|
@ -21,35 +24,80 @@ keychain_path = "/Library/Keychains/System.keychain"
|
|||
def set_env_var(name, value):
|
||||
text = f'export {name}="${name}:{value}"'
|
||||
file = os.path.expanduser(shell_rc)
|
||||
with open(file, "r") as f:
|
||||
if text in f.read():
|
||||
return
|
||||
if os.path.exists(file):
|
||||
with open(file, "r") as f:
|
||||
if text in f.read():
|
||||
return
|
||||
|
||||
print(f"Setting environment variable: {name}={name}")
|
||||
with open(file, "a") as f:
|
||||
f.write(f"\n{text}")
|
||||
f.write(f"\n{text}\n")
|
||||
print(f"Appended to {shell_rc}: {text}")
|
||||
|
||||
|
||||
def set_cmake_prefix_env_var(cmake_prefix_command):
|
||||
result = cmd_utils.run(
|
||||
cmake_prefix_command, get_output=True, shell=True, print_cmd=True
|
||||
)
|
||||
cmake_prefix = result.stdout.strip()
|
||||
set_env_var(cmake_env_var, cmake_prefix)
|
||||
def set_env_vars(cmake_prefix_command):
|
||||
cmd_sub = f"$({cmake_prefix_command})"
|
||||
set_env_var(path_env, cmd_sub)
|
||||
set_env_var(cmake_env, cmd_sub)
|
||||
|
||||
|
||||
def package(filename_base):
|
||||
codesign_id = env.get_env("APPLE_CODESIGN_ID")
|
||||
cert_base64 = env.get_env("APPLE_P12_CERTIFICATE")
|
||||
cert_password = env.get_env("APPLE_P12_PASSWORD")
|
||||
"""
|
||||
Package the application for macOS.
|
||||
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()
|
||||
install_certificate(cert_base64, cert_password)
|
||||
assert_certificate_installed(codesign_id)
|
||||
sign_bundle(codesign_id)
|
||||
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():
|
||||
|
|
@ -57,9 +105,19 @@ def build_bundle():
|
|||
# cmake build install target should run macdeployqt
|
||||
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):
|
||||
print(f"Signing bundle {app_path}...")
|
||||
|
||||
assert_certificate_installed(codesign_id)
|
||||
cmd_utils.run(
|
||||
[
|
||||
codesign_path,
|
||||
|
|
@ -75,6 +133,8 @@ def sign_bundle(codesign_id):
|
|||
|
||||
|
||||
def assert_certificate_installed(codesign_id):
|
||||
print(f"Checking certificate: {codesign_id}")
|
||||
|
||||
installed = cmd_utils.run(
|
||||
"security find-identity -v -p codesigning",
|
||||
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}...")
|
||||
notary_tool = NotaryTool()
|
||||
notary_tool.store_credentials(
|
||||
env.get_env("APPLE_NOTARY_USER"),
|
||||
env.get_env("APPLE_NOTARY_PASSWORD"),
|
||||
env.get_env("APPLE_TEAM_ID"),
|
||||
)
|
||||
|
||||
notary_tool.store_credentials(user, password, team_id)
|
||||
notary_tool.submit_and_wait(dmg_path)
|
||||
|
||||
|
||||
|
|
@ -186,10 +241,10 @@ class NotaryTool:
|
|||
notarytool_path,
|
||||
"store-credentials",
|
||||
"notarytool-password",
|
||||
"--apple-id",
|
||||
user,
|
||||
"--team-id",
|
||||
team_id,
|
||||
"--apple-id",
|
||||
user,
|
||||
"--password",
|
||||
password,
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
find_package(
|
||||
Qt6
|
||||
COMPONENTS Core Widgets Network Core5Compat
|
||||
COMPONENTS Core5Compat Core Widgets Network
|
||||
REQUIRED)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
|
@ -17,13 +17,6 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
|||
list(APPEND GUI_SOURCE_FILES ${GUI_MAC_SOURCE_FILES})
|
||||
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)
|
||||
list(REMOVE_ITEM GUI_SOURCE_FILES ${ACTIVATION_FILES})
|
||||
list(REMOVE_ITEM GUI_UI_FILES ${ACTIVATION_FILES})
|
||||
|
|
@ -51,17 +44,23 @@ if(WIN32)
|
|||
endif()
|
||||
|
||||
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
|
||||
AND WIN32
|
||||
AND TARGET Qt6::qmake
|
||||
|
|
@ -83,6 +82,7 @@ if(WIN32)
|
|||
${imported_location})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(TARGET Qt6::windeployqt)
|
||||
# execute windeployqt in a tmp directory after build
|
||||
add_custom_command(
|
||||
|
|
@ -92,4 +92,5 @@ if(WIN32)
|
|||
COMMAND Qt6::windeployqt
|
||||
"$<TARGET_FILE_DIR:synergy>/$<TARGET_FILE_NAME:synergy>")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
|
|
|||
Loading…
Reference in a new issue