<?xml version="1.0" encoding="utf-8"?>
<!--
 Copyright (C) 2025 The Qt Company Ltd.
 SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-->

<!--
///////////////////////////////////////////////////////////////////////////////////////////////////
// Deployment of Qt dependencies
// -->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Setup property page
  // -->
  <ItemGroup>
    <PropertyPageSchema
      Include="$(MSBuildThisFileDirectory)qtdeploy.xml" />
  </ItemGroup>

  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Default deploy log location
  // -->
  <PropertyGroup>
    <QtDeployLog Condition="'$(QtDeployLog)' == ''">$(IntDir)windeployqt.log</QtDeployLog>
  </PropertyGroup>

  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Schedule QtDeploy target to run after Link
  // -->
  <PropertyGroup Condition="'$(QtDeploy)' == 'true' AND '$(ApplicationType)' != 'Linux'">
    <BuildLinkTargets>$(BuildLinkTargets);QtDeploy</BuildLinkTargets>
  </PropertyGroup>

  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Fallback to default property values
  // -->
  <PropertyGroup Condition="'$(QtDeployFiles)' == ''">
    <QtDeployFiles>$(TargetPath)</QtDeployFiles>
  </PropertyGroup>
  <PropertyGroup Condition="'$(QtDeployEnv)' == ''">
    <QtDeployEnv>VCINSTALLDIR=$(VCInstallDir)</QtDeployEnv>
  </PropertyGroup>
  <PropertyGroup Condition="'$(QtDeployAddToolsDirToPath)' == 'true'">
    <QtDeployEnv
      >$(QtDeployEnv);PATH=$([System.String]::Copy('$(QtToolsPath)%3B$(Path)'))</QtDeployEnv>
  </PropertyGroup>
  <PropertyGroup Condition="'$(QtDeployDir)' == ''">
    <QtDeployDir Condition="'$(QtDeployToProjectDir)' == 'true'">$(ProjectDir)</QtDeployDir>
    <QtDeployDir Condition="'$(QtDeployToProjectDir)' != 'true'">$(OutDir)</QtDeployDir>
  </PropertyGroup>

  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Deploy Qt files
  // -->
  <Target Name="QtDeploy"
    AfterTargets="Link"
    Inputs="$(TargetPath)" Outputs="$(QtDeployLog)"
    Condition="'$(QtDeploy)' == 'true' AND '$(ApplicationType)' != 'Linux'">

    <ItemGroup>
      <QtDeploy Include="$(TargetPath)">
        <QtDeploy>$(QtDeploy)</QtDeploy>
        <QtDeployFiles>$(QtDeployFiles)</QtDeployFiles>
        <QtDeployEnv>$(QtDeployEnv)</QtDeployEnv>
        <QtDeployDir>$(QtDeployDir)</QtDeployDir>
        <QtDeployLibDir>$(QtDeployLibDir)</QtDeployLibDir>
        <QtDeployPluginDir>$(QtDeployPluginDir)</QtDeployPluginDir>
        <QtDeployDebugRelease>$(QtDeployDebugRelease)</QtDeployDebugRelease>
        <QtDeployPdb>$(QtDeployPdb)</QtDeployPdb>
        <QtDeployForce>$(QtDeployForce)</QtDeployForce>
        <QtDeployNoPatchQt>$(QtDeployNoPatchQt)</QtDeployNoPatchQt>
        <QtDeployNoPlugins>$(QtDeployNoPlugins)</QtDeployNoPlugins>
        <QtDeployNoLibraries>$(QtDeployNoLibraries)</QtDeployNoLibraries>
        <QtDeployQmlDir>$(QtDeployQmlDir)</QtDeployQmlDir>
        <QtDeployQmlImport>$(QtDeployQmlImport)</QtDeployQmlImport>
        <QtDeployNoQuickImport>$(QtDeployNoQuickImport)</QtDeployNoQuickImport>
        <QtDeployNoTranslations>$(QtDeployNoTranslations)</QtDeployNoTranslations>
        <QtDeployNoSystemD3dCompiler>$(QtDeployNoSystemD3dCompiler)</QtDeployNoSystemD3dCompiler>
        <QtDeployNoVirtualKeyboard>$(QtDeployNoVirtualKeyboard)</QtDeployNoVirtualKeyboard>
        <QtDeployCompilerRuntime>$(QtDeployCompilerRuntime)</QtDeployCompilerRuntime>
        <QtDeployWebkit2>$(QtDeployWebkit2)</QtDeployWebkit2>
        <QtDeployAngle>$(QtDeployAngle)</QtDeployAngle>
        <QtDeployNoOpenglSw>$(QtDeployNoOpenglSw)</QtDeployNoOpenglSw>
        <QtDeployIncludeModules>$(QtDeployIncludeModules)</QtDeployIncludeModules>
        <QtDeployExcludeModules>$(QtDeployExcludeModules)</QtDeployExcludeModules>
        <QtDeployVerbose>$(QtDeployVerbose)</QtDeployVerbose>
        <QtDeployVsContent>$(QtDeployVsContent)</QtDeployVsContent>
      </QtDeploy>
    </ItemGroup>

    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Convert string lists in source item properties to lists of items
    // -->
    <Flatten Items="@(QtDeploy)"
      Metadata="QtDeployFiles;
                QtDeployDir;
                QtDeployLibDir;
                QtDeployPluginDir;
                QtDeployDebugRelease;
                QtDeployPdb;
                QtDeployForce;
                QtDeployNoPatchQt;
                QtDeployNoPlugins;
                QtDeployNoLibraries;
                QtDeployQmlDir;
                QtDeployQmlImport;
                QtDeployNoQuickImport;
                QtDeployNoTranslations;
                QtDeployNoSystemD3dCompiler;
                QtDeployNoVirtualKeyboard;
                QtDeployCompilerRuntime;
                QtDeployWebkit2;
                QtDeployAngle;
                QtDeployNoOpenglSw;
                QtDeployIncludeModules;
                QtDeployExcludeModules;
                QtDeployVerbose">
      <Output
        TaskParameter="Result" ItemName="Options" />
    </Flatten>

    <ItemGroup>
      <!--
      /////////////////////////////////////////////////////////////////////////////////////////////
      // Remove quotes from all paths
      // -->
      <Options>
        <Value Condition="( '%(Name)' == 'QtDeployFiles'
                         OR '%(Name)' == 'QtDeployDir'
                         OR '%(Name)' == 'QtDeployLibDir'
                         OR '%(Name)' == 'QtDeployPluginDir'
                         OR '%(Name)' == 'QtDeployQmlDir'
                         OR '%(Name)' == 'QtDeployQmlImport' )"
          >$([System.String]::Copy('%(Value)').Replace('&quot;', ''))</Value>
      </Options>
      <!--
        ///////////////////////////////////////////////////////////////////////////////////////////
        // Escape trailing back-slash in paths
        // -->
      <Options>
        <Value Condition="( '%(Name)' == 'QtDeployFiles'
                         OR '%(Name)' == 'QtDeployDir'
                         OR '%(Name)' == 'QtDeployLibDir'
                         OR '%(Name)' == 'QtDeployPluginDir'
                         OR '%(Name)' == 'QtDeployQmlDir'
                         OR '%(Name)' == 'QtDeployQmlImport' )
                        AND $([System.String]::Copy('%(Value)').Contains(' '))
                        AND $([System.String]::Copy('%(Value)').EndsWith('\'))"
          >%(Value)\</Value>
      </Options>
      <!--
        ///////////////////////////////////////////////////////////////////////////////////////////
        // Add quotes to paths containing spaces
        // -->
      <Options>
        <Value Condition="( '%(Name)' == 'QtDeployFiles'
                         OR '%(Name)' == 'QtDeployDir'
                         OR '%(Name)' == 'QtDeployLibDir'
                         OR '%(Name)' == 'QtDeployPluginDir'
                         OR '%(Name)' == 'QtDeployQmlDir'
                         OR '%(Name)' == 'QtDeployQmlImport' )
                        AND $([System.String]::Copy('%(Value)').Contains(' '))"
          >&quot;%(Value)&quot;</Value>
      </Options>
      <!--
      /////////////////////////////////////////////////////////////////////////////////////////////
      // Generate tool command line arguments
      // -->
      <Options>
        <!-- [files]                  Binaries or directory containing the binary. -->
        <PosArg Condition="'%(Name)' == 'QtDeployFiles'">%(Value)</PosArg>
      </Options>
      <Options>
        <!-- -dir <directory>         Use directory instead of binary directory. -->
        <Arg Condition="'%(Name)' == 'QtDeployDir'">--dir %(Value)</Arg>
      </Options>
      <Options>
        <!-- -libdir <path>           Copy libraries to path. -->
        <Arg Condition="'%(Name)' == 'QtDeployLibDir'">--libdir %(Value)</Arg>
      </Options>
      <Options>
        <!-- -plugindir <path>        Copy plugins to path. -->
        <Arg Condition="'%(Name)' == 'QtDeployPluginDir'">--plugindir %(Value)</Arg>
      </Options>
      <Options>
        <!-- -debug                   Assume debug binaries.
             -release                 Assume release binaries.-->
        <Arg Condition="'%(Name)' == 'QtDeployDebugRelease' AND '%(Value)' == 'debug'"
               >--debug</Arg>
        <Arg Condition="'%(Name)' == 'QtDeployDebugRelease' AND '%(Value)' == 'release'"
               >--release</Arg>
      </Options>
      <Options>
        <!-- -pdb                     Deploy .pdb files (MSVC). -->
        <Arg Condition="'%(Name)' == 'QtDeployPdb' AND '%(Value)' == 'true'"
               >--pdb</Arg>
      </Options>
      <Options>
        <!-- -force                   Force updating files. -->
        <Arg Condition="'%(Name)' == 'QtDeployForce' AND '%(Value)' == 'true'"
               >--force</Arg>
      </Options>
      <Options>
        <!-- -no-patchqt              Do not patch the Qt5Core library. -->
        <Arg Condition="'%(Name)' == 'QtDeployNoPatchQt' AND '%(Value)' == 'true'"
               >--no-patchqt</Arg>
      </Options>
      <Options>
        <!-- -no-plugins              Skip plugin deployment. -->
        <Arg Condition="'%(Name)' == 'QtDeployNoPlugins' AND '%(Value)' == 'true'"
               >--no-plugins</Arg>
      </Options>
      <Options>
        <!-- -no-libraries            Skip library deployment. -->
        <Arg Condition="'%(Name)' == 'QtDeployNoLibraries' AND '%(Value)' == 'true'"
               >--no-libraries</Arg>
      </Options>
      <Options>
        <!-- -qmldir <directory>      Scan for QML-imports starting from directory. -->
        <Arg Condition="'%(Name)' == 'QtDeployQmlDir'">--qmldir %(Value)</Arg>
      </Options>
      <Options>
        <!-- -qmlimport <directory>   Add the given path to the QML module search
                                      locations. -->
        <Arg Condition="'%(Name)' == 'QtDeployQmlImport'">--qmlimport %(Value)</Arg>
      </Options>
      <Options>
        <!-- -no-quick-import         Skip deployment of Qt Quick imports. -->
        <Arg Condition="'%(Name)' == 'QtDeployNoQuickImport' AND '%(Value)' == 'true'"
               >--no-quick-import</Arg>
      </Options>
      <Options>
        <!-- -no-translations         Skip deployment of translations. -->
        <Arg Condition="'%(Name)' == 'QtDeployNoTranslations' AND '%(Value)' == 'true'"
               >--no-translations</Arg>
      </Options>
      <Options>
        <!-- -no-system-d3d-compiler  Skip deployment of the system D3D compiler. -->
        <Arg Condition="'%(Name)' == 'QtDeployNoSystemD3dCompiler' AND '%(Value)' == 'true'"
               >--no-system-d3d-compiler</Arg>
      </Options>
      <Options>
        <!-- -no-virtualkeyboard      Disable deployment of the Virtual Keyboard. -->
        <Arg Condition="'%(Name)' == 'QtDeployNoVirtualKeyboard' AND '%(Value)' == 'true'"
               >--no-virtualkeyboard</Arg>
      </Options>
      <Options>
        <!-- -compiler-runtime        Deploy compiler runtime (Desktop only).
             -no-compiler-runtime     Do not deploy compiler runtime (Desktop only). -->
        <Arg Condition="'%(Name)' == 'QtDeployCompilerRuntime' AND '%(Value)' == 'deploy'"
               >--compiler-runtime</Arg>
        <Arg Condition="'%(Name)' == 'QtDeployCompilerRuntime' AND '%(Value)' == 'skip'"
               >--no-compiler-runtime</Arg>
      </Options>
      <Options>
        <!-- -webkit2                 Deployment of WebKit2 (web process).
             -no-webkit2              Skip deployment of WebKit2. -->
        <Arg Condition="'%(Name)' == 'QtDeployWebkit2' AND '%(Value)' == 'deploy'"
               >--webkit2</Arg>
        <Arg Condition="'%(Name)' == 'QtDeployWebkit2' AND '%(Value)' == 'skip'"
               >--no-webkit2</Arg>
      </Options>
      <Options>
        <!-- -angle                   Force deployment of ANGLE.
             -no-angle                Disable deployment of ANGLE. -->
        <Arg Condition="'%(Name)' == 'QtDeployAngle' AND '%(Value)' == 'deploy'"
               >--angle</Arg>
        <Arg Condition="'%(Name)' == 'QtDeployAngle' AND '%(Value)' == 'skip'"
               >--no-angle</Arg>
      </Options>
      <Options>
        <!-- -no-opengl-sw            Do not deploy the software rasterizer library. -->
        <Arg Condition="'%(Name)' == 'QtDeployNoOpenglSw' AND '%(Value)' == 'true'"
               >--no-opengl-sw</Arg>
      </Options>
      <Options>
        <!-- Qt libraries can be added by passing their name (-xml) ... -->
        <Arg Condition="'%(Name)' == 'QtDeployIncludeModules'">-%(Value)</Arg>
      </Options>
      <Options>
        <!-- ... or removed by passing the name prepended by -no- (-no-xml). -->
        <Arg Condition="'%(Name)' == 'QtDeployExcludeModules'">--no-%(Value)</Arg>
      </Options>
    </ItemGroup>
    <ItemGroup>
      <Args Include="%(Options.Arg)" Condition="'%(Options.Arg)' != ''"/>
      <PosArgs Include="%(Options.PosArg)" Condition="'%(Options.PosArg)' != ''"/>
    </ItemGroup>

    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Run windeployqt
    // -->
    <PropertyGroup>
      <Cmd><![CDATA["$(QtToolsPath)\windeployqt.exe"]]></Cmd>
      <Cmd>$(Cmd) --list target</Cmd>
      <Cmd>$(Cmd) @(Args->'%(Identity)',' ')</Cmd>
      <Cmd>$(Cmd) @(PosArgs->'%(Identity)',' ')</Cmd>
    </PropertyGroup>
    <Message Importance="high" Text="Qt Deploy: $(Cmd)" />
    <Exec Command="$(Cmd) > &quot;$(QtDeployLog)&quot;"
          EnvironmentVariables="$(QtDeployEnv)" />

    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Read deploy log into QtDeployed list
    // -->
    <ReadLinesFromFile File="$(QtDeployLog)">
      <Output TaskParameter="Lines" ItemName="QtDeployed" />
    </ReadLinesFromFile>
    <ItemGroup>
      <QtDeployed Remove="@(QtDeployed)" Condition="!Exists('%(Fullpath)')"/>
    </ItemGroup>

    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Mark deployed files as source content for VS deployment project
    // -->
    <ItemGroup>
      <None Include="@(QtDeployed)" Condition="'%(QtDeploy.QtDeployVsContent)' == 'true'">
        <DeploymentContent>true</DeploymentContent>
        <RootFolder>$(ProjectDir)</RootFolder>
      </None>
    </ItemGroup>

    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Deploy project output
    // -->
    <PropertyGroup>
      <CopyDestinationFolder>$(QtDeployDir)</CopyDestinationFolder>
    </PropertyGroup>
    <Message Condition="'$(QtDeployCopyFiles)' == 'true'" Importance="high"
      Text="Qt Deploy: Copying project output" />
    <Copy Condition="'$(QtDeployCopyFiles)' == 'true'"
      SourceFiles="$(TargetPath)" DestinationFolder="$(CopyDestinationFolder)" />
    <PropertyGroup Condition="'$(QtDeployCopyFiles)' == 'true'">
      <QtDeployLog
        >$(QtDeployLog);$(QtDeployDir)\$([System.IO.Path]::GetFileName($(TargetPath)))</QtDeployLog>
    </PropertyGroup>

    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Log output files; used by VS on clean and up-to-date check
    // -->
    <ItemGroup>
      <QtDeployLog Include="$(QtDeployLog)"/>
      <QtDeployed Include="$(QtDeployLog)"/>
    </ItemGroup>
    <WriteLinesToFile
      File="$(TLogLocation)windeployqt.read.1u.tlog"
      Lines="^$(ProjectPath)"
      Overwrite="true" Encoding="Unicode"/>
    <WriteLinesToFile
      File="$(TLogLocation)windeployqt.write.1u.tlog"
      Lines="^$(ProjectPath);@(QtDeployLog->'%(Fullpath)')"
      Overwrite="true" Encoding="Unicode"/>
    <WriteLinesToFile
      File="$(TLogLocation)$(ProjectName).write.1u.tlog"
      Lines="^$(ProjectFileName);@(QtDeployed->'%(Fullpath)')"
      Overwrite="false" Encoding="Unicode"/>

    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Clean-up
    // -->
    <PropertyGroup>
      <Cmd/>
      <CopyDestinationFolder/>
    </PropertyGroup>
    <ItemGroup>
      <Options Remove="@(Options)"/>
      <QtDeploy Remove="@(QtDeploy)"/>
      <QtDeployLog Remove="@(QtDeployLog)"/>
      <QtDeployed Remove="@(QtDeployed)"/>
      <Args Remove="@(Args)"/>
      <PosArgs Remove="@(PosArgs)"/>
    </ItemGroup>
  </Target>
</Project>
