From 0402dec63a45e59971a26e8ac274b84022658082 Mon Sep 17 00:00:00 2001 From: miyanyan <1138989048@qq.com> Date: Fri, 31 Jul 2026 13:40:01 +0800 Subject: [PATCH] z-applocal: add qt6 support, read plugins from Qt6/modules/xxx.json --- .../e2e-projects/applocal/qt/build.bat | 81 ++++++++++ .../qt/installed/debug/plugins/qtdeploy.ps1 | 1 + .../qt/installed/plugins/qtdeploy.ps1 | 1 + .../qt/installed/share/Qt6/modules/Core.json | 4 + .../qt/installed/share/Qt6/modules/Gui.json | 12 ++ .../installed/share/Qt6/modules/Network.json | 8 + .../share/Qt6/modules/PrintSupport.json | 6 + .../qt/installed/share/Qt6/modules/Sql.json | 6 + .../installed/share/Qt6/modules/Widgets.json | 6 + .../e2e-projects/applocal/qt/main.cpp | 7 + .../e2e-projects/applocal/qt/qtcore.cpp | 1 + .../e2e-projects/applocal/qt/qtgui.cpp | 3 + .../e2e-projects/applocal/qt/qtnetwork.cpp | 3 + .../e2e-projects/applocal/qt/qtplugin.cpp | 1 + .../applocal/qt/qtprintsupport.cpp | 3 + .../e2e-projects/applocal/qt/qtsql.cpp | 3 + .../e2e-projects/applocal/qt/qtwidgets.cpp | 3 + .../end-to-end-tests-dir/z-applocalcpp.ps1 | 143 ++++++++++++++++++ src/vcpkg/commands.z-applocal.cpp | 122 ++++++++++++++- 19 files changed, 407 insertions(+), 7 deletions(-) create mode 100644 azure-pipelines/e2e-projects/applocal/qt/build.bat create mode 100644 azure-pipelines/e2e-projects/applocal/qt/installed/debug/plugins/qtdeploy.ps1 create mode 100644 azure-pipelines/e2e-projects/applocal/qt/installed/plugins/qtdeploy.ps1 create mode 100644 azure-pipelines/e2e-projects/applocal/qt/installed/share/Qt6/modules/Core.json create mode 100644 azure-pipelines/e2e-projects/applocal/qt/installed/share/Qt6/modules/Gui.json create mode 100644 azure-pipelines/e2e-projects/applocal/qt/installed/share/Qt6/modules/Network.json create mode 100644 azure-pipelines/e2e-projects/applocal/qt/installed/share/Qt6/modules/PrintSupport.json create mode 100644 azure-pipelines/e2e-projects/applocal/qt/installed/share/Qt6/modules/Sql.json create mode 100644 azure-pipelines/e2e-projects/applocal/qt/installed/share/Qt6/modules/Widgets.json create mode 100644 azure-pipelines/e2e-projects/applocal/qt/main.cpp create mode 100644 azure-pipelines/e2e-projects/applocal/qt/qtcore.cpp create mode 100644 azure-pipelines/e2e-projects/applocal/qt/qtgui.cpp create mode 100644 azure-pipelines/e2e-projects/applocal/qt/qtnetwork.cpp create mode 100644 azure-pipelines/e2e-projects/applocal/qt/qtplugin.cpp create mode 100644 azure-pipelines/e2e-projects/applocal/qt/qtprintsupport.cpp create mode 100644 azure-pipelines/e2e-projects/applocal/qt/qtsql.cpp create mode 100644 azure-pipelines/e2e-projects/applocal/qt/qtwidgets.cpp diff --git a/azure-pipelines/e2e-projects/applocal/qt/build.bat b/azure-pipelines/e2e-projects/applocal/qt/build.bat new file mode 100644 index 0000000000..807e653452 --- /dev/null +++ b/azure-pipelines/e2e-projects/applocal/qt/build.bat @@ -0,0 +1,81 @@ +@echo off +setlocal +cd /d %~dp0 + +call :build_qt 5 "" qt5-release installed\bin installed\plugins +if errorlevel 1 exit /b 1 +call :build_qt 5 d qt5-debug installed\debug\bin installed\debug\plugins +if errorlevel 1 exit /b 1 +call :build_qt 6 "" qt6-release installed\bin installed\Qt6\plugins +if errorlevel 1 exit /b 1 +call :build_qt 6 d qt6-debug installed\debug\bin installed\debug\Qt6\plugins +if errorlevel 1 exit /b 1 +exit /b 0 + +:build_qt +set "qt_major=%~1" +set "debug_suffix=%~2" +set "app_dir=%~3" +set "bin_dir=%~4" +set "plugins_dir=%~5" + +if not exist "%app_dir%" mkdir "%app_dir%" +if not exist "%bin_dir%" mkdir "%bin_dir%" +if not exist "%plugins_dir%\generic" mkdir "%plugins_dir%\generic" +if not exist "%plugins_dir%\imageformats" mkdir "%plugins_dir%\imageformats" +if not exist "%plugins_dir%\platforms" mkdir "%plugins_dir%\platforms" +if not exist "%plugins_dir%\platformthemes" mkdir "%plugins_dir%\platformthemes" +if not exist "%plugins_dir%\printsupport" mkdir "%plugins_dir%\printsupport" +if not exist "%plugins_dir%\sqldrivers" mkdir "%plugins_dir%\sqldrivers" +if not exist "%plugins_dir%\styles" mkdir "%plugins_dir%\styles" + +cl /nologo /LD qtcore.cpp /Fe:%bin_dir%\Qt%qt_major%Core%debug_suffix%.dll /link /IMPLIB:%bin_dir%\Qt%qt_major%Core%debug_suffix%.lib +if errorlevel 1 exit /b 1 +cl /nologo /LD qtnetwork.cpp %bin_dir%\Qt%qt_major%Core%debug_suffix%.lib /Fe:%bin_dir%\Qt%qt_major%Network%debug_suffix%.dll /link /IMPLIB:%bin_dir%\Qt%qt_major%Network%debug_suffix%.lib +if errorlevel 1 exit /b 1 +cl /nologo /LD qtsql.cpp %bin_dir%\Qt%qt_major%Core%debug_suffix%.lib /Fe:%bin_dir%\Qt%qt_major%Sql%debug_suffix%.dll /link /IMPLIB:%bin_dir%\Qt%qt_major%Sql%debug_suffix%.lib +if errorlevel 1 exit /b 1 +cl /nologo /LD qtprintsupport.cpp %bin_dir%\Qt%qt_major%Core%debug_suffix%.lib /Fe:%bin_dir%\Qt%qt_major%PrintSupport%debug_suffix%.dll /link /IMPLIB:%bin_dir%\Qt%qt_major%PrintSupport%debug_suffix%.lib +if errorlevel 1 exit /b 1 +cl /nologo /LD qtgui.cpp %bin_dir%\Qt%qt_major%Core%debug_suffix%.lib /Fe:%bin_dir%\Qt%qt_major%Gui%debug_suffix%.dll /link /IMPLIB:%bin_dir%\Qt%qt_major%Gui%debug_suffix%.lib +if errorlevel 1 exit /b 1 +cl /nologo /LD qtwidgets.cpp %bin_dir%\Qt%qt_major%Gui%debug_suffix%.lib /Fe:%bin_dir%\Qt%qt_major%Widgets%debug_suffix%.dll /link /IMPLIB:%bin_dir%\Qt%qt_major%Widgets%debug_suffix%.lib +if errorlevel 1 exit /b 1 +cl /nologo /EHsc main.cpp %bin_dir%\Qt%qt_major%Gui%debug_suffix%.lib %bin_dir%\Qt%qt_major%Network%debug_suffix%.lib %bin_dir%\Qt%qt_major%PrintSupport%debug_suffix%.lib %bin_dir%\Qt%qt_major%Sql%debug_suffix%.lib %bin_dir%\Qt%qt_major%Widgets%debug_suffix%.lib /Fe:%app_dir%\main.exe +if errorlevel 1 exit /b 1 +cl /nologo /LD qtplugin.cpp /Fe:%plugins_dir%\qtplugin.dll +if errorlevel 1 exit /b 1 +call :copy_plugin "%plugins_dir%\qtplugin.dll" "%bin_dir%\libssl-unused.dll" +if errorlevel 1 exit /b 1 + +call :copy_plugin "%plugins_dir%\qtplugin.dll" "%plugins_dir%\imageformats\qjpeg%debug_suffix%.dll" +if errorlevel 1 exit /b 1 +call :copy_plugin "%plugins_dir%\qtplugin.dll" "%plugins_dir%\platforms\qwindows%debug_suffix%.dll" +if errorlevel 1 exit /b 1 +call :copy_plugin "%plugins_dir%\qtplugin.dll" "%plugins_dir%\generic\qgeneric%debug_suffix%.dll" +if errorlevel 1 exit /b 1 +call :copy_plugin "%plugins_dir%\qtplugin.dll" "%plugins_dir%\platformthemes\qplatformtheme%debug_suffix%.dll" +if errorlevel 1 exit /b 1 +call :copy_plugin "%plugins_dir%\qtplugin.dll" "%plugins_dir%\printsupport\qprint%debug_suffix%.dll" +if errorlevel 1 exit /b 1 +call :copy_plugin "%plugins_dir%\qtplugin.dll" "%plugins_dir%\sqldrivers\qsqlite%debug_suffix%.dll" +if errorlevel 1 exit /b 1 +call :copy_plugin "%plugins_dir%\qtplugin.dll" "%plugins_dir%\styles\qstyle%debug_suffix%.dll" +if errorlevel 1 exit /b 1 + +if "%qt_major%"=="5" ( + if not exist "%plugins_dir%\bearer" mkdir "%plugins_dir%\bearer" + call :copy_plugin "%plugins_dir%\qtplugin.dll" "%plugins_dir%\bearer\qbearer%debug_suffix%.dll" +) else ( + if not exist "%plugins_dir%\networkinformation" mkdir "%plugins_dir%\networkinformation" + if not exist "%plugins_dir%\tls" mkdir "%plugins_dir%\tls" + call :copy_plugin "%plugins_dir%\qtplugin.dll" "%plugins_dir%\networkinformation\qnetworkinformation%debug_suffix%.dll" + if errorlevel 1 exit /b 1 + call :copy_plugin "%plugins_dir%\qtplugin.dll" "%plugins_dir%\tls\qtls%debug_suffix%.dll" +) +if errorlevel 1 exit /b 1 +exit /b 0 + +:copy_plugin +copy /Y "%~1" "%~2" >nul +exit /b %errorlevel% diff --git a/azure-pipelines/e2e-projects/applocal/qt/installed/debug/plugins/qtdeploy.ps1 b/azure-pipelines/e2e-projects/applocal/qt/installed/debug/plugins/qtdeploy.ps1 new file mode 100644 index 0000000000..61179c0a12 --- /dev/null +++ b/azure-pipelines/e2e-projects/applocal/qt/installed/debug/plugins/qtdeploy.ps1 @@ -0,0 +1 @@ +This file exists to tell z-applocal that Qt 5 is installed and is not executed by the test. diff --git a/azure-pipelines/e2e-projects/applocal/qt/installed/plugins/qtdeploy.ps1 b/azure-pipelines/e2e-projects/applocal/qt/installed/plugins/qtdeploy.ps1 new file mode 100644 index 0000000000..61179c0a12 --- /dev/null +++ b/azure-pipelines/e2e-projects/applocal/qt/installed/plugins/qtdeploy.ps1 @@ -0,0 +1 @@ +This file exists to tell z-applocal that Qt 5 is installed and is not executed by the test. diff --git a/azure-pipelines/e2e-projects/applocal/qt/installed/share/Qt6/modules/Core.json b/azure-pipelines/e2e-projects/applocal/qt/installed/share/Qt6/modules/Core.json new file mode 100644 index 0000000000..365d55f08e --- /dev/null +++ b/azure-pipelines/e2e-projects/applocal/qt/installed/share/Qt6/modules/Core.json @@ -0,0 +1,4 @@ +{ + "name": "Core", + "plugin_types": [] +} diff --git a/azure-pipelines/e2e-projects/applocal/qt/installed/share/Qt6/modules/Gui.json b/azure-pipelines/e2e-projects/applocal/qt/installed/share/Qt6/modules/Gui.json new file mode 100644 index 0000000000..7109b26977 --- /dev/null +++ b/azure-pipelines/e2e-projects/applocal/qt/installed/share/Qt6/modules/Gui.json @@ -0,0 +1,12 @@ +{ + "name": "Gui", + "plugin_types": [ + "accessiblebridge", + "platforms", + "platformthemes", + "platforminputcontexts", + "generic", + "iconengines", + "imageformats" + ] +} diff --git a/azure-pipelines/e2e-projects/applocal/qt/installed/share/Qt6/modules/Network.json b/azure-pipelines/e2e-projects/applocal/qt/installed/share/Qt6/modules/Network.json new file mode 100644 index 0000000000..ce53b3efc8 --- /dev/null +++ b/azure-pipelines/e2e-projects/applocal/qt/installed/share/Qt6/modules/Network.json @@ -0,0 +1,8 @@ +{ + "name": "Network", + "plugin_types": [ + "networkaccess", + "networkinformation", + "tls" + ] +} diff --git a/azure-pipelines/e2e-projects/applocal/qt/installed/share/Qt6/modules/PrintSupport.json b/azure-pipelines/e2e-projects/applocal/qt/installed/share/Qt6/modules/PrintSupport.json new file mode 100644 index 0000000000..da62cf76fc --- /dev/null +++ b/azure-pipelines/e2e-projects/applocal/qt/installed/share/Qt6/modules/PrintSupport.json @@ -0,0 +1,6 @@ +{ + "name": "PrintSupport", + "plugin_types": [ + "printsupport" + ] +} diff --git a/azure-pipelines/e2e-projects/applocal/qt/installed/share/Qt6/modules/Sql.json b/azure-pipelines/e2e-projects/applocal/qt/installed/share/Qt6/modules/Sql.json new file mode 100644 index 0000000000..a6bd891ad4 --- /dev/null +++ b/azure-pipelines/e2e-projects/applocal/qt/installed/share/Qt6/modules/Sql.json @@ -0,0 +1,6 @@ +{ + "name": "Sql", + "plugin_types": [ + "sqldrivers" + ] +} diff --git a/azure-pipelines/e2e-projects/applocal/qt/installed/share/Qt6/modules/Widgets.json b/azure-pipelines/e2e-projects/applocal/qt/installed/share/Qt6/modules/Widgets.json new file mode 100644 index 0000000000..ee608750a3 --- /dev/null +++ b/azure-pipelines/e2e-projects/applocal/qt/installed/share/Qt6/modules/Widgets.json @@ -0,0 +1,6 @@ +{ + "name": "Widgets", + "plugin_types": [ + "styles" + ] +} diff --git a/azure-pipelines/e2e-projects/applocal/qt/main.cpp b/azure-pipelines/e2e-projects/applocal/qt/main.cpp new file mode 100644 index 0000000000..91c694061c --- /dev/null +++ b/azure-pipelines/e2e-projects/applocal/qt/main.cpp @@ -0,0 +1,7 @@ +extern "C" __declspec(dllimport) int qt_gui(); +extern "C" __declspec(dllimport) int qt_network(); +extern "C" __declspec(dllimport) int qt_printsupport(); +extern "C" __declspec(dllimport) int qt_sql(); +extern "C" __declspec(dllimport) int qt_widgets(); + +int main() { return qt_gui() + qt_network() + qt_printsupport() + qt_sql() + qt_widgets(); } diff --git a/azure-pipelines/e2e-projects/applocal/qt/qtcore.cpp b/azure-pipelines/e2e-projects/applocal/qt/qtcore.cpp new file mode 100644 index 0000000000..f29f19b907 --- /dev/null +++ b/azure-pipelines/e2e-projects/applocal/qt/qtcore.cpp @@ -0,0 +1 @@ +extern "C" __declspec(dllexport) int qt_core() { return 0; } diff --git a/azure-pipelines/e2e-projects/applocal/qt/qtgui.cpp b/azure-pipelines/e2e-projects/applocal/qt/qtgui.cpp new file mode 100644 index 0000000000..7db4f080f6 --- /dev/null +++ b/azure-pipelines/e2e-projects/applocal/qt/qtgui.cpp @@ -0,0 +1,3 @@ +extern "C" __declspec(dllimport) int qt_core(); + +extern "C" __declspec(dllexport) int qt_gui() { return qt_core(); } diff --git a/azure-pipelines/e2e-projects/applocal/qt/qtnetwork.cpp b/azure-pipelines/e2e-projects/applocal/qt/qtnetwork.cpp new file mode 100644 index 0000000000..cbed16902f --- /dev/null +++ b/azure-pipelines/e2e-projects/applocal/qt/qtnetwork.cpp @@ -0,0 +1,3 @@ +extern "C" __declspec(dllimport) int qt_core(); + +extern "C" __declspec(dllexport) int qt_network() { return qt_core(); } diff --git a/azure-pipelines/e2e-projects/applocal/qt/qtplugin.cpp b/azure-pipelines/e2e-projects/applocal/qt/qtplugin.cpp new file mode 100644 index 0000000000..0958d30d32 --- /dev/null +++ b/azure-pipelines/e2e-projects/applocal/qt/qtplugin.cpp @@ -0,0 +1 @@ +extern "C" __declspec(dllexport) int qt_plugin() { return 0; } diff --git a/azure-pipelines/e2e-projects/applocal/qt/qtprintsupport.cpp b/azure-pipelines/e2e-projects/applocal/qt/qtprintsupport.cpp new file mode 100644 index 0000000000..0637f93cec --- /dev/null +++ b/azure-pipelines/e2e-projects/applocal/qt/qtprintsupport.cpp @@ -0,0 +1,3 @@ +extern "C" __declspec(dllimport) int qt_core(); + +extern "C" __declspec(dllexport) int qt_printsupport() { return qt_core(); } diff --git a/azure-pipelines/e2e-projects/applocal/qt/qtsql.cpp b/azure-pipelines/e2e-projects/applocal/qt/qtsql.cpp new file mode 100644 index 0000000000..d0f0bb3b2d --- /dev/null +++ b/azure-pipelines/e2e-projects/applocal/qt/qtsql.cpp @@ -0,0 +1,3 @@ +extern "C" __declspec(dllimport) int qt_core(); + +extern "C" __declspec(dllexport) int qt_sql() { return qt_core(); } diff --git a/azure-pipelines/e2e-projects/applocal/qt/qtwidgets.cpp b/azure-pipelines/e2e-projects/applocal/qt/qtwidgets.cpp new file mode 100644 index 0000000000..711ce41c27 --- /dev/null +++ b/azure-pipelines/e2e-projects/applocal/qt/qtwidgets.cpp @@ -0,0 +1,3 @@ +extern "C" __declspec(dllimport) int qt_gui(); + +extern "C" __declspec(dllexport) int qt_widgets() { return qt_gui(); } diff --git a/azure-pipelines/end-to-end-tests-dir/z-applocalcpp.ps1 b/azure-pipelines/end-to-end-tests-dir/z-applocalcpp.ps1 index a83c5bb3ba..b19906b425 100644 --- a/azure-pipelines/end-to-end-tests-dir/z-applocalcpp.ps1 +++ b/azure-pipelines/end-to-end-tests-dir/z-applocalcpp.ps1 @@ -33,6 +33,149 @@ if ($IsWindows) { --installed-bin-dir=$basicDir Throw-IfNotFailed + # Tests deploy Qt 5 and Qt 6 libraries and plugins when both versions are installed + $qtDir = "$TestingRoot/applocal/qt" + Run-Vcpkg env "$qtDir/build.bat" + + $qtCases = @( + @{ + Name = "Qt 5 release" + Major = 5 + Suffix = "" + AppDir = "qt5-release" + InstalledBinDir = "installed/bin" + PluginsDir = "installed/plugins" + OtherPluginsDir = "installed/Qt6/plugins" + }, + @{ + Name = "Qt 5 debug" + Major = 5 + Suffix = "d" + AppDir = "qt5-debug" + InstalledBinDir = "installed/debug/bin" + PluginsDir = "installed/debug/plugins" + OtherPluginsDir = "installed/debug/Qt6/plugins" + }, + @{ + Name = "Qt 6 release" + Major = 6 + Suffix = "" + AppDir = "qt6-release" + InstalledBinDir = "installed/bin" + PluginsDir = "installed/Qt6/plugins" + OtherPluginsDir = "installed/plugins" + }, + @{ + Name = "Qt 6 debug" + Major = 6 + Suffix = "d" + AppDir = "qt6-debug" + InstalledBinDir = "installed/debug/bin" + PluginsDir = "installed/debug/Qt6/plugins" + OtherPluginsDir = "installed/debug/plugins" + } + ) + + foreach ($qtCase in $qtCases) + { + $appDir = Join-Path $qtDir $qtCase.AppDir + $installedBinDir = Join-Path $qtDir $qtCase.InstalledBinDir + $coreLibrary = "Qt$($qtCase.Major)Core$($qtCase.Suffix).dll" + $guiLibrary = "Qt$($qtCase.Major)Gui$($qtCase.Suffix).dll" + $networkLibrary = "Qt$($qtCase.Major)Network$($qtCase.Suffix).dll" + $printSupportLibrary = "Qt$($qtCase.Major)PrintSupport$($qtCase.Suffix).dll" + $sqlLibrary = "Qt$($qtCase.Major)Sql$($qtCase.Suffix).dll" + $widgetsLibrary = "Qt$($qtCase.Major)Widgets$($qtCase.Suffix).dll" + $imageFormatPlugin = "qjpeg$($qtCase.Suffix).dll" + $platformPlugin = "qwindows$($qtCase.Suffix).dll" + $otherSuffix = if ($qtCase.Suffix) { "" } else { "d" } + $otherImageFormatPlugin = "qjpeg$otherSuffix.dll" + $otherPlatformPlugin = "qwindows$otherSuffix.dll" + $copiedFilesLog = Join-Path $appDir "copied-files.log" + $pluginFiles = @( + "imageformats/$imageFormatPlugin", + "platforms/$platformPlugin", + "printsupport/qprint$($qtCase.Suffix).dll", + "sqldrivers/qsqlite$($qtCase.Suffix).dll", + "styles/qstyle$($qtCase.Suffix).dll" + ) + if ($qtCase.Major -eq 5) + { + $pluginFiles += "bearer/qbearer$($qtCase.Suffix).dll" + } + else + { + $pluginFiles += @( + "generic/qgeneric$($qtCase.Suffix).dll", + "networkinformation/qnetworkinformation$($qtCase.Suffix).dll", + "platformthemes/qplatformtheme$($qtCase.Suffix).dll", + "tls/qtls$($qtCase.Suffix).dll" + ) + } + + Require-FileNotExists (Join-Path $appDir $coreLibrary) + Require-FileNotExists (Join-Path $appDir $guiLibrary) + Require-FileNotExists (Join-Path $appDir $networkLibrary) + Require-FileNotExists (Join-Path $appDir $printSupportLibrary) + Require-FileNotExists (Join-Path $appDir $sqlLibrary) + Require-FileNotExists (Join-Path $appDir $widgetsLibrary) + Require-FileNotExists (Join-Path $appDir "qt.conf") + foreach ($pluginFile in $pluginFiles) + { + Require-FileNotExists (Join-Path $appDir "plugins/$pluginFile") + } + + Run-Vcpkg z-applocal ` + "--target-binary=$(Join-Path $appDir 'main.exe')" ` + "--installed-bin-dir=$installedBinDir" ` + "--copied-files-log=$copiedFilesLog" + Throw-IfFailed + Require-FileExists (Join-Path $appDir $coreLibrary) + Require-FileExists (Join-Path $appDir $guiLibrary) + Require-FileExists (Join-Path $appDir $networkLibrary) + Require-FileExists (Join-Path $appDir $printSupportLibrary) + Require-FileExists (Join-Path $appDir $sqlLibrary) + Require-FileExists (Join-Path $appDir $widgetsLibrary) + Require-FileExists (Join-Path $appDir "qt.conf") + foreach ($pluginFile in $pluginFiles) + { + Require-FileExists (Join-Path $appDir "plugins/$pluginFile") + } + + Require-FileNotExists (Join-Path $appDir "plugins/imageformats/$otherImageFormatPlugin") + Require-FileNotExists (Join-Path $appDir "plugins/platforms/$otherPlatformPlugin") + if ($qtCase.Major -eq 5) + { + Require-FileNotExists (Join-Path $appDir "plugins/generic/qgeneric$($qtCase.Suffix).dll") + Require-FileNotExists (Join-Path $appDir "plugins/platformthemes/qplatformtheme$($qtCase.Suffix).dll") + Require-FileNotExists (Join-Path $appDir "plugins/tls/qtls$($qtCase.Suffix).dll") + Require-FileExists (Join-Path $appDir "libssl-unused.dll") + } + else + { + Require-FileNotExists (Join-Path $appDir "plugins/bearer/qbearer$($qtCase.Suffix).dll") + Require-FileNotExists (Join-Path $appDir "libssl-unused.dll") + } + + if ((Get-Content -Raw -LiteralPath (Join-Path $appDir "qt.conf")) -ne "[Paths]`n") + { + throw "z-applocal generated an unexpected $($qtCase.Name) qt.conf" + } + + $copiedFiles = Get-Content -LiteralPath $copiedFilesLog + $expectedPluginSource = Join-Path (Join-Path $qtDir $qtCase.PluginsDir) "platforms/$platformPlugin" + $unexpectedPluginSource = Join-Path (Join-Path $qtDir $qtCase.OtherPluginsDir) "platforms/$platformPlugin" + if ($copiedFiles -notcontains $expectedPluginSource) + { + throw "z-applocal didn't deploy the $($qtCase.Name) platform plugin from $expectedPluginSource" + } + + if ($copiedFiles -contains $unexpectedPluginSource) + { + throw "z-applocal deployed the $($qtCase.Name) platform plugin from $unexpectedPluginSource" + } + } + # Tests deploy azure kinect sensor SDK plugins $pluginsDir = "$TestingRoot/applocal/plugins" Run-Vcpkg env "$pluginsDir/build.bat" diff --git a/src/vcpkg/commands.z-applocal.cpp b/src/vcpkg/commands.z-applocal.cpp index d1a6ab7e9d..445710480a 100644 --- a/src/vcpkg/commands.z-applocal.cpp +++ b/src/vcpkg/commands.z-applocal.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -95,6 +96,7 @@ namespace , m_deployment_dir(deployment_dir) , m_installed_bin_dir(installed_bin_dir) , m_installed(installed) + , m_qt6_modules_dir((is_debug ? Path(installed.parent_path()) : Path(installed)) / "share/Qt6/modules") , m_is_debug(is_debug) , m_verbose(verbose) #if defined(_WIN32) @@ -106,7 +108,8 @@ namespace m_fs.exists(m_installed / "tools/azure-kinect-sensor-sdk/k4adeploy.ps1", VCPKG_LINE_INFO)) , m_magnum_installed(m_fs.exists(m_installed / "bin/magnum/magnumdeploy.ps1", VCPKG_LINE_INFO) || m_fs.exists(m_installed / "bin/magnum-d/magnumdeploy.ps1", VCPKG_LINE_INFO)) - , m_qt_installed(m_fs.exists(m_installed / "plugins/qtdeploy.ps1", VCPKG_LINE_INFO)) + , m_qt5_installed(m_fs.exists(m_installed / "plugins/qtdeploy.ps1", VCPKG_LINE_INFO)) + , m_qt6_installed(m_fs.exists(m_installed / "Qt6/plugins", VCPKG_LINE_INFO)) #if !defined(_WIN32) , m_temp_dir(m_fs.create_or_get_temp_directory(VCPKG_LINE_INFO)) #endif // ^^^ !_WIN32 @@ -171,9 +174,13 @@ namespace imported_name); } - if (m_qt_installed) + if (m_qt5_installed && Strings::case_insensitive_ascii_starts_with(imported_name, "Qt5")) { - deployQt(m_deployment_dir, m_installed / "plugins", imported_name); + deployQt5(m_deployment_dir, m_installed_bin_dir, m_installed / "plugins", imported_name); + } + else if (m_qt6_installed && Strings::case_insensitive_ascii_starts_with(imported_name, "Qt6")) + { + deployQt6(m_deployment_dir, m_installed / "Qt6/plugins", imported_name); } resolve(m_deployment_dir / imported_name); @@ -336,10 +343,11 @@ namespace } } - void deployQt(const Path& target_binary_dir, const Path& qt_plugins_dir, StringView target_binary_name) + void deployQt5(const Path& target_binary_dir, + const Path& bin_dir, + const Path& qt_plugins_dir, + StringView target_binary_name) { - Path bin_dir = Path(qt_plugins_dir.parent_path()) / "bin"; - if (Strings::case_insensitive_ascii_equals(target_binary_name, "Qt5Cored.dll") || Strings::case_insensitive_ascii_equals(target_binary_name, "Qt5Core.dll")) { @@ -524,6 +532,104 @@ namespace } } + void deployQt6(const Path& target_binary_dir, const Path& qt_plugins_dir, StringView target_binary_name) + { + static constexpr StringLiteral qt6_prefix = "Qt6"; + static constexpr StringLiteral dll_suffix = ".dll"; + + if (!Strings::case_insensitive_ascii_starts_with(target_binary_name, qt6_prefix) || + !Strings::case_insensitive_ascii_ends_with(target_binary_name, dll_suffix)) + { + return; + } + + if (Strings::case_insensitive_ascii_equals(target_binary_name, "Qt6Cored.dll") || + Strings::case_insensitive_ascii_equals(target_binary_name, "Qt6Core.dll")) + { + std::error_code ec; + if (!m_fs.exists(target_binary_dir / "qt.conf", ec)) + { + m_fs.write_contents(target_binary_dir / "qt.conf", "[Paths]\n", ec); + } + } + else if (Strings::case_insensitive_ascii_equals(target_binary_name, "Qt6Guid.dll") || + Strings::case_insensitive_ascii_equals(target_binary_name, "Qt6Gui.dll")) + { + Debug::println(" Deploying platforms"); + + std::error_code ec; + Path new_dir = target_binary_dir / "plugins" / "platforms"; + m_fs.create_directories(new_dir, ec); + + std::vector children = m_fs.get_files_non_recursive(qt_plugins_dir / "platforms", ec); + for (auto&& c : children) + { + auto c_filename = c.filename(); + if (Strings::case_insensitive_ascii_starts_with(c_filename, "qwindows") && + Strings::case_insensitive_ascii_ends_with(c_filename, ".dll")) + { + deploy_binary(new_dir, qt_plugins_dir / "platforms", c_filename); + } + } + } + + auto module_name = target_binary_name.substr( + qt6_prefix.size(), target_binary_name.size() - qt6_prefix.size() - dll_suffix.size()); + if (m_is_debug && Strings::case_insensitive_ascii_ends_with(module_name, "d")) + { + module_name = module_name.substr(0, module_name.size() - 1); + } + + const auto module_metadata_path = m_qt6_modules_dir / Strings::concat(module_name, ".json"); + std::error_code ec; + const auto module_metadata_contents = m_fs.read_contents(module_metadata_path, ec); + if (ec) + { + Debug::println(" Skipping Qt 6 plugin metadata ", module_metadata_path, ": ", ec.message()); + return; + } + + auto maybe_module_metadata = Json::parse_object(module_metadata_contents, module_metadata_path); + const auto module_metadata = maybe_module_metadata.get(); + if (!module_metadata) + { + Debug::println(" Skipping invalid Qt 6 plugin metadata ", + module_metadata_path, + ": ", + maybe_module_metadata.error()); + return; + } + + const auto plugin_types_value = module_metadata->get("plugin_types"); + if (!plugin_types_value) + { + return; + } + + const auto plugin_types = plugin_types_value->maybe_array(); + if (!plugin_types) + { + Debug::println(" Skipping non-array plugin_types in ", module_metadata_path); + return; + } + + for (const auto& plugin_type_value : *plugin_types) + { + const auto plugin_type = plugin_type_value.maybe_string(); + if (!plugin_type) + { + Debug::println(" Skipping non-string plugin type in ", module_metadata_path); + continue; + } + + // The Gui-specific logic above deploys only qwindows[d].dll. + if (*plugin_type != "platforms") + { + deployPluginsQt(*plugin_type, target_binary_dir, qt_plugins_dir); + } + } + } + bool deploy_binary(const Path& target_binary_dir, const Path& installed_dir, StringView target_binary_name) { auto source = installed_dir / target_binary_name; @@ -591,6 +697,7 @@ namespace Path m_deployment_dir; Path m_installed_bin_dir; Path m_installed; + Path m_qt6_modules_dir; bool m_is_debug; bool m_verbose; #if defined(_WIN32) @@ -601,7 +708,8 @@ namespace bool m_openni2_installed; bool m_azurekinectsdk_installed; bool m_magnum_installed; - bool m_qt_installed; + bool m_qt5_installed; + bool m_qt6_installed; #if !defined(_WIN32) Path m_temp_dir; #endif // ^^^ !_WIN32