# Copyright (c) 2023-present The Limenka developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://opensource.org/license/mit/.
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
enable_language(OBJCXX)
set(CMAKE_OBJCXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
set(CMAKE_OBJCXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
set(CMAKE_OBJCXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
set(CMAKE_OBJCXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL}")
string(APPEND CMAKE_OBJCXX_COMPILE_OBJECT " ${APPEND_CPPFLAGS} ${APPEND_CXXFLAGS}")
endif()
get_target_property(qt_lib_type "Qt${WITH_QT_VERSION}::Core" TYPE)
function(import_plugins target)
if(qt_lib_type STREQUAL "STATIC_LIBRARY")
set(plugins "Qt${WITH_QT_VERSION}::QMinimalIntegrationPlugin")
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
list(APPEND plugins "Qt${WITH_QT_VERSION}::QXcbIntegrationPlugin")
elseif(WIN32)
if("${WITH_QT_VERSION}" STREQUAL "5")
list(APPEND plugins Qt5::QWindowsIntegrationPlugin Qt5::QWindowsVistaStylePlugin)
else() # Qt 6
list(APPEND plugins Qt6::QWindowsIntegrationPlugin Qt6::QModernWindowsStylePlugin)
endif() # Qt version
elseif(APPLE)
list(APPEND plugins "Qt${WITH_QT_VERSION}::QCocoaIntegrationPlugin" "Qt${WITH_QT_VERSION}::QMacStylePlugin")
endif()
cmake_language(CALL "qt${WITH_QT_VERSION}_import_plugins" ${target}
INCLUDE ${plugins}
EXCLUDE_BY_TYPE
accessiblebridge
platforms
platforms_darwin
xcbglintegrations
platformthemes
platforminputcontexts
generic
iconengines
imageformats
egldeviceintegrations
styles
networkaccess
networkinformation
tls
)
endif()
endfunction()
# For Qt-specific commands and variables, please consult:
# - https://cmake.org/cmake/help/latest/manual/cmake-qt.7.html
# - https://doc.qt.io/qt-5/cmake-manual.html
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOMOC_MOC_OPTIONS "-p${CMAKE_CURRENT_SOURCE_DIR}")
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOUIC_SEARCH_PATHS forms)
# TODO: The file(GLOB ...) command should be replaced with an explicit
# file list. Such a change must be synced with the corresponding change
# to https://github.com/limenka/limenka-maintainer-tools/blob/main/update-translations.py
file(GLOB ts_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} locale/*.ts)
set_source_files_properties(${ts_files} PROPERTIES OUTPUT_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/locale)
cmake_language(CALL "qt${WITH_QT_VERSION}_add_translation" qm_files ${ts_files})
set(FONT_PATH "res/fonts/OCR-Limenka.ttf")
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/res/fonts")
add_custom_command(
OUTPUT ${FONT_PATH}
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}"
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${FONT_PATH}.in
VERBATIM
)
set(ICON_PATH "res/rendered_icons")
set(ICO_SPECS
256 64 48 32 24 20 16
)
set(ICNS_SPECS
1024
)
set(EXTRA_ICON_SPECS
290 256
)
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
set(limenka_svg "res/src/limenka-mac.svg")
else()
set(limenka_svg "res/src/limenka.svg")
endif()
set(ICON_SPECS ${ICO_SPECS} ${ICNS_SPECS} ${EXTRA_ICON_SPECS})
list(REMOVE_DUPLICATES ICON_SPECS)
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${ICON_PATH}")
foreach(size IN LISTS ICON_SPECS)
set(png "${ICON_PATH}/limenka${size}.png")
add_custom_command(
OUTPUT ${png}
COMMAND "${RSVG_CONVERT}" -f png -d ${size} -p ${size} --output "${png}" "${CMAKE_CURRENT_SOURCE_DIR}/${limenka_svg}"
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${limenka_svg}"
COMMENT "Generating ${png} from ${limenka_svg}"
VERBATIM
)
# NOTE: ImageMagick will never convert transparent PNGs to 8-bit ICOs, but GIF is fine
set(gif "${ICON_PATH}/limenka${size}d8.gif")
add_custom_command(
OUTPUT ${gif}
COMMAND "${IMAGEMAGICK_CONVERT}" "${png}" -colors 256 -channel A -threshold 50% "${gif}"
DEPENDS "${png}"
COMMENT "Generating ${gif} from ${png}"
VERBATIM
)
endforeach()
set(limenka_icns "${ICON_PATH}/limenka.icns")
set(ICNS_SRC_FILES ${ICNS_SPECS})
list(TRANSFORM ICNS_SRC_FILES PREPEND "${ICON_PATH}/limenka")
list(TRANSFORM ICNS_SRC_FILES APPEND ".png")
add_custom_command(
OUTPUT "${limenka_icns}"
COMMAND "${PNG2ICNS}" "${limenka_icns}" ${ICNS_SRC_FILES}
DEPENDS ${ICNS_SRC_FILES}
COMMENT "Generating ${limenka_icns} from individual images"
VERBATIM
)
add_custom_target(generate_icns DEPENDS "${limenka_icns}")
set(limenka_ico "${ICON_PATH}/limenka.ico")
set(ICO_SRC_FILES ${ICO_SPECS})
list(TRANSFORM ICO_SRC_FILES PREPEND "${ICON_PATH}/limenka")
list(TRANSFORM ICO_SRC_FILES APPEND ".png")
list(PREPEND ICO_SRC_FILES "${ICON_PATH}/limenka32d8.gif")
add_custom_command(
OUTPUT "${limenka_ico}"
COMMAND "${IMAGEMAGICK_CONVERT}" ${ICO_SRC_FILES} "${limenka_ico}"
DEPENDS ${ICO_SRC_FILES}
COMMENT "Generating ${limenka_ico} from individual images"
VERBATIM
)
set(testnet_ico "${ICON_PATH}/limenka_testnet.ico")
add_custom_command(
OUTPUT "${testnet_ico}"
COMMAND "${IMAGEMAGICK_CONVERT}" ${limenka_ico} -modulate 100,100,138.9 -colorspace HSL -channel G -evaluate subtract "11.76%" +channel -colorspace sRGB "${testnet_ico}"
DEPENDS ${limenka_ico}
COMMENT "Generating ${testnet_ico} from ${limenka_ico}"
VERBATIM
)
add_custom_target(generate_ico DEPENDS "${limenka_ico}" "${testnet_ico}")
set(logo_svg "res/src/limenkaknots-logo.svg")
set(png "${ICON_PATH}/limenkaknots-logo.png")
set(size 960)
add_custom_command(
OUTPUT ${png}
COMMAND "${RSVG_CONVERT}" -f png -d ${size} -p ${size} --output "${png}" "${CMAKE_CURRENT_SOURCE_DIR}/${logo_svg}"
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${logo_svg}"
COMMENT "Generating ${png} from ${logo_svg}"
VERBATIM
)
set(nsis_wizard_input "${ICON_PATH}/limenka290.png")
set(nsis_wizard_bmp "${ICON_PATH}/nsis-wizard.bmp")
add_custom_command(
OUTPUT "${nsis_wizard_bmp}"
COMMAND "${IMAGEMAGICK_CONVERT}" ${nsis_wizard_input} -crop 164x290+68+0 -border 0x12 -strip BMP3:${nsis_wizard_bmp}
DEPENDS ${nsis_wizard_input}
COMMENT "Generating ${nsis_wizard_bmp} from ${nsis_wizard_input}"
VERBATIM
)
set(nsis_header_input "res/src/nsis-header.svg")
set(nsis_header_bmp "${ICON_PATH}/nsis-header.bmp")
set(ABS_FONT_DIR ${CMAKE_CURRENT_BINARY_DIR}/res/fonts)
add_custom_command(
OUTPUT "${nsis_header_bmp}"
COMMAND echo ${ABS_FONT_DIR} > 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}
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${nsis_header_input}" "${FONT_PATH}"
COMMENT "Generating ${nsis_header_bmp} from ${nsis_header_input}"
VERBATIM
)
add_custom_target(generate_nsis_images DEPENDS "${nsis_wizard_bmp}" "${nsis_header_bmp}")
configure_file(limenka_locale.qrc limenka_locale.qrc USE_SOURCE_PERMISSIONS COPYONLY)
# The rendered qrc references the doc logo via res/, so make it available in
# the build tree as well (the source qrc path would otherwise break in builds).
file(COPY ${CMAKE_SOURCE_DIR}/doc/limenka_logo_doxygen.png
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/res)
configure_file(limenka_rendered.qrc limenka_rendered.qrc USE_SOURCE_PERMISSIONS COPYONLY)
configure_file(font.qrc font.qrc USE_SOURCE_PERMISSIONS COPYONLY)
# The limenkaqt sources have to include headers in
# order to parse them to collect translatable strings.
add_library(limenkaqt STATIC EXCLUDE_FROM_ALL
bantablemodel.cpp
bantablemodel.h
limenka.cpp
limenka.h
limenkaaddressvalidator.cpp
limenkaaddressvalidator.h
limenkaamountfield.cpp
limenkaamountfield.h
limenkagui.cpp
limenkagui.h
limenkaunits.cpp
limenkaunits.h
blockview.cpp
blockview.h
clientmodel.cpp
clientmodel.h
csvmodelwriter.cpp
csvmodelwriter.h
guiutil.cpp
guiutil.h
initexecutor.cpp
initexecutor.h
intro.cpp
intro.h
$<$:macdockiconhandler.h>
$<$:macdockiconhandler.mm>
$<$:macnotificationhandler.h>
$<$:macnotificationhandler.mm>
$<$:macos_appnap.h>
$<$:macos_appnap.mm>
modaloverlay.cpp
mempoolstats.cpp
modaloverlay.h
netwatch.cpp
networkstyle.cpp
networkstyle.h
notificator.cpp
notificator.h
optionsdialog.cpp
optionsdialog.h
optionsmodel.cpp
optionsmodel.h
pairingpage.cpp
pairingpage.h
peertablemodel.cpp
peertablemodel.h
peertablesortproxy.cpp
peertablesortproxy.h
platformstyle.cpp
platformstyle.h
qrimagewidget.cpp
qrimagewidget.h
qvalidatedlineedit.cpp
qvalidatedlineedit.h
qvaluecombobox.cpp
qvaluecombobox.h
rpcconsole.cpp
rpcconsole.h
splashscreen.cpp
splashscreen.h
tonalutils.cpp
tonalutils.h
trafficgraphwidget.cpp
trafficgraphwidget.h
utilitydialog.cpp
utilitydialog.h
$<$:winshutdownmonitor.cpp>
$<$:winshutdownmonitor.h>
limenka.qrc
${CMAKE_CURRENT_BINARY_DIR}/limenka_locale.qrc
${CMAKE_CURRENT_BINARY_DIR}/limenka_rendered.qrc
${CMAKE_CURRENT_BINARY_DIR}/font.qrc
)
target_compile_definitions(limenkaqt
PUBLIC
QT_NO_KEYWORDS
QT_USE_QSTRINGBUILDER
)
target_include_directories(limenkaqt
PUBLIC
$
)
set_property(SOURCE macnotificationhandler.mm
# Ignore warnings "'NSUserNotificationCenter' is deprecated: first deprecated in macOS 11.0".
APPEND PROPERTY COMPILE_OPTIONS -Wno-deprecated-declarations
)
target_link_libraries(limenkaqt
PUBLIC
"Qt${WITH_QT_VERSION}::Widgets"
PRIVATE
core_interface
limenka_cli
leveldb
Boost::headers
$
$
$<$:-framework\ AppKit>
$<$:shlwapi>
)
if(ENABLE_WALLET)
target_sources(limenkaqt
PRIVATE
addressbookpage.cpp
addressbookpage.h
addresstablemodel.cpp
addresstablemodel.h
askpassphrasedialog.cpp
askpassphrasedialog.h
coincontroldialog.cpp
coincontroldialog.h
coincontroltreewidget.cpp
coincontroltreewidget.h
createwalletdialog.cpp
createwalletdialog.h
editaddressdialog.cpp
editaddressdialog.h
openuridialog.cpp
openuridialog.h
overviewpage.cpp
overviewpage.h
paymentserver.cpp
paymentserver.h
psbtoperationsdialog.cpp
psbtoperationsdialog.h
qrimagewidget.cpp
qrimagewidget.h
receivecoinsdialog.cpp
receivecoinsdialog.h
receiverequestdialog.cpp
receiverequestdialog.h
recentrequeststablemodel.cpp
recentrequeststablemodel.h
sendcoinsdialog.cpp
sendcoinsdialog.h
sendcoinsentry.cpp
sendcoinsentry.h
signverifymessagedialog.cpp
signverifymessagedialog.h
sweepprivkeydialog.cpp
sweepprivkeydialog.h
transactiondesc.cpp
transactiondesc.h
transactiondescdialog.cpp
transactiondescdialog.h
transactionfilterproxy.cpp
transactionfilterproxy.h
transactionoverviewwidget.cpp
transactionoverviewwidget.h
transactionrecord.cpp
transactionrecord.h
transactiontablemodel.cpp
transactiontablemodel.h
transactionview.cpp
transactionview.h
walletcontroller.cpp
walletcontroller.h
walletframe.cpp
walletframe.h
walletmodel.cpp
walletmodel.h
walletmodeltransaction.cpp
walletmodeltransaction.h
walletview.cpp
walletview.h
)
target_link_libraries(limenkaqt
PRIVATE
limenka_wallet
"Qt${WITH_QT_VERSION}::Network"
)
endif()
if(WITH_DBUS)
target_link_libraries(limenkaqt PRIVATE "Qt${WITH_QT_VERSION}::DBus")
endif()
if(WITH_TASKBAR_PROGRESS)
target_sources(limenkaqt
PRIVATE
$<$:wintaskbarprogress.cpp>
$<$:wintaskbarprogress.h>
)
target_link_libraries(limenkaqt
PRIVATE
$<$:ole32>
)
endif()
if(qt_lib_type STREQUAL "STATIC_LIBRARY")
# We want to define static plugins to link ourselves, thus preventing
# automatic linking against a "sane" set of default static plugins.
cmake_language(CALL "qt${WITH_QT_VERSION}_import_plugins" limenkaqt
EXCLUDE_BY_TYPE
bearer
accessiblebridge
platforms
platforms_darwin
xcbglintegrations
platformthemes
platforminputcontexts
generic
iconengines
imageformats
egldeviceintegrations
styles
networkaccess
networkinformation
tls
)
endif()
add_executable(limenka-qt
main.cpp
../init/limenka-qt.cpp
)
if(NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin")
add_dependencies(limenka-qt generate_ico)
endif()
if(WIN32)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/res/limenka-qt-res.rc ${CMAKE_CURRENT_BINARY_DIR}/res/limenka-qt-res.rc USE_SOURCE_PERMISSIONS @ONLY)
add_windows_resources(limenka-qt ${CMAKE_CURRENT_BINARY_DIR}/res/limenka-qt-res.rc)
endif()
target_link_libraries(limenka-qt
core_interface
limenkaqt
limenka_node
)
import_plugins(limenka-qt)
install_binary_component(limenka-qt HAS_MANPAGE)
if(WIN32)
set_target_properties(limenka-qt PROPERTIES WIN32_EXECUTABLE TRUE)
endif()
if(WITH_MULTIPROCESS)
add_executable(limenka-gui
main.cpp
../init/limenka-gui.cpp
)
target_link_libraries(limenka-gui
core_interface
limenkaqt
limenka_node
limenka_ipc
)
import_plugins(limenka-gui)
install_binary_component(limenka-gui)
if(WIN32)
set_target_properties(limenka-gui PROPERTIES WIN32_EXECUTABLE TRUE)
endif()
endif()
if(BUILD_GUI_TESTS)
add_subdirectory(test)
endif()
# Gets sources to be parsed to gather translatable strings.
function(get_translatable_sources var)
set(result)
set(targets)
foreach(dir IN ITEMS ${ARGN})
get_directory_property(dir_targets DIRECTORY ${PROJECT_SOURCE_DIR}/${dir} BUILDSYSTEM_TARGETS)
list(APPEND targets ${dir_targets})
endforeach()
foreach(target IN LISTS targets)
get_target_property(target_sources ${target} SOURCES)
if(target_sources)
foreach(source IN LISTS target_sources)
# Get an expression from the generator expression, if any.
if(source MATCHES ":([^>]+)>$")
set(source ${CMAKE_MATCH_1})
endif()
cmake_path(GET source EXTENSION LAST_ONLY ext)
if(ext STREQUAL ".qrc")
continue()
endif()
if(NOT IS_ABSOLUTE source)
get_target_property(target_source_dir ${target} SOURCE_DIR)
cmake_path(APPEND target_source_dir ${source} OUTPUT_VARIABLE source)
endif()
get_property(is_generated
SOURCE ${source} TARGET_DIRECTORY ${target}
PROPERTY GENERATED
)
if(NOT is_generated)
list(APPEND result ${source})
endif()
endforeach()
endif()
endforeach()
set(${var} ${result} PARENT_SCOPE)
endfunction()
find_program(XGETTEXT_EXECUTABLE xgettext)
find_program(SED_EXECUTABLE sed)
if(NOT XGETTEXT_EXECUTABLE)
add_custom_target(translate
COMMAND ${CMAKE_COMMAND} -E echo "Error: GNU gettext-tools not found"
)
elseif(NOT SED_EXECUTABLE)
add_custom_target(translate
COMMAND ${CMAKE_COMMAND} -E echo "Error: GNU sed not found"
)
else()
set(translatable_sources_directories src src/qt src/util)
if(ENABLE_WALLET)
list(APPEND translatable_sources_directories src/wallet)
endif()
get_translatable_sources(translatable_sources ${translatable_sources_directories})
get_translatable_sources(qt_translatable_sources src/qt)
file(GLOB ui_files ${CMAKE_CURRENT_SOURCE_DIR}/forms/*.ui)
add_custom_target(translate
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}
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
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
COMMAND ${SED_EXECUTABLE} -i.old -e "s|source-language=\"en\" target-language=\"en\"|source-language=\"en\"|" -e "/<\\/target>/d" ${CMAKE_CURRENT_SOURCE_DIR}/locale/limenka_en.xlf
COMMAND ${CMAKE_COMMAND} -E rm ${CMAKE_CURRENT_SOURCE_DIR}/locale/limenka_en.xlf.old
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src
VERBATIM
)
endif()