在 MsBuild 命令行参数中使用 $(SolutionName)
Use $(SolutionName) in the MsBuild commandline parameters
为了在基于任务的新 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) 未在 Predefined variables.
中列出
作为替代方案,我们可以使用解决方案名称命名构建定义,然后将 MSBuild 参数指定为:/p:OutputPath="$(Build.BinariesDirectory)$(Build.DefinitionName)"
这样,我们可以在解决方案名称下获取输出。
一种解决方案是通过更改项目文件中的 OutputPath 自己模仿这样的 'late evaluation'。如果不手动更改每个项目文件,您可以使用 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 我认为这正是您所追求的。
正如我担心的那样,似乎没有一种简单的方法可以在评估阶段从命令行覆盖 属性 并将另一个 属性 的值 "inject" 覆盖到其中.
有几种方法可以解决这个问题,但它们并不理想,而且对于 MsBuild 支持的每种语言来说肯定不是通用的。可惜了。
我调试了 MsBuild 目标文件并找到了重现 2005/2008 时代旧行为的解决方案。不完全是每个解决方案,但它会将项目重定向到子文件夹中。
/p:GenerateProjectSpecificOutputFolder=true /p:OutDirWasSpecified=true
/p:OutputPath=$(Build.BinariesDirectory)
通常,$(SolutionName)
是在执行solution-level MSBuild管道时定义的,例如根解决方案目录中的运行 dotnet restore
。
要使 $(SolutionName)
可用于 project-level MSBuild 管道,请在解决方案的根目录中添加一个包含以下内容的 Directory.Build.props
文件:
<Project>
<PropertyGroup>
<SolutionName Condition="'$(SolutionName)' == ''">
$([System.IO.Path]::GetFileNameWithoutExtension($([System.IO.Directory]::GetFiles("$(MSBuildThisFileDirectory)", "*.sln")[0])))
</SolutionName>
</PropertyGroup>
</Project>
现在即使在执行 project-level MSBuild 管道时也会定义 $(SolutionName)
。
当解决方案目录的根目录中只有一个解决方案文件时,此答案最有效。对于其他项目结构,您需要稍微修改以上内容。
当然,你也可以偷懒,直接指定解决方案名称,但这会带来重构问题的可能性(如果解决方案名称发生变化,需要记得更新此文件)。
<Project>
<PropertyGroup>
<SolutionName Condition="'$(SolutionName)' == ''">
MySolutionName
</SolutionName>
</PropertyGroup>
</Project>
为了在基于任务的新 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) 未在 Predefined variables.
作为替代方案,我们可以使用解决方案名称命名构建定义,然后将 MSBuild 参数指定为:/p:OutputPath="$(Build.BinariesDirectory)$(Build.DefinitionName)"
这样,我们可以在解决方案名称下获取输出。
一种解决方案是通过更改项目文件中的 OutputPath 自己模仿这样的 'late evaluation'。如果不手动更改每个项目文件,您可以使用 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 我认为这正是您所追求的。
正如我担心的那样,似乎没有一种简单的方法可以在评估阶段从命令行覆盖 属性 并将另一个 属性 的值 "inject" 覆盖到其中.
有几种方法可以解决这个问题,但它们并不理想,而且对于 MsBuild 支持的每种语言来说肯定不是通用的。可惜了。
我调试了 MsBuild 目标文件并找到了重现 2005/2008 时代旧行为的解决方案。不完全是每个解决方案,但它会将项目重定向到子文件夹中。
/p:GenerateProjectSpecificOutputFolder=true /p:OutDirWasSpecified=true
/p:OutputPath=$(Build.BinariesDirectory)
通常,$(SolutionName)
是在执行solution-level MSBuild管道时定义的,例如根解决方案目录中的运行 dotnet restore
。
要使 $(SolutionName)
可用于 project-level MSBuild 管道,请在解决方案的根目录中添加一个包含以下内容的 Directory.Build.props
文件:
<Project>
<PropertyGroup>
<SolutionName Condition="'$(SolutionName)' == ''">
$([System.IO.Path]::GetFileNameWithoutExtension($([System.IO.Directory]::GetFiles("$(MSBuildThisFileDirectory)", "*.sln")[0])))
</SolutionName>
</PropertyGroup>
</Project>
现在即使在执行 project-level MSBuild 管道时也会定义 $(SolutionName)
。
当解决方案目录的根目录中只有一个解决方案文件时,此答案最有效。对于其他项目结构,您需要稍微修改以上内容。
当然,你也可以偷懒,直接指定解决方案名称,但这会带来重构问题的可能性(如果解决方案名称发生变化,需要记得更新此文件)。
<Project>
<PropertyGroup>
<SolutionName Condition="'$(SolutionName)' == ''">
MySolutionName
</SolutionName>
</PropertyGroup>
</Project>