Personalizar una compilaciónCustomize your build

Los proyectos de MSBuild que usan el proceso de compilación estándar (la importación de Microsoft.Common.props y Microsoft.Common.targets) tienen varios enlaces de extensibilidad que se pueden usar para personalizar el proceso de compilación.MSBuild projects that use the standard build process (importing Microsoft.Common.props and Microsoft.Common.targets) have several extensibility hooks that you can use to customize your build process.

Adición de argumentos a las invocaciones de MSBuild de línea de comandos para el proyectoAdd arguments to command-line MSBuild invocations for your project

Un archivo Directory.Build.rsp en el directorio de origen o por encima se aplica a las compilaciones de línea de comandos del proyecto.A Directory.Build.rsp file in or above your source directory will be applied to command-line builds of your project. Para obtener más información, vea Archivos de respuesta de MSBuild.For details, see MSBuild response files.

Directory.Build.props y Directory.Build.targetsDirectory.Build.props and Directory.Build.targets

Antes de la versión 15 de MSBuild, si quería proporcionar una nueva propiedad personalizada a los proyectos de la solución, tenía que agregar manualmente una referencia a esa propiedad en cada archivo de proyecto de la solución.Prior to MSBuild version 15, if you wanted to provide a new, custom property to projects in your solution, you had to manually add a reference to that property to every project file in the solution. O, tenía que definir la propiedad en un archivo .props y, después, importar explícitamente el archivo .props en cada proyecto de la solución, entre otras cosas.Or, you had to define the property in a .props file and then explicitly import the .props file in every project in the solution, among other things.

Pero ahora se puede agregar una propiedad nueva a cada proyecto en un paso si se define en un único archivo denominado Directory.Build.props en la carpeta raíz que contiene el código fuente.However, now you can add a new property to every project in one step by defining it in a single file called Directory.Build.props in the root folder that contains your source. Cuando se ejecuta MSBuild, Microsoft.Common.props busca su estructura de directorio para el archivo Directory.Build.props (y Microsoft.Common.targets busca Directory.Build.targets).When MSBuild runs, Microsoft.Common.props searches your directory structure for the Directory.Build.props file (and Microsoft.Common.targets looks for Directory.Build.targets). Si encuentra uno, importa la propiedad.If it finds one, it imports the property. Directory.Build.props es un archivo definido por el usuario que proporciona personalizaciones a los proyectos de un directorio.Directory.Build.props is a user-defined file that provides customizations to projects under a directory.

Note

Los sistemas de archivos basados en Linux distinguen mayúsculas de minúsculas.Linux-based file systems are case-sensitive. Asegúrese de que las mayúsculas y minúsculas del nombre del archivo Directory.Build.props coincidan de manera exacta o no se detectará durante el proceso de compilación.Make sure the casing of the Directory.Build.props filename matches exactly, or it won't be detected during the build process.

Consulte este problema de GitHub para más información.See this GitHub issue for more information.

Ejemplo de Directory.Build.propsDirectory.Build.props example

Por ejemplo, si quisiera permitir que todos sus proyectos tuvieran acceso a la nueva característica /deterministic de Roslyn (que se expone en el destino CoreCompile de Roslyn mediante la propiedad $(Deterministic)), podría realizar lo siguiente.For example, if you wanted to enable all of your projects to access the new Roslyn /deterministic feature (which is exposed in the Roslyn CoreCompile target by the property $(Deterministic)), you could do the following.

  1. Crear un archivo en la raíz de su repositorio denominado Directory.Build.props.Create a new file in the root of your repo called Directory.Build.props.

  2. Agregar el siguiente XML al archivo.Add the following XML to the file.

    <Project>
     <PropertyGroup>
       <Deterministic>true</Deterministic>
     </PropertyGroup>
    </Project>
    
  3. Ejecutar MSBuild.Run MSBuild. Las importaciones existentes del proyecto de Microsoft.Common.props y Microsoft.Common.targets encuentran el archivo y lo importan.Your project’s existing imports of Microsoft.Common.props and Microsoft.Common.targets find the file and import it.

