MSBuild calling incorrect version of csc.exe - msbuild

I am using team city to call a nant script, currently this nant script is very simplistic and only calls an msbuild task on a single project in the solution.
The build is failing, it looks like msbuild 3.5 is being called, but it is incorrectly calling the csc.exe from the .net 2.0 folder. Since we are using .net 3.5 language features the compilation fails.
Looking at the csproj file, both the ToolsVersion and TargetFrameworkVersion are both set to use 3.5. What would be causing msbuild to pick the wrong version of csc.exe?

MSBuild uses a Toolset of tasks, targets, and tools to build an application. Typically, a MSBuild Toolset includes a microsoft.common.tasks file, a microsoft.common.targets file, and compilers such as csc.exe and vbc.exe. To ensure MSBuild invokes the correct C# compiler (csc.exe), specify the Toolset in the ToolsVersion attribute on the Project element in the project file.
The following example specifies that the project should be built by using the MSBuild 4.0 Toolset.
<Project ToolsVersion="4.0" ... </Project>
More information pertaining to the ToolsVersion attribute can be found here:
http://msdn.microsoft.com/en-us/library/78f4aasd.aspx

Do you have the 2.0 version of csc directly in your path, perhaps?
What happens when you run msbuild from a Visual Studio 2008 Command Prompt?

You can directly point which msbuild you want to use in nant script by declaring:
<!-- Initial path to use MSBuild from .NET Framework 3.5 -->
<property name="MSBuildApp" value="C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe" />
And then execute build via msbuild:
<exec failonerror="true" program="${MSBuildApp}" verbose="true">
<arg value="${SlnDir}\${SlnFile}" />
<arg value="/t:Rebuild" />
<arg value="/p:Configuration=${SlnConfig}" />
</exec>
Or you can point to proper .NET framework version when running NANT script:
nant CreateYouProjectTask -t:net-3.5 -buildfile:BuildYourProject.build

Related

Visual Studio for mac project.json

When I use Visual Studio for Mac to create a web project with .Net core 1.1, there is no project.json in my project. Is there any mistake when I create
this project?
Project.json was never released in production. It was replaced by a new, vastly simplified MSBuild project format before .NET Core was released. The new format works a lot like the project.json format - it supports globbing, package references and compiles all *.cs* files found in a folder. You don't need to define dependent packages in the project file any more, you can specify *one* root package and all dependencies will be added when you executedotnet restore`
.NET Core allows you to add commandlets that appear as commands to the .NET CLI. dotnet watch executes the dotnet-watch executable. dotnet ef searches for and executes the dotnet-ef executable.
You have to add an option to the MSBuild project that installs the tool in the first place with the <DotNetCliToolReference> element. After that, dotnet restore will install the tool just like any other package.
This is described in .NET Core Command Line Tools for EF Core.
The MSBuild project file should look like this :
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.0.0" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" />
</ItemGroup>
</Project>
This file is enough to build your project and execute ef commands from the command line, since all *.cs files will be compiled by default
project.json is deprecated and was never supported outside preview .NET Core tooling in VS 2015. The new tooling uses csproj files and can be used in VS 2017 and VS for Mac (and others like VSCode, Rider, …).

How to use MSBuild to build multiple platforms

I am using Visual Studio online build with an MSBuild task. I currently have the following MSBuild Arguments fed to my task:
/p:Configuration=Release;AppxBundle=Always;AppxBundlePlatforms="x86|x64|ARM";AppxPackageDir="$(Build.BinariesDirectory)\AppxPackages\\";UapAppxPackageBuildMode=StoreUpload
This creates my application in x86, x64 and ARM. It creates Release version of the libraries in x86 BUT creates Debug version of my libraries in x64 and ARM.
When my .appxupload package is creates it fails Windows Certification tests because my libraries are built in debug.
How can I make MSBuild build for all 3 configurations. My guess is because I haven't provided a /platform configuration. How do I provide this configuration for 3 platforms?
I have tried platform="x86|x64|ARM" but it returned an error
For a standard project file there's no way to do this in a single command. Either use multiple commands to build the project for each platform/configuration combination needed, or use a 'master' build file which does the same for you, something like:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="FullRebuild">
<Target>
<ItemGroup>
<Configurations Include="Debug;Release"/>
<Platforms Include="x86;x64;ARM"/>
<ConfigAndPlatform Include="#(Configurations)">
<Platform>%(Platforms.Identity)</Platform>
</ConfigAndPlatform>
</ItemGroup>
<MSBuild Projects="myproject.sln" Targets="Build"
Properties="Configuration=%(ConfigAndPlatform.Identity);Platform=%(ConfigAndPlatform.Platform)"/>
</Target>
</Project>

