c++visual-studiocustom-build

Extend Visual Studio (2010+) Item Type handlers


When looking at the file's properties in Visual Studio (2010 and above), it is possible to set the Item Type in the General section. For instance, for C++, the item type is "C/C++ compiler".

There is a "Custom Build Tool" type available, but it has to be completely configured for each file falling in that category.

My questions are:

  1. Is there a way to configure a "Custom Build Tool" and make it available in the Item Type list;
  2. Is is possible to then associate a file extension with this new Item Type builder?

Solution

  • I found the answer using the following references:

    It turns out that a full setup is quite complicated, so I'll limit my answer to answering my two initial questions with minimalist steps:

    To add a Custom Build Tool in MSVC

    1. In the project file (vcxproj), include a new build definition (there is probably a way to include it system-wide, but I haven't looked into it yet):

      <ImportGroup Label="ExtensionTargets">
      <Import Project="mybuild.targets" />
      </ImportGroup>
      

    This can go right before the closing </Project>.

    1. Create a text file called mybuild.targets in the same folder as the vcxproj file.

    2. Insert the following in mybuild.targets:

      <?xml version="1.0" encoding="utf-8"?>
      <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
        <ItemGroup>
          <PropertyPageSchema 
              Include="$(MSBuildThisFileDirectory)$(MSBuildThisFileName).xml" />
        </ItemGroup>
      </Project>
      
    3. This targets file refers to a xml file with more details ($(MSBuildThisFileDirectory)$(MSBuildThisFileName).xml which refers in this example to mybuild.xml). Create mybuild.xml.

    4. Insert the following in mybuild.xml:

      <?xml version="1.0" encoding="utf-8"?>
      <ProjectSchemaDefinitions xmlns="http://schemas.microsoft.com/build/2009/properties"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
            xmlns:sys="clr-namespace:System;assembly=mscorlib">
        <ItemType Name="MYBUILD" DisplayName="My Custom Build" />
      </ProjectSchemaDefinitions>
      

    What we just did: The project file now includes a new target definition (mybuild.targets). This file would normally hold more information about how execute the actual build, but here it contains only an include to a mybuild.xml file. This mybuild.xml file contains a new item type definition called with internal name MYBUILD and display name My Custom Build. When the project is reopened in Visual Studio, a new item type will be available in the Item Type list. Selecting it sets the type of this item to MYBUILD and since we have no rule defined for that kind of item at this point, it will simply be ignored from the build.

    To associate a file extension with a custom item type MSVC

    This is done in two steps:

    1. Associate the file extension to a content type. This is done by adding an entry in mybuild.xml like this:

       <FileExtension Name="*.myext" ContentType="MYBUILD" />
      
    2. Associate the content type to the item type. This is done by adding an entry in mybuild.xml like this:

       <ContentType Name="MYBUILD" DisplayName="My Custom Build" ItemType="MYBUILD" />
      

    At this point, mybuild.xml looks like this:

        <?xml version="1.0" encoding="utf-8"?>
        <ProjectSchemaDefinitions xmlns="http://schemas.microsoft.com/build/2009/properties"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
              xmlns:sys="clr-namespace:System;assembly=mscorlib">
          <ItemType Name="MYBUILD" DisplayName="My Custom Build" />
          <FileExtension Name="*.hh" ContentType="MYBUILD" />
          <ContentType Name="MYBUILD" DisplayName="My Custom Build" ItemType="MYBUILD" />
        </ProjectSchemaDefinitions>
    

    What we just did: Visual Studio now knows that the extension .myext contains data of type MYBUILD. It also knows that files with content of type MYBUILD are items of type MYBUILD. Once the project is reopened in Visual Studio, when adding files with the extension .myext, Visual Studio will automatically set the item type to "My Custom Build" for these files.

    To execute a custom tool on a custom item MSVC

    At this point, we have a file extension that is associated to a custom item type. We need to associate that item type with a set of build rules.

    1. Associate the item type to a build target. In mybuild.targets Add the following in the same ItemGroup as our PropertyPageSchema:

       <AvailableItemName Include="MYBUILD">
         <Targets>_MYBUILD</Targets>
       </AvailableItemName>
      

    So that it now looks like this:

        <ItemGroup>
          <PropertyPageSchema
                Include="$(MSBuildThisFileDirectory)$(MSBuildThisFileName).xml" />
          <AvailableItemName Include="MYBUILD">
            <Targets>_MYBUILD</Targets>
          </AvailableItemName>
        </ItemGroup>
    
    1. Define the custom target. This is where you would map all the properties and variables that should be used to configure the build task. In the next step, we will use a build task that uses a command line template, so in our target, we will configure the actual command line. This goes right below the ItemGroup defined in the previous step:

       <Target Name="_MYBUILD">
           <MYBUILD CommandLineTemplate="explorer $(IntDir)"></MYBUILD>
       </Target>
      

    Our command line will simply open an explorer window.

    1. Declare a custom build task. This goes right after the Target from the previous step:

       <UsingTask TaskName="MYBUILD" TaskFactory="XamlTaskFactory" AssemblyName="Microsoft.Build.Tasks.v4.0">
           <Task>$(MSBuildThisFileDirectory)$(MSBuildThisFileName).xml</Task>
       </UsingTask>
      

    Here, we refer to a task that will be defined in our mybuild.xml file.

    1. In mybuild.xml, add the following rule:

       <Rule Name="MYBUILD" PageTemplate="tool" DisplayName="My Custom Build" Order="200"/>
      

    What we just did: We mapped the custom item type to a custom target, and a custom build task which opens an explorer window. When we build .myext files, we can now expect Visual Studio to pop an explorer window.

    Customizing the build

    There are ways to add configuration fields in the property window, map them to variables and use them to configure a task. This is not covered here but discussed in the links provided at the top.