Msbuild 使用外部任务确定OutputPath

Msbuild 使用外部任务确定OutputPath,msbuild,msbuild-task,msbuild-4.0,Msbuild,Msbuild Task,Msbuild 4.0,我正试图通过使用外部任务来获取有关我希望将最终输出存储在何处的信息,从而在csproj中全局覆盖OutputPath参数 我创建了一个任务: <Target Name="SetSolutionTarget"> <SetSolutionConfiguration SolutionPath="$(SolutionPath)"> <Output PropertyName="SolutionConfig" TaskParameter="SolutionC

我正试图通过使用外部任务来获取有关我希望将最终输出存储在何处的信息,从而在csproj中全局覆盖OutputPath参数

我创建了一个任务:

<Target Name="SetSolutionTarget">
    <SetSolutionConfiguration SolutionPath="$(SolutionPath)">
      <Output PropertyName="SolutionConfig" TaskParameter="SolutionConfiguration"/>
    </SetSolutionConfiguration>
    <Message Text="SolutionConfiguration is: $(SolutionConfig)" Importance="high" />
</Target>
该任务工作正常,消息将在我要输出文件的位置输出正确的值

问题是当我尝试将它与OutputPath集成时。 尝试做:

<OutputPath>$(SolutionConfig)</OutputPath>
不工作-它引发错误:未设置OutputPath属性….-这意味着要么变量不在任务之间传递,要么在执行构建之前必须设置OutputPath的变量


我也尝试过其他方法,比如在任务中设置一个环境变量,而不是输出结果,但仍然没有成功。

我意识到这是一个老问题,但找到解决方案是一件令人厌烦的事情。因此,将我的发现发布在这里,希望能节省其他人花费的大量时间

建议的解决方案1 既然MSBuild已经开源,我就他的MSBuild示例repo向MSFT团队成员Jeff Kluge询问了一个类似的问题,例外是,我正在尝试一个内联任务,并收到了一个解决方案:

@杰夫克尔说,

以下是我的例子:


有关用法、限制及其解决方法的更多详细信息,请参阅。

是否确实在导入Microsoft目标文件之前执行了任务?实际上,我不确定。我的项目定义如下:-所以集合是在构建之前执行的,或者应该在构建之前执行。我认为这不会起作用。请尝试替代BeforeBuild目标,但可能仍然太迟。解决方案1似乎不适用于Visual Studio 2017。所有内容都正确编译到更改的目录位置。不幸的是,Visual Studio拒绝确认更改,并尝试从以前的位置启动.exe。因此,它找不到.exe,无法在设计模式下启动调试或显示xaml。
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <UsingTask TaskName="GetOutputPath" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
    <ParameterGroup>
      <OutputPath ParameterType="System.String" Output="true" />
    </ParameterGroup>
    <Task>
      <Code Type="Fragment" Language="cs">
        <![CDATA[
          OutputPath = Path.Combine("bin", Guid.NewGuid().ToString("N")) + System.IO.Path.DirectorySeparatorChar;
        ]]>
      </Code>
    </Task>
  </UsingTask>
  
  <Target Name="SetOutputPath"
          BeforeTargets="_CheckForInvalidConfigurationAndPlatform">

    <Message Text="Before:" />
    <Message Text=" OutputPath: '$(OutputPath)'" />
    <Message Text=" OutDir: '$(OutDir)'" />
    <Message Text=" PublishDir: '$(PublishDir)'" />
    <Message Text=" _InvalidConfigurationError: '$(_InvalidConfigurationError)'" />
    <Message Text=" _InvalidConfigurationWarning: '$(_InvalidConfigurationWarning)'" />

    <GetOutputPath>
      <Output TaskParameter="OutputPath" PropertyName="OutputPath"/>
      <!--
        OutDir is set in Microsoft.Common.CurrentVersion.targets as a copy of $(OutputPath). Since
        we've reset $(OutputPath), we need to reset $(OutDir) as well for backwards compatibility.
      -->
      <Output TaskParameter="OutputPath" PropertyName="OutDir" />
    </GetOutputPath>


    <PropertyGroup>
      <!--
        PublishDir is set in Microsoft.Common.CurrentVersion.targets and starts with $(OutputPath).
        Since we've reset $(OutputPath), we need to reset $(PublishDir).  We have to do this in a
        <PropertyGroup /> because the <Output /> from <GetOutputPath /> can't append text.
      -->
      <PublishDir>$(OutputPath)app.publish\</PublishDir>
      <!--
        If <OutputPath /> is not set in a top-level <PropertyGroup /> then $(_InvalidConfigurationError)
        is set to 'true' which will cause a build error.  However, we've set $(OutputPath) in a task 
        just before _CheckForInvalidConfigurationAndPlatform ran so we can turn off the error now that
        we know everything is set properly. 
      -->
      <_InvalidConfigurationError>false</_InvalidConfigurationError>
      <_InvalidConfigurationWarning>false</_InvalidConfigurationWarning>
    </PropertyGroup>

    <Message Text="After:" />
    <Message Text=" OutputPath: '$(OutputPath)'" />
    <Message Text=" OutDir: '$(OutDir)'" />
    <Message Text=" PublishDir: '$(PublishDir)'" />
    <Message Text=" _InvalidConfigurationError: '$(_InvalidConfigurationError)'" />
    <Message Text=" _InvalidConfigurationWarning: '$(_InvalidConfigurationWarning)'" />

  </Target>
</Project>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProjectGuid>{C76AA0AA-3B50-48D6-BE46-0F2D8DC56C02}</ProjectGuid>
    <OutputType>Exe</OutputType>
    <RootNamespace>OutputPathViaInlineTask</RootNamespace>
    <AssemblyName>OutputPathViaInlineTask</AssemblyName>
    <TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "/>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "/>
  
  <ItemGroup>
    <Reference Include="System" />
    <Compile Include="Program.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
    <None Include="App.config" />
  </ItemGroup>
  
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  <Import Project="$(MSBuildThisFileDirectory)build.targets" />
  
</Project>
# cmd
set MSBUILDENABLEALLPROPERTYFUNCTIONS=1 && msbuild my.sln

# PowerShell
$env:MSBUILDENABLEALLPROPERTYFUNCTIONS=1 ; msbuild my.sln


# UnixShell
MSBUILDENABLEALLPROPERTYFUNCTIONS=1 dotnet build my.sln