61

在给定相对路径的情况下,如何让 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\'

4

5 回答 5

103

在 MSBuild 4.0中,最简单的方法如下:

$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)\your\path'))

即使脚本被<Import>编入另一个脚本,此方法也有效;路径是相对于包含上述代码的文件的。

(合并自Aaron 的回答以及Sayed 回答的最后一部分)


在 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>编辑的文件中,这将与该文件无关。

于 2009-08-09T11:22:53.097 回答
34

MSBuild 4.0 添加了属性函数,允许您调用某些 .net 系统 dll 中的静态函数。属性函数的一个非常好的事情是它们将评估目标的外部。

要评估完整路径,您可以在定义如下属性时使用System.IO.Path.GetFullPath :

<PropertyGroup>
  <Source_Dir>$([System.IO.Path]::GetFullPath('..\..\..\Public\Server\'))</Source_Dir>
</PropertyGroup>

语法有点难看,但非常强大。

于 2011-02-04T04:05:21.310 回答
7

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>
于 2008-10-07T03:32:33.030 回答
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”,您应该已经准备就绪。

于 2008-10-07T03:38:19.400 回答
4

如果您需要将属性转换为项目,您有两种选择。使用 msbuild 2,您可以使用CreateItem任务

  <Target Name='Build'>
    <CreateItem Include='$(Source_Dir)'>
      <Output ItemName='SRCDIR' TaskParameter='Include' />
    </CreateItem>

并且使用 MSBuild 3.5,您可以在 Task 中包含 ItemGroups

  <Target Name='Build'>
    <ItemGroup>
      <SRCDIR2 Include='$(Source_Dir)' />
    </ItemGroup>
    <Message Text="%(SRCDIR2.FullPath)" />
    <Message Text="%(SRCDIR.FullPath)" />
  </Target>
于 2008-10-07T16:24:50.693 回答