解决方案范围内的预构建事件?

use*_*783 65 projects-and-solutions visual-studio pre-build-event

我在Visual Studio中有一个包含多个项目的解决方案.我想在每次构建的最初阶段运行一个命令 - 无论涉及哪个项目以及它们是否是最新的.

基本上我需要类似于解决方案范围的预构建事件,但不幸的是VS似乎不支持这些.有没有人知道实现我需要的另一种方式?

Han*_*ant 44

不寻常的要求.但这是可以完成的.向解决方案添加新项目,使用Visual C++>常规> Makefile项目模板.将其NMake> Build Command Line设置设置为您要执行的命令.使用Project> Project Dependencies使所有其他项目依赖于它.

  • 我不推荐.我的解决方案可以完全在IDE中完成,而无需手动反复攻击项目文件.它确实*不*生成"空dll". (27认同)
  • 我不推荐这个,下面的答案指向我的博客文章,这是要走的路.发布网址:http://sedodream.com/2010/10/22/MSBuildExtendingTheSolutionBuild.aspx (7认同)
  • @SayedIbrahimHashimi您的策略_not_在Visual Studio中工作.你是如何在一个以"我在Visual Studio中找到解决方案......"开头的问题中推荐它的? (7认同)
  • IDE构建和系统构建使用不同程序的事实令人抓狂!Sayed的解决方案仅适用于MSBuild,而不适用于IDE.但是,维护项目依赖性对于大型项目来说具有太多的开销. (5认同)
  • 这是一个可怕的黑客.我不推荐这个 (5认同)
  • @HansPassant项目文件*意味着*(由Microsoft)"手动"修改,这样做并不等于"黑客",特别是对于像这样的一次性任务.MSBuild项目文件在MSDN上完整记录,并且完全支持添加自定义功能.Sayed在这里写了这本书. (2认同)
  • 不那么不寻常.如果你想让每个开发人员运行一套通用的工具作为私有构建(模仿他们工作站上的CI构建的一部分,那么附加这样的命令集会非常方便(例如FxCop,StyleCop,计算测试覆盖率) ,...)一次完整的解决方案,不要再担心了. (2认同)
  • 是的,这是一个黑客,而且效果很好。仅使用 Visual Studio 的 IDE 就可以 100% 完成,无需使用文本编辑器编辑任何项目文件(这对我来说也像是黑客),也不需要任何其他第三方软件。因此,当新手尝试理解整个解决方案时,它使依赖关系变得更加清晰。这就是为什么这是一种流行且有效的方法,它既适用于开发人员的本地计算机构建,也适用于 VSTS 服务器构建。我希望微软有一天能够在 IDE 中实现解决方案构建前/构建后事件。 (2认同)

小智 41

下面简要介绍我的变体

只是一个注释:它是所有现有的不完整列表(另见其他答案等),我只支持我在实际状态下的原始技巧...

摘要

笔记:

  • 1 - 不需要任何额外的扩展.但它可能只能通过项目级别工作,因此我们使用它来模拟我们的解决方案级别...对于通用解决方案来说很难和不方便,但它是变体.见下文.
  • 2 - vsSolutionBuildEvent的原始引擎提供了几种统一支持VS和msbuild.exe的方法.targets mode调用after.<name>.sln.targets仅适用于msbuild.exe 的简单方法(这不需要额外的步骤,只需要操作).但只有原始引擎(包括vsCommandEvent)可能允许额外的脚本支持,例如(7zip archiver,包含没有nuget.exe的nuget包,远程服务器等).但是,它对我们的问题/问题并不重要,如果您+在上面看到,您可以使用任何可用选项来支持解决方案级别.

变体1:Microsoft.VisualStudio.Shell.Interop

此变体不适用于VS的简单用户.但是,它对您的完整解决方案等有用.

你应该实现,例如:

例如:

