feat: productbuild cpack support

This commit is contained in:
Yaroslav Gurov
2026-04-13 02:56:18 +02:00
parent de5e2635e3
commit 3ad6a7a46d
19 changed files with 200 additions and 150 deletions

View File

@@ -45,4 +45,6 @@ if(NOT IOS AND NOT ANDROID AND NOT MACOS_NE)
add_subdirectory(service)
endif()
include(${CMAKE_SOURCE_DIR}/cmake/CPack.cmake)
if ((LINUX AND NOT ANDROID) OR (APPLE AND NOT IOS AND NOT MACOS_NE) OR (WIN32))
include(${CMAKE_SOURCE_DIR}/cmake/CPack.cmake)
endif()

View File

@@ -210,11 +210,11 @@ endif()
install(TARGETS ${PROJECT}
DESTINATION ${CMAKE_INSTALL_BINDIR}
COMPONENT client
COMPONENT AmneziaVPN
)
install(FILES $<TARGET_RUNTIME_DLLS:${PROJECT}>
DESTINATION ${CMAKE_INSTALL_BINDIR}
COMPONENT client
COMPONENT AmneziaVPN
)
set(deploy_tool_options "")
@@ -229,5 +229,5 @@ qt_generate_deploy_qml_app_script(
DEPLOY_TOOL_OPTIONS ${deploy_tool_options}
)
install(SCRIPT ${QT_DEPLOY_SCRIPT}
COMPONENT client
COMPONENT AmneziaVPN
)

View File