Referencing macros on msbuild (12.0) command line property assignment

I am curious, is it possible to reference a macro on a command line property assignment for MSBuild?
E.g:
msbuild.exe MySolution.sln /p:CustomBeforeMicrosoftCSharpTargets="$(SolutionDir)\custom.targets"
Would this also work when specified as "MSBuildArguments" from an "Edit Build Definition"/"Queue New Build" from Visual Studio connected to TFS?
E.g:
/p:CustomBeforeMicrosoftCSharpTargets="$(SolutionDir)\custom.targets"
Because it doesn't appear to be importing these targets for me. But the targets file is definitely there, alongside the solution, in the build workspace.
I don't want to have to specify an absolute path. Not sure how working with relative paths is meant to work here, can't find any advice on the internet, and debugging it is quite difficult, as it is called on a build agent using a workflow. The workflow logging is definitely reporting it is calling MSBuild with these arguments, but nowhere in the verbose logging output can I see it is making reference to the CustomBeforeMicrosoftCSharpTargets target, or calling it.
EDIT
I wrote a little test build project buildme.proj to further my understanding.
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<SetMe>NotInTheSandbox</SetMe>
</PropertyGroup>
<PropertyGroup>
<SomeMacroValue>c:\Sandbox\BuildTest</SomeMacroValue>
</PropertyGroup>
<PropertyGroup>
<AlreadySet>$(SomeMacroValue)\InTheSandbox</AlreadySet>
</PropertyGroup>
<Target Name="Build">
<Message Text="I am building!" />
<Message Text="Some macro value: $(SomeMacroValue)" />
<Message Text="$(SetMe)" />
<Message Text="$(AlreadySet)" />
</Target>
</Project>
When I execute with the command:
msbuild buildme.proj /p:SetMe="$(SomeMacroValue)\StillNotInSandbox"
I get the following output:
Microsoft (R) Build Engine version 12.0.31101.0
[Microsoft .NET Framework, version 4.0.30319.42000]
Copyright (C) Microsoft Corporation. All rights reserved.
Build started 10/12/2015 22:12:08.
Project "C:\Sandbox\BuildTest\buildme.proj" on node 1 (default targets).
Build:
I am building!
Some macro value: c:\Sandbox\BuildTest
$(SomeMacroValue)\StillNotInSandbox
c:\Sandbox\BuildTest\InTheSandbox
Done Building Project "C:\Sandbox\BuildTest\buildme.proj" (default targets).
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:00.02
So clearly, it is not behaving how I expected: The macro identifier appears in the output message text.
Is there a solution to this?
A "macro" like $(SolutionDir) exists only in VisualStudio and VS passes the value to MSBuild.
Instead MSBuild makes Environment variables available as properties, so a batch file like this
set SomeMacroValue=foo
msbuild buildme.proj /p:SetMe="$(SomeMacroValue)\StillNotInSandbox"
is probably what you are looking for.
And you can set environment variables per-user or per-machine (Control Panel\All Control Panel Items\System Advanced System Settings, Environment variables).

How do you publish a clickonce installer that includes .net installer and Auto-Update functionality?

