Tutorial: Crear un archivo de proyecto de MSBuild desde cero

Los lenguajes de programación destinados a .NET Framework usan archivos de proyecto de MSBuild para describir y controlar el proceso de compilación de aplicaciones. Cuando se usa Visual Studio para crear un archivo del proyecto de MSBuild, el XML adecuado se agrega al archivo automáticamente. Sin embargo, puede ser de utilidad comprender cómo se organiza el XML y cómo se puede cambiar para controlar una compilación.

Nota

Si desea obtener información sobre los aspectos básicos de cómo funciona MSBuild independientemente del SDK, este es su artículo. La compilación con un SDK como, por ejemplo, cuando se usa dotnet build o se añade el atributo Sdk al elemento de proyecto raíz, no se trata en este artículo. Consulte SDKs de un proyecto .NET.

Para información sobre cómo crear un archivo del proyecto para un proyecto de C++, consulte MSBuild (C++).

Este tutorial muestra la forma de crear un archivo básico del proyecto de forma incremental, utilizando solo un editor de texto. El tutorial sigue estos pasos:

  1. Ampliar la variable de entorno PATH.

  2. Crear un archivo de código fuente de aplicación mínima.

  3. Crear un archivo del proyecto de MSBuild mínimo.

  4. Compilar la aplicación utilizando el archivo del proyecto.

  5. Agregar propiedades para controlar la compilación.

  6. Controlar la compilación cambiando los valores de propiedad.

  7. Agregar destinos a la compilación.

  8. Controlar la compilación especificando destinos.

  9. Compilar de forma incremental.

Este tutorial muestra la forma de compilar el proyecto en el símbolo del sistema y examinar los resultados. Para obtener más información sobre MSBuild y cómo ejecutar MSBuild en el símbolo del sistema, vea Tutorial: Usar MSBuild.

Para completar la guía paso a paso, hay que tener instalado Visual Studio porque incluye MSBuild y el compilador de C#, necesarios en dicha guía.

Ampliación de la ruta de acceso

Para poder tener acceso a MSBuild, debe ampliar la variable de entorno PATH para incluir todas las herramientas necesarias. Puede usar el Símbolo del sistema para desarrolladores de Visual Studio. Búsquelo en Windows 10 mediante el cuadro de búsqueda de la barra de tareas de Windows. Para configurar el entorno en un símbolo del sistema normal o en un entorno de scripting, ejecute VSDevCmd.bat en la subcarpeta Common7/Tools de una instalación de Visual Studio.

Creación de una aplicación mínima

En esta sección se muestra cómo crear un archivo de código fuente de aplicación de C# mínimo mediante un editor de texto.

  1. En el símbolo del sistema, vaya a la carpeta en la que quiere crear la aplicación, por ejemplo, \My Documents\ o \Desktop.

  2. Cree una subcarpeta llamada \HelloWorld\ y sitúese en ella.

  3. En un editor de texto, cree el archivo HelloWorld.cs y copie y pegue el siguiente código:

    using System;
    
    class HelloWorld
    {
        static void Main()
        {
    #if DebugConfig
            Console.WriteLine("WE ARE IN THE DEBUG CONFIGURATION");
    #endif
    
            Console.WriteLine("Hello, world!");
        }
    }
    
  4. Escriba csc helloworld.cs en el símbolo del sistema para compilar la aplicación.

  5. Escriba helloworld en el símbolo del sistema para probar la aplicación.

    Se debe mostrar el mensaje Hello, world!.

  6. Elimine el ejecutable.

Creación de un archivo de proyecto de MSBuild mínimo

Ahora que tiene un archivo de código fuente de aplicación mínima, puede crear un archivo del proyecto mínimo para compilar la aplicación. Este archivo del proyecto contiene los elementos siguientes:

  • El nodo raíz Project necesario.

  • Un nodo ItemGroup para contener los elementos.

  • Un elemento que hace referencia al archivo de código fuente de aplicación.

  • Un nodo Target para contener las tareas necesarias para compilar la aplicación.

  • Un elemento Task para iniciar el compilador de C# a fin de compilar la aplicación.

