c# - argumentos - Suprimir objetivos de AfterBuild cuando no se ha construido un csproj
msbuild project (7)
Tengo un objetivo de creación posterior en MSBuild para copiar algunos resultados de compilación.
Esto está vinculado como una dependencia del objetivo AfterBuild
(expuesto por Microsoft.CSharp.targets
):
<Target Name="AfterBuild" DependsOnTargets="InstallUtil;CopyPostBuildFiles" />
¿Hay alguna forma de evitar que se copien los archivos si la compilación no se reconstruyó?
Por ejemplo, cuando el análisis de dependencias de MSBuild afirma que no es necesario compilar el proyecto porque ninguno de sus archivos fuente se ha actualizado, no se compila, pero aún ejecuta mi copia. hay alguna forma de prevenir esto?
¿Qué tal esto?
- BuildBreak . Se establece en verdadero cuando se produce un error de compilación; de lo contrario, es falso. Puede usarse en objetivos de compilación para determinar si se están ejecutando después de un error de compilación o si se están ejecutando normalmente.
http://blogs.msdn.com/aaronhallberg/archive/2008/02/12/team-build-2008-property-reference.aspx
No lo he intentado, pero parece bastante prometedor.
La definición del objetivo de compilación es:
<Target Name = "Build" DependsOnTargets="BeforeBuild;CoreBuild;AfterBuild"/>
Creo que CoreBuild no se ejecuta si sus archivos no han cambiado, por lo que podría intentar usar AfterCompile en lugar de AfterBuild.
<Target Name="AfterCompile" DependsOnTargets="InstallUtil;CopyPostBuildFiles" />
¿Qué pasa con el uso de las propiedades del objetivo de Entradas y Salidas como se hace en el objetivo de compilación?
<PropertyGroup>
<PostBuildDir>CopiedFilesDirectory</PostBuildDir>
</PropertyGroup>
<Target Name="AfterBuild" DependsOnTargets="InstallUtil;CopyPostBuildFiles" />
<Target Name="CopyPostBuildFiles"
Inputs="@(PostBuildFiles)"
Outputs="@(PostBuildFiles -> ''$(PostBuildDir)%(Filename)%(Extension)''">
<Copy SourceFiles="@(PostBuildFiles)"
DestinationFolder="PostBuildDir"/>
</Target>
Podrías usar eso en CopyPostBuildFiles e InstallUtil o directamente en AfterBuild .
Consulte esta página para obtener más información sobre los objetivos Entradas Salidas
Acabo de buscar en Google esto y encontré esta respuesta de años. Encontré una manera, para hacer esto un poco más fácil, robando una Idea de los objetivos principales. Anule BeforeBuild y AfterBuild y haga algo como:
<Target Name="BeforeBuild">
<PropertyGroup>
<MyBeforeCompileTimestamp>%(IntermediateAssembly.ModifiedTime)
</MyBeforeCompileTimestamp>
</PropertyGroup>
</Target>
<Target Name="AfterBuild">
<CallTarget Condition="$(MyBeforeCompileTimestamp) !=
%(IntermediateAssembly.ModifiedTime)" Targets="MyTarget" />
</Target>
No sé mucho sobre MSBuild, pero en el caso de los proyectos de MSBuild utilizados por Visual Studio para C # hay una alternativa simple: utilizar un evento de compilación Post-build en lugar de un objetivo AfterBuild.
Puede configurar un evento de compilación Post-build a través del diálogo de propiedades del proyecto de Visual Studio, en la tercera pestaña "Build Events". Para algunas situaciones, puede ser una idea ingresar algunos comandos en este cuadro de diálogo y luego editar el archivo .csproj directamente una vez que haya determinado cómo funciona.
Recuerde seleccionar "Ejecutar este evento posterior a la creación: cuando la compilación actualiza la salida del proyecto" en el cuadro de diálogo: esa es la clave para obtener la funcionalidad solicitada por el OP.
Como digo, no sé mucho sobre MSBuild, y puede ser que el evento de compilación Post-build no sea aplicable para algunas cosas que el objetivo de AfterBuild puede hacer. Pero lo he usado para copiar archivos y ejecutar secuencias de comandos BAT, y para eso funciona bien.
EDITAR:
Agregaré algunas notas acerca de cómo suelo usar eventos posteriores a la construcción en mis proyectos de C #.
Para separar diferentes áreas de funcionalidad, normalmente creo un script BAT llamado PostBuildEvent.bat, y lo coloco en la misma carpeta que el archivo .csproj. Entonces mi evento post-build contiene solo dos líneas:
cd $(ProjectDir)
PostBuildEvent.bat
Luego coloco los comandos que quiero en el archivo PostBuildEvent.bat. Aquí hay un ejemplo:
copy "../../../../../Shared Bin/Merlinia.CommonClasses.NamedPipesNative.dll" bin
copy "../../../../../Shared Bin/Merlinia.CommonClasses.NamedPipesNative.pdb" bin
cd Packed-NonObfuscated
call PackForWindowsSystem32-NonObfuscated.bat
cd ../
cd Packed-Obfuscated
call PackForWindowsSystem32-Obfuscated.bat
cd ../
pause
Recuerde que para llamar a un script BAT desde un script BAT especifica explícitamente "call". Tenga en cuenta también el uso de "pausa": esto permite probar el guión haciendo doble clic en el archivo BAT y luego puede ver los mensajes de error en la ventana del cmd. La "pausa" se ignora cuando el script se ejecuta a través de MSBuild.
Ya que está anulando el objetivo AfterBuild, siempre se ejecutará después de que se produzca la compilación. Este es el caso para una reconstrucción o una construcción normal. Si desea realizar algunas acciones después de la reconstrucción (y no compilar), debe extender la propiedad de dependencia para el objetivo de Reconstrucción. Entonces, en su caso para inyectar los objetivos después de que se produce una reconstrucción, su archivo de proyecto debería verse de la siguiente manera:
<Project ...>
<!-- some content here -->
<Import Project="... Microsoft.Csharp.targets" />
<PropertyGroup>
<RebuildDependsOn>
$(RebuildDependsOn);
InstallUtil;
CopyPostBuildFiles
</RebuildDependsOn>
</PropertyGroup>
</Project>
Este método amplía la propiedad que usan los objetivos Rebuild para declarar de qué objetivos depende. He detallado esto en el artículo Dentro de MSBuild , ver la sección Extendiendo el proceso de compilación .
También lo que está tratando de lograr puede lograrse mediante el objetivo AfterBuild si puede especificar qué archivos " activarán " una actualización. En otras palabras, puede especificar un conjunto de "entradas" en el destino y un conjunto de "salidas" que son ambos archivos. Si todas las salidas se crearon después de todas las entradas, entonces el objetivo se consideraría actualizado y omitido. este concepto se conoce como Incremental Building y lo he cubierto en el artículo MSBuild Best Practices Part 2 . También he detallado esto en mi libro, Inside the Microsoft Build Engine: utilizando MS Build Build Team Foundation .
EDITAR: Agregar el ejemplo de BuildDependsOn
Si desea que el destino solo se ejecute cuando los archivos están realmente construidos y no solo cuando se ejecuta el objetivo Rebuild. Entonces deberías crear tu proyecto para que sea como el siguiente:
<Project ...>
<!-- some content here -->
<Import Project="... Microsoft.Csharp.targets" />
<PropertyGroup>
<BuildDependsOn>
$(BuildDependsOn);
CustomAfterBuild;
</BuildDependsOn>
</PropertyGroup>
<Target Name="CustomAfterBuild" Inputs="$(MSBuildAllProjects);
@(Compile);
@(_CoreCompileResourceInputs);
$(ApplicationIcon);
$(AssemblyOriginatorKeyFile);
@(ReferencePath);
@(CompiledLicenseFile);
@(EmbeddedDocumentation);
$(Win32Resource);
$(Win32Manifest);
@(CustomAdditionalCompileInputs)"
Outputs="@(DocFileItem);
@(IntermediateAssembly);
@(_DebugSymbolsIntermediatePath);
$(NonExistentFile);
@(CustomAdditionalCompileOutputs)">
<!-- Content here -->
</Target>
</Project>
Acabo de copiar las entradas y salidas del objetivo CoreCompile dentro de Microsoft.CSharp.targets ( supongo que estás usando C # aquí ) y lo pegué aquí. Lo que esto significa es que el objetivo se omitirá siempre que se ejecute el objetivo CoreCompile . Además, desde que extendí BuildDependsOn, sabemos que MSBuild intentará ejecutarlo cada vez que se construya el proyecto.
Esto invocará el objetivo AfterBuild si y solo si el archivo de destino del proyecto ha sido reconstruido:
<Target Name="AfterBuild"
DependsOnTargets="InstallUtil;CopyPostBuildFiles"
Inputs="$(TargetPath)"
Outputs="$(DeployPath)/$(TargetFileName)" />
Esto supone que ha definido una propiedad $(DeployPath)
que identifica la carpeta donde copió el archivo de salida de destino.