¿Evento de pre-construcción para toda la solución?


Tengo una solución en Visual Studio que contiene varios proyectos. Me gustaría ejecutar un comando al principio de cada compilación, sin importar qué proyectos estén involucrados y si están actualizados o no.

Esencialmente necesito algo similar a un evento de pre-construcción de toda la solución, pero desafortunadamente VS no parece admitir estos. ¿Alguien conoce una forma alternativa de lograr lo que necesito?

Author: Andreas Niedermair, 2010-02-19

6 answers

Requisito Inusual. Pero se puede hacer. Agregue un nuevo proyecto a su solución, utilice la plantilla de proyecto Visual C++ > General > Makefile. Establezca su configuración NMake > Build de línea de comandos en los comandos que desea ejecutar. Use Proyecto > Dependencias del proyecto para hacer que todos los demás proyectos dependan de él.

 41
Author: Hans Passant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-08-07 22:18:10

Breve descripción de mis variantes a continuación

solo una nota: es una lista incompleta de todos los existentes (ver también otras respuestas, etc.), solo apoyo mis trucos originales en estado real...

Resumen

Notas:

  • 1 - No requiere ninguna extensión adicional. Pero puede funcionar solo a nivel de proyectos, por lo que lo usamos para emular nuestro nivel de solución... Es difícil e inconveniente para la solución común, pero es variante. Véase más adelante.
  • 2 - El motor original de vsSolutionBuildEvent proporciona algunas formas de soporte unificado de VS y msbuild.exe. Una forma sencilla de llamar al targets mode after.<name>.sln.targets eso solo está disponible para msbuild.exe (esto no requiere pasos adicionales, simplemente acción). Pero solo el motor original (inc. vsCommandEvent) puede permitir secuencias de comandos adicionales que soportan, por ejemplo (archivador 7zip, empaquetamiento de paquetes nuget sin nuget.exe, servidores remotos, etc.). Sin embargo, no es importante para nuestra pregunta/problema y puede usar cualquier opción disponible para soportar el nivel de solución si ve + arriba.

Variante 1: Microsoft.VisualStudio.Shell.Interop

Esta variante no es para usuarios simples de VS. Sin embargo, puede ser útil para su solución completa, etc.

Debe implementar, por ejemplo:

Ej:

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

Luego, registre el manejador con los métodos' Advise ' como oyente prioritario, es decir, para IVsUpdateSolutionEvents2 debe usar el AdviseUpdateSolutionEvents

Es importante, debido a que el BuildEvents (ver EnvDTE) - probablemente no ayuda y puede trabajar demasiado tarde - Ejemplo

Muestra con Advise Updatesolutionevents:

// 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);

Donde:

  • el campo sbm debe formar parte de la clase de protección contra GC.
  • para obtener el servicio SVsSolutionBuildManager se utiliza el ServiceProvider pero puede ser como usted necesita. Véase msdn

Ahora podemos trabajar con todos los proyectos a la vez - nivel de solución.

Variante 2: Objetivos y Mapa de proyectos.

Ok, te encanta algo como esto - MSBuild: Extendiendo la solución build , pero esta variante puede funcionar con procesos de compilación desde msbuild.exe y no de VS IDE...

Pero el VS is también utiliza objetivos (Build, Rebuild, Clean,..) en archivos de proyecto (*.csproj, *.vcxproj, ..) cuando se inician las operaciones de compilación. Así que también podemos probar esto, pero recuerde:

  • El VS también ignora lo asombroso .archivo sln. Forma todos los objetivos finales del entorno cargado con EnvDTE, etc.
  • El.sln debe ser procesado por msbuild.exe solo como: generar automáticamente el .metaproj (en memoria por defecto), que contiene 'qué y cuándo' será construido. Incluyendo un objetivo común para todos los proyectos si existe, por ejemplo:
...
<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" />
  • Y sí, el .metaproj tampoco puede ser visto por VS IDE.

Por lo tanto, para trabajar con objetivos comunes desde VS IDE, solo puede usar archivos de proyecto con alguna limitación (sin modificación/extensión de VS, significa).

Y así, si usted necesita el solución común (es decir, es posible que no sepa sobre proyectos, etc. - esto puede ser, por ejemplo, para algunas soluciones de caja y similares):

  • Añade tu común .archivos de destino en todos sus proyectos(puede ser automáticamente con cualquier herramienta, inc. los eventos NuGet etc.) , por ejemplo: <Import Project="..\<SolutionFile>.targets" />
  • Entonces, debe usar alguna limitación para:
    • "solo - antes de todos los proyectos"
    • "solo - después de todos los proyectos"

