Internal
Public Access
Parses mRemoteNG's confCons.xml export format directly -- schema verified against mRemoteNG's own XmlConnectionsDeserializer.cs source and a real exported sample, not guessed at. Maps nested <Node Type="Container"> folders and <Node Type="Connection"> entries onto OrbitHub profiles: RDP stays RDP, SSH1/SSH2 collapse to OrbitHub's single SSH protocol, anything else (VNC, Telnet, HTTP, PowerShell, ...) is skipped and listed in the import summary rather than silently dropped. Passwords are never read, not even for the common case where they're technically readable without a master password (mRemoteNG only encrypts the Password attribute itself, everything else -- Hostname, Username, Domain, Protocol -- is plaintext). A FullFileEncryption="true" export encrypts the whole node tree instead and genuinely can't be read without the user's master password; that case is detected and refused with a clear message rather than failing confusingly. The parser (src/mremoteng_importer.h/.cpp) is a pure function decoupled from any file/UI I/O, matching this session's established pattern of keeping business logic separately testable from the Qt Widgets shell that calls it (ProfilesWindow::importFromMRemoteNG() is the thin wrapper: QFileDialog, call the parser, write results via ProfileRepository, show a summary). 11 test cases against realistic sample XML. Hit a real moc gotcha along the way: a literal "//" inside a raw string literal (the xmlns URL) makes moc's lexer think a line comment started there, silently desyncing its parse so it never finds the QObject-derived test class at all (no error, just a missing vtable at link time). Fixed by moving the XML fixtures into a plain non-QObject header moc never scans, split across two adjacent literals as a second safeguard. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
292 lines
11 KiB
CMake
292 lines
11 KiB
CMake
cmake_minimum_required(VERSION 3.21)
|
|
|
|
project(OrbitHub VERSION 2026.9.15 LANGUAGES CXX)
|
|
|
|
set(CMAKE_CXX_STANDARD 17)
|
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
|
|
|
set(CMAKE_AUTOMOC ON)
|
|
set(CMAKE_AUTOUIC ON)
|
|
set(CMAKE_AUTORCC ON)
|
|
|
|
include(GNUInstallDirs)
|
|
|
|
find_package(Qt6 6.2 REQUIRED COMPONENTS Widgets Sql)
|
|
|
|
qt_standard_project_setup()
|
|
|
|
option(ORBITHUB_BUILD_TESTS "Build unit tests (requires Qt6::Test)" ON)
|
|
if(ORBITHUB_BUILD_TESTS)
|
|
find_package(Qt6 6.2 QUIET COMPONENTS Test)
|
|
if(TARGET Qt6::Test)
|
|
enable_testing()
|
|
else()
|
|
message(STATUS "Qt6::Test not found -- skipping unit tests (set ORBITHUB_BUILD_TESTS=OFF to silence this)")
|
|
set(ORBITHUB_BUILD_TESTS OFF)
|
|
endif()
|
|
endif()
|
|
|
|
add_subdirectory(third_party/KodoTerm)
|
|
|
|
if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/third_party/FreeRDP/CMakeLists.txt")
|
|
message(FATAL_ERROR "Vendored FreeRDP source is missing at third_party/FreeRDP")
|
|
endif()
|
|
|
|
# Pin FreeRDP build to the vendored source tree so headers/libs are always from the same revision.
|
|
set(FREERDP_UNIFIED_BUILD ON CACHE BOOL "" FORCE)
|
|
set(WITH_MANPAGES OFF CACHE BOOL "" FORCE)
|
|
set(WITH_SAMPLE OFF CACHE BOOL "" FORCE)
|
|
set(BUILD_TESTING OFF CACHE BOOL "" FORCE)
|
|
set(BUILD_TESTING_INTERNAL OFF CACHE BOOL "" FORCE)
|
|
set(WITH_CLIENT_COMMON ON CACHE BOOL "" FORCE)
|
|
set(WITH_CLIENT OFF CACHE BOOL "" FORCE)
|
|
set(WITH_CLIENT_SDL OFF CACHE BOOL "" FORCE)
|
|
set(WITH_CLIENT_INTERFACE OFF CACHE BOOL "" FORCE)
|
|
set(WITH_SERVER OFF CACHE BOOL "" FORCE)
|
|
set(WITH_CHANNELS ON CACHE BOOL "" FORCE)
|
|
set(WITH_CLIENT_CHANNELS ON CACHE BOOL "" FORCE)
|
|
set(WITH_FUSE OFF CACHE BOOL "" FORCE)
|
|
set(CHANNEL_DRDYNVC ON CACHE BOOL "" FORCE)
|
|
set(CHANNEL_DRDYNVC_CLIENT ON CACHE BOOL "" FORCE)
|
|
set(CHANNEL_DISP ON CACHE BOOL "" FORCE)
|
|
set(CHANNEL_DISP_CLIENT ON CACHE BOOL "" FORCE)
|
|
set(CHANNEL_AINPUT OFF CACHE BOOL "" FORCE)
|
|
set(CHANNEL_AUDIN OFF CACHE BOOL "" FORCE)
|
|
set(CHANNEL_CLIPRDR ON CACHE BOOL "" FORCE)
|
|
set(CHANNEL_CLIPRDR_CLIENT ON CACHE BOOL "" FORCE)
|
|
set(CHANNEL_DRIVE OFF CACHE BOOL "" FORCE)
|
|
set(CHANNEL_ECHO OFF CACHE BOOL "" FORCE)
|
|
set(CHANNEL_ENCOMSP OFF CACHE BOOL "" FORCE)
|
|
set(CHANNEL_GEOMETRY OFF CACHE BOOL "" FORCE)
|
|
set(CHANNEL_LOCATION OFF CACHE BOOL "" FORCE)
|
|
set(CHANNEL_PARALLEL OFF CACHE BOOL "" FORCE)
|
|
set(CHANNEL_PRINTER OFF CACHE BOOL "" FORCE)
|
|
set(CHANNEL_RAIL OFF CACHE BOOL "" FORCE)
|
|
set(CHANNEL_RDPDR OFF CACHE BOOL "" FORCE)
|
|
set(CHANNEL_RDPEAR OFF CACHE BOOL "" FORCE)
|
|
set(CHANNEL_RDPECAM OFF CACHE BOOL "" FORCE)
|
|
set(CHANNEL_RDPEI OFF CACHE BOOL "" FORCE)
|
|
set(CHANNEL_RDPEMSC OFF CACHE BOOL "" FORCE)
|
|
set(CHANNEL_RDPGFX OFF CACHE BOOL "" FORCE)
|
|
set(CHANNEL_RDPSND OFF CACHE BOOL "" FORCE)
|
|
set(CHANNEL_REMDESK OFF CACHE BOOL "" FORCE)
|
|
set(CHANNEL_SERIAL OFF CACHE BOOL "" FORCE)
|
|
set(CHANNEL_SMARTCARD OFF CACHE BOOL "" FORCE)
|
|
set(CHANNEL_SSHAGENT OFF CACHE BOOL "" FORCE)
|
|
set(CHANNEL_TELEMETRY OFF CACHE BOOL "" FORCE)
|
|
set(CHANNEL_URBDRC OFF CACHE BOOL "" FORCE)
|
|
set(CHANNEL_VIDEO OFF CACHE BOOL "" FORCE)
|
|
set(WITH_FFMPEG OFF CACHE BOOL "" FORCE)
|
|
set(WITH_DSP_FFMPEG OFF CACHE BOOL "" FORCE)
|
|
set(WITH_VIDEO_FFMPEG OFF CACHE BOOL "" FORCE)
|
|
set(WITH_CAIRO OFF CACHE BOOL "" FORCE)
|
|
set(WITH_SWSCALE OFF CACHE BOOL "" FORCE)
|
|
set(WITH_JPEG OFF CACHE BOOL "" FORCE)
|
|
set(WITH_KRB5 OFF CACHE BOOL "" FORCE)
|
|
set(WITH_UNICODE_BUILTIN ON CACHE BOOL "" FORCE)
|
|
set(WITH_WINPR_TOOLS OFF CACHE BOOL "" FORCE)
|
|
|
|
add_subdirectory(third_party/FreeRDP EXCLUDE_FROM_ALL)
|
|
|
|
set(ORBITHUB_SOURCES
|
|
src/about_dialog.cpp
|
|
src/about_dialog.h
|
|
src/user_guide_dialog.cpp
|
|
src/user_guide_dialog.h
|
|
docs/user_guide.qrc
|
|
src/app_icon.cpp
|
|
src/app_icon.h
|
|
src/main.cpp
|
|
src/mremoteng_importer.cpp
|
|
src/mremoteng_importer.h
|
|
src/profile_dialog.cpp
|
|
src/profile_dialog.h
|
|
src/profile_repository.cpp
|
|
src/profile_repository.h
|
|
src/profiles_tree_widget.cpp
|
|
src/profiles_tree_widget.h
|
|
src/profiles_window.cpp
|
|
src/profiles_window.h
|
|
src/session_backend.h
|
|
src/session_backend_factory.cpp
|
|
src/session_backend_factory.h
|
|
src/session_tab.cpp
|
|
src/session_tab.h
|
|
src/rdp_display_widget.cpp
|
|
src/rdp_display_widget.h
|
|
src/terminal_view.cpp
|
|
src/terminal_view.h
|
|
src/session_window.cpp
|
|
src/session_window.h
|
|
src/rdp_session_backend.cpp
|
|
src/rdp_session_backend.h
|
|
src/ssh_session_backend.cpp
|
|
src/ssh_session_backend.h
|
|
src/unsupported_session_backend.cpp
|
|
src/unsupported_session_backend.h
|
|
)
|
|
|
|
if(WIN32)
|
|
list(APPEND ORBITHUB_SOURCES packaging/windows/orbithub.rc)
|
|
endif()
|
|
|
|
if(APPLE)
|
|
list(APPEND ORBITHUB_SOURCES packaging/macos/orbithub.icns)
|
|
set_source_files_properties(packaging/macos/orbithub.icns PROPERTIES
|
|
MACOSX_PACKAGE_LOCATION "Resources"
|
|
)
|
|
set(MACOSX_BUNDLE_ICON_FILE orbithub.icns)
|
|
set(MACOSX_BUNDLE_BUNDLE_NAME "OrbitHub")
|
|
set(MACOSX_BUNDLE_GUI_IDENTIFIER "org.darksingularity.OrbitHub")
|
|
set(MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION}")
|
|
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION}")
|
|
endif()
|
|
|
|
add_executable(orbithub WIN32 MACOSX_BUNDLE ${ORBITHUB_SOURCES})
|
|
|
|
target_link_libraries(orbithub PRIVATE Qt6::Widgets Qt6::Sql)
|
|
target_link_libraries(orbithub PRIVATE KodoTerm::KodoTerm)
|
|
target_compile_definitions(orbithub PRIVATE ORBITHUB_VERSION_STRING="${PROJECT_VERSION}")
|
|
if(TARGET freerdp AND TARGET winpr)
|
|
target_compile_definitions(orbithub PRIVATE ORBITHUB_HAS_FREERDP)
|
|
target_include_directories(orbithub PRIVATE
|
|
${CMAKE_CURRENT_SOURCE_DIR}/third_party/FreeRDP/include
|
|
${CMAKE_CURRENT_SOURCE_DIR}/third_party/FreeRDP/winpr/include
|
|
${CMAKE_CURRENT_BINARY_DIR}/third_party/FreeRDP/include
|
|
${CMAKE_CURRENT_BINARY_DIR}/third_party/FreeRDP/winpr/include
|
|
)
|
|
target_link_libraries(orbithub PRIVATE freerdp winpr)
|
|
if(TARGET freerdp-client)
|
|
target_link_libraries(orbithub PRIVATE freerdp-client)
|
|
endif()
|
|
else()
|
|
message(FATAL_ERROR "Vendored FreeRDP targets were not produced as expected.")
|
|
endif()
|
|
|
|
# Qt loads platform integration and SQL driver plugins dynamically at
|
|
# runtime (QFactoryLoader), so they never appear in orbithub.exe's import
|
|
# table. vcpkg's automatic DLL deployment only follows the import table, so
|
|
# these plugins have to be copied out explicitly or the app fails to start
|
|
# with "Could not find the Qt platform plugin" / "can not load requested
|
|
# driver 'QSQLITE'".
|
|
if(WIN32)
|
|
if(TARGET Qt6::QWindowsIntegrationPlugin)
|
|
add_custom_command(TARGET orbithub POST_BUILD
|
|
COMMAND ${CMAKE_COMMAND} -E make_directory
|
|
"$<TARGET_FILE_DIR:orbithub>/platforms"
|
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
|
"$<TARGET_FILE:Qt6::QWindowsIntegrationPlugin>"
|
|
"$<TARGET_FILE_DIR:orbithub>/platforms/"
|
|
COMMENT "Deploying Qt Windows platform plugin"
|
|
)
|
|
install(FILES "$<TARGET_FILE:Qt6::QWindowsIntegrationPlugin>"
|
|
DESTINATION "${CMAKE_INSTALL_BINDIR}/platforms"
|
|
)
|
|
endif()
|
|
|
|
if(TARGET Qt6::QSQLiteDriverPlugin)
|
|
add_custom_command(TARGET orbithub POST_BUILD
|
|
COMMAND ${CMAKE_COMMAND} -E make_directory
|
|
"$<TARGET_FILE_DIR:orbithub>/sqldrivers"
|
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
|
"$<TARGET_FILE:Qt6::QSQLiteDriverPlugin>"
|
|
"$<TARGET_FILE_DIR:orbithub>/sqldrivers/"
|
|
COMMENT "Deploying Qt SQLite driver plugin"
|
|
)
|
|
install(FILES "$<TARGET_FILE:Qt6::QSQLiteDriverPlugin>"
|
|
DESTINATION "${CMAKE_INSTALL_BINDIR}/sqldrivers"
|
|
)
|
|
|
|
# vcpkg's qtbase[sql-sqlite] links the plugin against vcpkg's own
|
|
# shared sqlite3 port rather than bundling SQLite into the plugin,
|
|
# so the plugin fails to load ("can not load requested driver
|
|
# 'QSQLITE'") unless sqlite3.dll also ships next to the executable.
|
|
find_file(ORBITHUB_SQLITE3_DLL
|
|
NAMES sqlite3.dll
|
|
PATHS ${CMAKE_PREFIX_PATH}
|
|
PATH_SUFFIXES bin
|
|
)
|
|
if(ORBITHUB_SQLITE3_DLL)
|
|
add_custom_command(TARGET orbithub POST_BUILD
|
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
|
"${ORBITHUB_SQLITE3_DLL}"
|
|
"$<TARGET_FILE_DIR:orbithub>/"
|
|
COMMENT "Deploying sqlite3.dll (Qt SQLite plugin dependency)"
|
|
)
|
|
install(FILES "${ORBITHUB_SQLITE3_DLL}" DESTINATION "${CMAKE_INSTALL_BINDIR}")
|
|
endif()
|
|
endif()
|
|
endif()
|
|
|
|
if(APPLE)
|
|
# Mirrors macdeployqt's own layout for Qt frameworks: dylibs live in
|
|
# Contents/Frameworks inside the bundle, found via @executable_path
|
|
# (the macOS/dyld equivalent of Linux's $ORIGIN token, which dyld
|
|
# does not understand).
|
|
set_target_properties(orbithub PROPERTIES
|
|
INSTALL_RPATH "@executable_path/../Frameworks"
|
|
INSTALL_RPATH_USE_LINK_PATH ON
|
|
)
|
|
else()
|
|
set_target_properties(orbithub PROPERTIES
|
|
BUILD_RPATH_USE_ORIGIN ON
|
|
INSTALL_RPATH "$ORIGIN/../${CMAKE_INSTALL_LIBDIR}/orbithub"
|
|
INSTALL_RPATH_USE_LINK_PATH ON
|
|
)
|
|
endif()
|
|
|
|
install(TARGETS orbithub
|
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
|
BUNDLE DESTINATION .
|
|
)
|
|
|
|
if(APPLE)
|
|
set(ORBITHUB_PRIVATE_LIB_DESTINATION "OrbitHub.app/Contents/Frameworks")
|
|
else()
|
|
set(ORBITHUB_PRIVATE_LIB_DESTINATION "${CMAKE_INSTALL_LIBDIR}/orbithub")
|
|
endif()
|
|
set(ORBITHUB_RUNTIME_TARGETS KodoTerm freerdp winpr)
|
|
if(TARGET freerdp-client)
|
|
list(APPEND ORBITHUB_RUNTIME_TARGETS freerdp-client)
|
|
endif()
|
|
foreach(runtime_target IN LISTS ORBITHUB_RUNTIME_TARGETS)
|
|
if(TARGET ${runtime_target})
|
|
install(TARGETS ${runtime_target}
|
|
RUNTIME DESTINATION ${ORBITHUB_PRIVATE_LIB_DESTINATION}
|
|
LIBRARY DESTINATION ${ORBITHUB_PRIVATE_LIB_DESTINATION}
|
|
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
)
|
|
endif()
|
|
endforeach()
|
|
|
|
install(FILES
|
|
packaging/linux/org.darksingularity.OrbitHub.desktop
|
|
DESTINATION ${CMAKE_INSTALL_DATADIR}/applications
|
|
)
|
|
foreach(icon_size IN ITEMS 16 24 32 48 64 128 256)
|
|
install(FILES
|
|
packaging/linux/icons/${icon_size}x${icon_size}/apps/org.darksingularity.OrbitHub.png
|
|
DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/${icon_size}x${icon_size}/apps
|
|
)
|
|
endforeach()
|
|
install(FILES
|
|
packaging/linux/org.darksingularity.OrbitHub.metainfo.xml
|
|
DESTINATION ${CMAKE_INSTALL_DATADIR}/metainfo
|
|
)
|
|
install(FILES LICENSE
|
|
DESTINATION ${CMAKE_INSTALL_DATADIR}/licenses/org.darksingularity.OrbitHub
|
|
)
|
|
install(FILES third_party/FreeRDP/LICENSE
|
|
DESTINATION ${CMAKE_INSTALL_DATADIR}/licenses/org.darksingularity.OrbitHub
|
|
RENAME LICENSE-FreeRDP
|
|
)
|
|
install(FILES third_party/KodoTerm/LICENSE
|
|
DESTINATION ${CMAKE_INSTALL_DATADIR}/licenses/org.darksingularity.OrbitHub
|
|
RENAME LICENSE-KodoTerm
|
|
)
|
|
|
|
if(ORBITHUB_BUILD_TESTS)
|
|
add_subdirectory(tests)
|
|
endif()
|