@@ -2,17 +2,20 @@ set(CPACK_PACKAGE_VENDOR AmneziaVPN)
set(CPACK_PACKAGE_VERSION ${AMNEZIAVPN_VERSION})
set(CPACK_PACKAGE_INSTALL_DIRECTORY AmneziaVPN)
set(CPACK_PACKAGE_EXECUTABLES AmneziaVPN AmneziaVPN)
# set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE")
set(CPACK_PRE_BUILD_SCRIPTS ${CMAKE_CURRENT_LIST_DIR}/sign_binaries.cmake)
set(CPACK_POST_BUILD_SCRIPTS ${CMAKE_CURRENT_LIST_DIR}/sign_packages.cmake)
set(CPACK_PROJECT_CONFIG_FILE ${CMAKE_CURRENT_LIST_DIR}/CPackOptions.cmake)
set(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_SOURCE_DIR}/deploy/data/LICENSE.txt)
if (LINUX AND NOT ANDROID)
set(CPACK_GENERATOR IFW)
elseif (WIN32)
list(PREPEND CPACK_COMPONENTS_ALL AmneziaVPN)
if(APPLE)
set(CPACK_GENERATOR productbuild)
else()
set(CPACK_GENERATOR IFW)
endif()
# === CPack IFW generator settings ===
set(CPACK_IFW_PACKAGE_NAME AmneziaVPN)
set(CPACK_IFW_PACKAGE_TITLE AmneziaVPN)
set(CPACK_IFW_PACKAGE_WIZARD_DEFAULT_WIDTH 600)
@@ -21,63 +24,68 @@ set(CPACK_IFW_PACKAGE_WIZARD_STYLE Modern)
set(CPACK_IFW_PACKAGE_REMOVE_TARGET_DIR ON)
set(CPACK_IFW_PACKAGE_ALLOW_SPACE_IN_PATH ON)
set(CPACK_IFW_PACKAGE_ALLOW_NON_ASCII_CHARACTERS ON)
set(CPACK_IFW_PACKAGE_CONTROL_SCRIPT "${CMAKE_SOURCE_DIR}/deploy/installer/qif/controlscript.js")
set(CPACK_IFW_PACKAGE_CONTROL_SCRIPT ${CMAKE_SOURCE_DIR}/deploy/installer/qif/controlscript.js)
set(CPACK_WIX_VERSION 4)
set(CPACK_WIX_UPGRADE_GUID "{2D55AC62-96D6-4692-8C05-0D85BBF95485}")
set(CPACK_WIX_PRODUCT_ICON "${CMAKE_SOURCE_DIR}/client/images/app.ico")
set(CPACK_WIX_CUSTOM_XMLNS "util=http://wixtoolset.org/schemas/v4/wxs/util")
# === CPack WIX generator settings ===
set(CPACK_WIX_VERSION 4)
set(CPACK_WIX_UPGRADE_GUID "{2D55AC62-96D6-4692-8C05-0D85BBF95485}")
set(CPACK_WIX_PRODUCT_ICON ${CMAKE_SOURCE_DIR}/client/images/app.ico)
set(CPACK_WIX_CUSTOM_XMLNS "util=http://wixtoolset.org/schemas/v4/wxs/util")
set(_AMNEZIA_WIX_PATCH_SERVICE ${CMAKE_SOURCE_DIR}/deploy/installer/wix/service_install_patch.xml)
set(_AMNEZIA_WIX_PATCH_CLOSE_APP ${CMAKE_SOURCE_DIR}/deploy/installer/wix/close_client_patch.xml)
file(TO_CMAKE_PATH "${_AMNEZIA_WIX_PATCH_SERVICE}" _AMNEZIA_WIX_PATCH_SERVICE_CMAKE)
file(TO_CMAKE_PATH "${_AMNEZIA_WIX_PATCH_CLOSE_APP}" _AMNEZIA_WIX_PATCH_CLOSE_APP_CMAKE)
list(APPEND CPACK_WIX_PATCH_FILE "${_AMNEZIA_WIX_PATCH_SERVICE_CMAKE}" "${_AMNEZIA_WIX_PATCH_CLOSE_APP_CMAKE}")
list(APPEND CPACK_WIX_EXTENSIONS "WixToolset.Util.wixext")
set(_AMNEZIA_WIX_PATCH_SERVICE "${CMAKE_SOURCE_DIR}/deploy/installer/wix/service_install_patch.xml")
set(_AMNEZIA_WIX_PATCH_CLOSE_APP "${CMAKE_SOURCE_DIR}/deploy/installer/wix/close_client_patch.xml")
file(TO_CMAKE_PATH "${_AMNEZIA_WIX_PATCH_SERVICE}" _AMNEZIA_WIX_PATCH_SERVICE_CMAKE)
file(TO_CMAKE_PATH "${_AMNEZIA_WIX_PATCH_CLOSE_APP}" _AMNEZIA_WIX_PATCH_CLOSE_APP_CMAKE)
set(CPACK_WIX_PATCH_FILE "${_AMNEZIA_WIX_PATCH_SERVICE_CMAKE};${_AMNEZIA_WIX_PATCH_CLOSE_APP_CMAKE}")
set(CPACK_WIX_EXTENSIONS "${CPACK_WIX_EXTENSIONS};WixToolset.Util.wixext")
# === CPack productbuild generator settings ===
set(CPACK_PRODUCTBUILD_IDENTIFIER org.amneziavpn)
set(CPACK_PREFLIGHT_AMNEZIAVPN_SCRIPT ${CMAKE_SOURCE_DIR}/deploy/data/macos/post_uninstall.sh)
set(CPACK_POSTFLIGHT_AMNEZIAVPN_SCRIPT ${CMAKE_SOURCE_DIR}/deploy/data/macos/post_install.sh)
set(CPACK_POSTFLIGHT_UNINSTALL_SCRIPT ${CMAKE_SOURCE_DIR}/deploy/data/macos/post_uninstall.sh)
# provide custom CPack.distribution.dist.in
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/deploy/data/macos)
if(LINUX AND NOT ANDROID)
install(FILES
"${CMAKE_SOURCE_DIR}/deploy/data/linux/AmneziaVPN.service"
"${CMAKE_SOURCE_DIR}/deploy/data/linux/AmneziaVPN.png"
"${CMAKE_SOURCE_DIR}/deploy/data/linux/AmneziaVPN.desktop"
"${CMAKE_SOURCE_DIR}/deploy/data/linux/post_install.sh"
"${CMAKE_SOURCE_DIR}/deploy/data/linux/post_uninstall.sh"
${CMAKE_SOURCE_DIR}/deploy/data/linux/AmneziaVPN.service
${CMAKE_SOURCE_DIR}/deploy/data/linux/AmneziaVPN.png
${CMAKE_SOURCE_DIR}/deploy/data/linux/AmneziaVPN.desktop
${CMAKE_SOURCE_DIR}/deploy/data/linux/post_install.sh
${CMAKE_SOURCE_DIR}/deploy/data/linux/post_uninstall.sh
DESTINATION "."
COMPONENT auxiliary
COMPONENT AmneziaVPN
)
endif()
if(WIN32)
install(FILES
"${CMAKE_SOURCE_DIR}/deploy/data/windows/post_install.cmd"
"${CMAKE_SOURCE_DIR}/deploy/data/windows/post_uninstall.cmd"
${CMAKE_SOURCE_DIR}/deploy/data/windows/post_install.cmd
${CMAKE_SOURCE_DIR}/deploy/data/windows/post_uninstall.cmd
DESTINATION "."
COMPONENT auxiliary
COMPONENT AmneziaVPN
)
endif()
include(CPack)
cpack_add_component_group(AmneziaVPN
DISPLAY_NAME AmneziaVPN
)
cpack_add_component(client
DISPLAY_NAME "AmneziaVPN Client"
GROUP AmneziaVPN
)
cpack_add_component(service
DISPLAY_NAME "AmneziaVPN Service"
GROUP AmneziaVPN
)
cpack_add_component(auxiliary
DISPLAY_NAME "Auxiliary scripts"
GROUP AmneziaVPN
)
if (APPLE AND NOT IOS AND NOT MACOS_NE)
install(FILES ${CMAKE_SOURCE_DIR}/deploy/data/macos/AmneziaVPN.plist
DESTINATION "AmneziaVPN.app/Contents/Resources"
COMPONENT AmneziaVPN
)
endif()
include(CPackIFW)
cpack_ifw_configure_component_group(AmneziaVPN
cpack_ifw_configure_component(AmneziaVPN
VERSION ${AMNEZIAVPN_VERSION}
RELEASE_DATE ${RELEASE_DATE}
REQUIRES_ADMIN_RIGHTS
FORCED_INSTALLATION
SCRIPT "${CMAKE_SOURCE_DIR}/deploy/installer/qif/componentscript.js"
SCRIPT ${CMAKE_SOURCE_DIR}/deploy/installer/qif/componentscript.js
)
include(CPack)
cpack_add_component(Uninstall
DISPLAY_NAME "Uninstall AmneziaVPN"
REQUIRES_ADMIN_RIGHTS
DISABLED
)

View File

@@ -1,5 +1,5 @@
if (CPACK_GENERATOR STREQUAL IFW)
set(CPACK_COMPONENTS_ALL client service auxiliary)
else()
set(CPACK_MONOLITHIC_INSTALL TRUE)
set(CPACK_COMPONENTS_ALL AmneziaVPN)
if (CPACK_GENERATOR STREQUAL productbuild)
list(APPEND CPACK_COMPONENTS_ALL Uninstall)
endif()

View File

@@ -25,6 +25,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Android")
CACHE STRING "" FORCE)
endif()
if (WIN32)
if (WIN32 OR APPLE)
set(CMAKE_INSTALL_BINDIR ".")
endif()

