I'm trying to build upon this question:
Reading a single value from a file in MSBuild
My goal is to have a single place to put the version number that's used in several projects, and I also want a portion of the version number in the DLL file name for one of the projects.
Based on the question above, I already got the first part, but I'm having difficulty with the second part and would appreciate some guidance.
In my solution, I set up a plain text file called Version.txt containing my full version number only:
1.1.0.0
In both of my projects, I opened their AssemblyInfo.cs files and removed the AssemblyVersion and AssemblyFileVersion items, then modified both projects to generate them in a separate file as described in the question above.
<ItemGroup>
<VersionFile Include="..\Version.txt" />
</ItemGroup>
<Target Name="BeforeBuild">
<ReadLinesFromFile File="@(VersionFile)">
<Output TaskParameter="Lines" PropertyName="VersionNumber" />
</ReadLinesFromFile>
<Delete Files="Properties\Version.cs" />
<WriteLinesToFile File="Properties\Version.cs" Lines="using System.Reflection%3B

[assembly: AssemblyVersion("$(VersionNumber)")]
[assembly: AssemblyFileVersion("$(VersionNumber)")]" />
</Target>
Now when I build, I get a generated Properties\Version.cs file for each project, which is used to build the EXE/DLL and shows up as "1.1.0.0" in their file properties. This is exactly what I want.
For the DLL, I would like to name the assembly "filename.v1.1.dll", where the "1.1" comes from the first two components in Version.txt above. I'm flexible on the format of Version.txt as long as I can get the full "1.1.0.0" in the EXE/DLL properties and "1.1" in the DLL file name.
To try this out, I modified the DLL's csproj file to have:
<RootNamespace>dllfile</RootNamespace>
<AssemblyName>dllfile.v$(VersionNumber)</AssemblyName>
Of course, this will insert the full version number in the file name, which I don't want.
Does anyone have any tips on how to proceed?
Thanks.
EDIT: I have been able to extract the major/minor components of the version number by adding the following to my .csproj BeforeBuild target:
<ReadLinesFromFile File="@(VersionFile)">
<Output TaskParameter="Lines" PropertyName="VersionNumber" />
</ReadLinesFromFile>
<PropertyGroup>
<VersionNumberFirstDotIndex>$(VersionNumber.IndexOf('.'))</VersionNumberFirstDotIndex>
<VersionNumberMajorStart>0</VersionNumberMajorStart>
<VersionNumberMajorLen>$(VersionNumberFirstDotIndex)</VersionNumberMajorLen>
<VersionNumberMinorStart>$([MsBuild]::Add(1, $(VersionNumberFirstDotIndex)))</VersionNumberMinorStart>
<VersionNumberSecondDotIndex>$(VersionNumber.IndexOf('.', $(VersionNumberMinorStart)))</VersionNumberSecondDotIndex>
<VersionNumberMinorLen>$([MSBuild]::Subtract($([MSBuild]::Subtract($(VersionNumberSecondDotIndex), $(VersionNumberFirstDotIndex))), 1))</VersionNumberMinorLen>
<VersionNumberMajor>$(VersionNumber.Substring($(VersionNumberMajorStart), $(VersionNumberMajorLen)))</VersionNumberMajor>
<VersionNumberMinor>$(VersionNumber.Substring($(VersionNumberMinorStart), $(VersionNumberMinorLen)))</VersionNumberMinor>
<VersionNumberShort>$(VersionNumberMajor).$(VersionNumberMinor)</VersionNumberShort>
</PropertyGroup>
<Message Text="DEBUG1 VersionNumberFull=$(VersionNumber)" Importance="High" />
<Message Text="DEBUG2 VersionNumberAbbrev=$(VersionNumberShort)" Importance="High" />
<Delete Files="Properties\Version.cs" />
<WriteLinesToFile File="Properties\Version.cs" Lines="using System.Reflection%3B

[assembly: AssemblyVersion("$(VersionNumber)")]
[assembly: AssemblyFileVersion("$(VersionNumber)")]" />
The only piece I'm missing now is how to get this VersionNumberShort into the DLL file name. Unless someone has a better idea, I can take Peter's suggestion and use Move tasks:
<Target Name="AfterBuild">
<Move SourceFiles="$(OutputPath)$(AssemblyName).pdb" DestinationFiles="$(OutputPath)$(AssemblyName).v$(VersionNumberShort).pdb" />
<Move SourceFiles="$(OutputPath)$(AssemblyName).dll" DestinationFiles="$(OutputPath)$(AssemblyName).v$(VersionNumberShort).dll" />
</Target>
<Target Name="AfterClean" DependsOnTargets="Common">
<Delete Files="$(OutputPath)$(AssemblyName).v$(VersionNumberShort).pdb" ContinueOnError="true" />
<Delete Files="$(OutputPath)$(AssemblyName).v$(VersionNumberShort).dll" ContinueOnError="true" />
</Target>
Since I needed the same property definitions as before, I moved the snippet above into a "Common" target and referenced it in both the build and clean tasks shown here.
Peter - If you want to move your comment as an answer, I'll accept it.
Thanks!
EDIT: Following jdlugosz's answer, I tried setting the AssemblyName inside my task. Unfortunately, this still didn't seem to have any effect based on the original example listed at the top:
<Target Name="BeforeBuild">
...
<WriteLinesToFile ... />
<PropertyGroup>
<AssemblyName>dllfile.v$(VersionNumber)</AssemblyName>
</PropertyGroup>
</Target>
I tried running this with MSBuild from a Visual Studio Developer Command Prompt:
msbuild /target:clean projfile.csproj
msbuild /verbosity:diag projfile.csproj > out.txt
Prior to this, I renamed the at the top of my csproj file and in the "redefinition" to something unique to make it easy to search (e.g. "dllfileoriginal" vs. "dllfilemodified").
Looking through the output log, I can't find any reference to the modified text; it's still dllfileoriginal everywhere in the output.
Following the WriteLinesToFile task, it looks like the following targets were built:
- IncrementalClean (finished)
- PostBuildEvent
- CoreBuild
- AfterBuild
- Build
There's no reference to either DLL name inside these.
It looks like the is currently my best bet still.