Ámbito de búsquedaSearch scope

Al buscar el archivo Directory.Build.props, MSBuild recorre la estructura del directorio hacia arriba desde la ubicación del proyecto ($(MSBuildProjectFullPath)), deteniéndose después de que encuentra un archivo Directory.Build.props.When searching for a Directory.Build.props file, MSBuild walks the directory structure upwards from your project location ($(MSBuildProjectFullPath)), stopping after it locates a Directory.Build.props file. Por ejemplo, si su $(MSBuildProjectFullPath) fuera c:\users\username\code\test\case1, MSBuild empezaría a buscar allí y, después, buscaría en la estructura del directorio hacia arriba hasta que encontrara un archivo Directory.Build.props, como en la siguiente estructura de directorio.For example, if your $(MSBuildProjectFullPath) was c:\users\username\code\test\case1, MSBuild would start searching there and then search the directory structure upward until it located a Directory.Build.props file, as in the following directory structure.

c:\users\username\code\test\case1
c:\users\username\code\test
c:\users\username\code
c:\users\username
c:\users
c:\

La ubicación del archivo de solución es irrelevante para Directory.Build.props.The location of the solution file is irrelevant to Directory.Build.props.

Orden de importaciónImport order

Directory.Build.props se importa muy pronto en Microsoft.Common.props, y las propiedades definidas después no están disponibles en él.Directory.Build.props is imported very early in Microsoft.Common.props, and properties defined later are unavailable to it. Por tanto, evite hacer referencia a propiedades que todavía no están definidas (y que se van a evaluar como vacías).So, avoid referring to properties that are not yet defined (and will evaluate to empty).

Directory.Build.targets se importa desde Microsoft.Common.targets después de importar los archivos .targets de paquetes NuGet.Directory.Build.targets is imported from Microsoft.Common.targets after importing .targets files from NuGet packages. Por tanto, puede reemplazar propiedades y destinos definidos en la mayoría de la lógica de compilación, pero a veces puede que necesite personalizar el archivo de proyecto después de la importación final.So, it can override properties and targets defined in most of the build logic, but sometimes you may need to customize the project file after the final import.

Caso de uso: combinación de varios nivelesUse case: multi-level merging

Imagínese que tiene esta estructura de solución estándar:Suppose you have this standard solution structure:

\
  MySolution.sln
  Directory.Build.props     (1)
  \src
    Directory.Build.props   (2-src)
    \Project1
    \Project2
  \test
    Directory.Build.props   (2-test)
    \Project1Tests
    \Project2Tests

Puede que convenga tener propiedades comunes para todos los proyectos (1) , propiedades comunes para los proyectos src (2-src) y propiedades comunes para los proyectos test (2-test) .It might be desirable to have common properties for all projects (1), common properties for src projects (2-src), and common properties for test projects (2-test).

Para que MSBuild combine correctamente los archivos "internos" (2-src y 2-test) con el archivo "externo" (1), debe tener en cuenta que, cuando MSBuild encuentra un archivo Directory.Build.props, detiene el análisis.To make MSBuild correctly merge the "inner" files (2-src and 2-test) with the "outer" file (1), you must take into account that once MSBuild finds a Directory.Build.props file, it stops further scanning. Para continuar con el análisis y efectuar la combinación con el archivo externo, coloque este código en ambos archivos internos:To continue scanning and merge into the outer file, place this code into both inner files:

<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" />

