Need support for dynamic 'deployment content' for UWP/WinRT projects
I'm working with a large Qt based project using CMake and Visual Studio 2017 (among other target platforms). We're trying to make our code work on the UWP/WinRT platform. Both Qt and CMake have functionality that allows us to look at a built artifact and determine a set of dependency files we need to distribute with it (windeployqt for Qt and the BundleUtilities for CMake). Unfortunately I can't find an easy way to use these in a CMake generated Visual Studio project.
The problem is that the generated VS project builds the executable in the standard location, but then when you try to run a UWP app, it deploys the executable to a new directory. While we've been successful in the past using post-build commands to populate the build directory with all the required DLLs, those don't get copied in the deployment step so they're missing when you try to run as a UWP app and the app fails to launch.
If I create a Qt project file for UWP and use it to export a Visual Studio project, it resolves it with these targets in the generated project:
<Target Name="WinDeployQt_Debug|x64" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Inputs="$(OutDir)\$(TargetName).exe" Outputs="$(TargetName).windeployqt.$(Platform).$(Configuration)">
<Message Text="C:\qt\5.9.1\winrt_x64_msvc2017\bin\windeployqt.exe -qmldir C:\Users\bdavi\git\hifi\tests\uwp -list relative -dir "$(MSBuildProjectDirectory)" "$(OutDir)\$(TargetName).exe" > "$(TargetName).windeployqt.$(Platform).$(Configuration)"" />
<Exec Command="C:\qt\5.9.1\winrt_x64_msvc2017\bin\windeployqt.exe -qmldir C:\Users\bdavi\git\hifi\tests\uwp -list relative -dir "$(MSBuildProjectDirectory)" "$(OutDir)\$(TargetName).exe" > "$(TargetName).windeployqt.$(Platform).$(Configuration)"" />
</Target>
<Target Name="PopulateWinDeployQtItems_Debug|x64" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" AfterTargets="Link" DependsOnTargets="WinDeployQt_Debug|x64">
<ReadLinesFromFile File="$(TargetName).windeployqt.$(Platform).$(Configuration)">
<Output TaskParameter="Lines" ItemName="DeploymentItems" />
</ReadLinesFromFile>
<ItemGroup>
<None Include="@(DeploymentItems)">
<DeploymentContent>true</DeploymentContent>
</None>
</ItemGroup>
</Target>
The first target uses windeployqt.exe to both copy a bunch of files to the project directory AND write a file in the project directory containing the names of all the copied files. I can replicate this functionality with add_custom_command
. The second part is more interesting. It reads the contents of the file and says that the list of files contained therein are to be considered deployment items, so they will be copied over along with the exe.
If I add this to my CMake file
add_custom_command(
TARGET ${TARGET_NAME}
POST_BUILD
COMMAND CMD /C "${WINDEPLOYQT_COMMAND} ${EXTRA_DEPLOY_OPTIONS} --dir . --list relative \"$<TARGET_FILE:${TARGET_NAME}>\" \> ${TARGET_NAME}.windeployqt.$<CONFIG>"
)
and then after cmake generation I manually paste that second target into my generated Visual Studio project file, then I'm able to run my UWP build.
However, what I'd like is some CMake specific mechanism for doing the same thing... basically specify either a file or a command where the contents of the file or the output of the command will be treated as deployment items by visual studio. Most likely it will need to be done in a context where it can accept generator expressions as well to differentiate the different requirements of debug and release builds.
It feels like being able to manipulate the set of files that are treated as deployable content for a given project is a critical feature of being able to build UWP projects. I get that VS_DEPLOYMENT_CONTENT
provides much of this functionality, but as far as I can tell that only works if you're able / willing to determine the exact set of dependencies at CMake generation time. If you need to determine the content as a post-build step, there doesn't seem to be a way to do it right now using CMake.