Y para ejemplo, sí, puede ser el 'Mapa de proyectos':

  • El 'Mapa de proyectos' ilustra los 'eventos' PRE/POST de toda la solución para las operaciones de compilación desde Visual Studio IDE (es decir, primario desde 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>
...

En general, usaremos el mapa de proyectos y ahora sabemos 'qué y cuándo' debería suceder. Es seguro para todos o la mayoría de los casos (cambios de orden de compilación o eliminación de cualquier proyecto de la solución). Sin embargo! debe administrar la sección <Import> para nuevos proyectos en primera init. Esto es realmente inconveniente, pero también es variante...

Variante 3: Plugin vsSolutionBuildEvent

Hoy en día es la solución más completa para trabajar con una gran cantidad de eventos como el Events-Catcher con una variedad de acciones avanzadas para el mantenimiento de sus proyectos y bibliotecas, procesos de construcción y procesos en tiempo de ejecución desde su herramienta Visual Studio y MSBuild.

Diferentes tipos de acción para todos los subproyectos a la vez en solución como Solución-Eventos o individualmente para cada uno.

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

plugin-vsSolutionBuildEvent

Cómo funciona dentro

Si desea utilizar la variante 1 anterior o necesita ver cómo trabajar con Shell.Interop, EnvDTE, IVsUpdateSolutionEvents2, motor de MSBuild etc., ver aquí:

Esquema

Variante 4. EnvDTE.CommandEvents

Esto la variante tampoco es para usuarios simples de VS. Sin embargo, en cuanto a La Variante 1 puede ser útil para su box-solution, etc.

No es lo mismo, pero sí, también es posible con EnvDTE.CommandEvents como en Variante 1 anterior.

Ya debería saber (ver arriba) acerca de esta solución para el trabajo prioritario con el tipo actual de la acción de compilación... Entonces, ¿por qué no usar esto como solución primaria para el problema actual ?

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

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

};

Donde: 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 /

Además, opcional puede suprimir estos comandos si lo necesita. En la variante a continuación verá la solución completa para esta manera.

Variante 5. Plugin vsCommandEvent

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

También presenta manejador avanzado de la mayoría de los eventos, pero a diferencia el primero se especializó para MS Visual Studio para trabajos avanzados con todos los comandos y datos de salida como gestor de este. No solo para proyectos y soluciones, sino también para todo el IDE de Visual studio.

En general, es la solución común de Variante 4 y simplemente puede anular todos los comandos anteriores para resolver este problema.

Y para el mismo modelo de Acciones de eventos como en vsSolutionBuildEvent puede ser útil para la mayoría caso.

Esquema

"Ayúdame con las variantes"

Hay implementación abierta para todas estas variantes. Ver aquí y sonreír :

 40
Author: reg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:41

Puede echar un vistazo a este artículo: MSBuild: Extending the solution build.

Parece ser exactamente lo que necesitas.

 17
Author: Andriy K,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-19 17:49:38

Hacemos esto agregando un proyecto vacío y configurando eventos de compilación para este proyecto. Luego tienes que darle a cada proyecto dependencia a este proyecto vacío para asegurarte de que se construye cada vez.

 9
Author: erelender,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-19 10:24:35

Ha pasado un tiempo, y algunas cosas en la infraestructura.Net cambiaron desde entonces, dando nuevas opciones. Ahora mi elección para resolver este problema son los paquetes nuget. Puse mis pasos de compilación en un paquete que luego se incluyó en cada proyecto. De manera útil, Visual Studio Package manager ofrece una visión general de los paquetes a nivel de solución, por lo que es bastante fácil verificar esta regla.

 0
Author: Andriy K,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-05 18:30:21

Otro post antiguo, pero inspirado por la solución @reg, quería ejecutar un temporizador de compilación simple que registrara el tiempo transcurrido para una compilación de solución. Tengo los eventos de compilación trabajando con un módulo de Powershell que cargo a través de la consola del administrador de paquetes cuando se inicia el IDE de Visual Studio.

Así que crea un módulo de powershell como 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

Importe el módulo cuando el host Gestor de paquetes se inicie:

  1. En la consola del administrador de paquetes escriba profile profile para obtener la ubicación de su perfil de powershell
  2. Busque ese directorio en el disco, si no hay ningún archivo allí crear uno con el nombre devuelto por el comando anterior (por ejemplo, NuGet_profile.ps1)
  3. Abra el archivo en el bloc de notas y agregue las siguientes líneas

    Import-Module -Name <Path to your ps module>\BuildEvents -Force
    RegisterBuildEvents
    
 0
Author: James Close,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-24 09:39:36