Para crear un archivo del proyecto de MSBuild mínimo

  1. En el editor de texto, cree el archivo HelloWorld.csproj y escriba el código siguiente:

    <Project>
      <ItemGroup>
        <Compile Include="helloworld.cs" />
      </ItemGroup>
    </Project>
    

    Este ItemGroup contiene el elemento de elemento (item) Compile y especifica un archivo de origen como elemento.

  2. Agregue un nodo Target como elemento secundario del nodo Project. Asigne un nombre al nodo Build.

    <Target Name="Build">
    </Target>
    
  3. Inserte este elemento de tarea como elemento secundario del nodo Target:

    <Csc Sources="@(Compile)"/>
    
  4. Guarde este archivo del proyecto y denomínelo Helloworld.csproj.

Su archivo del proyecto mínimo debe ser similar al código siguiente:

<Project>
  <ItemGroup>
    <Compile Include="helloworld.cs"/>
  </ItemGroup>
  <Target Name="Build">
    <Csc Sources="@(Compile)"/>
  </Target>
</Project>

Las tareas en el destino Build se ejecutan secuencialmente. En este caso, la tarea Csc del compilador de C# es la única tarea. Espera la compilación de una lista de archivos de código fuente y esto se produce mediante el valor del elemento Compile. El elemento Compile hace referencia a solo un archivo de código fuente, Helloworld.cs.

Nota

En el elemento, puede utilizar el carácter comodín asterisco (*) para hacer referencia a todos los archivos cuya extensión de nombre de archivo sea .cs, del modo siguiente:

<Compile Include="*.cs" />

Compilar la aplicación

Ahora, para compilar la aplicación, utilice el archivo del proyecto que acaba de crear.

  1. En el símbolo del sistema, escriba msbuild helloworld.csproj -t:Build.

    Esto genera el destino de compilación del archivo del proyecto Helloworld al invocar al compilador de C# para crear la aplicación Helloworld.

  2. Escriba helloworld para probar la aplicación.

    Se debe mostrar el mensaje Hello, world!.

Nota

Puede ver más detalles sobre la compilación aumentando el nivel de detalle. Para establecer el nivel de detalle en "detailed", escriba este comando en el símbolo del sistema:

msbuild helloworld.csproj -t:Build -verbosity:detailed

Agregar propiedades de compilación

Puede agregar propiedades de compilación al archivo del proyecto para controlar mejor la compilación. Agregue ahora estas propiedades:

  • Una propiedad AssemblyName para especificar el nombre de la aplicación.

  • Una propiedad OutputPath para especificar una carpeta que contenga la aplicación.

Para agregar propiedades de compilación

  1. Elimine el ejecutable de la aplicación existente (más adelante, añadirá un destino Clean para controlar la eliminación de archivos de salida antiguos).

  2. En el archivo del proyecto, inserte este elemento PropertyGroup justo después del elemento Project de apertura:

    <PropertyGroup>
      <AssemblyName>MSBuildSample</AssemblyName>
      <OutputPath>Bin\</OutputPath>
    </PropertyGroup>
    
  3. Agregue esta tarea al destino Build, justo antes de la tarea Csc:

    <MakeDir Directories="$(OutputPath)" Condition="!Exists('$(OutputPath)')" />
    

    La tarea MakeDir crea una carpeta denominada por la propiedad OutputPath, con tal de que no exista actualmente ninguna carpeta con ese nombre.

  4. Agregue este atributo OutputAssembly a la tarea Csc.

    <Csc Sources="@(Compile)" OutputAssembly="$(OutputPath)$(AssemblyName).exe" />
    

    Esto indica al compilador de C# que cree un ensamblado nombrado por la propiedad AssemblyName y lo coloque en la carpeta nombrada por la propiedad OutputPath.

  5. Guarde los cambios.

Su archivo del proyecto debe ser ahora similar al código siguiente:

<Project>
  <PropertyGroup>
    <AssemblyName>MSBuildSample</AssemblyName>
    <OutputPath>Bin\</OutputPath>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="helloworld.cs" />
  </ItemGroup>
  <Target Name="Build">
    <MakeDir Directories="$(OutputPath)" Condition="!Exists('$(OutputPath)')" />
    <Csc Sources="@(Compile)" OutputAssembly="$(OutputPath)$(AssemblyName).exe" />
  </Target>
</Project>

Nota

Se recomienda agregar el delimitador de ruta de acceso de barra diagonal inversa (\) al final del nombre de la carpeta al especificarlo en el elemento OutputPath, en lugar de agregarlo en el atributo OutputAssembly de la tarea Csc. Por lo tanto,

<OutputPath>Bin\</OutputPath>

OutputAssembly="$(OutputPath)$(AssemblyName).exe" />

es mejor que

<OutputPath>Bin</OutputPath>

OutputAssembly="$(OutputPath)\$(AssemblyName).exe" />

