CMakeLists.txt raw

   1  # Copyright (c) 2023-present The Limenka developers
   2  # Distributed under the MIT software license, see the accompanying
   3  # file COPYING or https://opensource.org/license/mit/.
   4  
   5  if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
   6    enable_language(OBJCXX)
   7    set(CMAKE_OBJCXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
   8    set(CMAKE_OBJCXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
   9    set(CMAKE_OBJCXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
  10    set(CMAKE_OBJCXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL}")
  11    string(APPEND CMAKE_OBJCXX_COMPILE_OBJECT " ${APPEND_CPPFLAGS} ${APPEND_CXXFLAGS}")
  12  endif()
  13  
  14  get_target_property(qt_lib_type "Qt${WITH_QT_VERSION}::Core" TYPE)
  15  
  16  function(import_plugins target)
  17    if(qt_lib_type STREQUAL "STATIC_LIBRARY")
  18      set(plugins "Qt${WITH_QT_VERSION}::QMinimalIntegrationPlugin")
  19      if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
  20        list(APPEND plugins "Qt${WITH_QT_VERSION}::QXcbIntegrationPlugin")
  21      elseif(WIN32)
  22        if("${WITH_QT_VERSION}" STREQUAL "5")
  23        list(APPEND plugins Qt5::QWindowsIntegrationPlugin Qt5::QWindowsVistaStylePlugin)
  24        else()  # Qt 6
  25          list(APPEND plugins Qt6::QWindowsIntegrationPlugin Qt6::QModernWindowsStylePlugin)
  26        endif()  # Qt version
  27      elseif(APPLE)
  28        list(APPEND plugins "Qt${WITH_QT_VERSION}::QCocoaIntegrationPlugin" "Qt${WITH_QT_VERSION}::QMacStylePlugin")
  29      endif()
  30      cmake_language(CALL "qt${WITH_QT_VERSION}_import_plugins" ${target}
  31        INCLUDE ${plugins}
  32        EXCLUDE_BY_TYPE
  33          accessiblebridge
  34          platforms
  35          platforms_darwin
  36          xcbglintegrations
  37          platformthemes
  38          platforminputcontexts
  39          generic
  40          iconengines
  41          imageformats
  42          egldeviceintegrations
  43          styles
  44          networkaccess
  45          networkinformation
  46          tls
  47      )
  48    endif()
  49  endfunction()
  50  
  51  # For Qt-specific commands and variables, please consult:
  52  #  - https://cmake.org/cmake/help/latest/manual/cmake-qt.7.html
  53  #  - https://doc.qt.io/qt-5/cmake-manual.html
  54  
  55  set(CMAKE_AUTOMOC ON)
  56  set(CMAKE_AUTOMOC_MOC_OPTIONS "-p${CMAKE_CURRENT_SOURCE_DIR}")
  57  set(CMAKE_AUTORCC ON)
  58  set(CMAKE_AUTOUIC ON)
  59  set(CMAKE_AUTOUIC_SEARCH_PATHS forms)
  60  
  61  # TODO: The file(GLOB ...) command should be replaced with an explicit
  62  # file list. Such a change must be synced with the corresponding change
  63  # to https://github.com/limenka/limenka-maintainer-tools/blob/main/update-translations.py
  64  file(GLOB ts_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} locale/*.ts)
  65  set_source_files_properties(${ts_files} PROPERTIES OUTPUT_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/locale)
  66  cmake_language(CALL "qt${WITH_QT_VERSION}_add_translation" qm_files ${ts_files})
  67  
  68  set(FONT_PATH "res/fonts/OCR-Limenka.ttf")
  69  file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/res/fonts")
  70  add_custom_command(
  71    OUTPUT ${FONT_PATH}
  72    COMMAND ${PYTHON_COMMAND} -c "import base64, lzma, sys; sys.stdout.buffer.write(lzma.decompress(base64.b85decode(sys.stdin.read())))" < "${CMAKE_CURRENT_SOURCE_DIR}/${FONT_PATH}.in" > "${FONT_PATH}.new" && mv "${FONT_PATH}.new" "${FONT_PATH}"
  73    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${FONT_PATH}.in
  74    VERBATIM
  75  )
  76  
  77  set(ICON_PATH "res/rendered_icons")
  78  set(ICO_SPECS
  79    256 64 48 32 24 20 16
  80  )
  81  set(ICNS_SPECS
  82    1024
  83  )
  84  set(EXTRA_ICON_SPECS
  85    290 256
  86  )
  87  
  88  if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
  89    set(limenka_svg "res/src/limenka-mac.svg")
  90  else()
  91    set(limenka_svg "res/src/limenka.svg")
  92  endif()
  93  
  94  set(ICON_SPECS ${ICO_SPECS} ${ICNS_SPECS} ${EXTRA_ICON_SPECS})
  95  list(REMOVE_DUPLICATES ICON_SPECS)
  96  file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${ICON_PATH}")
  97  foreach(size IN LISTS ICON_SPECS)
  98    set(png "${ICON_PATH}/limenka${size}.png")
  99    add_custom_command(
 100      OUTPUT ${png}
 101      COMMAND "${RSVG_CONVERT}" -f png -d ${size} -p ${size} --output "${png}" "${CMAKE_CURRENT_SOURCE_DIR}/${limenka_svg}"
 102      DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${limenka_svg}"
 103      COMMENT "Generating ${png} from ${limenka_svg}"
 104      VERBATIM
 105    )
 106  
 107    # NOTE: ImageMagick will never convert transparent PNGs to 8-bit ICOs, but GIF is fine
 108    set(gif "${ICON_PATH}/limenka${size}d8.gif")
 109    add_custom_command(
 110      OUTPUT ${gif}
 111      COMMAND "${IMAGEMAGICK_CONVERT}" "${png}" -colors 256 -channel A -threshold 50% "${gif}"
 112      DEPENDS "${png}"
 113      COMMENT "Generating ${gif} from ${png}"
 114      VERBATIM
 115    )
 116  endforeach()
 117  
 118  set(limenka_icns "${ICON_PATH}/limenka.icns")
 119  set(ICNS_SRC_FILES ${ICNS_SPECS})
 120  list(TRANSFORM ICNS_SRC_FILES PREPEND "${ICON_PATH}/limenka")
 121  list(TRANSFORM ICNS_SRC_FILES APPEND ".png")
 122  add_custom_command(
 123    OUTPUT "${limenka_icns}"
 124    COMMAND "${PNG2ICNS}" "${limenka_icns}" ${ICNS_SRC_FILES}
 125    DEPENDS ${ICNS_SRC_FILES}
 126    COMMENT "Generating ${limenka_icns} from individual images"
 127    VERBATIM
 128  )
 129  add_custom_target(generate_icns DEPENDS "${limenka_icns}")
 130  
 131  set(limenka_ico "${ICON_PATH}/limenka.ico")
 132  set(ICO_SRC_FILES ${ICO_SPECS})
 133  list(TRANSFORM ICO_SRC_FILES PREPEND "${ICON_PATH}/limenka")
 134  list(TRANSFORM ICO_SRC_FILES APPEND ".png")
 135  list(PREPEND ICO_SRC_FILES "${ICON_PATH}/limenka32d8.gif")
 136  add_custom_command(
 137    OUTPUT "${limenka_ico}"
 138    COMMAND "${IMAGEMAGICK_CONVERT}" ${ICO_SRC_FILES} "${limenka_ico}"
 139    DEPENDS ${ICO_SRC_FILES}
 140    COMMENT "Generating ${limenka_ico} from individual images"
 141    VERBATIM
 142  )
 143  set(testnet_ico "${ICON_PATH}/limenka_testnet.ico")
 144  add_custom_command(
 145    OUTPUT "${testnet_ico}"
 146    COMMAND "${IMAGEMAGICK_CONVERT}" ${limenka_ico} -modulate 100,100,138.9 -colorspace HSL -channel G -evaluate subtract "11.76%" +channel -colorspace sRGB "${testnet_ico}"
 147    DEPENDS ${limenka_ico}
 148    COMMENT "Generating ${testnet_ico} from ${limenka_ico}"
 149    VERBATIM
 150  )
 151  add_custom_target(generate_ico DEPENDS "${limenka_ico}" "${testnet_ico}")
 152  
 153  set(logo_svg "res/src/limenkaknots-logo.svg")
 154  set(png "${ICON_PATH}/limenkaknots-logo.png")
 155  set(size 960)
 156  add_custom_command(
 157    OUTPUT ${png}
 158    COMMAND "${RSVG_CONVERT}" -f png -d ${size} -p ${size} --output "${png}" "${CMAKE_CURRENT_SOURCE_DIR}/${logo_svg}"
 159    DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${logo_svg}"
 160    COMMENT "Generating ${png} from ${logo_svg}"
 161    VERBATIM
 162  )
 163  
 164  set(nsis_wizard_input "${ICON_PATH}/limenka290.png")
 165  set(nsis_wizard_bmp "${ICON_PATH}/nsis-wizard.bmp")
 166  add_custom_command(
 167    OUTPUT "${nsis_wizard_bmp}"
 168    COMMAND "${IMAGEMAGICK_CONVERT}" ${nsis_wizard_input} -crop 164x290+68+0 -border 0x12 -strip BMP3:${nsis_wizard_bmp}
 169    DEPENDS ${nsis_wizard_input}
 170    COMMENT "Generating ${nsis_wizard_bmp} from ${nsis_wizard_input}"
 171    VERBATIM
 172  )
 173  set(nsis_header_input "res/src/nsis-header.svg")
 174  set(nsis_header_bmp "${ICON_PATH}/nsis-header.bmp")
 175  set(ABS_FONT_DIR ${CMAKE_CURRENT_BINARY_DIR}/res/fonts)
 176  add_custom_command(
 177    OUTPUT "${nsis_header_bmp}"
 178    COMMAND echo <fontconfig><dir>${ABS_FONT_DIR}</dir></fontconfig> > res/fonts/fonts.conf && FONTCONFIG_PATH=${ABS_FONT_DIR} ${RSVG_CONVERT} -f png -d 57 -p 57 ${CMAKE_CURRENT_SOURCE_DIR}/${nsis_header_input} | ${IMAGEMAGICK_CONVERT} - -background white -alpha remove BMP3:${nsis_header_bmp}
 179    DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${nsis_header_input}" "${FONT_PATH}"
 180    COMMENT "Generating ${nsis_header_bmp} from ${nsis_header_input}"
 181    VERBATIM
 182  )
 183  add_custom_target(generate_nsis_images DEPENDS "${nsis_wizard_bmp}" "${nsis_header_bmp}")
 184  
 185  configure_file(limenka_locale.qrc limenka_locale.qrc USE_SOURCE_PERMISSIONS COPYONLY)
 186  # The rendered qrc references the doc logo via res/, so make it available in
 187  # the build tree as well (the source qrc path would otherwise break in builds).
 188  file(COPY ${CMAKE_SOURCE_DIR}/doc/limenka_logo_doxygen.png
 189       DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/res)
 190  configure_file(limenka_rendered.qrc limenka_rendered.qrc USE_SOURCE_PERMISSIONS COPYONLY)
 191  configure_file(font.qrc font.qrc USE_SOURCE_PERMISSIONS COPYONLY)
 192  
 193  # The limenkaqt sources have to include headers in
 194  # order to parse them to collect translatable strings.
 195  add_library(limenkaqt STATIC EXCLUDE_FROM_ALL
 196    bantablemodel.cpp
 197    bantablemodel.h
 198    limenka.cpp
 199    limenka.h
 200    limenkaaddressvalidator.cpp
 201    limenkaaddressvalidator.h
 202    limenkaamountfield.cpp
 203    limenkaamountfield.h
 204    limenkagui.cpp
 205    limenkagui.h
 206    limenkaunits.cpp
 207    limenkaunits.h
 208    blockview.cpp
 209    blockview.h
 210    clientmodel.cpp
 211    clientmodel.h
 212    csvmodelwriter.cpp
 213    csvmodelwriter.h
 214    guiutil.cpp
 215    guiutil.h
 216    initexecutor.cpp
 217    initexecutor.h
 218    intro.cpp
 219    intro.h
 220    $<$<PLATFORM_ID:Darwin>:macdockiconhandler.h>
 221    $<$<PLATFORM_ID:Darwin>:macdockiconhandler.mm>
 222    $<$<PLATFORM_ID:Darwin>:macnotificationhandler.h>
 223    $<$<PLATFORM_ID:Darwin>:macnotificationhandler.mm>
 224    $<$<PLATFORM_ID:Darwin>:macos_appnap.h>
 225    $<$<PLATFORM_ID:Darwin>:macos_appnap.mm>
 226    modaloverlay.cpp
 227    mempoolstats.cpp
 228    modaloverlay.h
 229    netwatch.cpp
 230    networkstyle.cpp
 231    networkstyle.h
 232    notificator.cpp
 233    notificator.h
 234    optionsdialog.cpp
 235    optionsdialog.h
 236    optionsmodel.cpp
 237    optionsmodel.h
 238    pairingpage.cpp
 239    pairingpage.h
 240    peertablemodel.cpp
 241    peertablemodel.h
 242    peertablesortproxy.cpp
 243    peertablesortproxy.h
 244    platformstyle.cpp
 245    platformstyle.h
 246    qrimagewidget.cpp
 247    qrimagewidget.h
 248    qvalidatedlineedit.cpp
 249    qvalidatedlineedit.h
 250    qvaluecombobox.cpp
 251    qvaluecombobox.h
 252    rpcconsole.cpp
 253    rpcconsole.h
 254    splashscreen.cpp
 255    splashscreen.h
 256    tonalutils.cpp
 257    tonalutils.h
 258    trafficgraphwidget.cpp
 259    trafficgraphwidget.h
 260    utilitydialog.cpp
 261    utilitydialog.h
 262    $<$<PLATFORM_ID:Windows>:winshutdownmonitor.cpp>
 263    $<$<PLATFORM_ID:Windows>:winshutdownmonitor.h>
 264    limenka.qrc
 265    ${CMAKE_CURRENT_BINARY_DIR}/limenka_locale.qrc
 266    ${CMAKE_CURRENT_BINARY_DIR}/limenka_rendered.qrc
 267    ${CMAKE_CURRENT_BINARY_DIR}/font.qrc
 268  )
 269  target_compile_definitions(limenkaqt
 270    PUBLIC
 271      QT_NO_KEYWORDS
 272      QT_USE_QSTRINGBUILDER
 273  )
 274  target_include_directories(limenkaqt
 275    PUBLIC
 276      $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src>
 277  )
 278  set_property(SOURCE macnotificationhandler.mm
 279    # Ignore warnings "'NSUserNotificationCenter' is deprecated: first deprecated in macOS 11.0".
 280    APPEND PROPERTY COMPILE_OPTIONS -Wno-deprecated-declarations
 281  )
 282  target_link_libraries(limenkaqt
 283    PUBLIC
 284      "Qt${WITH_QT_VERSION}::Widgets"
 285    PRIVATE
 286      core_interface
 287      limenka_cli
 288      leveldb
 289      Boost::headers
 290      $<TARGET_NAME_IF_EXISTS:MiniUPnPc::MiniUPnPc>
 291      $<TARGET_NAME_IF_EXISTS:QRencode::QRencode>
 292      $<$<PLATFORM_ID:Darwin>:-framework\ AppKit>
 293      $<$<CXX_COMPILER_ID:MSVC>:shlwapi>
 294  )
 295  
 296  if(ENABLE_WALLET)
 297    target_sources(limenkaqt
 298      PRIVATE
 299        addressbookpage.cpp
 300        addressbookpage.h
 301        addresstablemodel.cpp
 302        addresstablemodel.h
 303        askpassphrasedialog.cpp
 304        askpassphrasedialog.h
 305        coincontroldialog.cpp
 306        coincontroldialog.h
 307        coincontroltreewidget.cpp
 308        coincontroltreewidget.h
 309        createwalletdialog.cpp
 310        createwalletdialog.h
 311        editaddressdialog.cpp
 312        editaddressdialog.h
 313        openuridialog.cpp
 314        openuridialog.h
 315        overviewpage.cpp
 316        overviewpage.h
 317        paymentserver.cpp
 318        paymentserver.h
 319        psbtoperationsdialog.cpp
 320        psbtoperationsdialog.h
 321        qrimagewidget.cpp
 322        qrimagewidget.h
 323        receivecoinsdialog.cpp
 324        receivecoinsdialog.h
 325        receiverequestdialog.cpp
 326        receiverequestdialog.h
 327        recentrequeststablemodel.cpp
 328        recentrequeststablemodel.h
 329        sendcoinsdialog.cpp
 330        sendcoinsdialog.h
 331        sendcoinsentry.cpp
 332        sendcoinsentry.h
 333        signverifymessagedialog.cpp
 334        signverifymessagedialog.h
 335        sweepprivkeydialog.cpp
 336        sweepprivkeydialog.h
 337        transactiondesc.cpp
 338        transactiondesc.h
 339        transactiondescdialog.cpp
 340        transactiondescdialog.h
 341        transactionfilterproxy.cpp
 342        transactionfilterproxy.h
 343        transactionoverviewwidget.cpp
 344        transactionoverviewwidget.h
 345        transactionrecord.cpp
 346        transactionrecord.h
 347        transactiontablemodel.cpp
 348        transactiontablemodel.h
 349        transactionview.cpp
 350        transactionview.h
 351        walletcontroller.cpp
 352        walletcontroller.h
 353        walletframe.cpp
 354        walletframe.h
 355        walletmodel.cpp
 356        walletmodel.h
 357        walletmodeltransaction.cpp
 358        walletmodeltransaction.h
 359        walletview.cpp
 360        walletview.h
 361    )
 362    target_link_libraries(limenkaqt
 363      PRIVATE
 364        limenka_wallet
 365        "Qt${WITH_QT_VERSION}::Network"
 366    )
 367  endif()
 368  
 369  if(WITH_DBUS)
 370    target_link_libraries(limenkaqt PRIVATE "Qt${WITH_QT_VERSION}::DBus")
 371  endif()
 372  if(WITH_TASKBAR_PROGRESS)
 373    target_sources(limenkaqt
 374      PRIVATE
 375        $<$<PLATFORM_ID:Windows>:wintaskbarprogress.cpp>
 376        $<$<PLATFORM_ID:Windows>:wintaskbarprogress.h>
 377    )
 378    target_link_libraries(limenkaqt
 379      PRIVATE
 380        $<$<PLATFORM_ID:Windows>:ole32>
 381    )
 382  endif()
 383  
 384  if(qt_lib_type STREQUAL "STATIC_LIBRARY")
 385    # We want to define static plugins to link ourselves, thus preventing
 386    # automatic linking against a "sane" set of default static plugins.
 387    cmake_language(CALL "qt${WITH_QT_VERSION}_import_plugins" limenkaqt
 388      EXCLUDE_BY_TYPE
 389        bearer
 390        accessiblebridge
 391        platforms
 392        platforms_darwin
 393        xcbglintegrations
 394        platformthemes
 395        platforminputcontexts
 396        generic
 397        iconengines
 398        imageformats
 399        egldeviceintegrations
 400        styles
 401        networkaccess
 402        networkinformation
 403        tls
 404    )
 405  endif()
 406  
 407  add_executable(limenka-qt
 408    main.cpp
 409    ../init/limenka-qt.cpp
 410  )
 411  
 412  if(NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin")
 413    add_dependencies(limenka-qt generate_ico)
 414  endif()
 415  
 416  if(WIN32)
 417    configure_file(${CMAKE_CURRENT_SOURCE_DIR}/res/limenka-qt-res.rc ${CMAKE_CURRENT_BINARY_DIR}/res/limenka-qt-res.rc USE_SOURCE_PERMISSIONS @ONLY)
 418    add_windows_resources(limenka-qt ${CMAKE_CURRENT_BINARY_DIR}/res/limenka-qt-res.rc)
 419  endif()
 420  
 421  target_link_libraries(limenka-qt
 422    core_interface
 423    limenkaqt
 424    limenka_node
 425  )
 426  
 427  import_plugins(limenka-qt)
 428  install_binary_component(limenka-qt HAS_MANPAGE)
 429  if(WIN32)
 430    set_target_properties(limenka-qt PROPERTIES WIN32_EXECUTABLE TRUE)
 431  endif()
 432  
 433  if(WITH_MULTIPROCESS)
 434    add_executable(limenka-gui
 435      main.cpp
 436      ../init/limenka-gui.cpp
 437    )
 438    target_link_libraries(limenka-gui
 439      core_interface
 440      limenkaqt
 441      limenka_node
 442      limenka_ipc
 443    )
 444    import_plugins(limenka-gui)
 445    install_binary_component(limenka-gui)
 446    if(WIN32)
 447      set_target_properties(limenka-gui PROPERTIES WIN32_EXECUTABLE TRUE)
 448    endif()
 449  endif()
 450  
 451  if(BUILD_GUI_TESTS)
 452    add_subdirectory(test)
 453  endif()
 454  
 455  
 456  # Gets sources to be parsed to gather translatable strings.
 457  function(get_translatable_sources var)
 458    set(result)
 459    set(targets)
 460    foreach(dir IN ITEMS ${ARGN})
 461      get_directory_property(dir_targets DIRECTORY ${PROJECT_SOURCE_DIR}/${dir} BUILDSYSTEM_TARGETS)
 462      list(APPEND targets ${dir_targets})
 463    endforeach()
 464    foreach(target IN LISTS targets)
 465      get_target_property(target_sources ${target} SOURCES)
 466      if(target_sources)
 467        foreach(source IN LISTS target_sources)
 468          # Get an expression from the generator expression, if any.
 469          if(source MATCHES ":([^>]+)>$")
 470            set(source ${CMAKE_MATCH_1})
 471          endif()
 472          cmake_path(GET source EXTENSION LAST_ONLY ext)
 473          if(ext STREQUAL ".qrc")
 474            continue()
 475          endif()
 476          if(NOT IS_ABSOLUTE source)
 477            get_target_property(target_source_dir ${target} SOURCE_DIR)
 478            cmake_path(APPEND target_source_dir ${source} OUTPUT_VARIABLE source)
 479          endif()
 480          get_property(is_generated
 481            SOURCE  ${source} TARGET_DIRECTORY ${target}
 482            PROPERTY GENERATED
 483          )
 484          if(NOT is_generated)
 485            list(APPEND result ${source})
 486          endif()
 487        endforeach()
 488      endif()
 489    endforeach()
 490    set(${var} ${result} PARENT_SCOPE)
 491  endfunction()
 492  
 493  find_program(XGETTEXT_EXECUTABLE xgettext)
 494  find_program(SED_EXECUTABLE sed)
 495  if(NOT XGETTEXT_EXECUTABLE)
 496    add_custom_target(translate
 497      COMMAND ${CMAKE_COMMAND} -E echo "Error: GNU gettext-tools not found"
 498    )
 499  elseif(NOT SED_EXECUTABLE)
 500    add_custom_target(translate
 501      COMMAND ${CMAKE_COMMAND} -E echo "Error: GNU sed not found"
 502    )
 503  else()
 504    set(translatable_sources_directories src src/qt src/util)
 505    if(ENABLE_WALLET)
 506      list(APPEND translatable_sources_directories src/wallet)
 507    endif()
 508    get_translatable_sources(translatable_sources ${translatable_sources_directories})
 509    get_translatable_sources(qt_translatable_sources src/qt)
 510    file(GLOB ui_files ${CMAKE_CURRENT_SOURCE_DIR}/forms/*.ui)
 511    add_custom_target(translate
 512      COMMAND ${CMAKE_COMMAND} -E env XGETTEXT=${XGETTEXT_EXECUTABLE} COPYRIGHT_HOLDERS=${COPYRIGHT_HOLDERS} ${Python3_EXECUTABLE} ${PROJECT_SOURCE_DIR}/share/qt/extract_strings_qt.py ${translatable_sources}
 513      COMMAND "Qt${WITH_QT_VERSION}::lupdate" -no-obsolete -I ${PROJECT_SOURCE_DIR}/src -locations relative ${CMAKE_CURRENT_SOURCE_DIR}/limenkastrings.cpp ${ui_files} ${qt_translatable_sources} -ts ${CMAKE_CURRENT_SOURCE_DIR}/locale/limenka_en.ts
 514      COMMAND "Qt${WITH_QT_VERSION}::lconvert" -drop-translations -o ${CMAKE_CURRENT_SOURCE_DIR}/locale/limenka_en.xlf -i ${CMAKE_CURRENT_SOURCE_DIR}/locale/limenka_en.ts
 515      COMMAND ${SED_EXECUTABLE} -i.old -e "s|source-language=\"en\" target-language=\"en\"|source-language=\"en\"|" -e "/<target xml:space=\"preserve\"><\\/target>/d" ${CMAKE_CURRENT_SOURCE_DIR}/locale/limenka_en.xlf
 516      COMMAND ${CMAKE_COMMAND} -E rm ${CMAKE_CURRENT_SOURCE_DIR}/locale/limenka_en.xlf.old
 517      WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src
 518      VERBATIM
 519    )
 520  endif()
 521