【问题标题】:With MSBuild (VS2012), how do I intercept the path of an assembly file before it's generated?使用 MSBuild (VS2012),如何在生成程序集文件之前截取它的路径?
【发布时间】:2017-09-09 05:54:59
【问题描述】:

我想在我的所有 .vcxproj (Visual C++ 2012) 项目中注入一个自定义 MSBuild 任务,该任务将以下文件路径作为输入:

  • 即将生成的程序集(.exe 或 .dll)和 .pdb

  • 与二进制文件一起复制到输出文件夹的任何其他文件

该任务然后使用这些路径执行一些操作,然后让构建继续实际生成程序集并复制到输出文件夹。我该怎么办?

在问这个问题之前我已经做了很多研究,但是 MSBuild 示例非常稀缺,并且通常涉及一两个半硬编码路径,而不是通过自定义任务将要创建/复制的所有文件的名称管道化。

(如果你很好奇,这些操作可能包括检查文件是否已经存在并且是只读的,是否被程序锁定,没有在 Perforce 中签出,然后采取适当的措施。)

【问题讨论】:

    标签: c# c++ .net visual-studio-2012 msbuild


    【解决方案1】:

    没有一个项目包含 所有 文件,这些文件最终会进入输出目录。这基本上是一项不可能完成的任务,因为添加的任何自定义目标都可以将文件复制到输出目录。如果您想要所有这些,则必须手动解决。为此,您运行构建,详细程度设置为Detailed(选项-> 项目和解决方案-> 在 VS 中构建和运行,或在命令行上传递 /v:d)并查找包含您正在输出的文件的行后。例如,在某些时候你会看到

    Target "Link" in file "C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V120\Microsoft.CppCommon.targets"
    ...
    Outputs for ....
      my.EXE
      my.PDB
    

    然后您知道名为 Link 的目标最终会输出 exe 和 pdb,并且您可以通过在文本编辑器中打开该 .targets 文件来确定哪些属性包含这些路径。您将看到 Link 目标调用 Link 任务,该任务具有恰当命名的 OutputFile 和 ProgramDatabaseFile 输入。那就是您所追求的,它们被设置为 %(Link.OutputFile) 和 %(Link.ProgramDatabaseFile)。 % 表示法表示元数据被引用,因此 Link 实际上不是属性 Item 它是 MSBuild 等效的数组,因此理论上可能存在例如多个 .pdb 文件。然后编写一个目标来收集一个项目中的所有这些文件,并将它们传递给一个自定义任务,如下所示:

    <UsingTask TaskName="MyCustomTask" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v12.0.dll" >
      <ParameterGroup>
        <AllOutputFiles ParameterType="Microsoft.Build.Framework.ITaskItem[]" Output="True"/>
      </ParameterGroup>
      <Task>
        <Code Type="Fragment" Language="cs">
        //code here
        </Code>
      </Task>
    </UsingTask>
    
    <Target Name="CustomTarget" BeforeTargets="Link">
      <ItemGroup>
        <AllOutputFiles Include="@(Link->MetaData('ProgramDatabaseFile')->FullPath()->Distinct());@(Link->MetaData('OutputFile')->FullPath()->Distinct())"/>
      </ItemGroup>
      <Message Text="AllOutputFiles = @(AllOutputFiles)" />
      <MyCustomTask AllOutputFiles="@(AllOutputFiles)" />
    </Target>
    

    BeforeTargets="Link" 部分确保它在链接器之前运行。如果由于某种原因为时已晚,您可以使用许多其他目标:再次查看详细输出并选择一个。

    【讨论】:

    • 谢谢你,“教人钓鱼”的好答案。详细设置与自定义任务相结合以从链接(或任何其他)任务的项目中收集文件路径是我所需要的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多