visual-studio 解决方案范围的预构建事件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2295454/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Solution-wide pre-build event?
提问by user200783
I have a solution in Visual Studio which contains several projects. I'd like to run a command at the very beginning of every build - no matter which projects are involved and whether or not they are up-to-date.
我在 Visual Studio 中有一个解决方案,其中包含多个项目。我想在每次构建的最开始运行一个命令 - 无论涉及哪些项目以及它们是否是最新的。
Essentially I need something similar to a solution-wide pre-build event, but unfortunately VS does not appear to support these. Does anyone know an alternative way of achieving what I need?
基本上我需要类似于解决方案范围的预构建事件的东西,但不幸的是 VS 似乎不支持这些。有谁知道实现我需要的替代方法?
采纳答案by Hans Passant
Unusual requirement. But it can be done. Add a new project to your solution, use the Visual C++ > General > Makefile Project template. Set its NMake > Build Command Line setting to the commands you want to execute. Use Project > Project Dependencies to make all other projects depend on it.
不寻常的要求。但这是可以完成的。向您的解决方案添加一个新项目,使用 Visual C++ > General > Makefile Project 模板。将其 NMake > Build Command Line 设置设置为您要执行的命令。使用 Project > Project Dependencies 使所有其他项目都依赖于它。
回答by Denis Kuzmin
Short overview of my variants below
下面我的变体的简短概述
just a note: it is incomplete list of all existing (see also other answers etc.), I only support my original tricks in actual state...
只是一个说明:它是所有现有的不完整列表(另见其他答案等),我只支持我在实际状态下的原始技巧......
Notes:
笔记:
- 1- Requires no any additional extensions. But it may work only via projects-level so we use it for emulating the our solution-level... It is hard and inconvenient for common solution, but is variant. See below.
- 2- The original engine of vsSolutionBuildEvent provides a few ways of unified support of the VS and msbuild.exe. A simple way the
targets modeto call theafter.<name>.sln.targetsthat available only for msbuild.exe (this does not requires additional steps, simply action). But only original engine (inc. vsCommandEvent) may allow additional scripting which support for example (7zip archiver, packing of nuget package without nuget.exe, remote servers etc.). However, it's not important for our question/problem and you can use any available option to support the solution-level if you see+above.
- 1- 不需要任何额外的扩展。但它可能只能通过项目级别工作,所以我们用它来模拟我们的解决方案级别......通用解决方案很难且不方便,但它是变体。见下文。
- 2- vsSolutionBuildEvent 的原始引擎提供了几种方式统一支持VS 和msbuild.exe。
targets mode调用after.<name>.sln.targets仅适用于 msbuild.exe的简单方法(这不需要额外的步骤,只需操作)。但只有原始引擎(包括 vsCommandEvent)可能允许额外的脚本支持,例如(7zip 存档器、没有 nuget.exe 的 nuget 包的打包、远程服务器等)。但是,这对于我们的问题/问题并不重要,如果您看到+上述内容,您可以使用任何可用选项来支持解决方案级别。
Variant 1: Microsoft.VisualStudio.Shell.Interop
变体 1:Microsoft.VisualStudio.Shell.Interop
This variant is not for simple users of VS. However, it can be useful for your complete solution etc.
此变体不适用于 VS 的简单用户。但是,它对您的完整解决方案等很有用。
You should implement, for example:
您应该实施,例如:
e.g:
例如:
public sealed class YourPackage: Package, IVsSolutionEvents, IVsUpdateSolutionEvents2
{
...
public int UpdateSolution_Begin(ref int pfCancelUpdate)
{
//TODO:
}
}
Then, register handler with 'Advise' methods as priority listener, i.e. for IVsUpdateSolutionEvents2you should use the AdviseUpdateSolutionEvents
然后,将带有“Advise”方法的处理程序注册为优先级侦听器,即对于IVsUpdateSolutionEvents2,您应该使用AdviseUpdateSolutionEvents
It is important, because the BuildEvents(see EnvDTE) - probably will not help and may work too late - Example
这很重要,因为BuildEvents(请参阅EnvDTE)- 可能无济于事并且可能工作得太晚-示例
Sample with AdviseUpdateSolutionEvents:
带有 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);
Where:
在哪里:
- the
sbmfield should be as part of class for protection from GC. - to get the SVsSolutionBuildManager service is used the ServiceProvider but it can be as you need. See msdn
- 该
sbm字段应作为防止 GC 的类的一部分。 - 使用 ServiceProvider 来获取 SVsSolutionBuildManager 服务,但它可以根据您的需要。见msdn
Now we can work with all projects at once - solution-level.
现在我们可以同时处理所有项目 - 解决方案级别。
Variant 2: Targets & Map of projects.
变体 2:目标和项目地图。
ok, you love something like this - MSBuild: Extending the solution build, but this variant may work with build processes from msbuild.exe and not from VS IDE...
好的,你喜欢这样的东西 - MSBuild:扩展解决方案构建,但这个变体可能适用于来自 msbuild.exe 而不是来自 VS IDE 的构建过程......
But the VS is also uses targets (Build, Rebuild, Clean, ..) in project files (*.csproj, *.vcxproj, ..) when the build-operations is started. So we can also try this, but remember:
但是当构建操作启动时,VS 也在项目文件(*.csproj、*.vcxproj、..)中使用目标(构建、重建、清理、..)。所以我们也可以试试这个,但请记住:
- The VS is also ignores amazing .sln file. It forms the all end-targets from loaded environment with EnvDTE etc.
- The .sln should processed by msbuild.exe only as: automatically generate the .metaproj (in memory by default), which contains 'what and when' will be built. Including a common targets for all projects if exists, for example:
- VS 也忽略了惊人的 .sln 文件。它使用 EnvDTE 等从加载环境中形成所有最终目标。
- .sln 应由 msbuild.exe 仅处理为:自动生成 .metaproj(默认情况下在内存中),其中包含将构建的“内容和时间”。如果存在,包括所有项目的共同目标,例如:
...
<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" />
- And yes, the .metaproj is also cannot be viewed by VS IDE.
- 是的,VS IDE 也无法查看 .metaproj。
Therefore, for work with common targets from VS IDE you can use only project files with some limitation (without modification/extending of VS, it means).
因此,对于来自 VS IDE 的常见目标,您只能使用具有某些限制的项目文件(这意味着无需修改/扩展 VS)。
And so, if you need the common solution (i.e. you may not know about projects etc. - this can be, for example, for some box solutions and similar):
因此,如果您需要通用解决方案(即您可能不了解项目等 -例如,对于某些盒式解决方案和类似解决方案):
- Add your common .targets file into all your projects (it can be automatically with any tool, inc. the NuGet eventsetc.) , for example:
<Import Project="..\<SolutionFile>.targets" /> - Then, you should use some limitation for:
- "only - before all projects"
- "only - after all projects"
- 将您的通用 .targets 文件添加到您的所有项目中(它可以通过任何工具自动添加,包括NuGet 事件等),例如:
<Import Project="..\<SolutionFile>.targets" /> - 然后,您应该使用一些限制:
- “仅 - 在所有项目之前”
- “只有——毕竟是项目”
And for example, yes, it can be the 'Map of projects':
例如,是的,它可以是“项目地图”:
- The 'Map of projects'illustrates the solution-wide PRE/POST 'events' for build-operations from Visual Studio IDE (i.e. primary from VS IDE)
- 在“项目地图”说明了解决方案宽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>
...
In general, we'll use the map of projects and now we know 'what and when' should happen. It's safe for all or most cases (changes of build order or removing the any projects from solution). However! you should manage <Import>section for new projects in first init. This is really inconvenient, but is also variant...
通常,我们将使用项目地图,现在我们知道应该发生什么以及何时发生。对于所有或大多数情况(更改构建顺序或从解决方案中删除任何项目)都是安全的。然而!您应该<Import>在第一个 init 中管理新项目的部分。这真的很不方便,但也是变种......
Variant 3: Plugin vsSolutionBuildEvent
变体 3:插件 vsSolutionBuildEvent
Today it is the most complete solution for work with a lot of events as the Events-Catcher with a variety of advanced actions for maintenance of your projects and libraries, building processes and processes at runtime from your Visual Studio and MSBuild Tool.
今天,它是处理大量事件的最完整的解决方案,作为事件捕获器,它具有各种高级操作,用于维护您的项目和库、从 Visual Studio 和 MSBuild 工具在运行时构建流程和流程。
Different action types for all subprojects at once in solution as Solution-Events or individually for each.
解决方案中所有子项目的不同操作类型作为解决方案事件或单独用于每个。
https://visualstudiogallery.msdn.microsoft.com/0d1dbfd7-ed8a-40af-ae39-281bfeca2334/
https://visualstudiogallery.msdn.microsoft.com/0d1dbfd7-ed8a-40af-ae39-281bfeca2334/
How it works inside
内部如何运作
If you want to use the Variant 1above or need to see how to work with Shell.Interop, EnvDTE, IVsUpdateSolutionEvents2, MSBuild Engine etc., see here:
如果您想使用上面的变体 1或需要了解如何使用 Shell.Interop、EnvDTE、IVsUpdateSolutionEvents2、MSBuild Engine 等,请参见此处:
Variant 4. EnvDTE.CommandEvents
变体 4. EnvDTE.CommandEvents
This variant is also not for simple users of VS. However, as for Variant 1it can be useful for your box-solution etc.
此变体也不适用于 VS 的简单用户。但是,对于变体 1,它对您的盒子解决方案等很有用。
It is not the same, but yes, it's also possible with EnvDTE.CommandEventslike in Variant 1above.
它不一样,但是是的,它也可以使用EnvDTE.CommandEvents,就像上面的变体 1一样。
You should already know (see above) about this solutionfor priority work with current type of the build action... So why not to use this as primary solution for current problem ?
您应该已经知道(见上文)有关当前构建操作类型的优先工作的解决方案......那么为什么不将其用作当前问题的主要解决方案呢?
_cmdEvents.BeforeExecute += (string guid, int id, object customIn, object customOut, ref bool cancelDefault) => {
if(UnifiedTypes.Build.VSCommand.existsById(id)) {
// ... your action
}
};
Where:
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/
http://vsce.r-eg.net/doc/Features/Solution-wide/
Moreover, optional you can suppress this commands if you need. In variant below you will see the complete solution for this way.
此外,如果需要,您可以选择取消此命令。在下面的变体中,您将看到这种方式的完整解决方案。
Variant 5. Plugin vsCommandEvent
变体 5. 插件 vsCommandEvent
https://visualstudiogallery.msdn.microsoft.com/ad9f19b2-04c0-46fe-9637-9a52ce4ca661/
https://visualstudiogallery.msdn.microsoft.com/ad9f19b2-04c0-46fe-9637-9a52ce4ca661/
It also presents advanced handler of most events, but unlike the first it specialized for MS Visual Studio for advanced work with all commands and output data as manager of this. Not only for projects and solutions, but also for the whole Visual studio IDE.
它还提供了大多数事件的高级处理程序,但与第一个不同的是,它专门为 MS Visual Studio 提供高级处理所有命令和输出数据的管理器。不仅适用于项目和解决方案,还适用于整个 Visual Studio IDE。
In general, it is the common solution of Variant 4and you can simply override all commands above to solve this problem.
总的来说,这是变体4的通用解决方案,你可以简单地覆盖上面的所有命令来解决这个问题。
And for the same Event-Actions model like in vsSolutionBuildEvent it can be useful for most cases.
对于与 vsSolutionBuildEvent 中相同的 Event-Actions 模型,它在大多数情况下都很有用。
"Help me with variants"
“帮我弄个变种”
There are open implementation for all these variants. See here and smile:
所有这些变体都有开放的实现。看到这里并微笑:
回答by Andriy K
You can take a look on this article: MSBuild: Extending the solution build.
您可以查看这篇文章:MSBuild:扩展解决方案构建。
Seems to be exactly what you need.
似乎正是您所需要的。
回答by erelender
We do this by adding an empty project and setting build events for this project. Then you have to give each project dependency to this empty project to make sure that it gets built everytime.
为此,我们添加一个空项目并为此项目设置构建事件。然后,您必须将每个项目依赖项赋予这个空项目,以确保它每次都被构建。
回答by Andriy K
It's been a while, and some things in .Net infrastructure changed since, giving new options. Now my choice for solving this king of problem are nuget packages. I put my build steps into package which then included into every single project. Helpfully, Visual Studio package manager gives overview of packages on solution level, so it's pretty easy to check this rule.
已经有一段时间了,.Net 基础设施中的一些东西从那以后发生了变化,提供了新的选择。现在我选择解决这个问题之王是 nuget 包。我将构建步骤放入包中,然后将其包含到每个项目中。有用的是,Visual Studio 包管理器提供了解决方案级别的包概述,因此很容易检查此规则。
回答by James Close
Another old post but inspired by @reg solution I wanted to run a simple build timer that would log the elapsed time for a solution build. I got the build events working using a powershell module which I load via the package manager console when the Visual Studio IDE starts.
另一个旧帖子,但受到@reg 解决方案的启发,我想运行一个简单的构建计时器,该计时器将记录解决方案构建的经过时间。我使用 powershell 模块运行构建事件,当 Visual Studio IDE 启动时,我通过包管理器控制台加载该模块。
So create a powershell module like BuildEvents.psm1:
所以创建一个powershell模块,如BuildEvents.psm1:
<#
.SYNOPSIS
Register solution build events
.DESCRIPTION
Registers the OnBuildBegin and OnBuildDone events for the entire solution
De-registers the events if called multiple times.
.EXAMPLE
RegisterBuildEvents
#>
function RegisterBuildEvents{
try {
Unregister-Event -SourceIdentifier "OnBuildBegin" -Force
} catch {
#we don't care if this doesn't work
}
try {
Unregister-Event -SourceIdentifier "OnBuildDone" -Force
} catch {
#we don't care if this doesn't work
}
$obj = [System.Runtime.InteropServices.Marshal]::CreateWrapperOfType($dte.Application.Events.BuildEvents, [EnvDTE.BuildEventsClass])
Register-ObjectEvent -InputObject $obj -EventName OnBuildBegin -Action {
# do stuff here on build begin
Write-Host "Solution build started!"
} -SourceIdentifier "OnBuildBegin"
Register-ObjectEvent -InputObject $obj -EventName OnBuildDone -Action {
# do stuff here on build done
Write-Host "Solution build done!"
} -SourceIdentifier "OnBuildDone"
}
# export the functions from the module
export-modulemember -function RegisterBuildEvents
Import the module when the Package Manager host initialises:
在包管理器主机初始化时导入模块:
- In the package manager console type $profile to get the location of your powershell profile
- Browse to that directory on disk, if there is no file there create
one with the name returned by the above command (e.g.
NuGet_profile.ps1) Open the file in notepad and add the following lines
Import-Module -Name <Path to your ps module>\BuildEvents -Force RegisterBuildEvents
- 在包管理器控制台中键入 $profile 以获取您的 powershell 配置文件的位置
- 浏览到磁盘上的该目录,如果没有文件,则使用上述命令返回的名称创建一个文件(例如
NuGet_profile.ps1) 在记事本中打开文件并添加以下行
Import-Module -Name <Path to your ps module>\BuildEvents -Force RegisterBuildEvents


