Preparing app for Microsoft Store (Qt 6 + CMake)
-
In the past I've published my Qt app to the Microsoft Store, using Qt 5 + qmake.
I'm trying to do the same for Qt 6 + CMake.
Are there any tutorials or walkthroughs you can point me to?
In particular, at the moment I'm trying to work out the following:
- After doing all my development and local testing in Qt Creator, previously I would switch over to Visual Studio to do the final build and upload to the Microsoft Store. Is this still the recommended way? If so, I used to have a build step to
make generate_vs_project
that I added toQMAKE_EXTRA_TARGETS
. How do I make my project available in VS now that I'm using CMake? - Is
windeployqt
relevant for my use case? Previously, using qmake, if I was creating a standalone Windows app I'd usewindeployqt
but not if I was building an app for the Microsoft Store (UWP/WinRT at the time). - How do I get the assets (icons, splash screen) into the build?
- How do I make my
AppxManifest.xml
available to the build/upload/publish process? - Within
AppxManifest.xml
I used to have<Dependencies>...<PackageDependency Name="Microsoft.VCLibs.140.00"... />...
. Is this still necessary? My searches suggest it isn't but I'm not sure.
Thanks for your help.
- After doing all my development and local testing in Qt Creator, previously I would switch over to Visual Studio to do the final build and upload to the Microsoft Store. Is this still the recommended way? If so, I used to have a build step to
-
For anyone coming across this, I have successfully navigated the transition from Qt 5 + qmake (UWP app delivered via Microsoft Store) to Qt 6 + CMake (Win32 app delivered via Microsoft Store).
Here is my general cookbook for transitioning from qmake to CMake: https://github.com/paulmasri/qt6_cmake_cookbook
You need to note that Qt 6 no longer supports UWP, so you have to do things a little differently. Use the MSVC2019-64bit kit and see this important post.
The whole build process can be done within Qt/CMake but requires some additional steps. These can be configured in CMake and the post-build install step can also be configured in CMake to run as a post-build step. The following assumes Qt 6.5 and will not work in earlier versions.
# EDIT THIS! You'll need to set your own `APP_TARGET` (e.g. "MyAppTarget") # Create a directory `install` within the build directory. # Install everything there and use it to create the uploadable package. set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install") message(STATUS "CMAKE_INSTALL_PREFIX set (for the duration of this script) to ${CMAKE_INSTALL_PREFIX}") # Do the equivalent of windeployqt, with QML extras. qt_generate_deploy_qml_app_script( TARGET ${APP_TARGET} OUTPUT_SCRIPT deploy_script ) install(SCRIPT ${deploy_script}) # Ensure the VC redistributables are included. include(InstallRequiredSystemLibraries) # Install your AppxManifest. install( FILES "${CMAKE_CURRENT_BINARY_DIR}/AppxManifest.xml" DESTINATION "${CMAKE_INSTALL_PREFIX}" ) # Install Microsoft Store assets from source "assets" to store "Assets" install( DIRECTORY assets/ DESTINATION "${CMAKE_INSTALL_PREFIX}/Assets" FILES_MATCHING PATTERN "*" ) # Package, bundle and prepare for upload via Microsoft Partner Center. # The following assumes a single 64-bit package, within a bundle, with debug info. # Packages will be built in `packages` directory within build directory. # Final bundle and `.appxupload` will be built in the build directory root. # NOTES: # 1. If you have a single package and don't need to add it to a bundle, # skip the bundle step and pass just the package to the `create_appxupload_command`. # 2. Assumes you are building ReleaseWithDebugInformation, which will generate a .pdb # used in the following. If you don't need this, skip `compress_pdb_command` and # `rename_appxsym_command` and omit the appxsym file from `create_appxupload_command`. set(APPX_BUILD_VERSION_HYPHENATED "${PROJECT_VERSION_MAJOR}_${PROJECT_VERSION_MINOR}_${PROJECT_VERSION_PATCH}_0") set(APPX_PACKAGES_PREFIX "packages") set(APPX_PACKAGE_X64_FILE "${APP_TARGET}-${APPX_BUILD_VERSION_HYPHENATED}-x64.appx") set(APPX_BUNDLE_FILE "${APP_TARGET}-${APPX_BUILD_VERSION_HYPHENATED}.appxbundle") set(APPX_PDB_FILE "${APP_TARGET}.pdb") set(APPX_SYM_FILE "${APP_TARGET}-${APPX_BUILD_VERSION_HYPHENATED}.appxsym") set(APPX_UPLOAD_FILE "${APP_TARGET}-${APPX_BUILD_VERSION_HYPHENATED}.appxupload") message(STATUS "-- Generating install code and adding it to install") set(install_code) string(CONCAT install_code "${install_code}" "message(\"Removing previous packages and bundle (if present)\")\n" "file(REMOVE_RECURSE \"${CMAKE_BINARY_DIR}/${APPX_PACKAGES_PREFIX}\")\n" "file(REMOVE \"${CMAKE_BINARY_DIR}/${APPX_BUNDLE_FILE}\")\n" "file(REMOVE \"${CMAKE_BINARY_DIR}/${APPX_SYM_FILE}\")\n" "file(REMOVE \"${CMAKE_BINARY_DIR}/${APPX_UPLOAD_FILE}\")\n" ) # Package and bundle set(package_x64_command "MakeAppx.exe pack /d \"${CMAKE_INSTALL_PREFIX}\" /p \"${CMAKE_BINARY_DIR}/${APPX_PACKAGES_PREFIX}/${APPX_PACKAGE_X64_FILE}\"") set(package_x64_execute_process "execute_process(COMMAND ${package_x64_command})") set(bundle_command "MakeAppx.exe bundle /d \"${CMAKE_BINARY_DIR}/${APPX_PACKAGES_PREFIX}\" /p \"${CMAKE_BINARY_DIR}/${APPX_BUNDLE_FILE}\"") set(bundle_execute_process "execute_process(COMMAND ${bundle_command})") string(CONCAT install_code "${install_code}" "message(\"Packaging 64-bit app\")\n" "${package_x64_execute_process}\n" "message(\"Bundling all packages\")\n" "${bundle_execute_process}\n" ) # Convert .pdb to .appxsym. Add bundle and .appxsym to .appxupload. # You will drag'n'drop the .appxupload into the Microsoft Partner Center app package page. set(compress_pdb_command "powershell.exe -Command \"Compress-Archive -Path '${CMAKE_BINARY_DIR}/${APPX_PDB_FILE}' -DestinationPath '${CMAKE_BINARY_DIR}/${APPX_SYM_FILE}.zip' -Force\"") set(compress_pdb_execute_process "execute_process(COMMAND ${compress_pdb_command})") set(rename_appxsym_command "powershell.exe -Command \"Rename-Item -Path '${CMAKE_BINARY_DIR}/${APPX_SYM_FILE}.zip' -NewName '${APPX_SYM_FILE}'\"") set(rename_appxsym_execute_process "execute_process(COMMAND ${rename_appxsym_command})") set(create_appxupload_command "powershell.exe -Command \"Compress-Archive -Path '${CMAKE_BINARY_DIR}/${APPX_BUNDLE_FILE}', '${CMAKE_BINARY_DIR}/${APPX_SYM_FILE}' -DestinationPath '${CMAKE_BINARY_DIR}/${APPX_UPLOAD_FILE}.zip' -Force\"") set(create_appxupload_execute_process "execute_process(COMMAND ${create_appxupload_command})") set(rename_appxupload_command "powershell.exe -Command \"Rename-Item -Path '${CMAKE_BINARY_DIR}/${APPX_UPLOAD_FILE}.zip' -NewName '${APPX_UPLOAD_FILE}'\"") set(rename_appxupload_execute_process "execute_process(COMMAND ${rename_appxupload_command})") string(CONCAT install_code "${install_code}" "message(\"Converting .pdb to .appxsym\")\n" "${compress_pdb_execute_process}\n" "${rename_appxsym_execute_process}\n" "message(\"Creating .appxupload\")\n" "${create_appxupload_execute_process}\n" "${rename_appxupload_execute_process}\n" "message(\"Done.\")\n" ) # Install these scripts. install(CODE "${install_code}")
-
I think I've got the answer to #3 & #4 (although I cannot test this until I'm able to run the appropriate commands in Visual Studio, but I'm still stuck on the others.
Any help from anyone who has used Qt + CMake and published to the Microsoft Store would be very welcome.
What I've done for #3 & #4:
In CMake, I now have the following. Note thatAppxManifest.xml
is in the same folder as the CMake script and all the icons & splash screen assets are in subfolderassets
.set_property(SOURCE AppxManifest.xml PROPERTY VS_DEPLOYMENT_CONTENT 1) file(GLOB ASSET_FILES "${CMAKE_CURRENT_SOURCE_DIR}/assets/*.png") foreach(asset ${ASSET_FILES}) set_property(SOURCE "${asset}" PROPERTY VS_DEPLOYMENT_CONTENT 1) set_property(SOURCE "${asset}" PROPERTY VS_DEPLOYMENT_LOCATION "Assets") endforeach()
-
For anyone coming across this, I have successfully navigated the transition from Qt 5 + qmake (UWP app delivered via Microsoft Store) to Qt 6 + CMake (Win32 app delivered via Microsoft Store).
Here is my general cookbook for transitioning from qmake to CMake: https://github.com/paulmasri/qt6_cmake_cookbook
You need to note that Qt 6 no longer supports UWP, so you have to do things a little differently. Use the MSVC2019-64bit kit and see this important post.
The whole build process can be done within Qt/CMake but requires some additional steps. These can be configured in CMake and the post-build install step can also be configured in CMake to run as a post-build step. The following assumes Qt 6.5 and will not work in earlier versions.
# EDIT THIS! You'll need to set your own `APP_TARGET` (e.g. "MyAppTarget") # Create a directory `install` within the build directory. # Install everything there and use it to create the uploadable package. set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install") message(STATUS "CMAKE_INSTALL_PREFIX set (for the duration of this script) to ${CMAKE_INSTALL_PREFIX}") # Do the equivalent of windeployqt, with QML extras. qt_generate_deploy_qml_app_script( TARGET ${APP_TARGET} OUTPUT_SCRIPT deploy_script ) install(SCRIPT ${deploy_script}) # Ensure the VC redistributables are included. include(InstallRequiredSystemLibraries) # Install your AppxManifest. install( FILES "${CMAKE_CURRENT_BINARY_DIR}/AppxManifest.xml" DESTINATION "${CMAKE_INSTALL_PREFIX}" ) # Install Microsoft Store assets from source "assets" to store "Assets" install( DIRECTORY assets/ DESTINATION "${CMAKE_INSTALL_PREFIX}/Assets" FILES_MATCHING PATTERN "*" ) # Package, bundle and prepare for upload via Microsoft Partner Center. # The following assumes a single 64-bit package, within a bundle, with debug info. # Packages will be built in `packages` directory within build directory. # Final bundle and `.appxupload` will be built in the build directory root. # NOTES: # 1. If you have a single package and don't need to add it to a bundle, # skip the bundle step and pass just the package to the `create_appxupload_command`. # 2. Assumes you are building ReleaseWithDebugInformation, which will generate a .pdb # used in the following. If you don't need this, skip `compress_pdb_command` and # `rename_appxsym_command` and omit the appxsym file from `create_appxupload_command`. set(APPX_BUILD_VERSION_HYPHENATED "${PROJECT_VERSION_MAJOR}_${PROJECT_VERSION_MINOR}_${PROJECT_VERSION_PATCH}_0") set(APPX_PACKAGES_PREFIX "packages") set(APPX_PACKAGE_X64_FILE "${APP_TARGET}-${APPX_BUILD_VERSION_HYPHENATED}-x64.appx") set(APPX_BUNDLE_FILE "${APP_TARGET}-${APPX_BUILD_VERSION_HYPHENATED}.appxbundle") set(APPX_PDB_FILE "${APP_TARGET}.pdb") set(APPX_SYM_FILE "${APP_TARGET}-${APPX_BUILD_VERSION_HYPHENATED}.appxsym") set(APPX_UPLOAD_FILE "${APP_TARGET}-${APPX_BUILD_VERSION_HYPHENATED}.appxupload") message(STATUS "-- Generating install code and adding it to install") set(install_code) string(CONCAT install_code "${install_code}" "message(\"Removing previous packages and bundle (if present)\")\n" "file(REMOVE_RECURSE \"${CMAKE_BINARY_DIR}/${APPX_PACKAGES_PREFIX}\")\n" "file(REMOVE \"${CMAKE_BINARY_DIR}/${APPX_BUNDLE_FILE}\")\n" "file(REMOVE \"${CMAKE_BINARY_DIR}/${APPX_SYM_FILE}\")\n" "file(REMOVE \"${CMAKE_BINARY_DIR}/${APPX_UPLOAD_FILE}\")\n" ) # Package and bundle set(package_x64_command "MakeAppx.exe pack /d \"${CMAKE_INSTALL_PREFIX}\" /p \"${CMAKE_BINARY_DIR}/${APPX_PACKAGES_PREFIX}/${APPX_PACKAGE_X64_FILE}\"") set(package_x64_execute_process "execute_process(COMMAND ${package_x64_command})") set(bundle_command "MakeAppx.exe bundle /d \"${CMAKE_BINARY_DIR}/${APPX_PACKAGES_PREFIX}\" /p \"${CMAKE_BINARY_DIR}/${APPX_BUNDLE_FILE}\"") set(bundle_execute_process "execute_process(COMMAND ${bundle_command})") string(CONCAT install_code "${install_code}" "message(\"Packaging 64-bit app\")\n" "${package_x64_execute_process}\n" "message(\"Bundling all packages\")\n" "${bundle_execute_process}\n" ) # Convert .pdb to .appxsym. Add bundle and .appxsym to .appxupload. # You will drag'n'drop the .appxupload into the Microsoft Partner Center app package page. set(compress_pdb_command "powershell.exe -Command \"Compress-Archive -Path '${CMAKE_BINARY_DIR}/${APPX_PDB_FILE}' -DestinationPath '${CMAKE_BINARY_DIR}/${APPX_SYM_FILE}.zip' -Force\"") set(compress_pdb_execute_process "execute_process(COMMAND ${compress_pdb_command})") set(rename_appxsym_command "powershell.exe -Command \"Rename-Item -Path '${CMAKE_BINARY_DIR}/${APPX_SYM_FILE}.zip' -NewName '${APPX_SYM_FILE}'\"") set(rename_appxsym_execute_process "execute_process(COMMAND ${rename_appxsym_command})") set(create_appxupload_command "powershell.exe -Command \"Compress-Archive -Path '${CMAKE_BINARY_DIR}/${APPX_BUNDLE_FILE}', '${CMAKE_BINARY_DIR}/${APPX_SYM_FILE}' -DestinationPath '${CMAKE_BINARY_DIR}/${APPX_UPLOAD_FILE}.zip' -Force\"") set(create_appxupload_execute_process "execute_process(COMMAND ${create_appxupload_command})") set(rename_appxupload_command "powershell.exe -Command \"Rename-Item -Path '${CMAKE_BINARY_DIR}/${APPX_UPLOAD_FILE}.zip' -NewName '${APPX_UPLOAD_FILE}'\"") set(rename_appxupload_execute_process "execute_process(COMMAND ${rename_appxupload_command})") string(CONCAT install_code "${install_code}" "message(\"Converting .pdb to .appxsym\")\n" "${compress_pdb_execute_process}\n" "${rename_appxsym_execute_process}\n" "message(\"Creating .appxupload\")\n" "${create_appxupload_execute_process}\n" "${rename_appxupload_execute_process}\n" "message(\"Done.\")\n" ) # Install these scripts. install(CODE "${install_code}")
-