为了模仿" PerProject"在新的基于Build 2015任务的构建中,TFS 2013和XAML构建中的选项,我希望能够将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"
答案 0 :(得分:1)
一种解决方案是模仿这种后期评估'通过使用projectfile更改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覆盖到某个基本目录+ solutionname。然后,如果你构建像
这样的解决方案msbuild my.sln /p:CustomBeforeMicrosoftCSharpTargets=paths.targets;
OutputPathBaseDir=$(Build.BinariesDirectory)
每个项目都会导入paths.targets文件,并将输出属性设置为 valueOfBinariesDirectory \ my ,我认为这正是您所追求的。
答案 1 :(得分:1)
我担心似乎没有一种简单的方法可以从命令行覆盖属性,并在评估阶段“注入”另一个属性的值。
有几种方法可以解决这个问题,但是对于MsBuild支持的每种语言来说,它们都不是理想的,当然也不普遍。可惜。
我调试了MsBuild目标文件,并找到了一个重现2005/2008时代旧行为的解决方案。不完全是每个解决方案,但它确实将项目重定向到子文件夹。
/p:GenerateProjectSpecificOutputFolder=true /p:OutDirWasSpecified=true
/p:OutputPath=$(Build.BinariesDirectory)
答案 2 :(得分:0)
你是对的,TFS vNext版本无法识别OutputPath中的$(SolutionName)
,因为$(SolutionName)未在Predefined variables中列出。
作为替代方案,我们可以使用解决方案名称命名构建定义,然后以这种方式将MSBuild参数指定为:/p:OutputPath="$(Build.BinariesDirectory)\$(Build.DefinitionName)"
,我们可以在解决方案名称下获取输出。
答案 3 :(得分:0)
通常,$(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>
现在即使执行项目级MSBuild管道,也将定义$(SolutionName)
。
当解决方案目录的根目录中只有一个解决方案文件时,此答案最有效。您需要对其他项目结构进行以上介绍。
当然,您也可以懒惰并直接指定解决方案名称,但这带来了重构问题的可能性(如果解决方案名称更改,请记住要更新此文件)。
<Project>
<PropertyGroup>
<SolutionName Condition="'$(SolutionName)' == ''">
MySolutionName
</SolutionName>
</PropertyGroup>
</Project>