View File

@@ -4,8 +4,28 @@ if(WIN32)
"${CPACK_TEMPORARY_DIRECTORY}/*.exe"
)
if(BINARIES)
if(BINARIES AND SIGNTOOL_SUBJECT_NAME)
include(${CMAKE_CURRENT_LIST_DIR}/util/signtool.cmake)
signtool_sign_files("${BINARIES}" "${SIGNTOOL_SUBJECT_NAME}")
endif()
endif()
if(APPLE)
file(GLOB_RECURSE framework_files
"${CPACK_TEMPORARY_DIRECTORY}/*.framework"
"${CPACK_TEMPORARY_DIRECTORY}/*.dylib"
"${CPACK_TEMPORARY_DIRECTORY}/*.appex"
"${CPACK_TEMPORARY_DIRECTORY}/*.bundle"
"${CPACK_TEMPORARY_DIRECTORY}/*.xpc"
)
file(GLOB_RECURSE exec_files
"${CPACK_TEMPORARY_DIRECTORY}/Contents/MacOS/*"
)
set(files ${framework_files} ${exec_files})
if (files AND CODESIGN_SIGNATURE)
include(${CMAKE_CURRENT_LIST_DIR}/util/codesign.cmake)
codesign_sign_files("${files}" "${CODESIGN_SIGNATURE}" "${CODESIGN_KEYCHAIN}")
endif()
endif()

