如何让MSBuild在<Message />
任务中评估和打印给定相对路径的绝对路径?
物业组
<Source_Dir>..\..\..\Public\Server\</Source_Dir>
<Program_Dir>c:\Program Files (x86)\Program\</Program_Dir>
任务
<Message Importance="low" Text="Copying '$(Source_Dir.FullPath)' to '$(Program_Dir)'" />
输出
将''复制到'c:\ Program Files(x86)\ Program \'
答案 0 :(得分:91)
在MSBuild 4.0中,最简单的方法如下:
$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)\your\path'))
即使脚本<Import>
编入另一个脚本,此方法仍然有效;路径相对于包含上述代码的文件。
(从Aaron's answer合并以及Sayed's answer的最后一部分)
在MSBuild 3.5 中,您可以使用ConvertToAbsolutePath任务:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
DefaultTargets="Test"
ToolsVersion="3.5">
<PropertyGroup>
<Source_Dir>..\..\..\Public\Server\</Source_Dir>
<Program_Dir>c:\Program Files (x86)\Program\</Program_Dir>
</PropertyGroup>
<Target Name="Test">
<ConvertToAbsolutePath Paths="$(Source_Dir)">
<Output TaskParameter="AbsolutePaths" PropertyName="Source_Dir_Abs"/>
</ConvertToAbsolutePath>
<Message Text='Copying "$(Source_Dir_Abs)" to "$(Program_Dir)".' />
</Target>
</Project>
相关产出:
Project "P:\software\perforce1\main\XxxxxxXxxx\Xxxxx.proj" on node 0 (default targets).
Copying "P:\software\Public\Server\" to "c:\Program Files (x86)\Program\".
如果你问我,有点啰嗦,但它确实有效。这将相对于“原始”项目文件,因此如果放在获得<Import>
的文件中,则不会相对于该文件。
在MSBuild 2.0 中,有一种方法无法解析“..”。然而它的行为就像一条绝对路径:
<PropertyGroup>
<Source_Dir_Abs>$(MSBuildProjectDirectory)\$(Source_Dir)</Source_Dir_Abs>
</PropertyGroup>
$(MSBuildProjectDirectory)保留属性始终是包含此引用的脚本的目录。
这也与“原始”项目文件相关,因此如果放在获得<Import>
的文件中,则不会相对于该文件。
答案 1 :(得分:31)
MSBuild 4.0添加了Property Functions,允许您调用某些.net系统dll中的静态函数。关于属性函数的一个非常好的事情是它们将评估目标的一面。
要评估完整路径,您可以在定义如下属性时使用System.IO.Path.GetFullPath:
<PropertyGroup>
<Source_Dir>$([System.IO.Path]::GetFullPath('..\..\..\Public\Server\'))</Source_Dir>
</PropertyGroup>
语法有点难看但非常强大。
答案 2 :(得分:6)
Wayne是正确的,众所周知的元数据不适用于属性 - 仅适用于项目。使用诸如“MSBuildProjectDirectory”之类的属性将起作用,但我不知道有一种内置的方法来解析完整路径。
另一种选择是编写一个简单的自定义任务,该任务将采用相对路径并吐出完全解析的路径。它看起来像这样:
public class ResolveRelativePath : Task
{
[Required]
public string RelativePath { get; set; }
[Output]
public string FullPath { get; private set; }
public override bool Execute()
{
try
{
DirectoryInfo dirInfo = new DirectoryInfo(RelativePath);
FullPath = dirInfo.FullName;
}
catch (Exception ex)
{
Log.LogErrorFromException(ex);
}
return !Log.HasLoggedErrors;
}
}
您的MSBuild行看起来像:
<PropertyGroup>
<TaskAssembly>D:\BuildTasks\Build.Tasks.dll</TaskAssembly>
<Source_Dir>..\..\..\Public\Server\</Source_Dir>
<Program_Dir>c:\Program Files (x86)\Program\</Program_Dir>
</PropertyGroup>
<UsingTask AssemblyFile="$(TaskAssembly)" TaskName="ResolveRelativePath" />
<Target Name="Default">
<ResolveRelativePath RelativePath="$(Source_Dir)">
<Output TaskParameter="FullPath" PropertyName="_FullPath" />
</ResolveRelativePath>
<Message Importance="low" Text="Copying '$(_FullPath)' to '$(Program_Dir)'" />
</Target>
答案 3 :(得分:5)
您正尝试通过属性访问项元数据属性,这是不可能的。你想做的是这样的:
<PropertyGroup>
<Program_Dir>c:\Program Files (x86)\Program\</Program_Dir>
</PropertyGroup>
<ItemGroup>
<Source_Dir Include="..\Desktop"/>
</ItemGroup>
<Target Name="BuildAll">
<Message Text="Copying '%(Source_Dir.FullPath)' to '$(Program_Dir)'" />
</Target>
将生成输出为:
Copying 'C:\Users\sdorman\Desktop' to 'c:\Program Files (x86)\Program\'
(该脚本是从我的Documents文件夹运行的,所以.. \ Desktop是到达我桌面的正确相对路径。)
在您的情况下,在Source_Dir项目中将“.. \ Desktop”替换为“...... \ Public \ Server”,您应该全部设置。
答案 4 :(得分:4)
如果您需要将属性转换为项目,您有两个选项。使用msbuild 2,您可以使用 CreateItem 任务
<Target Name='Build'>
<CreateItem Include='$(Source_Dir)'>
<Output ItemName='SRCDIR' TaskParameter='Include' />
</CreateItem>
使用MSBuild 3.5,您可以在任务
中包含ItemGroup <Target Name='Build'>
<ItemGroup>
<SRCDIR2 Include='$(Source_Dir)' />
</ItemGroup>
<Message Text="%(SRCDIR2.FullPath)" />
<Message Text="%(SRCDIR.FullPath)" />
</Target>