演练:从头开始创建 MSBuild 项目文件


面向 .NET Framework 的编程语言将使用 MSBuild 项目文件来介绍并控制应用程序生成过程。使用 Visual Studio 创建 MSBuild 项目文件时,会自动将适当的 XML 添加到该文件。但是,你可能会发现,了解 XML 的组织方式以及如何能够更改 XML 来控制生成将非常有用。

有关创建 C++ 项目的项目文件的信息,请参阅MSBuild (Visual C++)。

此演练演示如何只使用文本编辑器以增量方式创建基本项目文件。演练采用以下步骤:

  • 创建最小的应用程序源文件。

  • 创建最小的 MSBuild 项目文件。

  • 扩展 PATH 环境变量以包括 MSBuild。

  • 使用项目文件生成应用程序。

  • 添加属性以控制生成。

  • 通过更改属性值来控制生成。

  • 将目标添加到生成。

  • 通过指定目标来控制生成。

  • 以增量方式生成。

此演练演示如何在命令提示符下生成项目并检查结果。有关 MSBuild 以及如何在命令提示符下运行 MSBuild 的详细信息,请参阅 演练:使用 MSBuild。

若要完成演练,你必须安装 .NET Framework(版本 2.0、3.5、4.0 或 4.5),因为其中包括演练所需的 MSBuild 和 Visual C# 编译器。

创建最小的应用程序

本节演示如何使用文本编辑器创建最小的 Visual C# 应用程序源文件。

创建最小的应用程序

  1. 在命令提示符下,浏览到要在其中创建应用程序的文件夹,例如,\My Documents\ 或 \Desktop\。

  2. 键入 md HelloWorld 创建名为 \HelloWorld\ 的子文件夹。

  3. 键入 cd HelloWorld 切换到该新文件夹。

  4. 启动记事本或其他文本编辑器,然后键入以下代码。

    using System;
    
    class HelloWorld
    {
        static void Main()
        {
    #if DebugConfig
            Console.WriteLine("WE ARE IN THE DEBUG CONFIGURATION");
    #endif
    
            Console.WriteLine("Hello, world!");
        }
    }
    
  5. 保存此源代码文件,并将其命名为 Helloworld.cs。

  6. 在命令提示符下,键入 csc helloworld.cs 来生成应用程序。

  7. 在命令提示符下,键入 helloworld 测试应用程序。

    此时应显示 Hello, world! 消息。

  8. 在命令提示符下,键入 del helloworld.exe 删除应用程序。

创建最小的 MSBuild 项目文件

既然有了最小的应用程序源文件,你就可以创建最小的项目文件来生成应用程序。此项目文件包含以下元素:

  • 必需的根 Project 节点。

  • 用于包含项元素的 ItemGroup 节点。

  • 引用应用程序源文件的项元素。

  • 一个 Target 节点,用于包含生成应用程序所需的任务。

  • 一个 Task 元素,用于启动 Visual C# 编译器以生成应用程序。

创建最小的 MSBuild 项目文件

  1. 在文本编辑器中,用以下两行替换现有文本:

    <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    </Project>
    
  2. 插入此 ItemGroup 节点,作为 Project 节点的子元素:

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

    请注意,此 ItemGroup 已包含一个项元素。

  3. 添加一个 Target 节点,作为 Project 节点的子元素。将该节点命名为 Build

    <Target Name="Build">
    </Target>
    
  4. 插入此 task 元素,作为 Target 节点的子元素:

    <Csc Sources="@(Compile)"/>
    
  5. 保存此项目文件,并将其命名为 Helloworld.csproj。

你的最小项目文件应类似于以下代码:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <Compile Include="helloworld.cs" />
  </ItemGroup>
  <Target Name="Build">
    <Csc Sources="@(Compile)"/>  
  </Target>
</Project>

Build 目标中的任务按顺序执行。在本例中,Visual C# 编译器 Csc 任务是唯一的任务。它需要编译一系列源文件,这一系列文件由 Compile 项的值指定。 Compile 项只引用一个源文件,即 Helloworld.cs。

注意

在项元素中,可以使用星号通配符 (*) 来引用文件扩展名为 .cs 的所有文件,如下所示:

<Compile Include="*.cs" />

但是,建议不要使用通配符,因为在添加或删除了源文件的情况下,这样会使调试和选择性目标设定更为困难。

扩展路径以包括 MSBuild

