Skip to content

Instantly share code, notes, and snippets.

@kzu
Last active December 30, 2015 20:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kzu/3f885734ac23a37eafc4 to your computer and use it in GitHub Desktop.
Save kzu/3f885734ac23a37eafc4 to your computer and use it in GitHub Desktop.
xbuild-achilles-heels
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Content>Hello \ Bye</Content>
</PropertyGroup>
<Target Name="Build">
<Message Text="$(Content)" />
<WriteLinesToFile File="out.cs" Lines="$(Content)" Overwrite="true" />
<Message Text="$([System.IO.File]::ReadAllText('out.cs'))" />
</Target>
<!--
MSBuild Output:
Hello \ Bye
Hello \ Bye
XBuild Output:
Hello / Bye
Hello / Bye
Why, oh WHY are the backslashes converted for things like Message.Text and WriteLinesToFile.Lines
which have NOTHING to do with paths?
-->
</Project>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<!-- Using %3B for the semicolon doesn't help either, it's dropped anyway -->
<Content>
public static class ThisAssembly
{
public const string AssemblyName = "$AssemblyName$";
}
</Content>
</PropertyGroup>
<PropertyGroup>
<AssemblyName>Foo</AssemblyName>
</PropertyGroup>
<Target Name="Build">
<PropertyGroup>
<!-- Need to do the replacement in another property, since it doesn't work
in the Lines attribute, as shown in property-functions-in-attributes.proj -->
<Replaced>$(Content.Replace('$AssemblyName$', '$(AssemblyName)'))</Replaced>
</PropertyGroup>
<Message Text="$(Replaced)" Importance="low" />
<WriteLinesToFile File="out.cs" Lines="$(Replaced)" Overwrite="true" />
<Message Text="$([System.IO.File]::ReadAllText('out.cs'))" />
</Target>
<!--
MSBuild Output:
public static class ThisAssembly
{
public const string AssemblyName = "Foo";
}
XBuild Output:
public static class ThisAssembly
{
public const string AssemblyName = "Foo"
}
(Note the missing semi-colon)
-->
</Project>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemDefinitionGroup>
<!-- Say you want to provide a default value for all, unless explicitly overriden -->
<File>
<IsPublic>true</IsPublic>
</File>
</ItemDefinitionGroup>
<ItemGroup>
<File Include="Default.resx" />
<File Include="NonPublic.resx">
<IsPublic>false</IsPublic>
</File>
<File Include="Public.resx">
<IsPublic>true</IsPublic>
</File>
</ItemGroup>
<Target Name="Build">
<Message Importance="high" Text="%(File.Identity): IsPublic=%(File.IsPublic)" />
<!--
MSBuild Output:
Default.resx: IsPublic=true
NonPublic.resx: IsPublic=false
Public.resx: IsPublic=true
XBuild:
Default.resx: IsPublic=
NonPublic.resx: IsPublic=false
Public.resx: IsPublic=true
-->
<Message Importance="high" Text="Public file: %(File.Identity)" Condition=" '%(File.IsPublic)' == 'true' " />
<!--
MSBuild Output:
Public file: Default.resx
Public file: Public.resx
XBuild:
Public file: Public.resx
(Note the default value was never applied)
-->
</Target>
</Project>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<None Include="a.txt" />
<None Include="b.txt" />
</ItemGroup>
<Target Name="Build">
<Message Text="Count @(None -> Count())" />
</Target>
<!--
MSBuild Output:
Count 2
XBuild Output:
Count @(None -> Count())
-->
</Project>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<None Include="a.txt" />
<None Include="a.txt" />
</ItemGroup>
<Target Name="Build">
<Message Text="None: @(None -> Distinct())" />
</Target>
<!--
MSBuild Output:
None: a.txt
XBuild Output:
None: @(None -> Distinct())
-->
</Project>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<None Include="a.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="b.txt" />
</ItemGroup>
<Target Name="Build">
<PropertyGroup>
<NoneWithCopy>@(None -> HasMetadata('CopyToOutputDirectory'))</NoneWithCopy>
</PropertyGroup>
<Message Importance="high" Text="$(NoneWithCopy)" />
<!--
MSBuild Output:
a.txt
XBuild Output:
@(None -> HasMetadata('CopyToOutputDirectory'))
-->
</Target>
</Project>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<TheItem Include="first">
<Plant>geranium</Plant>
</TheItem>
<TheItem Include="second">
<Plant>algae</Plant>
</TheItem>
<TheItem Include="third">
<Plant>geranium</Plant>
</TheItem>
</ItemGroup>
<Target Name="Build">
<Message Text="MetaData: @(TheItem->Metadata('Plant'))" />
<Message Text="HasMetadata: @(theItem->HasMetadata('Plant'))" />
<Message Text="WithMetadataValue: @(TheItem->WithMetadataValue('Plant', 'geranium'))" />
<Message Text=" " />
<Message Text="Count: @(theItem->Count())" />
<Message Text="Reverse: @(theItem->Reverse())" />
</Target>
<!--
MSBuild Output:
MetaData: geranium;algae;geranium
HasMetadata: first;second;third
WithMetadataValue: first;third
Count: 3
Reverse: third;second;first
XBuild Output:
MetaData: @(TheItem->Metadata('Plant'))
HasMetadata: @(theItem->HasMetadata('Plant'))
WithMetadataValue: @(TheItem->WithMetadataValue('Plant', 'geranium'))
Count: @(theItem->Count())
Reverse: @(theItem->Reverse())
-->
</Project>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<theItem Include="andromeda;tadpole;cartwheel" />
</ItemGroup>
<Target Name="Build">
<Message Text="IndexOf @(theItem->IndexOf('r'))" />
<Message Text="Replace @(theItem->Replace('tadpole', 'pinwheel'))" />
<Message Text="Length @(theItem->get_Length())" />
<Message Text="Chars @(theItem->get_Chars(2))" />
</Target>
<!--
MSBUild Output:
IndexOf 3;-1;2
Replace andromeda;pinwheel;cartwheel
Length 9;7;9
Chars d;d;r
XBuild Output:
IndexOf @(theItem->IndexOf('r'))
Replace @(theItem->Replace('tadpole', 'pinwheel'))
Length @(theItem->get_Length())
Chars @(theItem->get_Chars(2))
-->
</Project>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<EmbeddedResource Include="NonCode.resx" />
<EmbeddedResource Include="NonPublic.resx">
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Include="Public.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<ResxCode Include="@(EmbeddedResource -> WithMetadataValue('Generator', 'ResXFileCodeGenerator'))">
<Public>False</Public>
</ResxCode>
<ResxCode Include="@(EmbeddedResource -> WithMetadataValue('Generator', 'PublicResXFileCodeGenerator'))">
<Public>True</Public>
</ResxCode>
</ItemGroup>
<Target Name="Build">
<Message Importance="high" Text="Resx with code: %(ResxCode.Identity) (Public=%(ResxCode.Public))" />
<!--
MSBuild Output:
Resx with code: NonPublic.resx (Public=False)
Resx with code: Public.resx (Public=True)
XBuild:
Resx with code: @(EmbeddedResource -> WithMetadataValue('Generator', 'ResXFileCodeGenerator')) (Public=False)
Resx with code: @(EmbeddedResource -> WithMetadataValue('Generator', 'PublicResXFileCodeGenerator')) (Public=True)
-->
</Target>
</Project>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<None Include="a.txt" />
<None Include="b.txt" />
</ItemGroup>
<Target Name="Build">
<ItemGroup>
<None>
<OriginalIdentity>%(Identity)</OriginalIdentity>
</None>
</ItemGroup>
<Message Importance="high" Text="%(None.Identity)=%(None.OriginalIdentity)" />
<!--
MSBuild Output:
a.txt=a.txt
b.txt=b.txt
XBuild (with /v:diag):
: error : Error building target Build: Object reference not set to an instance of an object
Error building target Build: System.NullReferenceException: Object reference not set to an instance of an object
at Microsoft.Build.BuildEngine.Project.GetMetadataBatched (System.String itemName, System.String metadataName) <0x2b7ee08 + 0x00037> in <filename unknown>:0
-->
</Target>
</Project>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<None Include="a.txt" />
<None Include="b.txt" />
</ItemGroup>
<Target Name="Build">
<ItemGroup>
<None>
<Content>$([System.IO.File]::ReadAllText('%(Identity)'))</Content>
</None>
</ItemGroup>
<Message Importance="high" Text="%(None.Identity)=%(None.Content)" />
<!--
MSBuild Output:
a.txt=A
b.txt=B
XBuild (with /v:diag):
: error : Error building target Build: Exception has been thrown by the target of an invocation.
Error building target Build: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. -> System.IO.FileNotFoundException: Could not find file "/Volumes/C/Code/Personal/xbuildsucks/%(Identity)".
File name: '/Volumes/C/Code/Personal/xbuildsucks/%(Identity)'
-->
</Target>
</Project>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Content>Hello $Name$</Content>
</PropertyGroup>
<Target Name="Build">
<!-- This works on XBuild -->
<Message Importance="high" Text="$(Content.Replace('$Name$', 'Foo'))" />
<!-- This doesn't work on XBuild -->
<WriteLinesToFile File="out.cs" Lines="$(Content.Replace('$Name$', 'Foo'))" Overwrite="true" />
<Message Importance="high" Text="$([System.IO.File]::ReadAllText('out.cs'))" />
<!--
MSBuild Output:
Hello Foo
Hello Foo
XBuild Output:
Hello Foo
error : Error executing task WriteLinesToFile: Error converting Property named 'Lines' with value '$(Content.Replace('$Name$', 'Foo'))' to type Microsoft.Build.Framework.ITaskItem[]: The method or operation is not implemented.
-->
</Target>
</Project>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment