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:
Nick Bolton 2024-07-10 16:11:32 +01:00 committed by GitHub
parent 16c0472d4d
commit d8acb36e8d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 117 additions and 58 deletions

View file

@ -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"

View file

@ -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

View file

@ -7,12 +7,14 @@
"aqtinstall",
"codesign",
"codesigning",
"contribs",
"distros",
"dmgbuild",
"dotenv",
"gdrive",
"keychain",
"Keychains",
"LLDB",
"macdeployqt",
"msvc",
"notarytool",

View file

@ -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."""

View file

@ -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,
]

View file

@ -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()