必须先扩展 PATH 环境变量以包括 .NET Framework 文件夹,然后才能访问 MSBuild。

向你的路径添加 MSBuild

  • 从 Visual Studio 2013 开始,你可以在 MSBuild 文件夹中查找 MSBuild.exe(32 位操作系统上的 %ProgramFiles%\MSBuild,或者 64 位操作系统上的 %ProgramFiles(x86)%\MSBuild)。

    在命令提示符处,键入 set PATH=%PATH%;%ProgramFiles%\MSBuild 或 set PATH=%PATH%;%ProgramFiles(x86)%\MSBuild

    或者,如果安装了 Visual Studio,则可以使用“Visual Studio 命令提示”,其中有包括 MSBuild 文件夹的路径。

使用项目文件生成应用程序

现在,为了生成应用程序,请使用刚刚创建的项目文件。

生成应用程序

  1. 在命令提示符处,键入 msbuild helloworld.csproj /t:Build

    此操作将调用 Visual C# 编译器来创建 Helloworld 应用程序,从而生成 Helloworld 项目文件的 Build 目标。

  2. 通过键入 helloworld 测试应用程序。

    此时应显示 Hello, world! 消息。

注意

可以通过提高详细信息级别来查看有关生成的更多详细信息。要将详细信息级别设置为“详细”,请在命令提示符下键入以下任一命令:

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

添加生成属性

可以将生成属性添加到项目文件中,从而进一步控制生成。现在添加以下属性:

  • 一个 AssemblyName 属性,用于指定应用程序的名称。

  • 一个 OutputPath 属性,用于指定要包含应用程序的文件夹。

添加生成属性

  1. 在命令提示符下,键入 del helloworld.exe 删除现有应用程序。

  2. 在项目文件中,插入此 PropertyGroup 元素,置于起始 Project 元素的后面:

    <PropertyGroup>
      <AssemblyName>MSBuildSample</AssemblyName>
      <OutputPath>Bin\</OutputPath>
    </PropertyGroup>
    
  3. 将此任务添加到 Build 目标,置于 Csc 任务的前面:

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

    MakeDir 任务将创建一个由 OutputPath 属性命名的文件夹,前提是当前不存在具有该名称的文件夹。

  4. 将此 OutputAssembly 特性添加到 Csc 任务:

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

    这将指示 Visual C# 编译器生成由 AssemblyName 属性命名的程序集,并将其放在由 OutputPath 属性命名的文件夹中。

  5. 保存更改。

你的项目文件现在应类似于以下代码:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <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>
注意

当你在 OutputPath 元素中指定文件夹名称时,建议你在文件夹名称的末尾添加反斜杠 (\) 路径分隔符,而不是将其添加到 OutputAssembly任务的 Csc 特性中。因此,

<OutputPath>Bin\</OutputPath>

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

优于

<OutputPath>Bin</OutputPath>

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

测试生成属性

现在即可使用项目文件来生成应用程序,在该项目文件中,你使用了生成属性来指定输出文件夹和应用程序名称。

测试生成属性

  1. 在命令提示符处,键入 msbuild helloworld.csproj /t:Build

    这将创建 \Bin\ 文件夹,然后调用 Visual C# 编译器创建 MSBuildSample 应用程序,并将其放在 \Bin\ 文件夹中。

  2. 要验证 \Bin\ 文件夹是否已创建,以及该文件夹是否包含 MSBuildSample 应用程序,请键入 dir Bin

  3. 通过键入 Bin\MSBuildSample 测试应用程序。

    此时应显示 Hello, world! 消息。

添加生成目标

接下来,向项目文件中另外添加两个目标,如下所示:

  • 一个用于删除旧文件的 Clean 目标。

  • 一个 Rebuild 目标,该目标使用 DependsOnTargets 特性,强制使 Clean 任务在 Build 任务之前运行。

既然有多个目标,就可以将 Build 目标设置为默认目标。

添加生成目标

  1. 在项目文件中添加以下两个目标,置于 Build 目标的后面:

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

    Clean 目标调用 Delete 任务来删除应用程序。在 Clean 目标和 Build 目标均已运行之前,Rebuild 目标不会运行。尽管 Rebuild 目标没有任务,但它可使 Clean 目标在 Build 目标之前运行。

  2. 将此 DefaultTargets 特性添加到起始 Project 元素:

    <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    

    这会将 Build 目标设置为默认目标。