I am using TeamCity for a continuous integration server and am deploying my application using a ClickOnce installer. I can get the installer to function and deploy my application but I cannot figure out how to include the installer for .net 4.5 if the computer does not already have it installed or how to enable the auto-update check feature in ClickOnce deployments. I am currently using the MSBuild file below to build my installer
<Project DefaultTargets="DoPublish" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>
<PropertyGroup>
<Version>$(BUILD_NUMBER)</Version>
<Install>true</Install>
<InstallFrom>Unc</InstallFrom>
<UpdateEnabled>true</UpdateEnabled>
<UpdateMode>Background</UpdateMode>
<ClickOnceBuildDirectory>$(MSBuildProjectDirectory)\MyProject\bin\$(Configuration)\app.publish</ClickOnceBuildDirectory>
<ClickOnceInstallDirectory>$(MSBuildProjectDirectory)\Publish</ClickOnceInstallDirectory>
<ClickOnceFinalLocation>$(env_PublishUrl)</ClickOnceFinalLocation>
</PropertyGroup>
<Target Name="DoPublish">
<RemoveDir Directories="$(ClickOnceInstallDirectory)" ContinueOnError="true" />
<MSBuild Projects="MyProject.sln" Targets="Clean;Build" Properties="ApplicationVersion=$(Version);Configuration=$(Configuration)"/>
<MSBuild Projects="MyProject\MyProject.csproj" Targets="Publish" Properties="ApplicationVersion=$(Version);Configuration=$(Configuration);InstallUrl=$(ClickOnceFinalLocation)" />
<MakeDir Directories="$(ClickOnceInstallDirectory)"/>
<Exec Command="xcopy /E $(ClickOnceBuildDirectory) $(ClickOnceInstallDirectory)" />
</Target>
</Project>
You can use a bootstrapper to handle prerequisites like checking for the .NET Framework. Check the Application Deployment Prerequisites MSDN article, especially the sections about bootstrapping with ClickOnce and MSBuild.
There are also 2 more MSDN articles that detail how to install ClickOnce prerequisites and Creating bootstrapper packages.
As for auto-updates, do you want to locate the auto-update functionality outside the application itself, i.e., in an installer vs. in the application? There are several ways to allow ClickOnce updates in your application, including auto-updates via the ClickOnce Deployment API.
A brief explanation of using ClickOnce Bootstrapper packages can be found in this existing Stackoverflow article. Though you're not using WiX here, you can also check this this WiX thread, which is useful because you see some of the steps that didn't work along the way. These examples show the use of the GenerateBootstrapper MSBuild task to create the bootstrapper for the ClickOnce installer. Note that in the examples at the above links, the "Path" in the GenerateBootstrapper task is set to a subfolder under a Windows SDK location. This can be changed to another location, as long as that location has the necessary prerequisite packages.
Below is an example in which the .NET 4.5 Framework is set as a prerequisite for the install. The parent directory structure for the .NET 4.5 prerequisite is specified by the $(MyPathToPrerequisitePackages) property.
The BootstrapperFile item in the below example specifies the .NET 4.5 Framework prerequisite package. The value ".NETFramework,Version=v4.5" comes from the product.xml file in the Bootstrapper\Packages\DotNetFX45 folder, and allows the GenerateBootstrapper task to correctly identify the .NET 4.5 prerequisite/bootstrapper package. The "ProductName" value is simply a friendly description of the package.
<PropertyGroup>
<MyPathToPrerequisitePackages>C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\Bootstrapper</MyPathToPrerequisitePackages>
</PropertyGroup>
<ItemGroup>
<BootstrapperFile Include=".NETFramework,Version=v4.5">
<ProductName>.NET Framework 4.5</ProductName>
</BootstrapperFile>
</ItemGroup>
<GenerateBootstrapper
ApplicationFile="$(MyAppAssembly).application"
ApplicationUrl="$(MyClickOnceAppUrl)"
ApplicationName="$(MyClickOnceAppName)"
BootstrapperItems="#(BootstrapperFile)"
Culture="en"
FallbackCulture="en-US"
CopyComponents="true"
Validate="false"
Path="$(MyPathToPrerequisitePackages)"
SupportUrl="$(MyAppSupportUrl)"
OutputPath="$(MyDesiredOutputPath)\" />
Just posted a response on 'https://stackoverflow.com/a/39610060/1345870':
Just struggled with this myself - I chose to commit the bootstrapper files to source control. It is possible to override the path to bootstrappers, just provide /p:GenerateBootstrapperSdkPath=.build\Bootstrapper
Then no need to modify registry - and the added benefit that the build is now self-contained.
Only "problem" is that I have to manually copy the Bootstrapper files into source control. In my case (VStudio2015), this meant copying the files from C:\Program Files (x86)\Microsoft Visual Studio 14.0\SDK\Bootstrapper

