MSBuild Transforms 

A transform is a one-to-one conversion of one item collection into another. In addition to allowing a project to convert item collections, transforms allow a target to identify a direct mapping between its inputs and outputs. This topic explains transforms and how MSBuild uses them to build projects more efficiently.

Transform Modifiers

Transforms are not arbitrary, but are limited by special syntax in which all transform modifiers must be in the format %(ItemMetaDataName). Any item metadata can be used as a transform modifier, including the well-known item metadata assigned to every item upon creation. For a list of well-known item metadata, see MSBuild Well-known Item Metadata.

In the following example, a list of .resx files is transformed into a list of .resources files. The %(filename) transform modifier specifies that each .resources file has the same file name as the corresponding .resx file.

@(RESXFile->'%(filename).resources')

Note

You can specify a custom separator for a transformed item collection in the same way you can for a normal item collection. For example, to separate a transformed item collection with a comma (,) instead of the default semicolon (;), use the following XML.

@(RESXFile->'Toolset\%(filename)%(extension)', ',')

If, for example, the items in the @(RESXFile) item collection are Form1.resx, Form2.resx, and Form3.resx, the outputs in the transformed list will be Form1.resources, Form2.resources, and Form3.resources.

Using Multiple Modifiers

A transform can contain multiple modifiers, which can be combined in any order, and modifiers can be repeated in a transform expression. In the following example, the name of the directory that contains the files is changed but the files retain the original name and file extension.

@(RESXFile->'Toolset\%(filename)%(extension)')

If, for example, the items contained in the RESXFile item collection are Project1\Form1.resx, Project1\Form2.resx, and Project1\Form3.text, the outputs in the transformed list will be Toolset\Form1.resx, Toolset\Form2.resx, and Toolset\Form3.text.

Dependency Analysis

Transforms guarantee a one-to-one mapping between the transformed item collection and the original item collection. Because of this, if a target creates outputs that are transforms of the inputs, MSBuild can analyze the timestamps of the inputs and outputs, and decide whether to skip, build, or partially rebuild a target.

In the Copy task in the following example, each file in the BuiltAssemblies item collection maps to a file in the destination folder of the task, specified with a transform in the Outputs attribute. If any of the files in the BuiltAssemblies item colection changes, the Copy task will be run only for the changed files and all other files will be skipped. For more information on dependency analysis and using transforms, see How To: Build Incrementally.

<Target Name="CopyOutputs"
    Inputs="@(BuiltAssemblies)"
    Outputs="@(BuiltAssemblies -> '$(OutputPath)%(Filename)%(Extension)')">

    <Copy
        SourceFiles="@(BuiltAssemblies)"
        DestinationFolder="$(OutputPath)"/>

</Target>

Example

The following example shows an MSBuild project file using transforms. This example assumes a single .xsd file in the c:\sub0\sub1\sub2\sub3 directory, and a working directory of c:\sub0.

<Project xmlns="https://schemas.microsoft.com/developer/msbuild/2003">
    <ItemGroup>
        <Schema Include="sub1\**\*.xsd"/>
    </ItemGroup>

    <Target Name="Messages">
        <Message Text="rootdir: @(schema->'%(rootdir)')"/>
        <Message Text="fullpath: @(schema->'%(fullpath)')"/>
        <Message Text="rootdir + directory + filename + extension: @(schema->'%(rootdir)%(directory)%(filename)%(extension)')"/>
        <Message Text="identity: @(schema->'%(identity)')"/>
        <Message Text="filename: @(schema->'%(filename)')"/>
        <Message Text="directory: @(schema->'%(directory)')"/>
        <Message Text="relativedir: @(schema->'%(relativedir)')"/>
        <Message Text="extension: @(schema->'%(extension)')"/>
    </Target>
</Project>

This example produces the following output.

rootdir: C:\

fullpath: C:\xmake\sub1\sub2\sub3\myfile.xsd

rootdir + directory + filename + extension: C:\xmake\sub1\sub2\sub3\myfile.xsd

identity: sub1\sub2\sub3\myfile.xsd

filename: myfile

directory: xmake\sub1\sub2\sub3\

relativedir: sub1\sub2\sub3\

extension: .xsd

See Also

Tasks

How To: Build Incrementally

Other Resources

MSBuild Concepts
MSBuild Reference