View File

@@ -1,8 +1,22 @@
if(WIN32)
if (CPACK_PACKAGE_FILES)
if (SIGNTOOL_SUBJECT_NAME)
include(${CMAKE_CURRENT_LIST_DIR}/util/signtool.cmake)
foreach(PACKAGE_FILE IN LISTS CPACK_PACKAGE_FILES)
signtool_sign_files("${PACKAGE_FILE}" "${SIGNTOOL_SUBJECT_NAME}")
endforeach()
endif()
endif()
if(APPLE)
if(CODESIGN_SIGNATURE)
include(${CMAKE_CURRENT_LIST_DIR}/util/codesign.cmake)
codesign_sign_files("${CPACK_PACKAGE_FILES}" "${CODESIGN_SIGNATURE}" "${CODESIGN_KEYCHAIN}")
endif()
if(NOTARYTOOL_EMAIL AND NOTARYTOOL_TEAM_ID AND NOTARYTOOL_PASSWORD)
include(${CMAKE_CURRENT_LIST_DIR}/util/notarytool.cmake)
foreach(file IN LISTS CPACK_PACKAGE_FILES)
notarize_and_staple_file("${file}" "${NOTARYTOOL_EMAIL}" "${NOTARYTOOL_TEAM_ID}" "${NOTARYTOOL_PASSWORD}")
endforeach()
endif()
endif()

36
cmake/util/codesign.cmake Normal file
View File

@@ -0,0 +1,36 @@
find_program(CODESIGN_COMMAND codesign REQUIRED)
function(codesign_sign_files files signature keychain)
if (NOT signature)
message(FATAL_ERROR "codesign failed: signature is required")
endif()
set(args
--force
--verbose
--timestamp
--options runtime
--sign "${signature}"
)
if(keychain)
list(APPEND args --keychain "${keychain}")
endif()
foreach(file IN LISTS files)
set(cmd ${CODESIGN_COMMAND} ${args} "${file}")
list(JOIN cmd " " cmd_str)
message(STATUS "${cmd_str}")
execute_process(
COMMAND ${cmd}
RESULT_VARIABLE result
ERROR_VARIABLE error
)
if(NOT result EQUAL 0)
string(REPLACE "\n" "\n " error " ${error}")
message(FATAL_ERROR "codesign failed:\n${error}")
endif()
endforeach()
endfunction()

View File

@@ -0,0 +1,46 @@
find_program(XCRUN_COMMAND xcrun REQUIRED)
function(notarize_file file email team_id password)
set(args
--apple-id ${email}
--team-id ${team_id}
--password ${password}
--wait
)
set(cmd ${XCRUN_COMMAND} notarytool ${args} ${file})
list(JOIN cmd " " cmd_str)
message(STATUS ${cmd_str})
execute_process(COMMAND ${cmd}
RESULT_VARIABLE result
ERROR_VARIABLE error
)
if(NOT result EQUAL 0)
string(REPLACE "\n" "\n " error " ${error}")
message(FATAL_ERROR "notarytool failed:\n${error}")
endif()
endfunction()
function(staple_file file)
set(cmd ${XCRUN_COMMAND} staple ${file})
list(JOIN cmd " " cmd_str)
message(STATUS ${cmd_str})
execute_process(COMMAND ${cmd}
RESULT_VARIABLE result
ERROR_VARIABLE error
)
if(NOT result EQUAL 0)
string(REPLACE "\n" "\n " error " ${error}")
message(FATAL_ERROR "stapler failed:\n${error}")
endif()
endfunction()
function(notarize_and_staple_file file email team_id password)
notarize_file("${file}" "${email}" "${team_id}" "${password}")
staple_file("${file}")
endfunction()