A continuación tiene un resumen del enfoque general de MSBuild:A summary of MSBuild's general approach is as follows:

  • Para un proyecto dado, MSBuild busca el primer Directory.Build.props hacia arriba en la estructura de la solución, lo combina con valores predeterminados y detiene el análisis.For any given project, MSBuild finds the first Directory.Build.props upward in the solution structure, merges it with defaults, and stops scanning for more
  • Si quiere que se busquen y combinen varios niveles, efectúe una <Import...> (que se muestra arriba) del archivo "externo" desde el archivo "interno".If you want multiple levels to be found and merged, then <Import...> (shown above) the "outer" file from the "inner" file
  • Si el archivo "externo" no importa algo por encima de él, el análisis se detendrá en ese punto.If the "outer" file does not itself also import something above it, then scanning stops there
  • Para controlar el proceso de análisis/combinación, use $(DirectoryBuildPropsPath) e $(ImportDirectoryBuildProps).To control the scanning/merging process, use $(DirectoryBuildPropsPath) and $(ImportDirectoryBuildProps)

O más sencillo: el primer Directory.Build.props que no importa nada es donde se detiene MSBuild.Or more simply: the first Directory.Build.props that doesn't import anything is where MSBuild stops.

Elección entre la adición de propiedades a un archivo .props o .targetsChoose between adding properties to a .props or .targets file

MSBuild depende del orden de importación y la última definición de una propiedad (o una UsingTask o destino) es la definición usada.MSBuild is import-order dependent, and the last definition of a property (or a UsingTask or target) is the definition used.

Al usar importaciones explícitas, puede importar desde un archivo .props o .targets en cualquier momento.When using explicit imports, you can import from a .props or .targets file at any point. Esta es la convención que se usa ampliamente:Here is the widely used convention:

  • Los archivos .props se importan de forma temprana en el orden de importación..props files are imported early in the import order.

  • Los archivos .targets se importan de forma tardía en el orden de compilación..targets files are imported late in the build order.

Las importaciones <Project Sdk="SdkName"> aplican esta convención (es decir, primero se muestra la importación de Sdk.props, antes que todo el contenido del archivo, para después hacerlo la de Sdk.targets, después de todo este contenido).This convention is enforced by <Project Sdk="SdkName"> imports (that is, the import of Sdk.props comes first, before all of the contents of the file, then Sdk.targets comes last, after all of the contents of the file).

Para decidir dónde colocar las propiedades, use las siguientes instrucciones generales:When deciding where to put the properties, use the following general guidelines:

  • En el caso de que sean muchas las propiedades, no importa dónde se definan, ya que no se sobrescriben y serán de solo lectura en tiempo de ejecución.For many properties, it doesn't matter where they're defined, because they're not overwritten and will be read only at execution time.

  • Para un comportamiento que podría personalizarse en un proyecto individual, establezca valores predeterminados en los archivos .props.For behavior that might be customized in an individual project, set defaults in .props files.

  • Evite el establecimiento de propiedades dependientes en los archivos .props leyendo el valor de una propiedad posiblemente personalizada, ya que la personalización no tendrá lugar hasta que MSBuild lea el proyecto del usuario.Avoid setting dependent properties in .props files by reading the value of a possibly customized property, because the customization won't happen until MSBuild reads the user's project.

  • Establezca propiedades dependientes en los archivos .targets, ya que recogerán personalizaciones de proyectos individuales.Set dependent properties in .targets files, because they'll pick up customizations from individual projects.

  • Si tiene que reemplazar propiedades, hágalo en un archivo .targets, después de que todas las personalizaciones de proyecto de usuario hayan tenido la oportunidad de surtir efecto.If you need to override properties, do it in a .targets file, after all user-project customizations have had a chance to take effect. Tenga cuidado al usar propiedades derivadas, ya que también puede ser necesario reemplazarlas.Be cautious when using derived properties; derived properties may need to be overridden as well.

  • Incluya elementos en los archivos .props (condicionados por una propiedad).Include items in .props files (conditioned on a property). Se tienen en cuenta todas las propiedades antes que cualquier artículo, por lo que se recogen personalizaciones de propiedades de proyecto de usuario, lo que proporciona al proyecto del usuario la oportunidad de Remove o Update cualquier elemento incorporado por la importación.All properties are considered before any item, so user-project property customizations get picked up, and this gives the user's project the opportunity to Remove or Update any item brought in by the import.

  • Defina los destinos en los archivos .targets.Define targets in .targets files. Sin embargo, si un SDK importa el archivo .targets, recuerde que este escenario aumenta la dificultad del reemplazo del destino, ya que el proyecto del usuario carece de un lugar para reemplazarlo de forma predeterminada.However, if the .targets file is imported by an SDK, remember that this scenario makes overriding the target more difficult because the user's project doesn't have a place to override it by default.

  • Si es posible, opte por la personalización de propiedades en tiempo de evaluación en lugar del cambio de las mismas dentro de un destino.If possible, prefer customizing properties at evaluation time over changing properties inside a target. Esta instrucción hace que resulte más fácil cargar un proyecto y saber lo que hace.This guideline makes it easier to load a project and understand what it's doing.

