在MsBuild命令行参数中使用$(SolutionName)

在MsBuild命令行参数中使用$(SolutionName),msbuild,tfsbuild,tfs-2015,Msbuild,Tfsbuild,Tfs 2015,为了在新的build 2015基于任务的版本中模拟TFS 2013的XAML版本中的“PerProject”选项,我希望能够将SolutionName传递给msbuild命令行参数,而无需每次手动设置 我想做一些类似的事情: /p:OutputPath=$(Build.BinariesDirectory)\$(SolutionName)\ 其中,我希望MsBuild推断$(SolutionName)参数。但是,当在命令行上传递此命令时,新的任务运行程序将用正确的目标路径替换$(Build.Bi

为了在新的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"

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


或者,我们可以使用解决方案名称命名生成定义,然后将MSBuild参数指定为:
/p:OutputPath=“$(build.BinariesDirectory)\$(build.DefinitionName)”
,我们可以在解决方案名称下获得输出。

一种解决方案是通过使用项目文件更改OutputPath来模拟这种“后期评估”。要在不手动更改每个项目文件的情况下执行此操作,可以使用
custombeforemocrosoftcsharptargets
扩展点。这是一种奇特的说法,它只是一个属性,当找到并指向一个现有文件时,将导致该文件在所有实际构建逻辑之前导入到某个地方。这里的想法是:在某处创建一个类似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>

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

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

有几种方法可以解决这个问题,但它们并不理想,而且对于MsBuild支持的每种语言来说肯定不是通用的。真遗憾

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

 /p:GenerateProjectSpecificOutputFolder=true /p:OutDirWasSpecified=true
 /p:OutputPath=$(Build.BinariesDirectory)
通常,在执行解决方案级别的MSBuild管道时,例如在根解决方案目录中运行
dotnet restore
时,会定义
$(SolutionName)

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


$([System.IO.Path]::GetFileNameWithoutExtension($([System.IO.Directory]::GetFiles($(MSBuildThisFileDirectory)”,“*.sln”)[0]))
现在,即使在执行项目级MSBuild管道时,也将定义
$(SolutionName)

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

当然,您也可以懒惰,直接指定解决方案名称,但这会带来重构问题的可能性(如果解决方案名称更改,需要记住更新此文件)


MySolutionName

实际上不是一个选项,因为“PerProject”选项只有在构建多个解决方案时才有意义。当构建多个解决方案时,这将不起作用。我知道它不是Build 2015中的预定义变量,而是在MsBuild中。因此,我希望能说服MsBuild对变量进行处理。SolutionName确实是在构建解决方案时在MsBuild中定义的(但不是在构建单个项目时)。我知道,Xaml构建中的“PerProject”名称选择不当。分割和注入是在XAML工作流中处理的,它只接收传递给MsBuild的任何文件,剥离扩展名并创建一个具有该名称的文件夹。我怀疑术语“Project”源自2008年的时代,当时团队构建需要一个TfsBuild.proj文件。传递
/p:MyOutputPathBaseDir=$(Build.BinariesDirectory)
,然后在项目文件中将OutputPath属性设置为
$(MyOutputPathBaseDir)\$(SolutionName)
?这将需要我编辑所有项目文件,这是可行的,但我也可以插入自己的变量并使用ASCONFIGURED。这需要我编辑所有项目文件。不一定,msbuild有多个扩展点,它可以在命令行上导入您传递的任意文件。在您的情况下,该文件将只设置我所描述的属性。如何从命令行导入额外的目标文件?这将有助于在C、VB.NET和C++的组合中不起作用。我理解它是如何实现的,我怀疑还有3个属性可以尝试重写。是的,C++有强大的预测目标,对于VB我不知道,但是它会是相似的。
 /p:GenerateProjectSpecificOutputFolder=true /p:OutDirWasSpecified=true
 /p:OutputPath=$(Build.BinariesDirectory)