Prueba de las propiedades de compilación

Ahora puede compilar la aplicación utilizando el archivo del proyecto en el que utilizó propiedades de compilación para especificar la carpeta de salida y el nombre de aplicación.

  1. En el símbolo del sistema, escriba msbuild helloworld.csproj -t:Build.

    De este modo, se crea la carpeta \Bin y se invoca el compilador de C# para crear la aplicación MSBuildSample y colocarla en la carpeta \Bin\.

  2. Para comprobar que se ha creado la carpeta \Bin\ y que contiene la aplicación MSBuildSample, escriba dir Bin.

  3. Puede probar la aplicación escribiendo Bin\MSBuildSample para ejecutar el archivo ejecutable.

    Se debe mostrar el mensaje Hello, world!.

Agregar destinos de compilación

A continuación, agregue dos destinos más al archivo del proyecto, del siguiente modo:

  • Un destino Clean que elimine los archivos antiguos.

  • Un destino Rebuild que utilice el atributo DependsOnTargets para obligar a que la tarea Clean se ejecute antes que la tarea Build.

Ahora que tiene varios destinos, puede establecer el destino Build como destino predeterminado.

Para agregar destinos de compilación

  1. En el archivo del proyecto, agregue estos dos destinos justo después del destino Build:

    <Target Name="Clean" >
      <Delete Files="$(OutputPath)$(AssemblyName).exe" />
    </Target>
    <Target Name="Rebuild" DependsOnTargets="Clean;Build" />
    

    El destino Clean llama a la tarea Delete para eliminar la aplicación. El destino Rebuild no se ejecutará hasta que se hayan ejecutado el destino Clean y el destino Build. Aunque el destino Rebuild no tiene tareas, hace que el destino Clean se ejecute antes que el destino Build.

  2. Agregue este atributo DefaultTargets al elemento Project.

    <Project DefaultTargets="Build">
    

    Esto establece el destino Build como destino predeterminado.

Su archivo del proyecto debe ser ahora similar al código siguiente:

<Project DefaultTargets="Build">
  <PropertyGroup>
    <AssemblyName>MSBuildSample</AssemblyName>
    <OutputPath>Bin\</OutputPath>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="helloworld.cs" />
  </ItemGroup>
  <Target Name="Build">
    <MakeDir Directories="$(OutputPath)" Condition="!Exists('$(OutputPath)')" />
    <Csc Sources="@(Compile)" OutputAssembly="$(OutputPath)$(AssemblyName).exe" />
  </Target>
  <Target Name="Clean" >
    <Delete Files="$(OutputPath)$(AssemblyName).exe" />
  </Target>
  <Target Name="Rebuild" DependsOnTargets="Clean;Build" />
</Project>

Prueba de los destinos de compilación

Puede utilizar los nuevos destinos de compilación para probar estas características del archivo del proyecto:

  • Compilar la compilación predeterminada.

  • Establecer el nombre de aplicación en el símbolo del sistema.

  • Eliminar la aplicación antes de que se compile otra aplicación.

  • Eliminar la aplicación sin que se compile otra aplicación.

Para probar los destinos de compilación

  1. En el símbolo del sistema, escriba msbuild helloworld.csproj -p:AssemblyName=Greetings.

    Como no utilizó el modificador -t para establecer el destino explícitamente, MSBuild ejecutará el destino Build predeterminado. El modificador -p invalida la propiedad AssemblyName y le da el nuevo valor, Greetings. Esto hace que se cree una aplicación, Greetings.exe, en la carpeta \Bin\.

  2. Para comprobar que la carpeta \Bin\ contiene la aplicación MSBuildSample y la nueva aplicación Greetings, escriba dir Bin.

  3. Pruebe la aplicación Greetings (por ejemplo, escribiendo Bin\Greetings en Windows).

    Se debe mostrar el mensaje Hello, world!.

  4. Escriba msbuild helloworld.csproj -t:clean para eliminar la aplicación MSBuildSample.

    Esto ejecuta la tarea Clean para quitar la aplicación que tiene el valor de propiedad AssemblyName predeterminado, MSBuildSample.

  5. Escriba msbuild helloworld.csproj -t:clean -p:AssemblyName=Greetings para eliminar la aplicación Greetings.

    Esto ejecuta la tarea Clean para quitar la aplicación que tiene el valor de propiedad AssemblyName dado, Greetings.

  6. Para comprobar que la carpeta \Bin\ está ahora vacía, escriba dir Bin.

  7. Escriba msbuild.

    Aunque no se especifica un archivo de proyecto, MSBuild compila el archivo helloworld.csproj porque solo hay un archivo de proyecto en la carpeta actual. Esto hace que se cree la aplicación MSBuildSample en la carpeta \Bin\.

    Para comprobar que la carpeta \Bin\ contiene la aplicación MSBuildSample, escriba dir Bin.

