整个解决scheme范围的预生成事件?
我在Visual Studio中有一个包含多个项目的解决scheme。 我希望在每个构build的开始阶段都能执行一个命令 – 不pipe哪个项目涉及到哪个项目,以及它们是否是最新的。
基本上我需要类似于解决scheme范围的预生成事件,但不幸的是,VS似乎不支持这些事件。 有谁知道实现我所需要的另一种方法?
不寻常的要求。 但这是可以完成的。 添加一个新的项目到您的解决scheme,使用Visual C ++>常规>生成文件项目模板。 将其NMake>构build命令行设置设置为您要执行的命令。 使用“项目”>“项目依赖项”来使所有其他项目都依赖于它。
下面简要介绍我的变体
只是一个注释:它是所有现有的不完整列表(另请参阅其他答案等),我只支持我在实际状态中的原始技巧…
笔记:
- 1 – 不需要任何额外的分机。 但是它只能通过项目级别工作,所以我们用它来模拟我们的解决scheme级别…对于常见的解决scheme来说,这是很难和不方便的,但是是变体。 见下文。
- 2 – vsSolutionBuildEvent的原始引擎提供了几种统一支持VS和msbuild.exe的方法。 一个简单的方式来调用
targets mode
after.<name>.sln.targets
,它只适用于msbuild.exe(这不需要额外的步骤,简单的动作)。 但是,只有原始引擎(包括vsCommandEvent)可能允许额外的脚本,例如支持(7zip存档器,包装nuget包,没有nuget.exe,远程服务器等)。 但是,对于我们的问题/问题并不重要,如果您看到上面的+
,则可以使用任何可用的选项来支持解决scheme级别。
变体1:Microsoft.VisualStudio.Shell.Interop
这个变体不适用于VS的简单用户。 但是,它可以为您的完整解决scheme等。
你应该执行,例如:
- IVsUpdateSolutionEvents2 / IVsUpdateSolutionEvents
例如:
public sealed class YourPackage: Package, IVsSolutionEvents, IVsUpdateSolutionEvents2 { ... public int UpdateSolution_Begin(ref int pfCancelUpdate) { //TODO: } }
然后,注册与“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);
哪里:
-
sbm
领域应该作为保护GC的一部分。 - 获取SVsSolutionBuildManager服务是使用ServiceProvider,但它可以根据您的需要。 看msdn
现在,我们可以一次处理所有项目 – 解决scheme级别。
变体2:项目的目标和地图。
好吧,你喜欢这样的东西 – MSBuild:扩展解决scheme的构build ,但是这个变种可能与msbuild.exe而不是从VS IDE构build进程工作…
但是,在构build操作启动时,VS也使用项目文件(* .csproj,* .vcxproj,..)中的目标(Build,Rebuild,Clean,..)。 所以我们也可以试试这个,但请记住:
- VS也忽略了惊人的.sln文件。 它与EnvDTE等形成了从装载环境到全部terminal目标。
- .sln应该只处理msbuild.exe:自动生成.metaproj(内存默认情况下),其中包含什么和何时将被构build。 包括所有项目的共同目标(如果存在),例如:
... <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" />
- 是的,.metaproj也不能被VS IDE查看。
因此,对于使用VS IDE共同目标的工作,只能使用有限制的项目文件(不需要修改/扩展VS,这意味着)。
所以,如果你需要通用的解决scheme(即你可能不知道项目等 – 例如,这可能是一些盒子解决scheme和类似的 ):
- 将所有常见的.targets文件添加到所有项目中(可以自动使用任何工具,包括NuGet事件等),例如:
<Import Project="..\<SolutionFile>.targets" />
- 那么,你应该使用一些限制:
- “只有 – 在所有项目之前”
- “只有 – 毕竟项目”
例如,是的,它可以是“项目地图”:
- “项目地图”说明了Visual Studio IDE中的构build操作的解决scheme范围的PRE / POST“事件”(即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> ...
一般来说,我们将使用项目地图,现在我们知道应该发生什么和什么时候。 所有或大多数情况下都是安全的(更改构build顺序或从解决scheme中删除任何项目)。 然而! 您应该在第一个init中pipe理新项目的<Import>
部分。 这真的很不方便,但也是变种
变体3:插件vsSolutionBuildEvent
今天,作为Events-Catcher的事件处理工具,您可以使用Visual Studio和MSBuild工具在运行时维护项目和库,构buildstream程和stream程等各种高级操作。
解决scheme中的所有子项目的不同操作types都是解决scheme事件,或者针对每个子项目单独进行。
https://visualstudiogallery.msdn.microsoft.com/0d1dbfd7-ed8a-40af-ae39-281bfeca2334/
它是如何工作的
如果你想使用上面的Variant 1或者需要看看如何使用Shell.Interop,EnvDTE,IVsUpdateSolutionEvents2,MSBuild Engine等,请看这里 :
变种4. EnvDTE.CommandEvents
这个变种也不适合VS的简单用户。 然而,至于变种1,它可以用于你的盒子解决scheme等。
这是不一样的,但是,也可以像EnvDTE.CommandEvents一样在上面的变种1中 。
你应该已经知道(见上面)关于这个解决scheme的优先工作与当前types的构build操作…那么为什么不使用这个作为当前问题的主要解决scheme呢?
_cmdEvents.BeforeExecute += (string guid, int id, object customIn, object customOut, ref bool cancelDefault) => { if(UnifiedTypes.Build.VSCommand.existsById(id)) { // ... your action } };
其中: 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 | | |
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/
而且,可选的,如果你需要,你可以禁止这个命令。 在下面的变体中,您将看到完整的解决scheme。
变种5.插件vsCommandEvent
https://visualstudiogallery.msdn.microsoft.com/ad9f19b2-04c0-46fe-9637-9a52ce4ca661/
它还提供了大多数事件的高级处理程序,但与第一个不同的是,它专门用于MS Visual Studio,用于所有命令和输出数据的高级工作。 不仅适用于项目和解决scheme,还适用于整个Visual Studio IDE。
一般来说,这是Variant 4的常见解决scheme,您可以简单地覆盖上面的所有命令来解决这个问题。
对于像vsSolutionBuildEvent中一样的Event-Actions模型,在大多数情况下它可能很有用。
“帮助我的变种”
所有这些变体都有开放的实现。 看到这里,微笑着 :
你可以看看这篇文章: MSBuild:扩展解决scheme构build。
似乎正是你所需要的。
我们通过添加一个空的项目并为这个项目设置构build事件来做到这一点。 然后,您必须将每个项目依赖项都赋予此空项目,以确保每次都能构build它。