1
deploy/data/LICENSE.txt Symbolic link
View File

@@ -0,0 +1 @@
../../LICENSE

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<installer-gui-script minSpecVersion="1.0">
<title>@CPACK_PACKAGE_NAME@</title>
<license file="@CPACK_RESOURCE_FILE_LICENSE_NOPATH@"/>
@CPACK_APPLE_PKG_INSTALLER_CONTENT@
</installer-gui-script>

View File

@@ -1,5 +0,0 @@
#!/bin/bash
if [ -d "/Applications/AmneziaVPN.app" ] || pgrep -x "AmneziaVPN-service" >/dev/null; then
exit 1
fi
exit 0

View File

@@ -1,5 +0,0 @@
#!/bin/bash
if [ -d "/Applications/AmneziaVPN.app" ] || pgrep -x "AmneziaVPN-service" >/dev/null; then
exit 0
fi
exit 1

View File

@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<installer-gui-script minSpecVersion="1">
<title>AmneziaVPN Installer</title>
<license file="LICENSE"/>
<choices-outline>
<line choice="install"/>
<line choice="uninstall"/>
</choices-outline>
<choice id="install" title="Install AmneziaVPN" start_selected="true">
<pkg-ref id="org.amneziavpn.package"/>
</choice>
<choice id="uninstall" title="Uninstall AmneziaVPN" start_selected="false">
<pkg-ref id="org.amneziavpn.uninstall"/>
</choice>
<pkg-ref id="org.amneziavpn.package" auth="Root" install-check="scripts/check_install.sh">AmneziaVPN_install.pkg</pkg-ref>
<pkg-ref id="org.amneziavpn.uninstall" auth="Root" install-check="scripts/check_uninstall.sh">AmneziaVPN_uninstall_component.pkg</pkg-ref>
</installer-gui-script>

View File

@@ -1,13 +0,0 @@
<installer-gui-script minSpecVersion="1">
<title>Uninstall AmneziaVPN</title>
<options customize-install-button="always"/>
<welcome file="uninstall_welcome.html"/>
<conclusion file="uninstall_conclusion.html"/>
<choices-outline>
<line choice="uninstall"/>
</choices-outline>
<choice id="uninstall" title="Uninstall AmneziaVPN" start_selected="true">
<pkg-ref id="org.amneziavpn.uninstall"/>
</choice>
<pkg-ref id="org.amneziavpn.uninstall" auth="Root">AmneziaVPN_uninstall_component.pkg</pkg-ref>
</installer-gui-script>

View File

@@ -1,7 +0,0 @@
<html>
<head><title>Uninstall Complete</title></head>
<body>
<h1>AmneziaVPN has been uninstalled</h1>
<p>Thank you for using AmneziaVPN. The application and its components have been removed.</p>
</body>
</html>

View File

@@ -1,7 +0,0 @@
<html>
<head><title>Uninstall AmneziaVPN</title></head>
<body>
<h1>Uninstall AmneziaVPN</h1>
<p>This process will remove AmneziaVPN from your system. Click Continue to proceed.</p>
</body>
</html>

View File