MSBuildProjectExtensionsPathMSBuildProjectExtensionsPath

De forma predeterminada, Microsoft.Common.props importa $(MSBuildProjectExtensionsPath)$(MSBuildProjectFile).*.props y Microsoft.Common.targets importa $(MSBuildProjectExtensionsPath)$(MSBuildProjectFile).*.targets.By default, Microsoft.Common.props imports $(MSBuildProjectExtensionsPath)$(MSBuildProjectFile).*.props and Microsoft.Common.targets imports $(MSBuildProjectExtensionsPath)$(MSBuildProjectFile).*.targets. El valor predeterminado de MSBuildProjectExtensionsPath es $(BaseIntermediateOutputPath), obj/.The default value of MSBuildProjectExtensionsPath is $(BaseIntermediateOutputPath), obj/. NuGet usa este mecanismo para hacer referencia a la lógica de compilación que se entrega con paquetes, es decir, en tiempo de restauración, crea archivos {project}.nuget.g.props que hacen referencia al contenido del paquete.NuGet uses this mechanism to refer to build logic delivered with packages; that is, at restore time, it creates {project}.nuget.g.props files that refer to the package contents.

Puede deshabilitar este mecanismo de extensibilidad si establece la propiedad ImportProjectExtensionProps en false en Directory.Build.props o antes de importar Microsoft.Common.props.You can disable this extensibility mechanism by setting the property ImportProjectExtensionProps to false in a Directory.Build.props or before importing Microsoft.Common.props.

Note

La deshabilitación de las importaciones de MSBuildProjectExtensionsPath impedirá que la lógica de compilación que se entrega en los paquetes NuGet se aplique al proyecto.Disabling MSBuildProjectExtensionsPath imports will prevent build logic delivered in NuGet packages from applying to your project. Algunos paquetes NuGet requieren lógica de compilación para realizar su función y quedarán inutilizados si se deshabilita esta opción.Some NuGet packages require build logic to perform their function and will be rendered useless when this is disabled.

El archivo .user.user file

Microsoft.Common.CurrentVersion.targets importa $(MSBuildProjectFullPath).user, si existe, para que pueda crear un archivo junto al proyecto con esa extensión adicional.Microsoft.Common.CurrentVersion.targets imports $(MSBuildProjectFullPath).user if it exists, so you can create a file next to your project with that additional extension. Para cambios a largo plazo que se van a insertar en el repositorio de control de código fuente, es preferible cambiar el propio proyecto, para que en el futuro los encargados del mantenimiento no tengan que conocer este mecanismo de extensión.For long-term changes you plan to check into source control, prefer changing the project itself, so that future maintainers do not have to know about this extension mechanism.

MSBuildExtensionsPath y MSBuildUserExtensionsPathMSBuildExtensionsPath and MSBuildUserExtensionsPath

Warning

