给定相对路径时,如何让 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 元数据仅适用于在 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>
ed 的文件中,这将与该文件无关。
在 MSBuild 2.0 中,有一种方法不能解析“..”。然而,它的行为就像绝对路径:
<PropertyGroup>
<Source_Dir_Abs>$(MSBuildProjectDirectory)\$(Source_Dir)</Source_Dir_Abs>
</PropertyGroup>
$(MSBuildProjectDirectory) 保留属性始终是包含此引用的脚本目录。
这也将与“原始”项目文件相关,因此,如果放置在获得<Import>
ed 的文件中,则不会与该文件相关。
【讨论】:
小心[System.IO.Path]::GetFullPath
。我在 Visual Studio 中构建时遇到错误,因为 msbuild 中的当前工作目录是 C:\Windows\System32
。 GetFullPath
相对于工作目录而不是项目目录进行解析。
@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 如果你使用<Import>
,它仍然是相对于它导入的地方,这是一个耻辱。尽管如此,这是唯一也适用于目标之外的方法,这让我得到了 +1。有关解决 <Import>
问题的方法,请参阅 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 评估和打印完整路径?的主要内容,如果未能解决你的问题,请参考以下文章