From aca98a8b55482c9164938a3785b9c5efb56ca725 Mon Sep 17 00:00:00 2001 From: RL-Xiang Date: Thu, 20 Aug 2026 21:35:45 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8C=87=E5=AE=9A=E6=96=B0=E8=BF=81=E7=A7=BB?= =?UTF-8?q?=E8=AE=A1=E5=88=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MIGRATION_PLAN.md | 93 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 84 insertions(+), 9 deletions(-) diff --git a/MIGRATION_PLAN.md b/MIGRATION_PLAN.md index 0e24e28..349787f 100644 --- a/MIGRATION_PLAN.md +++ b/MIGRATION_PLAN.md @@ -1,6 +1,6 @@ # FancyInput WPF → Qt 6 (QML + C++) 迁移方案 -> 版本:v2.0 · 日期:2026-08-19 · 状态:待评审 +> 版本:v2.1 · 日期:2026-08-20 · 状态:待评审 > 源项目:`WPF\FancyInput`(.NET 8.0 WPF,约 132 文件 / 24,000 行) > 目标框架:**Qt 6.8.3(MinGW 13.1.0 x64 + CMake + QML)** > 目标:**UI 布局完全一致、逻辑相同**,代码用 QML + C++ 重写 @@ -9,6 +9,76 @@ --- +## 新会话快速上手(★ 新开会话先读这里) + +> 本工程已通过 **阶段 0(Hello World)+ 构建基础设施**,全部验证通过。以下信息足以让一个新会话立刻上手,详细踩坑记录见仓库记忆 `/memories/repo/qt-build-notes.md`(新会话会自动加载)。 + +### 当前工程结构(已验证可构建可运行) + +``` +Qt\ +├── CMakeLists.txt # 顶层工程(两个 QML 模块 + 部署裁剪) +├── CMakePresets.json # MinGW_64_Debug / MinGW_64_Release 预设 +├── MIGRATION_PLAN.md # 本文档 +├── .vscode\settings.json # qmlls import paths + cmake preset +├── src\ +│ ├── main.cpp # QGuiApplication + addImportPath("qrc:/") + loadFromModule +│ └── qml\ +│ ├── Main.qml # 主窗口(ApplicationWindow 600×480,阶段 0 骨架) +│ └── controls\ # ★ 用户自定义控件目录(URI: FancyInput.Controls) +│ └── Theme.qml # 全局主题单例(pragma Singleton) +├── bin\{Debug,Release}\ # exe + windeployqt 部署的 Qt 运行库(最终产物) +└── build\MinGW_64_{Debug,Release}\ # 中间产物 + QML 模块目录(qmlls 用) +``` + +### QML 模块架构(关键!) + +| 模块 | 类型 | URI | 内容 | 说明 | +|---|---|---|---|---| +| `FancyInputControls` | **静态库**(`STATIC` 关键字写在 `qt_add_qml_module` 内) | `FancyInput.Controls` | `src/qml/controls/*.qml`(GLOB 自动收集) | 以后**新增控件只需放 .qml 文件,无需改 CMakeLists** | +| `FancyInputQt` | 可执行文件主模块 | `FancyInputQt` | `src/qml/Main.qml` | `DEPENDENCIES FancyInputControls` | + +必须记住的三条铁律(踩过坑): +1. **静态 QML 模块必须链接插件 target**:`target_link_libraries(FancyInputQt PRIVATE FancyInputControls FancyInputControlsplugin ...)`,否则运行时报 "plugin FancyInputControlsplugin not found"; +2. **`pragma Singleton` 不会被自动识别**:必须 `set_source_files_properties(Theme.qml PROPERTIES QT_QML_SINGLETON_TYPE TRUE)` **且放在 `qt_add_qml_module` 调用之前**; +3. **`QT_QML_OUTPUT_DIRECTORY` 必须设置**:在**所有** `qt_add_qml_module` 之前写 `set(QT_QML_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")`——否则库模块输出到 build 根目录(Qt6QmlMacros.cmake:1430 警告)且 qmlls 找不到模块。 + +### 构建与验证命令(终端) + +```powershell +# 终端 PATH(每次新终端都要先执行) +$env:Path = "D:/Qt/6.8.3/mingw_64/bin;D:/Qt/Tools/mingw1310_64/bin;C:\Windows\System32;C:\Windows" +Set-Location "d:\Projects\FancyInput\Qt" + +# 配置(仅首次或 CMakeLists 变更时) +& "C:\Program Files\CMake\bin\cmake.exe" --preset MinGW_64_Debug + +# 编译(每次改完代码;干净重建加 --clean-first) +& "C:\Program Files\CMake\bin\cmake.exe" --build --preset MinGW_64_Debug + +# 运行验证(GUI 程序无控制台输出,用窗口标题确认) +# 先切干净 PATH 再运行,验证独立运行(不带 Qt bin 目录): +$env:Path = "C:\Windows\System32;C:\Windows" +Start-Process "bin\Debug\FancyInputQt.exe" -PassThru | Select-Object MainWindowTitle +# 期望标题:"FancyInput · Qt 迁移版(阶段 0)" + +# QML 模块解析验证(无输出 = 成功) +& "D:\Qt\6.8.3\mingw_64\bin\qmllint.exe" -I build/MinGW_64_Debug -I D:/Qt/6.8.3/mingw_64/qml src/qml/Main.qml src/qml/controls/Theme.qml +``` + +### 许可状态(2026-08-20 已核对,全部 LGPL 安全 ✅) + +- 部署的 Qt DLL 全部为 LGPL v3 官方模块(SPDX 核对 qtbase/qtdeclarative/qtsvg:`Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only`,开源版按 LGPL v3 使用); +- MinGW 运行时 DLL(libgcc_s_seh-1/libstdc++-6/libwinpthread-1):GPLv3 + **GCC Runtime Library Exception**(`D:\Qt\Tools\mingw1310_64\licenses\gcc\COPYING.RUNTIME` 已确认),允许闭源商用; +- **Qt6VirtualKeyboard(GPL v3)已被 CMakeLists 的 `GPL_COMPONENTS` 块强制裁剪**(windeployqt 会隐式部署,App 实际不用)——这是防御性安全网,不是已部署组件; +- bin/Release 实测 24 个 DLL(21 Qt6 + 3 MinGW 运行时)+ qml 模块仅 {QML, QtQml, QtQuick},无任何 GPL 文件。 + +### 下一步 + +**进入阶段 1(通用函数与数据结构)**,从 `src\core\common\Enums.h` 开始。详见下文第四、五节的分阶段计划。 + +--- + ## 〇、许可合规策略(重要) **核心原则:全部组件要么是 LGPL 动态链接(可免费闭源商用),要么是宽松许可(MIT/zlib/BSD),一律避开 GPL/AGPL。** @@ -259,14 +329,16 @@ Qt\ **每阶段通用验收流程**(适用于所有阶段): 1. 编写/调整代码 → 2. `cmake --build` 就地编译 → 3. 运行程序验证 → 4. 有变化才进入下一步 -**每阶段通用的构建命令**(`Qt\` 目录下): +**每阶段通用的构建命令**(`Qt\` 目录下,已改用 CMakePresets): ```powershell +# 终端 PATH +$env:Path = "D:/Qt/6.8.3/mingw_64/bin;D:/Qt/Tools/mingw1310_64/bin;C:\Windows\System32;C:\Windows" # 配置(仅首次或 CMakeLists 变更时) -cmake -S . -B build -G "MinGW Makefiles" -DCMAKE_PREFIX_PATH=D:/Qt/6.8.3/mingw_64 -DCMAKE_BUILD_TYPE=Debug +& "C:\Program Files\CMake\bin\cmake.exe" --preset MinGW_64_Debug # 编译(每次改完代码) -cmake --build build -j -# 运行 -.\build\FancyInputQt.exe +& "C:\Program Files\CMake\bin\cmake.exe" --build --preset MinGW_64_Debug +# 运行(exe 在 bin\Debug\ 下,非 build 目录) +.\bin\Debug\FancyInputQt.exe ``` --- @@ -278,10 +350,12 @@ cmake --build build -j - [x] `Qt\CMakeLists.txt`:`find_package(Qt6 COMPONENTS Core Gui Qml Quick QuickControls2)`;`qt_add_executable(FancyInputQt ...)` + `qt_add_qml_module` - [x] `src\main.cpp`:`QGuiApplication` + `QQmlApplicationEngine` 加载 QML(`objectCreationFailed` 兜底退出) - [x] `src\qml\Main.qml`:`ApplicationWindow` 600×480,标题 "FancyInput · Qt 迁移版(阶段 0)" -- [x] `src\qml\Theme.qml`:全局主题单例(主色 `#651F65`、背景 `#1E1E24`、字体 `Cascadia Mono`) +- [x] `src\qml\controls\Theme.qml`:全局主题单例(主色 `#651F65`、背景 `#1E1E24`、字体 `Cascadia Mono`)——**注意在 `controls\` 目录**(属 `FancyInput.Controls` 模块),不在 qml 根目录;用 `Theme.xxx` 引用 +- [x] 双 QML 模块架构:`FancyInput.Controls`(静态库,GLOB 自动收集 controls/ 下所有 .qml)+ `FancyInputQt`(主模块)——以后加控件零改 CMakeLists +- [x] 构建基础设施:CMakePresets(Debug/Release)、windeployqt 部署 + 体积裁剪、qmlls/qmllint 无警告 - [ ] 资源目录 `resources\icons\`(拷贝 Icon.png/ico,阶段 4 主界面时补) -**产出**:`FancyInputQt.exe` 可运行,窗口显示、主题色正确(已验证,2026-08-19)。 +**产出**:`bin\Debug\FancyInputQt.exe` 可运行,窗口显示、主题色正确(已验证,2026-08-19 至 08-20)。 ### 阶段 1:通用函数与数据结构(纯 C++,不依赖 UI) @@ -373,7 +447,7 @@ cmake --build build -j - [ ] 在线更新检查(QNetworkAccessManager,API 地址照搬) - [ ] 虚拟手柄完善(ViGEm 若未在前置做)+ 终端页(QProcess cmd/PowerShell) - [ ] 管理员自提权、单实例、命令行参数(.fip/.fips 打开) -- [ ] `windeployqt` 发布打包 + LGPL 合规文件(LGPLv3 文本 + Qt 版本声明) +- [ ] `windeployqt` 发布打包 + LGPL 合规文件(LGPLv3 文本 + Qt 版本声明)——**许可已核对(2026-08-20)**:全部部署组件 LGPL 安全(见文首快速上手章节),打包时需附 LGPLv3 文本 + 保留 DLL 可替换性 - [ ] UI 逐屏对照验收 + 行为对照验收 --- @@ -442,3 +516,4 @@ cmake --build build -j 5. **虚拟手柄(ViGEm)**:**已确认不做**;HidHide(GPL)同样不迁移 6. **范围**:按上表全功能迁移,宏系统/图像编辑器/在线更新延后(已定) 7. **代码中已注释掉的逻辑**(HidHide、MirrorGamepad、ConsoleWindow 等)是否一并迁移?建议不迁(保持与 WPF 行为一致) +8. **第三方依赖 DLL 存放方案**:待确认是否按 `bin//thirdparty/` 子目录存放第三方库(SDL3/ViGEmClient 等),与 Qt DLL 分离,便于许可管理(尚未实施,等 SDL3 接入时确认)