El uso de estos mecanismos de extensión hace más difícil obtener compilaciones repetibles entre equipos.Using these extension mechanisms makes it harder to get repeatable builds across machines. Pruebe a usar una configuración que se pueda insertar en el repositorio de control de código fuente y compartir entre todos los desarrolladores del código base.Try to use a configuration that can be checked into your source control system and shared among all developers of your codebase.

Por convención, muchos archivos de lógica de compilación principales importanBy convention, many core build logic files import

$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\{TargetFileName}\ImportBefore\*.targets

antes de su contenido, ybefore their contents, and

$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\{TargetFileName}\ImportAfter\*.targets

después.afterward. Esta convención permite que los SDK instalados aumenten la lógica de compilación de los tipos de proyecto comunes.This convention allows installed SDKs to augment the build logic of common project types.

Se busca la misma estructura de directorios en $(MSBuildUserExtensionsPath), que es la carpeta %LOCALAPPDATA%\Microsoft\MSBuild por usuario.The same directory structure is searched in $(MSBuildUserExtensionsPath), which is the per-user folder %LOCALAPPDATA%\Microsoft\MSBuild. Los archivos ubicados en esa carpeta se importarán para todas las compilaciones del tipo de proyecto correspondiente que se ejecuta con las credenciales del usuario.Files placed in that folder will be imported for all builds of the corresponding project type run under that user's credentials. Puede deshabilitar las extensiones de usuario si establece propiedades con el mismo nombre que el archivo de importación con el patrón ImportUserLocationsByWildcardBefore{ImportingFileNameWithNoDots}.You can disable the user extensions by setting properties named after the importing file in the pattern ImportUserLocationsByWildcardBefore{ImportingFileNameWithNoDots}. Por ejemplo, si se establece ImportUserLocationsByWildcardBeforeMicrosoftCommonProps en false se impedirá la importación de $(MSBuildUserExtensionsPath)\$(MSBuildToolsVersion)\Imports\Microsoft.Common.props\ImportBefore\*.For example, setting ImportUserLocationsByWildcardBeforeMicrosoftCommonProps to false would prevent importing $(MSBuildUserExtensionsPath)\$(MSBuildToolsVersion)\Imports\Microsoft.Common.props\ImportBefore\*.

Personalización de la compilación de la soluciónCustomize the solution build

Important

La personalización de la compilación de la solución de este modo solo se aplica a las compilaciones de línea de comandos con MSBuild.exe.Customizing the solution build in this way applies only to command-line builds with MSBuild.exe. No se aplica a las compilaciones dentro de Visual Studio.It does not apply to builds inside Visual Studio.

Cuando MSBuild compila un archivo de solución, primero lo convierte internamente en un archivo de proyecto y, después, lo compila.When MSBuild builds a solution file, it first translates it internally into a project file and then builds that. El archivo de proyecto generado importa before.{solutionname}.sln.targets antes de definir los destinos y after.{solutionname}.sln.targets después de importarlos, incluidos los destinos instalados en los directorios $(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\SolutionFile\ImportBefore y $(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\SolutionFile\ImportAfter.The generated project file imports before.{solutionname}.sln.targets before defining any targets and after.{solutionname}.sln.targets after importing targets, including targets installed to the $(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\SolutionFile\ImportBefore and $(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\SolutionFile\ImportAfter directories.

Por ejemplo, se podría definir un destino nuevo para escribir un mensaje de registro personalizado después de compilar MyCustomizedSolution.sln mediante la creación de un archivo en el mismo directorio denominado after.MyCustomizedSolution.sln.targets que contieneFor example, you could define a new target to write a custom log message after building MyCustomizedSolution.sln by creating a file in the same directory named after.MyCustomizedSolution.sln.targets that contains

<Project>
 <Target Name="EmitCustomMessage" AfterTargets="Build">
   <Message Importance="High" Text="The solution has completed the Build target" />
 </Target>
</Project>

Vea tambiénSee also