【问题标题】:Use $(SolutionName) in the MsBuild commandline parameters在 MsBuild 命令行参数中使用 $(Solution Name)
【发布时间】:2015-12-23 20:01:59
【问题描述】:

为了在基于新 Build 2015 任务的构建中模拟 TFS 2013 的 XAML 构建中的“PerProject”选项,我希望能够将 SolutionName 传递给 msbuild 命令行参数,而不必每次都手动设置它.

我想做这样的事情:

/p:OutputPath=$(Build.BinariesDirectory)\$(SolutionName)\

我希望 MsBuild 在哪里推断 $(SolutionName) 参数。但是当在命令行上传递它时,新的任务运行器将用正确的目标路径替换$(Build.BinariesDirectory),并单独留下$(SolutionName)。不幸的是,MsBuild 随后也离开了该属性:

Copying file from "obj\Debug\TFSBuild.exe" to "bin\debug\$(SolutionName)\TFSBuild.exe".
TFSBuild -> b\$(SolutionName)\TFSBuild.exe
Copying file from "obj\Debug\TFSBuild.pdb" to "b\$(SolutionName)\TFSBuild.pdb".

我不记得有什么方法可以将属性传递到命令行并让它进行后期扩展...有什么提示吗?

对于那些希望模仿 SingleFolder 或 AsConfigured 的人来说,这些都很容易:

SingleFolder -> /p:OutputPath="$(Build.BinariesDirectory)"
Asconfigured -> don't pass OutputPath
PerProject   -> /p:OutputPath="$(Build.BinariesDirectory)\HARDCODESOLUTIONNAME"

【问题讨论】:

  • 如何传递/p:MyOutputPathBaseDir=$(Build.BinariesDirectory) 然后在项目文件中将OutputPath 属性设置为$(MyOutputPathBaseDir)\$(SolutionName)?
  • 这需要我编辑所有项目文件,这可行,但我不妨插入自己的变量并使用 AsConfigured
  • 这将需要我编辑所有项目文件不一定,msbuild 有多个扩展点,它可以导入您在命令行上传递的任意文件。在您的情况下,该文件只会按照我的描述设置属性。
  • 如何从命令行导入额外的目标文件?这会很有帮助

标签: msbuild tfsbuild tfs-2015


【解决方案1】:

正如我所担心的,似乎没有一种简单的方法可以从命令行覆盖一个属性并在评估阶段将另一个属性的值“注入”到其中。

有几种方法可以绕过它,但它们并不理想,而且对于 MsBuild 支持的每种语言肯定不是通用的。可惜了。

我已经调试了 MsBuild 目标文件并找到了一个解决方案来重现 2005/2008 时代的旧行为。不完全是每个解决方案,但它确实将项目重定向到子文件夹中。

 /p:GenerateProjectSpecificOutputFolder=true /p:OutDirWasSpecified=true
 /p:OutputPath=$(Build.BinariesDirectory)

【讨论】:

    【解决方案2】:

    一种解决方案是通过使用项目文件更改 OutputPath 来自己模仿这种“后期评估”。为了不手动更改每个项目文件,您可以使用 CustomBeforeMicrosoftCSharpTargets 扩展点。这是一种奇特的说法,它只是一个属性,当找到并指向现有文件时,将导致该文件在所有实际构建逻辑之前被导入某个地方。想法是这样的:在某处创建一个类似 paths.targets 的文件 - 要么将其包含在源代码管理中,要么您可以在构建过程中动态生成它。内容:

    <?xml version="1.0" encoding="utf-8"?>
    <Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      <PropertyGroup>
        <OutputPath Condition="'$(OutputPathBaseDir)'!=''">$(OutputPathBaseDir)\$(SolutionName)</OutputPath>
      </PropertyGroup>
    </Project>
    

    所以这只是将 OutputPath 覆盖到某个基本目录 + 解决方案名称。然后,如果您构建解决方案,例如

    msbuild my.sln /p:CustomBeforeMicrosoftCSharpTargets=paths.targets;
                      OutputPathBaseDir=$(Build.BinariesDirectory)
    

    每个项目都将导入 paths.targets 文件并将输出属性设置为 valueOfBinariesDirectory\my,我认为这正是您所追求的。

    【讨论】:

    • 但是在 C#、VB.NET 和 C++ 的混合中是行不通的。我明白它是怎么做到的,我怀疑还有 3 个其他属性我可以尝试覆盖。
    • 是的,对于 C++,有 ForceImportBeforeCppTargets,对于 VB,我不知道,但它会类似。
    【解决方案3】:

    通常,$(SolutionName) 是在执行解决方案级 MSBuild 管道时定义的,例如在根解决方案目录中运行 dotnet restore。

    要使 $(SolutionName) 可用于项目级 MSBuild 管道,请在解决方案的根目录中添加一个 Directory.Build.props 文件,其中包含以下内容:

    <Project>
        <PropertyGroup>
            <SolutionName Condition="'$(SolutionName)' == ''">
                $([System.IO.Path]::GetFileNameWithoutExtension($([System.IO.Directory]::GetFiles("$(MSBuildThisFileDirectory)", "*.sln")[0])))
            </SolutionName>
        </PropertyGroup>
    </Project>
    

    现在 $(SolutionName) 即使在执行项目级 MSBuild 管道时也会被定义。

    当解决方案目录的根目录中只有一个解决方案文件时,此答案效果最佳。对于其他项目结构,您需要稍微调整一下上述内容。

    当然,你也可以偷懒,直接指定解决方案名称,但这打开了重构问题的可能性(如果解决方案名称发生变化,需要记住更新此文件)。

    <Project>
        <PropertyGroup>
            <SolutionName Condition="'$(SolutionName)' == ''">
                MySolutionName
            </SolutionName>
        </PropertyGroup>
    </Project>
    

    【讨论】:

      【解决方案4】:

      TFS vNext 构建无法识别 OutputPath 中的 $(SolutionName) 是对的,因为 $(SolutionName) 未在 Predefined variables 中列出。

      作为替代方案,我们可以使用解决方案名称命名构建定义,然后将 MSBuild 参数指定为:/p:OutputPath="$(Build.BinariesDirectory)\$(Build.DefinitionName)",这样我们就可以得到解决方案名称下的输出。

      【讨论】:

      • 不是一个真正的选项,因为“PerProject”选项仅在构建多个解决方案时才有意义。这在构建多个解决方案时不起作用。
      • 我知道它不是 Build 2015 中的预定义变量,它在 MsBuild 本身中。所以我的希望是哄着 MsBuild 对变量做点什么。
      • SolutionName is 在构建解决方案时确实在 msbuild 中定义(但不是在构建单个项目时)
      • 我知道,Xaml Build 中的“PerProject”名称选择不当。拆分和注入是在 XAML 工作流中处理的,它只需要您传递给 MsBuild 的任何文件,剥离扩展名并创建一个具有该名称的文件夹。我怀疑“项目”一词源于 2008 年 Team Build 需要 TfsBuild.proj 文件的时代。
      猜你喜欢
      • 1970-01-01
      • 2014-08-03
      • 1970-01-01
      • 1970-01-01
      • 2013-04-01
      • 1970-01-01
      • 2018-11-05
      • 2019-04-10
      • 2011-01-29
      相关资源
      最近更新 更多