From e62d473b6472e7c867554a2ddbb265e715a10f10 Mon Sep 17 00:00:00 2001 From: dijunkun Date: Fri, 25 Sep 2026 01:47:20 +0800 Subject: [PATCH] [perf] reduce desktop build dependencies and binary size --- .../src/common/task_queue_lock_free.cpp | 15 ++- .../desktop/src/common/task_queue_lock_free.h | 8 +- .../src/config_center/config_center.cpp | 112 +++++++++--------- .../desktop/src/config_center/config_center.h | 5 +- .../src/gui/application/gui_application.cpp | 1 + .../clipboard/clipboard_controller.cpp | 4 + .../features/clipboard/clipboard_controller.h | 12 +- .../devices/session_device_manager.cpp | 6 + .../features/devices/session_device_manager.h | 9 +- .../file_transfer/file_transfer_manager.h | 2 +- .../gui/rendering/slint_video_presenter.cpp | 1 + .../src/gui/rendering/slint_video_presenter.h | 8 +- apps/desktop/src/gui/runtime/gui_runtime.cpp | 2 + apps/desktop/src/gui/runtime/gui_runtime.h | 5 +- .../src/gui/runtime/peer_data_callbacks.cpp | 2 + .../src/gui/runtime/privacy_runtime.cpp | 2 + apps/desktop/src/log/rd_log.cpp | 9 ++ apps/desktop/src/log/rd_log.h | 11 -- .../gui/runtime/mac_permission_runtime.mm | 2 + .../gui/runtime/windows_service_runtime.cpp | 2 + .../src/version_checker/version_checker.cpp | 1 + .../src/version_checker/version_checker.h | 2 +- apps/desktop/tests/version_checker_test.cpp | 1 + apps/desktop/xmake/platform.lua | 14 +++ apps/desktop/xmake/rules/slint.lua | 105 ++++++++++------ apps/desktop/xmake/targets.lua | 55 +++++---- 26 files changed, 249 insertions(+), 147 deletions(-) diff --git a/apps/desktop/src/common/task_queue_lock_free.cpp b/apps/desktop/src/common/task_queue_lock_free.cpp index 273c4a31..99004cdb 100644 --- a/apps/desktop/src/common/task_queue_lock_free.cpp +++ b/apps/desktop/src/common/task_queue_lock_free.cpp @@ -1,5 +1,7 @@ #include "task_queue_lock_free.h" +#include + #include #include #include @@ -7,8 +9,15 @@ namespace crossdesk { +struct TaskQueueLockFree::QueueStorage { + moodycamel::ConcurrentQueue tasks; + // All submissions share one producer so different caller threads keep FIFO. + moodycamel::ProducerToken producer{tasks}; +}; + TaskQueueLockFree::TaskQueueLockFree() - : producer_(task_queue_), worker_([this] { WorkerThread(); }) {} + : queue_(std::make_unique()), + worker_([this] { WorkerThread(); }) {} TaskQueueLockFree::~TaskQueueLockFree() { Stop(); } @@ -24,7 +33,7 @@ std::future TaskQueueLockFree::PostTask(std::function task) { // Count before publishing: the worker may dequeue as soon as enqueue returns. ++pending_tasks_; - if (!task_queue_.enqueue(producer_, std::move(item))) { + if (!queue_->tasks.enqueue(queue_->producer, std::move(item))) { --pending_tasks_; throw std::bad_alloc(); } @@ -48,7 +57,7 @@ void TaskQueueLockFree::Stop() { void TaskQueueLockFree::WorkerThread() { while (true) { TaskItem item; - while (task_queue_.try_dequeue(item)) { + while (queue_->tasks.try_dequeue(item)) { --pending_tasks_; std::exception_ptr error; diff --git a/apps/desktop/src/common/task_queue_lock_free.h b/apps/desktop/src/common/task_queue_lock_free.h index f8fa8788..3b99cc70 100644 --- a/apps/desktop/src/common/task_queue_lock_free.h +++ b/apps/desktop/src/common/task_queue_lock_free.h @@ -12,11 +12,10 @@ #include #include #include +#include #include #include -#include - namespace crossdesk { // A single worker executes tasks in submission order. The concurrent queue @@ -41,9 +40,8 @@ class TaskQueueLockFree { void WorkerThread(); - moodycamel::ConcurrentQueue task_queue_; - // All submissions share one producer so different caller threads keep FIFO. - moodycamel::ProducerToken producer_; + struct QueueStorage; + std::unique_ptr queue_; std::atomic pending_tasks_{0}; std::mutex mutex_; std::condition_variable wake_; diff --git a/apps/desktop/src/config_center/config_center.cpp b/apps/desktop/src/config_center/config_center.cpp index 1015e6e9..996b6790 100644 --- a/apps/desktop/src/config_center/config_center.cpp +++ b/apps/desktop/src/config_center/config_center.cpp @@ -2,15 +2,19 @@ #include #include +#include #include #include #include +#include "SimpleIni.h" #include "autostart.h" #include "rd_log.h" namespace crossdesk { +struct ConfigCenter::IniStorage : CSimpleIniA {}; + namespace { bool IsValidTurnModeValue(long value) { @@ -21,15 +25,15 @@ bool IsValidTurnModeValue(long value) { } // namespace ConfigCenter::ConfigCenter(const std::string& config_path) - : config_path_(config_path) { - ini_.SetUnicode(true); + : config_path_(config_path), ini_(std::make_unique()) { + ini_->SetUnicode(true); Load(); } ConfigCenter::~ConfigCenter() {} int ConfigCenter::Load() { - SI_Error rc = ini_.LoadFile(config_path_.c_str()); + SI_Error rc = ini_->LoadFile(config_path_.c_str()); if (rc < 0) { Save(); return -1; @@ -38,18 +42,18 @@ int ConfigCenter::Load() { bool persist_config_migration = false; // These options now belong only to the active remote connection. Discard // legacy local defaults so they cannot affect this host or new connections. - persist_config_migration |= ini_.Delete(section_, "video_quality"); - persist_config_migration |= ini_.Delete(section_, "video_frame_rate"); - persist_config_migration |= ini_.Delete(section_, "video_adaptation_policy"); - persist_config_migration |= ini_.Delete(section_, "video_content_type"); - persist_config_migration |= ini_.Delete(section_, "screen_content"); + persist_config_migration |= ini_->Delete(section_, "video_quality"); + persist_config_migration |= ini_->Delete(section_, "video_frame_rate"); + persist_config_migration |= ini_->Delete(section_, "video_adaptation_policy"); + persist_config_migration |= ini_->Delete(section_, "video_content_type"); + persist_config_migration |= ini_->Delete(section_, "screen_content"); persist_config_migration |= - ini_.Delete(section_, "enable_desktop_quality_optimization"); + ini_->Delete(section_, "enable_desktop_quality_optimization"); persist_config_migration |= - ini_.Delete(section_, "enable_minimize_to_tray"); + ini_->Delete(section_, "enable_minimize_to_tray"); const long language_value = - ini_.GetLongValue(section_, "language", static_cast(language_)); + ini_->GetLongValue(section_, "language", static_cast(language_)); if (language_value < static_cast(LANGUAGE::CHINESE) || language_value > static_cast(LANGUAGE::RUSSIAN)) { language_ = LANGUAGE::ENGLISH; @@ -57,7 +61,7 @@ int ConfigCenter::Load() { language_ = static_cast(language_value); } - const long screen_capture_method_value = ini_.GetLongValue( + const long screen_capture_method_value = ini_->GetLongValue( section_, "screen_capture_method", static_cast(ScreenCaptureMethod::Auto)); screen_capture_method_ = IsValidScreenCaptureMethod(screen_capture_method_value) @@ -66,14 +70,14 @@ int ConfigCenter::Load() { : ScreenCaptureMethod::Auto; video_encode_format_ = static_cast( - ini_.GetLongValue(section_, "video_encode_format", + ini_->GetLongValue(section_, "video_encode_format", static_cast(video_encode_format_))); - hardware_video_codec_ = ini_.GetBoolValue(section_, "hardware_video_codec", + hardware_video_codec_ = ini_->GetBoolValue(section_, "hardware_video_codec", hardware_video_codec_); - const char* turn_mode_value = ini_.GetValue(section_, "turn_mode", nullptr); + const char* turn_mode_value = ini_->GetValue(section_, "turn_mode", nullptr); if (turn_mode_value != nullptr && strlen(turn_mode_value) > 0) { - const long parsed_turn_mode = ini_.GetLongValue( + const long parsed_turn_mode = ini_->GetLongValue( section_, "turn_mode", static_cast(turn_mode_)); if (IsValidTurnModeValue(parsed_turn_mode)) { turn_mode_ = static_cast(parsed_turn_mode); @@ -83,24 +87,24 @@ int ConfigCenter::Load() { turn_mode_ = TURN_MODE::AUTO_UDP_TCP; } } else { - const bool legacy_enable_turn = ini_.GetBoolValue( + const bool legacy_enable_turn = ini_->GetBoolValue( section_, "enable_turn", turn_mode_ != TURN_MODE::DISABLED); turn_mode_ = legacy_enable_turn ? TURN_MODE::AUTO_UDP_TCP : TURN_MODE::DISABLED; - ini_.SetLongValue(section_, "turn_mode", static_cast(turn_mode_)); + ini_->SetLongValue(section_, "turn_mode", static_cast(turn_mode_)); persist_config_migration = true; } // Migrate the former user switch. Keep true in the file for older builds, // while the current application always requests encrypted native media. - if (!ini_.GetBoolValue(section_, "enable_srtp", false)) { - ini_.SetBoolValue(section_, "enable_srtp", true); + if (!ini_->GetBoolValue(section_, "enable_srtp", false)) { + ini_->SetBoolValue(section_, "enable_srtp", true); persist_config_migration = true; } enable_self_hosted_ = - ini_.GetBoolValue(section_, "enable_self_hosted", enable_self_hosted_); + ini_->GetBoolValue(section_, "enable_self_hosted", enable_self_hosted_); const char* signal_server_host_value = - ini_.GetValue(section_, "signal_server_host", nullptr); + ini_->GetValue(section_, "signal_server_host", nullptr); if (signal_server_host_value != nullptr && strlen(signal_server_host_value) > 0) { signal_server_host_ = signal_server_host_value; @@ -108,25 +112,25 @@ int ConfigCenter::Load() { signal_server_host_ = ""; } const char* signal_server_port_value = - ini_.GetValue(section_, "signal_server_port", nullptr); + ini_->GetValue(section_, "signal_server_port", nullptr); if (signal_server_port_value != nullptr && strlen(signal_server_port_value) > 0) { signal_server_port_ = - static_cast(ini_.GetLongValue(section_, "signal_server_port", 0)); + static_cast(ini_->GetLongValue(section_, "signal_server_port", 0)); } else { signal_server_port_ = 0; } enable_autostart_ = - ini_.GetBoolValue(section_, "enable_autostart", enable_autostart_); - enable_daemon_ = ini_.GetBoolValue(section_, "enable_daemon", enable_daemon_); + ini_->GetBoolValue(section_, "enable_autostart", enable_autostart_); + enable_daemon_ = ini_->GetBoolValue(section_, "enable_daemon", enable_daemon_); enable_privacy_screen_.store( - ini_.GetBoolValue(section_, "enable_privacy_screen", true)); + ini_->GetBoolValue(section_, "enable_privacy_screen", true)); portable_service_prompt_suppressed_ = - ini_.GetBoolValue(section_, "portable_service_prompt_suppressed", + ini_->GetBoolValue(section_, "portable_service_prompt_suppressed", portable_service_prompt_suppressed_); const char* file_transfer_save_path_value = - ini_.GetValue(section_, "file_transfer_save_path", nullptr); + ini_->GetValue(section_, "file_transfer_save_path", nullptr); if (file_transfer_save_path_value != nullptr && strlen(file_transfer_save_path_value) > 0) { file_transfer_save_path_ = file_transfer_save_path_value; @@ -149,7 +153,7 @@ int ConfigCenter::CommitIni() { std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()) + "-" + std::to_string(sequence++); std::error_code error; - if (ini_.SaveFile(temporary.c_str()) < 0) { + if (ini_->SaveFile(temporary.c_str()) < 0) { LOG_ERROR("Failed to write configuration: {}", config_path_); std::filesystem::remove(temporary, error); return -1; @@ -174,46 +178,46 @@ int ConfigCenter::StoreValues( std::initializer_list> values) { std::vector>> previous; for (const auto& value : values) { - const char* old = ini_.GetValue(section_, value.first, nullptr); + const char* old = ini_->GetValue(section_, value.first, nullptr); previous.emplace_back(value.first, old ? std::optional(old) : std::nullopt); - ini_.SetValue(section_, value.first, value.second.c_str()); + ini_->SetValue(section_, value.first, value.second.c_str()); } if (CommitIni() == 0) return 0; for (const auto& value : previous) { - if (value.second) ini_.SetValue(section_, value.first, value.second->c_str()); - else ini_.Delete(section_, value.first); + if (value.second) ini_->SetValue(section_, value.first, value.second->c_str()); + else ini_->Delete(section_, value.first); } return -1; } int ConfigCenter::Save() { - ini_.SetLongValue(section_, "language", static_cast(language_)); - ini_.SetLongValue(section_, "screen_capture_method", + ini_->SetLongValue(section_, "language", static_cast(language_)); + ini_->SetLongValue(section_, "screen_capture_method", static_cast(screen_capture_method_)); - ini_.SetLongValue(section_, "video_encode_format", + ini_->SetLongValue(section_, "video_encode_format", static_cast(video_encode_format_)); - ini_.SetBoolValue(section_, "hardware_video_codec", hardware_video_codec_); - ini_.SetLongValue(section_, "turn_mode", static_cast(turn_mode_)); - ini_.SetBoolValue(section_, "enable_turn", + ini_->SetBoolValue(section_, "hardware_video_codec", hardware_video_codec_); + ini_->SetLongValue(section_, "turn_mode", static_cast(turn_mode_)); + ini_->SetBoolValue(section_, "enable_turn", turn_mode_ != TURN_MODE::DISABLED); - ini_.SetBoolValue(section_, "enable_srtp", true); - ini_.SetBoolValue(section_, "enable_self_hosted", enable_self_hosted_); + ini_->SetBoolValue(section_, "enable_srtp", true); + ini_->SetBoolValue(section_, "enable_self_hosted", enable_self_hosted_); // only save when self hosted if (enable_self_hosted_) { - ini_.SetValue(section_, "signal_server_host", signal_server_host_.c_str()); - ini_.SetLongValue(section_, "signal_server_port", + ini_->SetValue(section_, "signal_server_host", signal_server_host_.c_str()); + ini_->SetLongValue(section_, "signal_server_port", static_cast(signal_server_port_)); } - ini_.SetBoolValue(section_, "enable_autostart", enable_autostart_); - ini_.SetBoolValue(section_, "enable_daemon", enable_daemon_); - ini_.SetBoolValue(section_, "enable_privacy_screen", + ini_->SetBoolValue(section_, "enable_autostart", enable_autostart_); + ini_->SetBoolValue(section_, "enable_daemon", enable_daemon_); + ini_->SetBoolValue(section_, "enable_privacy_screen", enable_privacy_screen_.load()); - ini_.SetBoolValue(section_, "portable_service_prompt_suppressed", + ini_->SetBoolValue(section_, "portable_service_prompt_suppressed", portable_service_prompt_suppressed_); - ini_.SetValue(section_, "file_transfer_save_path", + ini_->SetValue(section_, "file_transfer_save_path", file_transfer_save_path_.c_str()); SI_Error rc = CommitIni(); @@ -237,9 +241,9 @@ int ConfigCenter::SetScreenCaptureMethod(ScreenCaptureMethod method) { if (!IsValidScreenCaptureMethod(static_cast(method))) { return -1; } - ini_.SetLongValue(section_, "screen_capture_method", static_cast(method)); + ini_->SetLongValue(section_, "screen_capture_method", static_cast(method)); if (CommitIni() < 0) { - ini_.SetLongValue(section_, "screen_capture_method", + ini_->SetLongValue(section_, "screen_capture_method", static_cast(screen_capture_method_)); return -1; } @@ -328,9 +332,9 @@ int ConfigCenter::SetDaemon(bool enabled) { int ConfigCenter::SetPrivacyScreen(bool enable_privacy_screen) { const bool previous = enable_privacy_screen_.load(); if (previous == enable_privacy_screen) return 0; - ini_.SetBoolValue(section_, "enable_privacy_screen", enable_privacy_screen); + ini_->SetBoolValue(section_, "enable_privacy_screen", enable_privacy_screen); if (CommitIni() < 0) { - ini_.SetBoolValue(section_, "enable_privacy_screen", previous); + ini_->SetBoolValue(section_, "enable_privacy_screen", previous); LOG_ERROR("Failed to save automatic privacy screen preference"); return -1; } @@ -342,7 +346,7 @@ int ConfigCenter::SetPrivacyScreen(bool enable_privacy_screen) { int ConfigCenter::SetPortableServicePromptSuppressed(bool suppressed) { portable_service_prompt_suppressed_ = suppressed; - ini_.SetBoolValue(section_, "portable_service_prompt_suppressed", + ini_->SetBoolValue(section_, "portable_service_prompt_suppressed", portable_service_prompt_suppressed_); SI_Error rc = CommitIni(); if (rc < 0) { diff --git a/apps/desktop/src/config_center/config_center.h b/apps/desktop/src/config_center/config_center.h index d8da2714..50e77837 100644 --- a/apps/desktop/src/config_center/config_center.h +++ b/apps/desktop/src/config_center/config_center.h @@ -9,11 +9,11 @@ #include #include +#include #include #include #include -#include "SimpleIni.h" #include "screen_capturer/screen_capture_method.h" namespace crossdesk { @@ -80,7 +80,8 @@ class ConfigCenter { int StoreValues(std::initializer_list> values); mutable std::mutex file_path_mutex_; std::string config_path_; - CSimpleIniA ini_; + struct IniStorage; + std::unique_ptr ini_; const char* section_ = "Settings"; LANGUAGE language_ = LANGUAGE::CHINESE; diff --git a/apps/desktop/src/gui/application/gui_application.cpp b/apps/desktop/src/gui/application/gui_application.cpp index 34dd264e..2a2b06f1 100644 --- a/apps/desktop/src/gui/application/gui_application.cpp +++ b/apps/desktop/src/gui/application/gui_application.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include diff --git a/apps/desktop/src/gui/features/clipboard/clipboard_controller.cpp b/apps/desktop/src/gui/features/clipboard/clipboard_controller.cpp index 8c4f70a5..14c42af4 100644 --- a/apps/desktop/src/gui/features/clipboard/clipboard_controller.cpp +++ b/apps/desktop/src/gui/features/clipboard/clipboard_controller.cpp @@ -1,5 +1,9 @@ #include "features/clipboard/clipboard_controller.h" +#include +#include +#include + #include #include #include diff --git a/apps/desktop/src/gui/features/clipboard/clipboard_controller.h b/apps/desktop/src/gui/features/clipboard/clipboard_controller.h index 3ac66cf6..938a244e 100644 --- a/apps/desktop/src/gui/features/clipboard/clipboard_controller.h +++ b/apps/desktop/src/gui/features/clipboard/clipboard_controller.h @@ -1,7 +1,11 @@ -#ifndef CROSSDESK_GUI_CLIPBOARD_CONTROLLER_H_ -#define CROSSDESK_GUI_CLIPBOARD_CONTROLLER_H_ +/* + * @Author: DI JUNKUN + * @Date: 2026-09-25 + * Copyright (c) 2026 by DI JUNKUN, All Rights Reserved. + */ -#include +#ifndef _CLIPBOARD_CONTROLLER_H_ +#define _CLIPBOARD_CONTROLLER_H_ #include #include @@ -42,4 +46,4 @@ private: } // namespace crossdesk -#endif // CROSSDESK_GUI_CLIPBOARD_CONTROLLER_H_ +#endif // _CLIPBOARD_CONTROLLER_H_ \ No newline at end of file diff --git a/apps/desktop/src/gui/features/devices/session_device_manager.cpp b/apps/desktop/src/gui/features/devices/session_device_manager.cpp index 50a60560..b563e872 100644 --- a/apps/desktop/src/gui/features/devices/session_device_manager.cpp +++ b/apps/desktop/src/gui/features/devices/session_device_manager.cpp @@ -1,5 +1,9 @@ #include "features/devices/session_device_manager.h" +#include +#include +#include + #include #include @@ -8,6 +12,8 @@ #include #include +#include "device_controller_factory.h" +#include "screen_capturer_factory.h" #include "platform.h" #include "rd_log.h" #include "runtime/gui_runtime.h" diff --git a/apps/desktop/src/gui/features/devices/session_device_manager.h b/apps/desktop/src/gui/features/devices/session_device_manager.h index 0e40e426..d1c9bf2a 100644 --- a/apps/desktop/src/gui/features/devices/session_device_manager.h +++ b/apps/desktop/src/gui/features/devices/session_device_manager.h @@ -8,8 +8,6 @@ #define _SESSION_DEVICE_MANAGER_H_ -#include - #include #include #include @@ -22,14 +20,17 @@ #include #include "device_controller.h" -#include "device_controller_factory.h" #include "display_info.h" -#include "screen_capturer_factory.h" #include "speaker_capture_controller.h" +struct SDL_AudioStream; + namespace crossdesk { class GuiRuntime; +class DeviceControllerFactory; +class ScreenCapturerFactory; +class ScreenCapturer; // Owns media capture/playback and remote input devices for the active GUI // session. GuiRuntime supplies application intent; this class handles device diff --git a/apps/desktop/src/gui/features/file_transfer/file_transfer_manager.h b/apps/desktop/src/gui/features/file_transfer/file_transfer_manager.h index fda31dca..fa143a47 100644 --- a/apps/desktop/src/gui/features/file_transfer/file_transfer_manager.h +++ b/apps/desktop/src/gui/features/file_transfer/file_transfer_manager.h @@ -12,7 +12,7 @@ #include #include -#include "runtime/gui_state.h" +#include "runtime/remote_session.h" namespace crossdesk { diff --git a/apps/desktop/src/gui/rendering/slint_video_presenter.cpp b/apps/desktop/src/gui/rendering/slint_video_presenter.cpp index def0fbd2..c36f380c 100644 --- a/apps/desktop/src/gui/rendering/slint_video_presenter.cpp +++ b/apps/desktop/src/gui/rendering/slint_video_presenter.cpp @@ -1,4 +1,5 @@ #include "rendering/slint_video_presenter.h" +#include "crossdesk_ui.h" #include #include diff --git a/apps/desktop/src/gui/rendering/slint_video_presenter.h b/apps/desktop/src/gui/rendering/slint_video_presenter.h index 39a52ce0..2fe2df21 100644 --- a/apps/desktop/src/gui/rendering/slint_video_presenter.h +++ b/apps/desktop/src/gui/rendering/slint_video_presenter.h @@ -14,7 +14,13 @@ #include #include -#include "crossdesk_ui.h" +namespace slint { +template class ComponentHandle; +} + +namespace crossdesk::ui { +class StreamWindow; +} namespace crossdesk { diff --git a/apps/desktop/src/gui/runtime/gui_runtime.cpp b/apps/desktop/src/gui/runtime/gui_runtime.cpp index ebb2591a..06c61f5b 100644 --- a/apps/desktop/src/gui/runtime/gui_runtime.cpp +++ b/apps/desktop/src/gui/runtime/gui_runtime.cpp @@ -1,5 +1,7 @@ #include "runtime/gui_runtime.h" +#include + #include #include #include diff --git a/apps/desktop/src/gui/runtime/gui_runtime.h b/apps/desktop/src/gui/runtime/gui_runtime.h index 303a24af..08476c58 100644 --- a/apps/desktop/src/gui/runtime/gui_runtime.h +++ b/apps/desktop/src/gui/runtime/gui_runtime.h @@ -8,6 +8,7 @@ #define _GUI_RUNTIME_H_ #include +#include #include #include #include @@ -44,8 +45,8 @@ class GuiRuntime : protected gui_detail::GuiState { GuiRuntime(); ~GuiRuntime(); - static void SdlCaptureAudioIn(void* userdata, Uint8* stream, int len); - static void SdlCaptureAudioOut(void* userdata, Uint8* stream, int len); + static void SdlCaptureAudioIn(void* userdata, uint8_t* stream, int len); + static void SdlCaptureAudioOut(void* userdata, uint8_t* stream, int len); int CreateConnectionPeer(); int ConnectTo(const std::string& remote_id, const char* password, diff --git a/apps/desktop/src/gui/runtime/peer_data_callbacks.cpp b/apps/desktop/src/gui/runtime/peer_data_callbacks.cpp index c99233a2..fd5df3e3 100644 --- a/apps/desktop/src/gui/runtime/peer_data_callbacks.cpp +++ b/apps/desktop/src/gui/runtime/peer_data_callbacks.cpp @@ -1,3 +1,5 @@ +#include + #include "runtime/peer_event_handler.h" #include diff --git a/apps/desktop/src/gui/runtime/privacy_runtime.cpp b/apps/desktop/src/gui/runtime/privacy_runtime.cpp index 2a9f4b7a..e91de5fb 100644 --- a/apps/desktop/src/gui/runtime/privacy_runtime.cpp +++ b/apps/desktop/src/gui/runtime/privacy_runtime.cpp @@ -1,3 +1,5 @@ +#include + /* * @Author: DI JUNKUN * @Date: 2026-09-11 diff --git a/apps/desktop/src/log/rd_log.cpp b/apps/desktop/src/log/rd_log.cpp index 1f5731ea..1b834dae 100644 --- a/apps/desktop/src/log/rd_log.cpp +++ b/apps/desktop/src/log/rd_log.cpp @@ -1,6 +1,15 @@ #include "rd_log.h" +#include +#include #include +#include +#include +#include +#include + +#include "spdlog/sinks/rotating_file_sink.h" +#include "spdlog/sinks/stdout_color_sinks.h" namespace crossdesk { diff --git a/apps/desktop/src/log/rd_log.h b/apps/desktop/src/log/rd_log.h index 20b7530f..74e2f7aa 100644 --- a/apps/desktop/src/log/rd_log.h +++ b/apps/desktop/src/log/rd_log.h @@ -7,20 +7,9 @@ #ifndef _RD_LOG_H_ #define _RD_LOG_H_ -#include -#include -#include #include -#include -#include #include -#include -#include "spdlog/common.h" -#include "spdlog/logger.h" -#include "spdlog/sinks/base_sink.h" -#include "spdlog/sinks/rotating_file_sink.h" -#include "spdlog/sinks/stdout_color_sinks.h" #include "spdlog/spdlog.h" #define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO diff --git a/apps/desktop/src/platform/macos/gui/runtime/mac_permission_runtime.mm b/apps/desktop/src/platform/macos/gui/runtime/mac_permission_runtime.mm index 0d69dc6d..71858d5c 100644 --- a/apps/desktop/src/platform/macos/gui/runtime/mac_permission_runtime.mm +++ b/apps/desktop/src/platform/macos/gui/runtime/mac_permission_runtime.mm @@ -1,5 +1,7 @@ #include "runtime/gui_runtime.h" +#include + #include "rd_log.h" #include diff --git a/apps/desktop/src/platform/windows/gui/runtime/windows_service_runtime.cpp b/apps/desktop/src/platform/windows/gui/runtime/windows_service_runtime.cpp index a5ac2f44..55c1ca73 100644 --- a/apps/desktop/src/platform/windows/gui/runtime/windows_service_runtime.cpp +++ b/apps/desktop/src/platform/windows/gui/runtime/windows_service_runtime.cpp @@ -1,5 +1,7 @@ #include "runtime/gui_runtime.h" +#include + #include #include diff --git a/apps/desktop/src/version_checker/version_checker.cpp b/apps/desktop/src/version_checker/version_checker.cpp index a8e35775..37282101 100644 --- a/apps/desktop/src/version_checker/version_checker.cpp +++ b/apps/desktop/src/version_checker/version_checker.cpp @@ -7,6 +7,7 @@ #include "version_checker.h" #include +#include #include "rd_log.h" diff --git a/apps/desktop/src/version_checker/version_checker.h b/apps/desktop/src/version_checker/version_checker.h index ba99e76c..eb7fb22a 100644 --- a/apps/desktop/src/version_checker/version_checker.h +++ b/apps/desktop/src/version_checker/version_checker.h @@ -7,7 +7,7 @@ #ifndef _VERSION_CHECKER_H_ #define _VERSION_CHECKER_H_ -#include +#include #include #include diff --git a/apps/desktop/tests/version_checker_test.cpp b/apps/desktop/tests/version_checker_test.cpp index f827ad84..d81754bc 100644 --- a/apps/desktop/tests/version_checker_test.cpp +++ b/apps/desktop/tests/version_checker_test.cpp @@ -1,5 +1,6 @@ #include "version_checker.h" +#include #include #include #include diff --git a/apps/desktop/xmake/platform.lua b/apps/desktop/xmake/platform.lua index dfc56ca2..ee75a943 100644 --- a/apps/desktop/xmake/platform.lua +++ b/apps/desktop/xmake/platform.lua @@ -24,6 +24,20 @@ local function collect_dbus_arch_include_dirs() end function setup_platform_settings() + -- Discard unreferenced functions/data without the extra build cost of LTO. + -- Keep debug builds unchanged for predictable debugger behavior. + if is_mode("release") then + if is_os("macosx") then + add_ldflags("-Wl,-dead_strip") + elseif is_os("linux") then + add_cxflags("-ffunction-sections", "-fdata-sections") + add_ldflags("-Wl,--gc-sections") + elseif is_os("windows") then + add_cxflags("/Gy", "/Gw") + add_ldflags("/OPT:REF", "/OPT:ICF") + end + end + if is_os("windows") then add_requires("libyuv", "miniaudio 0.11.21") add_defines("NOMINMAX") diff --git a/apps/desktop/xmake/rules/slint.lua b/apps/desktop/xmake/rules/slint.lua index a6e84803..5d22dd89 100644 --- a/apps/desktop/xmake/rules/slint.lua +++ b/apps/desktop/xmake/rules/slint.lua @@ -1,53 +1,80 @@ rule("slint") set_extensions(".slint") - on_config(function(target) - local rule_name = "slint" - if target:rule("c++.build") then - local cpp_rule = target:rule("c++.build"):clone() - cpp_rule:add("deps", rule_name, {order = true}) - target:rule_add(cpp_rule) - end - + after_load(function(target) local outputdir = path.join(target:autogendir(), "rules", "slint") - os.mkdir(outputdir) target:add("includedirs", outputdir, {public = true}) - local sourcebatch = target:sourcebatches()[rule_name] - if sourcebatch and sourcebatch.sourcefiles then - for _, sourcefile in ipairs(sourcebatch.sourcefiles) do - -- Make the generated include discoverable during C++ dependency - -- scanning; the real contents are produced before compilation. - os.touch(path.join(outputdir, path.basename(sourcefile) .. ".h")) + local sourcebatch = target:sourcebatches()["slint"] + local outputs = {} + for _, sourcefile in ipairs(sourcebatch and sourcebatch.sourcefiles or {}) do + local header = path.join(outputdir, path.basename(sourcefile) .. ".h") + local sources = {} + -- Slint supports moving definitions out of the header and splitting + -- them into independently compiled translation units. + for index = 1, 4 do + local cppfile = path.join(outputdir, + path.basename(sourcefile) .. "_" .. index .. ".cpp") + table.insert(sources, cppfile) + target:add("files", cppfile, {always_added = true}) end + outputs[sourcefile] = {header = header, sources = sources} + end + target:data_set("slint.outputs", outputs) + end) + + on_config(function(target) + if target:rule("c++.build") then + local cpp_rule = target:rule("c++.build"):clone() + cpp_rule:add("deps", "slint", {order = true}) + target:rule_add(cpp_rule) end end) - before_buildcmd_file(function(target, batchcmds, sourcefile, opt) - local package = assert(target:pkg("slint"), "the slint package is required by this target") - local compiler = path.join(package:installdir(), "bin", is_host("windows") and "slint-compiler.exe" or "slint-compiler") - local outputdir = path.join(target:autogendir(), "rules", "slint") - local outputfile = path.join(outputdir, path.basename(sourcefile) .. ".h") - local depfile = outputfile .. ".d" + before_build_file(function(target, sourcefile, opt) + import("core.project.depend") + import("core.tools.gcc.parse_deps", {alias = "parse_deps"}) + import("utils.progress") - batchcmds:show_progress(opt.progress, "${color.build.object}generating.slint %s", sourcefile) - batchcmds:mkdir(outputdir) - batchcmds:vrunv(compiler, { - sourcefile, - "-f", "cpp", - "-o", outputfile, - "--depfile", depfile, - "--style", "fluent", - "--embed-resources=embed-files", - "--cpp-namespace", "crossdesk::ui" - }) - -- The compiler's depfile is useful to external build systems, while - -- xmake needs imported .slint files registered explicitly so editing a - -- component regenerates the umbrella header without a forced rebuild. - for _, dependency in ipairs(os.files(path.join(path.directory(sourcefile), "*.slint"))) do - batchcmds:add_depfiles(dependency) + local package = assert(target:pkg("slint"), "the slint package is required by this target") + local compiler = path.join(package:installdir(), "bin", + is_host("windows") and "slint-compiler.exe" or "slint-compiler") + local outputs = target:data("slint.outputs")[sourcefile] + local depfile = outputs.header .. ".d" + -- Slint writes the -o path literally into each generated #include. + local argv = {sourcefile, "-f", "cpp", "-o", path.absolute(outputs.header), + "--depfile", depfile, "--style", "fluent", + "--embed-resources=embed-files", "--cpp-namespace", "crossdesk::ui"} + local missing_output = not os.isfile(outputs.header) + for _, cppfile in ipairs(outputs.sources) do + table.insert(argv, "--cpp-file") + table.insert(argv, path.absolute(cppfile)) + missing_output = missing_output or not os.isfile(cppfile) end - batchcmds:set_depmtime(os.mtime(outputfile)) - batchcmds:set_depcache(target:dependfile(outputfile)) + + local function dependencies() + local files = {sourcefile, compiler} + if os.isfile(depfile) then + -- Track imported components AND embedded images, including + -- resources outside the UI directory, using the compiler output. + table.join2(files, parse_deps(io.readfile(depfile, {continuation = "\\"}))) + end + files = table.unique(files) + table.sort(files) + return files + end + + local depopts = {dependfile = target:dependfile(outputs.header), + values = argv, files = dependencies(), + changed = target:is_rebuilt() or missing_output or not os.isfile(depfile)} + -- Slint preserves timestamps of unchanged outputs. Use the dependency + -- cache's successful-generation time, not the oldest output's time. + depend.on_changed(function() + progress.show(opt.progress, "${color.build.object}generating.slint %s", sourcefile) + os.mkdir(path.directory(outputs.header)) + os.vrunv(compiler, argv) + -- Save the freshly discovered dependencies on the first build too. + depopts.files = dependencies() + end, depopts) end) rule_end() diff --git a/apps/desktop/xmake/targets.lua b/apps/desktop/xmake/targets.lua index bd287c42..f17fe9c9 100644 --- a/apps/desktop/xmake/targets.lua +++ b/apps/desktop/xmake/targets.lua @@ -1,6 +1,4 @@ function setup_targets() - add_packages("spdlog", "libsdl3", "nlohmann_json") - includes("deps/submodules", "deps/thirdparty") local crossdesk_version = get_config("CROSSDESK_VERSION") or "0.0.0" @@ -65,15 +63,17 @@ function setup_targets() target("rd_log") set_kind("object") - add_packages("spdlog") + add_packages("spdlog", {public = true}) add_files("apps/desktop/src/log/rd_log.cpp") add_includedirs("apps/desktop/src/log", {public = true}) - target("common") + -- MiniRTC owns a target named "common". Reusing it merges the two targets + -- and makes the media library inherit desktop sources and dependencies. + target("desktop_common") set_kind("object") add_deps("rd_log", "crossdesk_wire") add_packages("libyuv") - add_packages("concurrentqueue", {public = true}) + add_packages("concurrentqueue") add_files("apps/desktop/src/common/*.cpp") if is_os("windows") then add_files("apps/desktop/src/platform/windows/system_info.cpp") @@ -169,6 +169,21 @@ function setup_targets() add_includedirs("apps/desktop/src/platform/windows/service") add_files("apps/desktop/tests/windows_sas_guard_test.cpp") + target("crossdesk_ui") + set_kind("static") + set_languages("c++20") + -- Generated bindings are not the video/rendering hot path. Optimizing + -- them for size avoids expensive inlining of the large UI object tree. + if is_mode("release") then + set_optimize("smallest") + end + add_packages("slint", {public = true}) + add_rules("slint") + add_files("apps/desktop/src/gui/ui/crossdesk_ui.slint") + if is_os("windows") then + add_cxxflags("/bigobj") + end + target("slint_ui_smoke_test") set_kind("binary") set_languages("c++20") @@ -177,17 +192,16 @@ function setup_targets() add_cxxflags("/bigobj") end add_packages("slint") + add_deps("crossdesk_ui") add_includedirs("apps/desktop/src/gui", "apps/desktop/src/gui/assets/fonts", "apps/desktop/src/gui/assets/localization") - add_rules("slint") - add_files("apps/desktop/src/gui/ui/crossdesk_ui.slint") add_files("apps/desktop/tests/slint_ui_smoke_test.cpp") after_build(copy_slint_runtime) target("version_checker_test") set_kind("binary") set_default(false) - add_packages("cpp-httplib") + add_packages("cpp-httplib", "nlohmann_json") add_deps("rd_log") add_includedirs("apps/desktop/src/version_checker") add_files("apps/desktop/tests/version_checker_test.cpp", @@ -240,12 +254,12 @@ function setup_targets() target("screen_capturer") set_kind("object") - add_deps("rd_log", "common", "crossdesk_wire") + add_deps("rd_log", "desktop_common", "crossdesk_wire") add_includedirs("apps/desktop/src/screen_capturer", {public = true}) add_includedirs("deps/submodules/minirtc/src/api", {public = true}) if is_os("windows") then add_deps("privacy") - add_packages("libyuv") + add_packages("libyuv", "nlohmann_json") add_files("apps/desktop/src/screen_capturer/captured_nv12_frame.cpp") add_files("apps/desktop/src/platform/windows/screen_capturer/screen_capturer_dxgi.cpp", "apps/desktop/src/platform/windows/screen_capturer/screen_capturer_gdi.cpp", @@ -312,7 +326,7 @@ function setup_targets() target("device_controller") set_kind("object") - add_deps("rd_log", "common", "crossdesk_wire") + add_deps("rd_log", "desktop_common", "crossdesk_wire") add_includedirs("apps/desktop/src/device_controller", {public = true}) add_includedirs("apps/desktop/src/platform/common/input") if is_os("windows") then @@ -347,7 +361,7 @@ function setup_targets() target("thumbnail") set_kind("object") add_packages("libyuv", "openssl3") - add_deps("rd_log", "common") + add_deps("rd_log", "desktop_common") add_files("apps/desktop/src/thumbnail/*.cpp") add_includedirs("apps/desktop/src/thumbnail", {public = true}) @@ -380,6 +394,7 @@ function setup_targets() target("version_checker") set_kind("object") add_packages("cpp-httplib") + add_packages("nlohmann_json", {public = true}) add_deps("rd_log") add_files("apps/desktop/src/version_checker/*.cpp") add_includedirs("apps/desktop/src/version_checker", {public = true}) @@ -390,7 +405,7 @@ function setup_targets() target("tools") set_kind("object") - add_deps("rd_log", "common", "crossdesk_wire") + add_deps("rd_log", "desktop_common", "crossdesk_wire") add_files("apps/desktop/src/tools/*.cpp") if is_os("windows") then add_files("apps/desktop/src/platform/windows/clipboard.cpp") @@ -409,24 +424,23 @@ function setup_targets() -- version and use fmt's supported runtime-parser fallback here. add_defines("FMT_CONSTEVAL=") add_packages("slint", {public = true}) - add_packages("libyuv", "tinyfiledialogs", "openssl3") - add_rules("slint") + add_packages("libyuv", "tinyfiledialogs", "openssl3", "libsdl3", "nlohmann_json") if is_config("CROSSDESK_PORTABLE", true) then -- RuntimeState changes layout in portable builds. Consumers of GUI -- headers must see the same definition, without affecting its deps. add_defines("CROSSDESK_PORTABLE=1", {public = true}) end - add_deps("rd_log", "common", "assets", "config_center", "minirtc", + add_deps("rd_log", "desktop_common", "assets", "config_center", "minirtc", "path_manager", "screen_capturer", "speaker_capturer", "device_controller", "thumbnail", "version_checker", "tools", - "crossdesk_wire", "privacy") + "crossdesk_wire", "privacy", "crossdesk_ui") add_files("apps/desktop/src/gui/render.cpp", "apps/desktop/src/gui/application/gui_application.cpp", "apps/desktop/src/gui/rendering/*.cpp", "apps/desktop/src/gui/runtime/*.cpp", "apps/desktop/src/platform/common/gui/service_status_runtime.cpp", "apps/desktop/src/gui/features/devices/*.cpp", "apps/desktop/src/gui/features/input/*.cpp", "apps/desktop/src/gui/features/clipboard/*.cpp", "apps/desktop/src/gui/features/file_transfer/*.cpp", - "apps/desktop/src/gui/features/settings/*.cpp", "apps/desktop/src/gui/ui/crossdesk_ui.slint") + "apps/desktop/src/gui/features/settings/*.cpp") -- Only these translation units consume the application version. Keep -- version changes out of the flags for media and the rest of the GUI. add_files("apps/desktop/src/gui/application/gui_application.cpp", @@ -494,6 +508,7 @@ function setup_targets() target("crossdesk_service") set_kind("binary") + add_packages("nlohmann_json") add_deps("rd_log", "path_manager") add_links("Advapi32", "Wtsapi32", "Ole32", "Userenv") add_files("apps/desktop/src/platform/windows/service/main.cpp", @@ -505,7 +520,7 @@ function setup_targets() target("crossdesk_session_helper") set_kind("binary") - add_packages("libyuv") + add_packages("libyuv", "nlohmann_json") add_deps("rd_log", "path_manager") add_links("Advapi32", "User32", "Wtsapi32", "Gdi32", "Setupapi") add_files("apps/desktop/src/platform/windows/service/session_helper_main.cpp") @@ -523,7 +538,7 @@ function setup_targets() target("crossdesk") set_kind("binary") - add_deps("rd_log", "common", "gui") + add_deps("rd_log", "desktop_common", "gui") add_files("apps/desktop/src/app/*.cpp") add_includedirs("apps/desktop/src", "apps/desktop/src/app", {public = true}) if is_os("windows") then