diff --git a/cmake/modules/DoOrFail.cmake b/cmake/modules/DoOrFail.cmake new file mode 100644 --- /dev/null +++ b/cmake/modules/DoOrFail.cmake @@ -0,0 +1,8 @@ +macro(find_program_or_fail VAR) + find_program(${VAR} NAMES ${ARGN}) + if(NOT ${VAR}) + message( + FATAL_ERROR + "Failed to find program [${ARGN}], please make sure that it is installed and reachable through the system PATH.") + endif() +endmacro() diff --git a/cmake/modules/ImageHelper.cmake b/cmake/modules/ImageHelper.cmake new file mode 100644 --- /dev/null +++ b/cmake/modules/ImageHelper.cmake @@ -0,0 +1,115 @@ +# Facilities for image transformations +include(DoOrFail) + +macro(convert_svg_to_png SVG PNG DPI) + find_program_or_fail(RSVG_CONVERT_EXECUTABLE rsvg-convert) + + add_custom_command( + OUTPUT + "${PNG}" + COMMAND + "${RSVG_CONVERT_EXECUTABLE}" + -f + png + -d + "${DPI}" + -p + "${DPI}" + "${SVG}" + -o + "${PNG}" + MAIN_DEPENDENCY + "${SVG}" + ) +endmacro() + +macro(_convert_png_to_tiff_linux PNG TIFF) + # find_package(ImageMagick) does not search in the default bin + # directories and fails. This is a known bug from FindImageMagick: + # https://gitlab.kitware.com/cmake/cmake/issues/16179 + # When the issue is solved the following can be uncommented: + # find_package(ImageMagick COMPONENTS convert REQUIRED CMAKE_FIND_ROOT_PATH_BOTH) + # + # For now, use find_program as a workaround. + find_program_or_fail(ImageMagick_convert_EXECUTABLE convert) + + add_custom_command( + OUTPUT + "${TIFF}" + COMMAND + "${ImageMagick_convert_EXECUTABLE}" + "${PNG}" + "${TIFF}" + MAIN_DEPENDENCY + "${PNG}" + ) +endmacro() + +macro(_convert_png_to_tiff_darwin PNG TIFF) + find_program_or_fail(SIPS_EXECUTABLE sips) + + add_custom_command( + OUTPUT + "${TIFF}" + COMMAND + "${SIPS_EXECUTABLE}" + -s + format + tiff + "${PNG}" + --out + "${TIFF}" + MAIN_DEPENDENCY + "${PNG}" + ) +endmacro() + +macro(convert_png_to_tiff PNG TIFF) + if(NOT CMAKE_CROSSCOMPILING AND ${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + _convert_png_to_tiff_darwin("${PNG}" "${TIFF}") + else() + _convert_png_to_tiff_linux("${PNG}" "${TIFF}") + endif() +endmacro() + +macro(_cat_multi_resolution_tiff_linux OUTPUT) + find_program_or_fail(TIFFCP_EXECUTABLE tiffcp) + + add_custom_command( + OUTPUT + "${OUTPUT}" + COMMAND + "${TIFFCP_EXECUTABLE}" + -c + none + ${ARGN} + "${OUTPUT}" + DEPENDS + ${ARGN} + ) +endmacro() + +macro(_cat_multi_resolution_tiff_darwin OUTPUT) + find_program_or_fail(TIFFUTIL_EXECUTABLE tiffutil) + + add_custom_command( + OUTPUT + "${OUTPUT}" + COMMAND + "${TIFFUTIL_EXECUTABLE}" + -cathidpicheck + ${ARGN} + -out + "${OUTPUT}" + DEPENDS + ${ARGN} + ) +endmacro() + +macro(cat_multi_resolution_tiff OUTPUT) + if(NOT CMAKE_CROSSCOMPILING AND ${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + _cat_multi_resolution_tiff_darwin("${OUTPUT}" ${ARGN}) + else() + _cat_multi_resolution_tiff_linux("${OUTPUT}" ${ARGN}) + endif() +endmacro() diff --git a/cmake/platforms/OSX.cmake b/cmake/platforms/OSX.cmake --- a/cmake/platforms/OSX.cmake +++ b/cmake/platforms/OSX.cmake @@ -39,3 +39,4 @@ find_program(CMAKE_AR ${TOOLCHAIN_PREFIX}-ar) find_program(CMAKE_RANLIB ${TOOLCHAIN_PREFIX}-ranlib) find_program(CMAKE_NM ${TOOLCHAIN_PREFIX}-nm) +find_program(CMAKE_STRIP ${TOOLCHAIN_PREFIX}-strip) diff --git a/contrib/macdeploy/background.svg.cmake.in b/contrib/macdeploy/background.svg.cmake.in new file mode 100644 --- /dev/null +++ b/contrib/macdeploy/background.svg.cmake.in @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + ${PACKAGE_NAME} + + + + + diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -296,12 +296,29 @@ NAME ) + set(INFO_PLIST_STRINGS_FILE "Base.lproj/InfoPlist.strings") + set(INFO_PLIST_STRINGS_PATH "${CMAKE_CURRENT_BINARY_DIR}/${INFO_PLIST_STRINGS_FILE}") + file(WRITE + "${INFO_PLIST_STRINGS_PATH}" + "{ CFBundleDisplayName = \"${PACKAGE_NAME}\"; CFBundleName = \"${PACKAGE_NAME}\"; }" + ) + + set(EMPTY_LPROJ_FILE "${CMAKE_CURRENT_BINARY_DIR}/empty.lproj") + file(TOUCH "${EMPTY_LPROJ_FILE}") + add_executable(BitcoinABC-Qt MACOSX_BUNDLE bitcoin.cpp "${BITCOINQT_BUNDLE_ICON}" + "${INFO_PLIST_STRINGS_PATH}" + "${EMPTY_LPROJ_FILE}" ) target_link_libraries(BitcoinABC-Qt bitcoin-qt-base) + string(JOIN ";" BITCOINQT_BUNDLE_RESOURCES + "${BITCOINQT_BUNDLE_ICON}" + "${EMPTY_LPROJ_FILE}" + ) + set_target_properties(BitcoinABC-Qt PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/share/qt/Info.plist.cmake.in" MACOSX_BUNDLE_BUNDLE_NAME "BitcoinABC-Qt" @@ -311,8 +328,221 @@ MACOSX_BUNDLE_INFO_STRING "${bitcoin-abc_VERSION}, Copyright © 2009-${COPYRIGHT_YEAR} ${COPYRIGHT_HOLDERS_FINAL}" MACOSX_BUNDLE_LONG_VERSION_STRING "${bitcoin-abc_VERSION}" MACOSX_BUNDLE_SHORT_VERSION_STRING "${bitcoin-abc_VERSION}" - RESOURCE "${BITCOINQT_BUNDLE_ICON}" + RESOURCE "${BITCOINQT_BUNDLE_RESOURCES}" + ) + set_source_files_properties( + "${INFO_PLIST_STRINGS_PATH}" + PROPERTIES + MACOSX_PACKAGE_LOCATION "Resources/${INFO_PLIST_STRINGS_FILE}" + ) + + include(DoOrFail) + find_program_or_fail( + INSTALLNAMETOOL_EXECUTABLE + "install_name_tool" + "${TOOLCHAIN_PREFIX}-install_name_tool" + ) + find_program_or_fail( + OTOOL_EXECUTABLE + "otool" + "${TOOLCHAIN_PREFIX}-otool" + ) + + set(QT_INSTALLER_SUPPORTED_LANGUAGES + "da" + "de" + "es" + "hu" + "ru" + "uk" + "zh_CN" + "zh_TW" ) + string(JOIN "," QT_LOCALES ${QT_INSTALLER_SUPPORTED_LANGUAGES}) + + get_target_property(QMAKE_EXECUTABLE Qt5::qmake IMPORTED_LOCATION) + execute_process( + COMMAND + "${QMAKE_EXECUTABLE}" + -query + QT_INSTALL_TRANSLATIONS + OUTPUT_VARIABLE + QT_TRANSLATION_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + function(get_qt_translation_dir QT_TRANSLATION_DIR) + foreach(_locale ${ARGN}) + find_path(_qt_translation_dir + "qt_${_locale}.qm" + HINTS + "${QT_TRANSLATION_DIR}" + PATH_SUFFIXES + "translations" + ) + + # Ensure that all the translation files are fund, and are located in + # the same directory. + if(NOT _qt_translation_dir OR (_qt_translation_dir_previous AND (NOT _qt_translation_dir_previous STREQUAL _qt_translation_dir))) + return() + endif() + + set(_qt_translation_dir_previous _qt_translation_dir) + endforeach() + + set(QT_TRANSLATION_DIR ${_qt_translation_dir} PARENT_SCOPE) + endfunction() + + get_qt_translation_dir(QT_TRANSLATION_DIR ${QT_INSTALLER_SUPPORTED_LANGUAGES}) + if(NOT QT_TRANSLATION_DIR) + message(FATAL_ERROR "Qt translation files are not found") + endif() + + set(MACDEPLOY_DIR "${CMAKE_SOURCE_DIR}/contrib/macdeploy") + set(MACDEPLOYQTPLUS "${MACDEPLOY_DIR}/macdeployqtplus") + set(DMG_DIST "${CMAKE_BINARY_DIR}/dist") + add_custom_command( + OUTPUT + "${DMG_DIST}" + COMMAND + "INSTALLNAMETOOL=${INSTALLNAMETOOL_EXECUTABLE}" + "OTOOL=${OTOOL_EXECUTABLE}" + "STRIP=${CMAKE_STRIP}" + "${PYTHON_EXECUTABLE}" + "${MACDEPLOYQTPLUS}" + "$" + -translations-dir + "${QT_TRANSLATION_DIR}" + -add-qt-tr + "${QT_LOCALES}" + WORKING_DIRECTORY + "${CMAKE_BINARY_DIR}" + DEPENDS + BitcoinABC-Qt + ) + + # Building the DMG background image requires several steps: + # 1/ The SVG file must be edited to display the package name + # 2/ The SVG file should be transformed into a couple PNG files, on for + # low resolution screens and one for high resolution screens. + # 3/ The PNG files must be transformed into a multi-resolution TIFF file. + # The names are not set arbitrarily, they follow Apple's guidelines for + # resolution independent bitmap images (see `man tiffutil`). + set(BACKGROUND_SVG "background.svg") + configure_file( + "${CMAKE_SOURCE_DIR}/contrib/macdeploy/background.svg.cmake.in" + "${BACKGROUND_SVG}" + ) + + include(ImageHelper) + set(BACKGROUND_PNG_LOWRES "${CMAKE_CURRENT_BINARY_DIR}/background_temp.png") + set(BACKGROUND_PNG_HIRES "${CMAKE_CURRENT_BINARY_DIR}/background_temp@2x.png") + set(BACKGROUND_TIFF_LOWRES "${CMAKE_CURRENT_BINARY_DIR}/background_temp.tiff") + set(BACKGROUND_TIFF_HIRES "${CMAKE_CURRENT_BINARY_DIR}/background_temp@2x.tiff") + set(BACKGROUND_TIFF_NAME "background.tiff") + set(BACKGROUND_TIFF_MULTIRES "${CMAKE_BINARY_DIR}/${BACKGROUND_TIFF_NAME}") + convert_svg_to_png("${BACKGROUND_SVG}" "${BACKGROUND_PNG_LOWRES}" 36) + convert_svg_to_png("${BACKGROUND_SVG}" "${BACKGROUND_PNG_HIRES}" 72) + convert_png_to_tiff("${BACKGROUND_PNG_LOWRES}" "${BACKGROUND_TIFF_LOWRES}") + convert_png_to_tiff("${BACKGROUND_PNG_HIRES}" "${BACKGROUND_TIFF_HIRES}") + cat_multi_resolution_tiff("${BACKGROUND_TIFF_MULTIRES}" "${BACKGROUND_TIFF_LOWRES}" "${BACKGROUND_TIFF_HIRES}") + + set(BACKGROUND_DIST_DIR "${DMG_DIST}/.background") + set(BACKGROUND_DIST_TIFF "${BACKGROUND_DIST_DIR}/${BACKGROUND_TIFF_NAME}") + add_custom_command( + OUTPUT + "${BACKGROUND_DIST_TIFF}" + COMMAND + ${CMAKE_COMMAND} -E make_directory "${BACKGROUND_DIST_DIR}" + COMMAND + ${CMAKE_COMMAND} -E copy "${BACKGROUND_TIFF_MULTIRES}" "${BACKGROUND_DIST_TIFF}" + DEPENDS + "${BACKGROUND_TIFF_MULTIRES}" + "${DMG_DIST}" + ) + + string(REPLACE " " "-" OSX_VOLNAME "${PACKAGE_NAME}") + file(WRITE "${CMAKE_BINARY_DIR}/osx_volname" "${OSX_VOLNAME}") + + set(DMG_DSSTORE "${DMG_DIST}/.DS_Store") + set(GEN_DSSTORE "${MACDEPLOY_DIR}/custom_dsstore.py") + add_custom_command( + OUTPUT + "${DMG_DSSTORE}" + COMMAND + "${PYTHON_EXECUTABLE}" + "${GEN_DSSTORE}" + "${DMG_DSSTORE}" + "${OSX_VOLNAME}" + DEPENDS + "${GEN_DSSTORE}" + "${DMG_DIST}" + ) + + set(OSX_APPLICATION_DIR "Applications") + set(OSX_APPLICATION_SYMLINK "${DMG_DIST}/${OSX_APPLICATION_DIR}") + add_custom_command( + OUTPUT + "${OSX_APPLICATION_SYMLINK}" + COMMAND + ${CMAKE_COMMAND} -E create_symlink "/${OSX_APPLICATION_DIR}" "${OSX_APPLICATION_SYMLINK}" + DEPENDS + "${DMG_DIST}" + ) + + add_custom_target(osx-deploydir + DEPENDS + "${OSX_APPLICATION_SYMLINK}" + "${DMG_DSSTORE}" + "${BACKGROUND_DIST_TIFF}" + ) + + if(CMAKE_CROSSCOMPILING) + find_program_or_fail(GENISOIMAGE_EXECUTABLE genisoimage) + + add_custom_target(osx-dmg + COMMAND + "${GENISOIMAGE_EXECUTABLE}" + -no-cache-inodes + -D + -l + -probe + -V + "${OSX_VOLNAME}" + -no-pad + -r + -dir-mode + 0755 + -apple + -o + "${OSX_VOLNAME}.dmg" + "${DMG_DIST}" + WORKING_DIRECTORY + "${CMAKE_BINARY_DIR}" + ) + add_dependencies(osx-dmg osx-deploydir) + else() + add_custom_target(osx-dmg + COMMAND + "${PYTHON_EXECUTABLE}" + "${MACDEPLOYQTPLUS}" + "$" + -translations-dir + "${QT_TRANSLATION_DIR}" + -add-qt-tr + "${QT_LOCALES}" + -dmg + -fancy + "${MACDEPLOY_DIR}/fancy.plist" + -volname + "${OSX_VOLNAME}" + WORKING_DIRECTORY + "${CMAKE_BINARY_DIR}" + DEPENDS + "${BACKGROUND_TIFF_MULTIRES}" + ) + add_dependencies(osx-dmg BitcoinABC-Qt) + endif() endif() # Test tests