public sealed class YourPackage: Package, IVsSolutionEvents, IVsUpdateSolutionEvents2
{
...
    public int UpdateSolution_Begin(ref int pfCancelUpdate)
    {
        //TODO:
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,使用'Advise'方法注册处理程序作为优先级侦听器,即对于IVsUpdateSolutionEvents2,您应该使用AdviseUpdateSolutionEvents

这很重要,因为BuildEvents(参见EnvDTE) - 可能无济于事,可能工作太晚 - 例如

使用AdviseUpdateSolutionEvents的示例:

// http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.shell.interop.ivssolutionbuildmanager2.aspx
private IVsSolutionBuildManager2 sbm;

// http://msdn.microsoft.com/en-us/library/bb141335.aspx
private uint _sbmCookie;
...

sbm = (IVsSolutionBuildManager2)ServiceProvider.GlobalProvider.GetService(typeof(SVsSolutionBuildManager));
sbm.AdviseUpdateSolutionEvents(this, out _sbmCookie);
Run Code Online (Sandbox Code Playgroud)

哪里:

  • sbm字段应作为保护GC的类的一部分.
  • 获取SVsSolutionBuildManager服务是使用ServiceProvider,但它可以根据您的需要.见msdn

现在我们可以同时处理所有项目 - 解决方案级别.

变式2:项目的目标和地图.

好吧,你喜欢这样的东西 - MSBuild:扩展解决方案构建,但这个变种可能适用于msbuild.exe而不是VS IDE的构建过程......

但是,当构建操作开始时,VS还在项目文件(*.csproj,*.vcxproj,..)中使用目标(Build,Rebuild,Clean,..).所以我们也可以尝试这个,但请记住:

  • VS也忽略了惊人的.sln文件.它使用EnvDTE等从加载环境形成所有终端目标.
  • .sln应该由msbuild.exe仅处理为:自动生成.metaproj(默认情况下在内存中),其中包含'what and when'将被构建.如果存在,则包括所有项目的公共目标,例如:
...
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\SolutionFile\ImportAfter\*" Condition="'$(ImportByWildcardBeforeSolution)' != 'false' and exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\SolutionFile\ImportAfter')" />
<Import Project="D:\tmp\p\after.name.sln.targets" Condition="exists('D:\tmp\p\after.name.sln.targets')" />
<Target Name="Build" />
<Target Name="Rebuild" />
<Target Name="Clean" />
<Target Name="Publish" />
Run Code Online (Sandbox Code Playgroud)
  • 是的,VS IDE也无法查看.metaproj.

因此,对于VS IDE中的常见目标,您只能使用具有一定限制的项目文件(无需修改/扩展VS,这意味着).

因此,如果您需要通用解决方案(即您可能不了解项目等等 - 例如,这可能是某些盒子解决方案等):

  • 将您的常见.targets文件添加到您的所有项目中(它可以自动使用任何工具,包括NuGet事件等),例如:<Import Project="..\<SolutionFile>.targets" />
  • 然后,你应该使用一些限制:
    • "仅 - 在所有项目之前"
    • "只有 - 在所有项目之后"

例如,是的,它可以是"项目地图":

  • "项目地图"说明了解决方案宽PRE/POST"事件"的集结行动从Visual Studio IDE(即主要来自VS IDE)
...
<Target Name="_Build" BeforeTargets="Build" DependsOnTargets="ProjectsMap">
    <CallTarget Targets="_BuildPRE" Condition="$(ScopeDetectFirst)" />
    <CallTarget Targets="_BuildPOST" Condition="$(ScopeDetectLast)" />
</Target>
<Target Name="_BuildPRE">
    <!-- ... -->
</Target>
<Target Name="_BuildPOST">
    <!-- ... -->
</Target>
...
Run Code Online (Sandbox Code Playgroud)

一般来说,我们将使用项目地图,现在我们知道应该发生什么和什么时候.它对所有或大多数情况都是安全的(更改构建顺序或从解决方案中删除任何项目).然而!你应该<Import>在第一个init中管理新项目的部分.这真的很不方便,但也是变种......

变体3:插件vsSolutionBuildEvent

今天,它是用于处理许多事件的最完整的解决方案,作为事件捕获器,具有各种高级操作,用于维护项目和库,在运行时从Visual Studio和MSBuild工具构建流程和流程.

所有子项目的不同操作类型在解决方案中作为解决方案事件一次或单独为每个子项目.

https://visualstudiogallery.msdn.microsoft.com/0d1dbfd7-ed8a-40af-ae39-281bfeca2334/

插件 -  vsSolutionBuildEvent

它是如何工作的

如果您想使用上面的Variant 1或需要了解如何使用Shell.Interop,EnvDTE,IVsUpdateSolutionEvents2,MSBuild Engine等,请参阅此处:

方案

变体4. EnvDTE.CommandEvents

此变体也不适用于VS的简单用户.但是,对于变体1,它可用于您的盒子解决方案等.

它不一样,但是也可以使用EnvDTE.CommandEvents,就像上面的Variant 1一样.

您应该已经知道(见上文)关于此解决方案的优先工作与当前类型的构建操作...那么为什么不将其用作当前问题的主要解决方案?

_cmdEvents.BeforeExecute += (string guid, int id, object customIn, object customOut, ref bool cancelDefault) => {

    if(UnifiedTypes.Build.VSCommand.existsById(id)) {
        // ... your action
    }

};
Run Code Online (Sandbox Code Playgroud)

哪里: Description | guid | id |In |Out| --------------------------|---------------------------------------|-----|---|---| Started: Build Solution |{5EFC7975-14BC-11CF-9B2B-00AA00573819} | 882 | | | Started: Rebuild Solution |{5EFC7975-14BC-11CF-9B2B-00AA00573819} | 883 | | | Started: Clean Solution |{5EFC7975-14BC-11CF-9B2B-00AA00573819} | 885 | | |

http://vsce.r-eg.net/doc/Features/Solution-wide/

此外,如果需要,您可以选择禁止此命令.在下面的变体中,您将看到这种方式的完整解决方案.

变体5.插件vsCommandEvent

https://visualstudiogallery.msdn.microsoft.com/ad9f19b2-04c0-46fe-9637-9a52ce4ca661/

它还提供了大多数事件的高级处理程序,但不像第一个专门用于MS Visual Studio的高级工作,所有命令和输出数据作为管理器.不仅适用于项目和解决方案,还适用于整个Visual Studio IDE.

通常,它是Variant 4的通用解决方案,您可以简单地覆盖上面的所有命令来解决此问题.

对于与vsSolutionBuildEvent相同的Event-Actions模型,它对大多数情况都很有用.

方案

"帮我解决变种"

所有这些变体都有开放式实现.看到这里微笑:


And*_*y K 18

您可以查看这篇文章:MSBuild:扩展解决方案构建.

似乎正是您所需要的.

  • 这似乎只有在使用MSBuild从命令行构建解决方案时才有效吗?在Visual Studio中,after.*.sln.targets文件似乎没有做任何事情. (17认同)

ere*_*der 9

我们通过添加一个空项目并为该项目设置构建事件来完成此操作.然后,您必须将每个项目依赖项提供给此空项目,以确保每次都构建它.