From 2522f80cf177e72ca90a6d16f646d2fd5749b86f Mon Sep 17 00:00:00 2001 From: Julien Wadel Date: Fri, 13 Oct 2023 17:19:55 +0200 Subject: [PATCH] Add DMG packaging for Mac. --- .gitlab-ci-files/job-macosx-desktop.yml | 4 +- cmake/install/install.cmake | 98 +++++++++++++++++++++---- cmake/install/macos/app_notarization.sh | 86 ++++++++++++++++++++++ cmake/install/macos/cleanCPack.cmake.in | 49 +++++++++++++ cmake/install/packaging.cmake.in | 4 +- 5 files changed, 222 insertions(+), 19 deletions(-) create mode 100755 cmake/install/macos/app_notarization.sh create mode 100644 cmake/install/macos/cleanCPack.cmake.in diff --git a/.gitlab-ci-files/job-macosx-desktop.yml b/.gitlab-ci-files/job-macosx-desktop.yml index 92443a964..cd1b899ab 100644 --- a/.gitlab-ci-files/job-macosx-desktop.yml +++ b/.gitlab-ci-files/job-macosx-desktop.yml @@ -122,8 +122,8 @@ job-macosx-codesigning: - $DEPLOY_MACOSX script: - cd build - - codesign --timestamp --options runtime,library --verbose -s "$MACOS_SIGNING_IDENTITY" OUTPUT/linphone-app/macos/Packages/Linphone*.dmg - - ./../tools/app_notarization.sh + - codesign --timestamp --options runtime,library --verbose -s "$MACOS_SIGNING_IDENTITY" OUTPUT/Linphone/macos/Packages/Linphone*.dmg + - ./../cmake/install/macos/app_notarization.sh artifacts: when: always paths: diff --git a/cmake/install/install.cmake b/cmake/install/install.cmake index ac4ba3d6d..286fd5f02 100644 --- a/cmake/install/install.cmake +++ b/cmake/install/install.cmake @@ -31,7 +31,9 @@ if (GIT_EXECUTABLE AND NOT(LINPHONEAPP_VERSION)) OUTPUT_STRIP_TRAILING_WHITESPACE WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../.." ) -elseif (NOT(LINPHONEAPP_VERSION)) +endif() + +if (NOT(LINPHONEAPP_VERSION)) set(LINPHONEAPP_VERSION "0.0.0") endif () @@ -49,11 +51,58 @@ if(ENABLE_APP_PACKAGE_ROOTCA) install(FILES "${LINPHONE_OUTPUT_DIR}/share/linphone/rootca.pem" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/${EXECUTABLE_NAME}") endif() +set(LINPHONE_QML_DIR "${CMAKE_SOURCE_DIR}/Linphone/view") +set(QT_PATH "${Qt6Core_DIR}/../../..") + +if(APPLE) + configure_file("${CMAKE_SOURCE_DIR}/cmake/install/macos/Info.plist.in" "${CMAKE_BINARY_DIR}/cmake/install/macos/Info.plist" @ONLY) + configure_file("${CMAKE_SOURCE_DIR}/cmake/install/macos/entitlements.xml.in" "${CMAKE_BINARY_DIR}/cmake/install/macos/entitlements.xml" @ONLY) + configure_file("${CMAKE_SOURCE_DIR}/cmake/install/macos/linphone.icns" "${CMAKE_BINARY_DIR}/cmake/install/macos/${EXECUTABLE_NAME}.icns" COPYONLY) + set(APP_QT_CONF_PATH "[Paths]\nPlugins = PlugIns\nImports = Resources/qml\nQml2Imports = Resources/qml") + + #configure_file("${CMAKE_SOURCE_DIR}/Linphone/../assets/qt.conf.in" "${CMAKE_BINARY_DIR}/cmake/install/macos/qt.conf" @ONLY) + #install(FILES "${CMAKE_BINARY_DIR}/cmake/install/macos/qt.conf" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/..") + install(FILES "${CMAKE_BINARY_DIR}/cmake/install/macos/Info.plist" DESTINATION "${APPLICATION_NAME}.app/Contents") + install(FILES "${CMAKE_BINARY_DIR}/cmake/install/macos/${EXECUTABLE_NAME}.icns" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/..") + file(GLOB SHARED_LIBRARIES "${LINPHONE_OUTPUT_DIR}/${CMAKE_INSTALL_LIBDIR}/lib*.dylib") + if( ENABLE_OPENH264 )# Remove openH264 lib from the installation. this codec will be download by user + foreach(item ${SHARED_LIBRARIES}) + get_filename_component(LIBRARY_FILENAME ${item} NAME) + if("${LIBRARY_FILENAME}" MATCHES "^libopenh264.*.dylib$") + list(REMOVE_ITEM SHARED_LIBRARIES ${item}) + endif() + endforeach(item) + endif() + install(FILES ${SHARED_LIBRARIES} DESTINATION "${CMAKE_INSTALL_LIBDIR}") + install(DIRECTORY "${LINPHONE_OUTPUT_DIR}/${CMAKE_INSTALL_DATAROOTDIR}/images" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}" USE_SOURCE_PERMISSIONS OPTIONAL) + #install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../../assets/linphonerc-factory" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/${EXECUTABLE_NAME}") + + file(GLOB SHARED_LIBRARIES "${CMAKE_BINARY_DIR}/cmake/install/macos/${APPLICATION_NAME}.app/Contents/Frameworks/lib*.dylib") + + foreach (LIBRARY ${SHARED_LIBRARIES}) + get_filename_component(LIBRARY_FILENAME ${LIBRARY} NAME) + message("Changing RPATH of ${LIBRARY_FILENAME} from '${LINPHONE_OUTPUT_DIR}/${CMAKE_INSTALL_LIBDIR}' to '@executable_path/../Frameworks'") + execute_process(COMMAND install_name_tool -rpath "${LINPHONE_OUTPUT_DIR}/${CMAKE_INSTALL_LIBDIR}" "@executable_path/../Frameworks" "${LIBRARY}") + endforeach () + install(TARGETS ${APP_PLUGIN} + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + ) + install(CODE "execute_process(COMMAND install_name_tool -add_rpath \"@executable_path/../Frameworks/\" \"\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/${EXECUTABLE_NAME}\")") + install(CODE "execute_process(COMMAND install_name_tool -add_rpath \"@executable_path/../lib/\" \"\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/${EXECUTABLE_NAME}\")") + get_filename_component(_qt_bin_dir "${qmake_executable}" DIRECTORY) + find_program(DEPLOYQT_PROGRAM macdeployqt HINTS "${_qt_bin_dir}") + if (NOT DEPLOYQT_PROGRAM) + message(FATAL_ERROR "Could not find the macdeployqt program. Make sure it is in the PATH.") + endif() + install(CODE "execute_process(COMMAND ${DEPLOYQT_PROGRAM} ${APPLICATION_OUTPUT_DIR}/${APPLICATION_NAME}.app -qmldir=${LINPHONE_QML_DIR} -no-strip )") +endif() + # ============================================================================== # CPack. # ============================================================================== -set(LINPHONE_QML_DIR "${CMAKE_SOURCE_DIR}/Linphone/view") -set(QT_PATH "${Qt6Core_DIR}/../../..") + if(${ENABLE_APP_PACKAGING}) set(CPACK_BINARY_STGZ OFF) @@ -74,22 +123,41 @@ if(${ENABLE_APP_PACKAGING}) unset(CPACK_RESOURCE_FILE_LICENSE) endif() set(CPACK_RESOURCE_FILE_LICENSE_PROVIDED ${ENABLE_APP_LICENSE}) - set(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/../../assets/icon.ico") + set(CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}/Linphone/data/icon.ico") set(PERFORM_SIGNING 0) + + if(APPLE) +############################################## +# APPLE +############################################## + set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${PACKAGE_VERSION}-mac") + set(CPACK_DMG_BACKGROUND_IMAGE "${CMAKE_SOURCE_DIR}/cmake/install/macos/background_dmg.jpg") + configure_file("${CMAKE_SOURCE_DIR}/cmake/install/macos/linphone_dmg.scpt.in" "${CMAKE_BINARY_DIR}/cmake/install/macos/linphone_dmg.scpt" @ONLY) + set(CPACK_DMG_DS_STORE_SETUP_SCRIPT "${CMAKE_BINARY_DIR}/cmake/install/macos/linphone_dmg.scpt") + set(CPACK_BINARY_DRAGNDROP ON) + set(CPACK_BUNDLE_APPLE_CERT_APP ${LINPHONE_BUILDER_SIGNING_IDENTITY}) + set(PACKAGE_EXT "dmg") + + configure_file("${CMAKE_SOURCE_DIR}/cmake/install/macos/cleanCpack.cmake.in" "${CMAKE_BINARY_DIR}/cmake/install/macos/cleanCpack.cmake" @ONLY) + set(CPACK_PRE_BUILD_SCRIPTS "${CMAKE_BINARY_DIR}/cmake/install/macos/cleanCPack.cmake") + + message(STATUS "Set DragNDrop CPack generator in OUTPUT/Packages") + else() ############################################## # LINUX ############################################## - set(DO_APPIMAGE YES) - set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${PACKAGE_VERSION}") - set(PACKAGE_EXT "AppImage") - configure_file("${CMAKE_SOURCE_DIR}/cmake/install/linux/linphone.desktop.cmake" "${CMAKE_BINARY_DIR}/cmake/install/linux/${EXECUTABLE_NAME}.desktop" @ONLY) - install(FILES "${CMAKE_BINARY_DIR}/cmake/install/linux/${EXECUTABLE_NAME}.desktop" DESTINATION "${CMAKE_INSTALL_DATADIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) - install(FILES "${CMAKE_SOURCE_DIR}/Linphone/data/image/logo.svg" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/apps/" RENAME "${EXECUTABLE_NAME}.svg") - set(ICON_DIRS 16x16 22x22 24x24 32x32 64x64 128x128 256x256) - foreach (DIR ${ICON_DIRS}) - install(FILES "${CMAKE_SOURCE_DIR}/Linphone/data/icon/hicolor/${DIR}/apps/icon.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/${DIR}/apps/" RENAME "${EXECUTABLE_NAME}.png") - endforeach () - message(STATUS "Set AppImage CPack generator in OUTPUT/Packages") + set(DO_APPIMAGE YES) + set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${PACKAGE_VERSION}") + set(PACKAGE_EXT "AppImage") + configure_file("${CMAKE_SOURCE_DIR}/cmake/install/linux/linphone.desktop.cmake" "${CMAKE_BINARY_DIR}/cmake/install/linux/${EXECUTABLE_NAME}.desktop" @ONLY) + install(FILES "${CMAKE_BINARY_DIR}/cmake/install/linux/${EXECUTABLE_NAME}.desktop" DESTINATION "${CMAKE_INSTALL_DATADIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) + install(FILES "${CMAKE_SOURCE_DIR}/Linphone/data/image/logo.svg" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/apps/" RENAME "${EXECUTABLE_NAME}.svg") + set(ICON_DIRS 16x16 22x22 24x24 32x32 64x64 128x128 256x256) + foreach (DIR ${ICON_DIRS}) + install(FILES "${CMAKE_SOURCE_DIR}/Linphone/data/icon/hicolor/${DIR}/apps/icon.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/${DIR}/apps/" RENAME "${EXECUTABLE_NAME}.png") + endforeach () + message(STATUS "Set AppImage CPack generator in OUTPUT/Packages") + endif() ############################################## configure_file("${CMAKE_SOURCE_DIR}/cmake/install/packaging.cmake.in" "${CMAKE_BINARY_DIR}/cmake/install/packaging.cmake" @ONLY) install(SCRIPT "${CMAKE_BINARY_DIR}/cmake/install/packaging.cmake") diff --git a/cmake/install/macos/app_notarization.sh b/cmake/install/macos/app_notarization.sh new file mode 100755 index 000000000..4ea762182 --- /dev/null +++ b/cmake/install/macos/app_notarization.sh @@ -0,0 +1,86 @@ +#!/bin/bash + +#Notarization for Mac. Launch it from the build folder + +#rm notarize_result.plist +FILES=OUTPUT/Linphone/macos/Packages/*.dmg +for f in $FILES +do + linphone_file=$f +done + +echo "Uploading $linphone_file file with xcrun altool" +xcrun altool --notarize-app --primary-bundle-id $MACOSX_SIGNING_IDENTIFIER -u "$MACOSX_SIGNING_MAIL" -p "$MACOSX_SIGNING_PASS" --asc-provider "$MACOSX_SIGNING_PROVIDER" --file $linphone_file --output-format xml > "notarize_result.plist" +echo "dmg processed. Checking UUID" +request_uuid="$("/usr/libexec/PlistBuddy" -c "Print notarization-upload:RequestUUID" notarize_result.plist)" +echo "Notarization UUID: ${request_uuid}" +#Get status from upload +declare -i tryCount=0 +declare -i maxCount=4 +for (( ; ; )) +do + echo "Getting notarization status" + xcrun altool --notarization-info "${request_uuid}" -u "$MACOSX_SIGNING_MAIL" -p "$MACOSX_SIGNING_PASS" --asc-provider "$MACOSX_SIGNING_PROVIDER" --output-format xml > "notarize_result2.plist" + xcrun_result=$? + if [ "${xcrun_result}" != "0" ] + then + if [ "$tryCount" -lt "$maxCount" ] + then + tryCount=$((tryCount + 1)) + sleep 60 + continue + else + echo "Notarization failed: ${xcrun_result}" + cat "notarize_result2.plist" + exit 1 + fi + fi + notarize_status="$("/usr/libexec/PlistBuddy" -c "Print notarization-info:Status" notarize_result2.plist)" + if [[ "${notarize_status}" == *"in progress"* ]]; then + echo "Waiting for notarization to complete: ${notarize_status}" + sleep 20 + else + echo "Notarization status: ${notarize_status}" + break + fi +done +log_url="$("/usr/libexec/PlistBuddy" -c "Print notarization-info:LogFileURL" notarize_result2.plist)" +echo "Notarization log URL: ${log_url}" + +if [ "${notarize_status}" != "success" ] +then + echo "Notarization failed." + if [ ! -z "${log_url}" ] + then + curl "${log_url}" + fi + exit 1 +fi + +echo "Stapling notarization result..." +for (( ; ; )) +do + xcrun stapler staple -q $linphone_file + stapler_result=$? + if [ "${stapler_result}" = "65" ] + then + echo "Waiting for stapling to find record" + sleep 10 + else + echo "Stapler status: ${stapler_result}" + break + fi +done + + +spctl --assess --type open --context context:primary-signature -v $linphone_file +#validation_result=$? + +echo "Validating image : $?" +#if [ "${validation_result}" != 0 ] +#then +# echo "Failed to validate image: ${validation_result}" +# curl "${log_url}" +# exit 1 +#fi +exit 0 diff --git a/cmake/install/macos/cleanCPack.cmake.in b/cmake/install/macos/cleanCPack.cmake.in new file mode 100644 index 000000000..131018f1a --- /dev/null +++ b/cmake/install/macos/cleanCPack.cmake.in @@ -0,0 +1,49 @@ +################################################################################ +# +# Copyright (c) 2017-2024 Belledonne Communications SARL. +# +# This file is part of linphone-desktop +# (see https://www.linphone.org). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +################################################################################ + +# This script is used for CPack to remove root folders that comes from SDK. +# As CPack call install() from SDK, its files are into cmake_install_prefix too. +# It is neccessary to use it because CPack doesn't take account of some install() (those that do the move) + +set(DO_SIGNING @LINPHONE_BUILDER_SIGNING_IDENTITY@) + +execute_process(COMMAND rsync -a --force "${CPACK_TEMPORARY_INSTALL_DIRECTORY}/ALL_IN_ONE/Frameworks/" "${CPACK_TEMPORARY_INSTALL_DIRECTORY}/ALL_IN_ONE/@CMAKE_INSTALL_LIBDIR@/") #Use rsync to bypass symlinks override issues of frameworks. copy_directory will fail without explicit error... +#execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${CPACK_TEMPORARY_INSTALL_DIRECTORY}/ALL_IN_ONE/Frameworks/" "${CPACK_TEMPORARY_INSTALL_DIRECTORY}/ALL_IN_ONE/@CMAKE_INSTALL_LIBDIR@/") +execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory "${CPACK_TEMPORARY_INSTALL_DIRECTORY}/ALL_IN_ONE/Frameworks/") + +execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${CPACK_TEMPORARY_INSTALL_DIRECTORY}/ALL_IN_ONE/include/" "${CPACK_TEMPORARY_INSTALL_DIRECTORY}/ALL_IN_ONE/@CMAKE_INSTALL_INCLUDEDIR@/") +execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory "${CPACK_TEMPORARY_INSTALL_DIRECTORY}/ALL_IN_ONE/include/") +# move share +execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${CPACK_TEMPORARY_INSTALL_DIRECTORY}/ALL_IN_ONE/share/" "${CPACK_TEMPORARY_INSTALL_DIRECTORY}/ALL_IN_ONE/@CMAKE_INSTALL_DATAROOTDIR@/") +execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory "${CPACK_TEMPORARY_INSTALL_DIRECTORY}/ALL_IN_ONE/share/") +# move mkspecs +execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${CPACK_TEMPORARY_INSTALL_DIRECTORY}/ALL_IN_ONE/mkspecs/" "${CPACK_TEMPORARY_INSTALL_DIRECTORY}/ALL_IN_ONE/@CMAKE_INSTALL_DATAROOTDIR@/") +execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory "${CPACK_TEMPORARY_INSTALL_DIRECTORY}/ALL_IN_ONE/mkspecs/") +# remove other folders +execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory "${CPACK_TEMPORARY_INSTALL_DIRECTORY}/ALL_IN_ONE/cmake/") +execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory "${CPACK_TEMPORARY_INSTALL_DIRECTORY}/ALL_IN_ONE/lib/") + +#CPack doesn't sign all files. +if (DO_SIGNING) + execute_process(COMMAND bash "@CMAKE_SOURCE_DIR@/cmake/install/sign_package.sh" codesign "@LINPHONE_BUILDER_SIGNING_IDENTITY@" "${CPACK_TEMPORARY_INSTALL_DIRECTORY}/ALL_IN_ONE") + #execute_process(COMMAND codesign --entitlements" "@CMAKE_CURRENT_BINARY_DIR@/../../entitlements.xml" "--force" "--deep" "--timestamp" "--options" "runtime,library" "--verbose" "-s" "@LINPHONE_BUILDER_SIGNING_IDENTITY@" "@APPLICATION_OUTPUT_DIR@/@APPLICATION_NAME@.app") +endif() diff --git a/cmake/install/packaging.cmake.in b/cmake/install/packaging.cmake.in index 1a8e19fb7..12e4c56d4 100644 --- a/cmake/install/packaging.cmake.in +++ b/cmake/install/packaging.cmake.in @@ -71,12 +71,12 @@ if (NOT "${CMAKE_INSTALL_PREFIX}" MATCHES .*/_CPack_Packages/.*) if (@PERFORM_SIGNING@) if(@PASSPHRASE_FILE@) execute_process( - COMMAND "@CMAKE_CURRENT_SOURCE_DIR@/../../tools/sign_package.bat" 1 "@PASSPHRASE_FILE@" "@SIGNTOOL_COMMAND@" "@PFX_FILE@" "@TIMESTAMP_URL@" @CPACK_PACKAGE_FILE_NAME@.@PACKAGE_EXT@ + COMMAND "@CMAKE_SOURCE_DIR@/cmake/install/sign_package.bat" 1 "@PASSPHRASE_FILE@" "@SIGNTOOL_COMMAND@" "@PFX_FILE@" "@TIMESTAMP_URL@" @CPACK_PACKAGE_FILE_NAME@.@PACKAGE_EXT@ RESULT_VARIABLE SIGNING_RESULT WORKING_DIRECTORY "@CPACK_PACKAGE_DIRECTORY@" ) else() execute_process( - COMMAND "@CMAKE_CURRENT_SOURCE_DIR@/../../tools/sign_package.bat" 2 "@SIGNTOOL_COMMAND@" "@TIMESTAMP_URL@" @SIGN_HASH@ @CPACK_PACKAGE_FILE_NAME@.@PACKAGE_EXT@ + COMMAND "@CMAKE_SOURCE_DIR@/cmake/install/sign_package.bat" 2 "@SIGNTOOL_COMMAND@" "@TIMESTAMP_URL@" @SIGN_HASH@ @CPACK_PACKAGE_FILE_NAME@.@PACKAGE_EXT@ RESULT_VARIABLE SIGNING_RESULT WORKING_DIRECTORY "@CPACK_PACKAGE_DIRECTORY@" ) endif()