@@ -1,23 +0,0 @@
if(WIN32)
set(RootDir "@RootDir@")
configure_file(
${CMAKE_CURRENT_LIST_DIR}/config/windows.xml.in
${CMAKE_BINARY_DIR}/installer/config/windows.xml
)
elseif(LINUX)
set(ApplicationsDir "@ApplicationsDir@")
configure_file(
${CMAKE_CURRENT_LIST_DIR}/config/linux.xml.in
${CMAKE_BINARY_DIR}/installer/config/linux.xml
)
configure_file(
${CMAKE_CURRENT_LIST_DIR}/config/AmneziaVPN.desktop.in
${CMAKE_BINARY_DIR}/../AppDir/AmneziaVPN.desktop
)
endif()
configure_file(
${CMAKE_CURRENT_LIST_DIR}/packages/org.amneziavpn.package/meta/package.xml.in
${CMAKE_BINARY_DIR}/installer/packages/org.amneziavpn.package/meta/package.xml
)

View File

@@ -345,21 +345,15 @@ endif()
qt_add_repc_sources(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipc_interface.rep)
qt_add_repc_sources(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipc_process_interface.rep)
# copy deploy artifacts required to run the application to the debug build folder
if(WIN32)
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
set(DEPLOY_PLATFORM_PATH "windows/x64")
else()
set(DEPLOY_PLATFORM_PATH "windows/x32")
endif()
elseif(LINUX)
list(APPEND CONAN_EXECS "${CMAKE_SOURCE_DIR}/deploy/data/linux/update-resolv-conf.sh")
elseif(APPLE AND NOT IOS)
set(DEPLOY_PLATFORM_PATH "macos")
if(APPLE)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/deploy/data/macos/pf
DESTINATION ${CMAKE_INSTALL_BINDIR}
COMPONENT AmneziaVPN
)
endif()
# install non-linked dependencies
if (WIN32)
if(WIN32)
find_package(awg-windows REQUIRED)
list(APPEND CONAN_EXECS $<TARGET_FILE:amnezia::awg-windows>)
@@ -389,12 +383,12 @@ if(WIN32)
# to the files so just omit it for it
install(FILES ${CONAN_EXECS}
DESTINATION ${CMAKE_INSTALL_BINDIR}
COMPONENT service
COMPONENT AmneziaVPN
)
else()
install(FILES ${CONAN_EXECS}
DESTINATION ${CMAKE_INSTALL_BINDIR}
COMPONENT service
COMPONENT AmneziaVPN
PERMISSIONS
OWNER_READ OWNER_EXECUTE
GROUP_READ GROUP_EXECUTE
@@ -403,7 +397,7 @@ else()
endif()
install(FILES ${CONAN_BINS}
DESTINATION ${CMAKE_INSTALL_BINDIR}
COMPONENT service
COMPONENT AmneziaVPN
)
# install drivers
@@ -416,7 +410,7 @@ if (WIN32)
)
install(DIRECTORY "${TAP_WINDOWS6_BIN}/"
DESTINATION "${CMAKE_INSTALL_BINDIR}/tap"
COMPONENT service
COMPONENT AmneziaVPN
)
find_package(win-split-tunnel REQUIRED)
@@ -427,18 +421,18 @@ if (WIN32)
)
install(DIRECTORY "${WIN_SPLIT_TUNNEL_BIN}/"
DESTINATION ${CMAKE_INSTALL_BINDIR}
COMPONENT service
COMPONENT AmneziaVPN
)
endif()
# install target
install(TARGETS ${PROJECT}
DESTINATION ${CMAKE_INSTALL_BINDIR}
COMPONENT service
COMPONENT AmneziaVPN
)
install(FILES $<TARGET_RUNTIME_DLLS:${PROJECT}>
DESTINATION ${CMAKE_INSTALL_BINDIR}
COMPONENT service
COMPONENT AmneziaVPN
)
qt_generate_deploy_app_script(
@@ -447,5 +441,5 @@ qt_generate_deploy_app_script(
NO_UNSUPPORTED_PLATFORM_ERROR
)
install(SCRIPT ${QT_DEPLOY_SCRIPT}
COMPONENT service
COMPONENT AmneziaVPN
)