你的项目文件现在应类似于以下代码:

<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <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>

测试生成目标

可以执行新的生成目标来测试项目文件的以下功能:

  • 生成默认生成。

  • 在命令提示符下设置应用程序名称。

  • 在生成其他应用程序之前删除应用程序。

  • 删除应用程序,而不生成其他应用程序。

测试生成目标

  1. 在命令提示符处,键入 msbuild helloworld.csproj /p:AssemblyName=Greetings

    由于未使用 /t 开关显式地设置目标,因此 MSBuild 将运行默认的 Build 目标。 /p 开关将重写 AssemblyName 属性,并为其指定新值Greetings这将导致在 \Bin\ 文件夹中创建一个新应用程序 Greetings.exe。

  2. 要验证 \Bin\ 文件夹是否同时包含 MSBuildSample 应用程序和新的 Greetings 应用程序,请键入 dir Bin

  3. 通过键入 Bin\Greetings 测试 Greetings 应用程序。

    此时应显示 Hello, world! 消息。

  4. 通过键入 msbuild helloworld.csproj /t:clean 删除 MSBuildSample 应用程序。

    这将运行 Clean 任务,以移除具有默认 AssemblyName 属性值 MSBuildSample 的应用程序。

  5. 通过键入 msbuild helloworld.csproj /t:clean /p:AssemblyName=Greetings 删除 Greetings 应用程序。

    这将运行 Clean 任务,以移除具有指定 AssemblyName 属性值 Greetings 的应用程序。

  6. 要验证 \Bin\ 文件夹现在是否为空,请键入 dir Bin

  7. 键入 msbuild

    尽管未指定项目文件,但 MSBuild 会生成 helloworld.csproj 文件,因为当前文件夹中只有一个项目文件。这将导致在 \Bin\ 文件夹中创建 MSBuildSample 应用程序。

    要验证 \Bin\ 文件夹是否包含 MSBuildSample 应用程序,请键入 dir Bin

以增量方式生成

可以指示 MSBuild 仅在目标所依赖的源文件或目标文件发生更改时才生成目标。MSBuild 使用文件的时间戳来确定文件是否已更改。

以增量方式生成

  1. 在项目文件中,将以下特性添加到起始 Build 目标:

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

    它指定 Build 目标依赖于 Compile 项组中指定的输入文件,并且输出目标为应用程序文件。

    生成的 Build 目标应类似于以下代码:

    <Target Name="Build" Inputs="@(Compile)" Outputs="$(OutputPath)$(AssemblyName).exe">
      <MakeDir Directories="$(OutputPath)" Condition="!Exists('$(OutputPath)')" />
      <Csc Sources="@(Compile)" OutputAssembly="$(OutputPath)$(AssemblyName).exe" />
    </Target>
    
  2. 在命令提示符下,键入 msbuild /v:d 测试 Build 目标。

    请记住,helloworld.csproj 是默认项目文件,并且 Build 为默认目标。

    /v:d 开关指定生成过程的详细说明。

    此时应显示以下各行:

    Skipping target "Build" because all output files are up-to-date with respect to the input files.

    Input files: HelloWorld.cs

    Output files: Bin\MSBuildSample.exe

    MSBuild 将跳过 Build 目标,原因是自上次生成应用程序以来没有任何源文件发生更改。

示例

描述

下面的示例演示一个项目文件,该项目文件编译 Visual C# 应用程序,并记录一条包含输出文件名的消息。

代码

C#
<Project DefaultTargets = "Compile"
    xmlns="http://schemas.microsoft.com/developer/msbuild/2003" >

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

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

    <Target Name = "Compile">
        <!-- Run the Visual 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>

注释

示例

描述

下面的示例演示一个项目文件,该项目文件编译 Visual Basic 应用程序,并记录一条包含输出文件名的消息。

代码

VB
<Project DefaultTargets = "Compile"
    xmlns="http://schemas.microsoft.com/developer/msbuild/2003" >

    <!-- 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>

接下来的内容

Visual Studio 能够自动执行本演练中演示的大部分工作。若要了解如何使用 Visual Studio 来创建、编辑、生成和测试 MSBuild 项目文件,请参阅演练:使用 MSBuild。

请参阅

MSBuild
MSBuild 参考

你可能感兴趣的:(演练:从头开始创建 MSBuild 项目文件)