How to change Assembly Version Number using AssemblyInfoTask?

I am trying to automate the process for setting the Version for all DLL's, after spending some time I came to know the AssemblyInfo Task with which it can most likely be achieved.
So I went ahead and installed it, specifically version 1.0.51130.0.
After Installing, I manually added the Import Tag (by unloading the each project) of AssemblyInfoTask in .cspoj files (the solution has more than 35 proj files).
<Import Project="$(MSBuildExtensionsPath)\Microsoft\AssemblyInfoTask\Microsoft.VersionNumber.Targets"/>
Next I modified the Microsoft.VersionNUmber.Target file which will be installed in path: C:\Program Files\MSBuild\Microsoft\AssemblyInfoTask, and I modified the following section:
<!-- Properties for controlling the Assembly Version -->
<PropertyGroup>
<AssemblyMajorVersion>4</AssemblyMajorVersion>
<AssemblyMinorVersion>0</AssemblyMinorVersion>
<AssemblyBuildNumber></AssemblyBuildNumber>
<AssemblyRevision></AssemblyRevision>
<AssemblyBuildNumberType>DateString</AssemblyBuildNumberType>
<AssemblyBuildNumberFormat>01MMdd</AssemblyBuildNumberFormat>
<AssemblyRevisionType>AutoIncrement</AssemblyRevisionType>
<AssemblyRevisionFormat>00</AssemblyRevisionFormat>
</PropertyGroup>
<!-- Properties for controlling the Assembly File Version -->
<PropertyGroup>
<AssemblyFileMajorVersion>4</AssemblyFileMajorVersion>
<AssemblyFileMinorVersion>0</AssemblyFileMinorVersion>
<AssemblyFileBuildNumber></AssemblyFileBuildNumber>
<AssemblyFileRevision></AssemblyFileRevision>
<AssemblyFileBuildNumberType>DateString</AssemblyFileBuildNumberType>
<AssemblyFileBuildNumberFormat>01MMdd</AssemblyFileBuildNumberFormat>
<AssemblyFileRevisionType>AutoIncrement</AssemblyFileRevisionType>
<AssemblyFileRevisionFormat>00</AssemblyFileRevisionFormat>
</PropertyGroup>
Next I set the assemblyInfo.cs file's version to 1.0.0.0 in every project. Finally I saved and close it, reopened solution, and built. It works like a champ!
Now what want is to customize the Version to 4.0.1053.1 where 10 is the part of year indicator which is 2010 and 53 denotes the week number, at last 1 denotes revision number.
How to achieve this using the AssemblyInfo Task? I came across several posts that a new version of AssemblyInfo Task is available in Build Extension Pack.
I have installed the MSBuild Extension Pack December 2010 and its version is MSBuild Extension Pack 4.0.2.0 Installer
First.. use a globalassemblyinfo.cs that is linked from each project.
Add its as linked file to each project.
This means you update one file, not 30+ assemblyinfo files...then:
use MSBuild.Community.Tasks....
Then call
<AssemblyInfo CodeLanguage="CS"
OutputFile="$(VersionFile)"
AssemblyCompany="Company"
AssemblyProduct="Product"
AssemblyCopyright="Copyright © Company 2011"
ComVisible="false"
AssemblyVersion="$(BUILD_NUMBER)"
AssemblyFileVersion="$(BUILD_NUMBER)" />
Assuming you have something like:
<Import Project=".\tasks\MSBuild.Community.Tasks.Targets"/>
I do this in Jenkins by having a package build that is parameterised using the List Subversion Tags parameter type. The Subversion tag must follow the version number format (major.minor.revision.build), e.g. tags/2.0.0.1. The tag name is then assigned to a Jenkins parameter, e.g. $VERSION becomes 2.0.0.1
I use the WriteLinesToFile msbuild task to write out the assembly attribute to a second file alongside the PropertyInfo.cs called VersionInfo.cs. As checked in to source control, this just contains a default version number:
// Do not change this. The version is set on package builds only by setting the AsmVersion MSBuild property
[assembly: System.Reflection.AssemblyVersion("0.0.0.0")]
The package build on the build server passes in the version via the AsmVersion parameter:
/p:AsmVersion=$VERSION
The .csproj file is modified to have a BeforeBuild target (Visual Studio creates a commented out one for you):
<Target Name="BeforeBuild">
<WriteLinesToFile
Condition=" '$(AsmVersion)' != '' " File="Properties\VersionInfo.cs"
Overwrite="True"
Lines="[assembly: System.Reflection.AssemblyVersion("$(AsmVersion)")] // Generated by build" />
</Target>
When building in Visual Studio, or without passing in the AsmVersion, your assembly will have a default version of 0.0.0.0. When building in the package build, you will get your desired build number.
As #bruceboughton proposed, you can easily generate a version assembly file during compilation without using MSBuild.Community.Tasks library:
<PropertyGroup>
<Version>0.0.0</Version>
<InformationalVersion>0.0.0-dev~commithash</InformationalVersion>
<VersionFileName>$(BaseIntermediateOutputPath)Version.cs</VersionFileName>
</PropertyGroup>
<Target Name="GenerateVersionFile" BeforeTargets="BeforeBuild">
<WriteLinesToFile
File="$(VersionFileName)"
Overwrite="True"
Lines="
[assembly: System.Reflection.AssemblyVersion("$(Version)")]
[assembly: System.Reflection.AssemblyFileVersion("$(Version)")]
[assembly: System.Reflection.AssemblyInformationalVersion("$(InformationalVersion)")]" />
<ItemGroup>
<Compile Include="$(VersionFileName)" />
</ItemGroup>
</Target>
Remove definitions of the parameters you specify in the generated file from Properties\AssemblyInfo.cs file.
After that you can specify version by adding a parameter to the msbuild:
msbuild /property:Version=1.2.3 /property:InformationalVersion=1.2.3-dev~commithash .\SolutionFile.sln
Update for .NET Core style .csproj files: If you've come upon this question after having transitioned to the new .csproj format used by .NET Core, you can just set the Version property (no need to to bother with MSBuild tasks).
How I finally got this to work MSBuild version 12 (VS 2013).
Used Nuget to get MSBuildTasks Community package
Edited my .csproj file and added a path to the import the package:
<Import Project="..\packages\MSBuildTasks.1.5.0.235\build\MSBuildTasks.targets" Condition="Exists('..\packages\MSBuildTasks.1.5.0.235\build\MSBuildTasks.target')"/>
Figured out the Regex to change just the Revision number in the AssemblyInfo.cs file:
(?<=AssemblyFileVersion\("[0-9]\.[0-9]\.[0-9]\.)(\*)
which is not XML compatible, so has to be changed to:
(?<=AssemblyFileVersion\("[0-9]\.[0-9]\.[0-9]\.)(\*)
Uncommented the <Target Name="BeforeBuild"> section and added the following:
<Target Name="BeforeBuild">
<FileUpdate Files="properties\AssemblyInfo.cs"
Regex="(?<=AssemblyFileVersion\("[0-9]\.[0-9]\.[0-9]\.)(\*)"
ReplacementText="$(Revision)" />
</Target>
When running MSBuild added the "Revision" property to the command line e.g.
msbuild.exe myProject.csproj /t:Build /p:Configuration=Release;Revision=12345