给定相对路径时,如何让 MSBUILD 评估和打印完整路径?

Posted

技术标签:

【中文标题】给定相对路径时,如何让 MSBUILD 评估和打印完整路径?【英文标题】:How can I get MSBUILD to evaluate and print the full path when given a relative path? 【发布时间】:2008-10-07 01:45:44 【问题描述】:

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

【问题讨论】:

我认为 FullPath 元数据仅适用于 项目,不适用于 属性。 我认为你是对的,有人知道从物业到完整/绝对路径的方法吗? 你可以“有点”通过使用 $(ProjectDir)$(Source_Dir) 到达那里,但你会有多余的 '..'s 【参考方案1】:

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

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

即使脚本被&lt;Import&gt;编辑到另一个脚本中,此方法仍然有效;路径是相对于包含上述代码的文件的。

(整合自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\".

如果你问我,有点啰嗦,但它有效。这将是相对于“原始”项目文件的,因此如果放在一个获得&lt;Import&gt;ed 的文件中,这将与该文件无关。


在 MSBuild 2.0 中,有一种方法不能解析“..”。然而,它的行为就像绝对路径:

<PropertyGroup>
    <Source_Dir_Abs>$(MSBuildProjectDirectory)\$(Source_Dir)</Source_Dir_Abs>
</PropertyGroup>

$(MSBuildProjectDirectory) 保留属性始终是包含此引用的脚本目录。

这也将与“原始”项目文件相关,因此,如果放置在获得&lt;Import&gt;ed 的文件中,则不会与该文件相关。

【讨论】:

小心[System.IO.Path]::GetFullPath。我在 Visual Studio 中构建时遇到错误,因为 msbuild 中的当前工作目录是 C:\Windows\System32GetFullPath 相对于工作目录而不是项目目录进行解析。 @ChrisChilvers 这很不幸。上次我测试这个(诚然很久以前),它是相对于包含代码的文件。 它也适用于回溯 ..\..\your\path 样式路径。另请注意,$(MSBuildThisFileDirectory) 宏已包含尾部斜杠,因此您必须指定不带前导斜杠的 your\path,即 $(MSBuildThisFileDirectory)your\path。这很重要的一种情况是,当您将它用于 Microsoft 单元测试框架测试的 OutDir 时,当您尝试运行测试时,它将无法评估连接路径中的 `\\` 以找到构建的 dll . @AdamYaxley GetFullPath 会自动折叠双反斜杠,因此即使您有额外的反斜杠,它也可以工作。您的问题一定是由其他原因引起的。【参考方案2】:

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

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

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

语法有点丑,但是很强大。

【讨论】:

+1 哦,伙计。这很棒!正是我想要的。谢谢。 它还评估相对于(据我所知)定义属性的项目文件的路径,当您想将该属性包含在其他文件中时,这非常好。对我来说,这是完美的解决方案。 @JeanHominal 如果你使用&lt;Import&gt;,它仍然是相对于它导入的地方,这是一个耻辱。尽管如此,这是唯一也适用于目标之外的方法,这让我得到了 +1。有关解决 &lt;Import&gt; 问题的方法,请参阅 this answer。 是的,当我说我所做的时我弄错了——所有的相对路径总是相对于“正在执行的项目”路径(MSBuild 当前正在执行的项目);但是,您可以使用$(MSBuildThisFileDirectory) 获取当前执行文件目录的完整路径。 正是我需要的。谢谢!【参考方案3】:

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>

【讨论】:

老兄,我已经从上面的那段代码中了解了有关如何构建 MS 任务的更多信息,然后我在 MSBuild 文档中就有了。谢谢! :-)【参考方案4】:

您正在尝试通过属性访问项目元数据属性,但这是不可能的。你想做的是这样的:

<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”,您应该已经准备就绪。

【讨论】:

+1 这很好用,我(和其他人一样)来到这里寻找规范化 ItemGroup 的方法(几乎假设需要批处理并复制到新的 ItemGroup) - 你显示的语法确实它没有那种混乱。 IOW 我忘记了 FullPath Well known metadata【参考方案5】:

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

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

在 MSBuild 3.5 中,您可以在任务中包含 ItemGroups

  <Target Name='Build'>
    <ItemGroup>
      <SRCDIR2 Include='$(Source_Dir)' />
    </ItemGroup>
    <Message Text="%(SRCDIR2.FullPath)" />
    <Message Text="%(SRCDIR.FullPath)" />
  </Target>

【讨论】:

以上是关于给定相对路径时,如何让 MSBUILD 评估和打印完整路径?的主要内容,如果未能解决你的问题,请参考以下文章

如何检索给定相对路径的绝对路径

delphi 打开本机相对路径的.html文件

给定两条绝对路径,我如何表达其中一条相对于另一条的路径?

如何在给定两个绝对路径的情况下找到相对路径?

编写python代码,仅打印给定列表中评估为True的表达式[关闭]

当我使用MSBuild构建Android Makefile项目并打印日志时,无法将字符串“error”和“:”放在一起