Compilación de forma incremental

Puede indicar a MSBuild que cree un destino sólo si los archivos de código fuente o los archivos de destino de los que depende el destino han cambiado. MSBuild utiliza la marca de tiempo de un archivo para determinar si ha cambiado.

Para compilar de forma incremental

  1. En el archivo del proyecto, agregue estos atributos al destino Build de apertura:

    Inputs="@(Compile)" Outputs="$(OutputPath)$(AssemblyName).exe"
    

    Esto especifica que el destino Build depende de los archivos de entrada que se especifican en el grupo de elementos Compile y que el destino de salida es el archivo de aplicación.

    El destino Build resultante debe ser similar al código siguiente:

    <Target Name="Build" Inputs="@(Compile)" Outputs="$(OutputPath)$(AssemblyName).exe">
      <MakeDir Directories="$(OutputPath)" Condition="!Exists('$(OutputPath)')" />
      <Csc Sources="@(Compile)" OutputAssembly="$(OutputPath)$(AssemblyName).exe" />
    </Target>
    
  2. Escriba msbuild -v:d en el símbolo del sistema para probar el destino Build.

    Recuerde que helloworld.csproj es el archivo de proyecto predeterminado y que Build es el destino predeterminado.

    El modificador -v:d es una abreviatura del -verbosity:detailed usado anteriormente.

    Si ya ha compilado, deberían aparecer estas líneas:

    Se omitirá el destino "Build" porque todos los archivos de salida están actualizados respecto a los archivos de entrada.

    MSBuild omite el destino Build porque ninguno de los archivos de código fuente ha cambiado desde que la aplicación se compiló por última vez.

Ejemplo de C#

En el ejemplo siguiente se muestra un archivo del proyecto que compila una aplicación de C# y registra un mensaje que contiene el nombre del archivo de salida.

Código

<Project DefaultTargets = "Compile">

    <!-- Set the application name as a property -->
    <PropertyGroup>
        <appname>HelloWorldCS</appname>
    </PropertyGroup>

    <!-- Specify the inputs by type and file name -->
    <ItemGroup>
        <CSFile Include = "*.cs"/>
    </ItemGroup>

    <Target Name="Compile">
        <!-- Run the C# compilation using input files of type CSFile -->
        <CSC
            Sources = "@(CSFile)"
            OutputAssembly = "$(appname).exe">
            <!-- Set the OutputAssembly attribute of the CSC task
            to the name of the executable file that is created -->
            <Output
                TaskParameter = "OutputAssembly"
                ItemName = "EXEFile" />
        </CSC>
        <!-- Log the file name of the output file -->
        <Message Text="The output file is @(EXEFile)"/>
    </Target>
</Project>

Ejemplo de Visual Basic

En el ejemplo siguiente se muestra un archivo del proyecto que compila una aplicación de Visual Basic y registra un mensaje que contiene el nombre del archivo de salida.

Código

<Project DefaultTargets = "Compile">

    <!-- Set the application name as a property -->
    <PropertyGroup>
        <appname>HelloWorldVB</appname>
    </PropertyGroup>

    <!-- Specify the inputs by type and file name -->
    <ItemGroup>
        <VBFile Include = "consolehwvb1.vb"/>
    </ItemGroup>

    <Target Name = "Compile">
        <!-- Run the Visual Basic compilation using input files of type VBFile -->
        <VBC
            Sources = "@(VBFile)"
            OutputAssembly= "$(appname).exe">
            <!-- Set the OutputAssembly attribute of the VBC task
            to the name of the executable file that is created -->
            <Output
                TaskParameter = "OutputAssembly"
                ItemName = "EXEFile" />
        </VBC>
        <!-- Log the file name of the output file -->
        <Message Text="The output file is @(EXEFile)"/>
    </Target>
</Project>

Pasos adicionales

Visual Studio puede realizar automáticamente gran parte del trabajo que se muestra en este tutorial. Para aprender a usar Visual Studio a fin de crear, editar, compilar y probar archivos de proyecto de MSBuild, vea Tutorial: Usar MSBuild.