How do I use custom variables in MSBuild scripts? - msbuild

Is there a way to use custom variables on the command-line when building with MSBuild.exe as follows:
MSBuild.exe bootstrapper.msbuild <custom_variable1=custom_variable_value1>
custom_variable2=custom_variable_value2>...<custom_variablen=custom_variable_valuen>
The purpose is to know whether I have to launch another executable or not.

You should start with the basics. The answer is found in the official documentation.
MSBuild calls these properties instead of variables.
In practice:
msbuild bootstrapper.msbuild /p:custom_variable1=custom_variable_value1
And in the MSBuild file you could use it as such:
<Target Name="MyTarget">
<PropertyGroup>
<custom_variable1 Condition="'$(custom_variable1)'==''">defaultValue</custom_variable1>
</PropertyGroup>
<Exec Condition="'$(custom_variable1)'=='someValue'" .../>
</Target>
This assigns a default value to the property if it doesn't exist or is empty, and only executes the Exec task if the value is equal to someValue.

Related

Pass property for single project on commandline when building a solution

When I use msbuild to build a solution containing multiple projects, can I pass a property on the command line in a way that the property will only be used for one of the projects?
That means, can I say that -p:Foo=42 shall be used for Project1, but not for Project2?
MSBuild cannot specify a property for one of the project by the solution file(msbuild xxx\xxx.sln) easily and only targets can be specified. Or you have to type multiple msbuild command line to specify to the related csproj file to enable that changed property like msbuild Project1.csproj -t:build -p:xxx=xxx, msbuild Project2.csproj -t:build. However, it is too complex and inconvenient.
So I recommend that you could use msbuild script to get what you want.
1) create a file called build.proj file:
<Project>
<ItemGroup>
<!--add all the projects from the solution and remove the any project you want to modify the foo property-->
<MostProjectFile Include="**\*.csproj;**\*.vcxproj" Exclude="**\Project1.csproj" />
<!--add any projects you want to modify the foo value-->
<SpecialProjectFile Include="**\Project1.csproj" />
</ItemGroup>
<Target Name="Build">
<!--build the most projects and remove the project which you want to change foo property-->
<MSBuild Projects="#(MostProjectFile)" Targets="Build" Properties="Configuration=Debug"/>
<!--build any projects that wants to modify the foo property separately-->
<MSBuild Projects="#(SpecialProjectFile)" Targets="Build" Properties="Configuration=Debug;Foo=42"/>
</Target>
</Project>
2) if you want to change the foo property again, you can just modify the build.proj based on your needs.
Run msbuild xxx\build.proj -t:Build to build it.

MSBuild target with MSBuild task pass in properties from command line

I have a targets file which uses the MSBuild task to compile bunch of .csproj files. This works as expected.
Is it possible to take the properties from the commandline?
<Target Name="MyBuild">
<MSBuild Projects="#(Projects)" Properties="FROM COMMAND LINE"/>
</Target>
msbuild mybuild.proj /p:myProperty=true
You can do something like this:
<Target Name="MyBuild">
<MSBuild Projects="#(Projects)" Properties="$(MyProperties)"/>
</Target>
and call MSBuild this way:
msbuild mybuild.proj /p:MyProperties="MyProperty=true;MyOtherProperty=false"
Environment variables can be used to set MSBuild properties. We use batch files to set env variables based on command line parameters, which then invokes MSBuild after setting env variables based on the command line parameters.

MSBuild $(version)?

In our target DestinationFiles we wish to set path to contain the version number of the project file we use to build. Is there a variable we can use to get that value?
< Target Name="CopyOutput">
<ItemGroup>
<PackagedFiles Include="blah blah"/>
</ItemGroup>
<Copy SourceFiles="#(PackagedFiles)"
DestinationFiles="#(PackagedFiles->'\\Blah\SOME_VERSION_NUMBER_FROM_BUILD\$(Configuration)\%(RecursiveDir)%(Filename)%(Extension)')"/>
</Target>
Sure just use $(VARNAME) and call msbuild with /p:VARNAME=XXXX
For more details regarding using enviornment vars with msbuild, you can have a look at https://sbarnea.com/articles/easy-windows-build-versioning/

USe MSBuild properties in windows batch command line?

defined some msbuild properties, is it possible to 'promote' it to be used in the windows batch file? i.e. in my .bat file write something 'echo %CustomProperty%' where the CustomProperty is defined in the msbuild script
Accessing MSbuild properties within a batch file doesn't seem to be the correct release approach and does not seem necessary. The same facility is easily available within Msbuild itself. In your example case you can use something like the following:
<Message Text="Copying $(ZipFile) to $(PublicFolderToDropZip)" Importance="high" />
to achieve what you were looking.
You can even run batch files in the following manner:
<Target Name="Default">
<Exec Command="CALL mybatch.cmd" />
</Target>

Conditional compilation with automated builds in Visual Studio

Here's what I'm trying to do:
A single build script
That script builds two executables from the same Visual Studio project.
The first compiled .exe has a small amount of code disabled.
The other compiled .exe has everything enabled.
I've been reading up on conditional compilation and that takes care of my needs as far as enabling/disabling blocks of code.
I just can't figure out how to control conditional compilation from a build script using msbuild.
Is there a way to manipulate conditional compilation variables from a build script or some other way to accomplish what I'm trying to do?
Use build configurations in your project file. Set the parameters in a PropertyGroup that is optionally included based on the configuration. The configuration can then also define the output path for the two different versions of the assembly.
For the version that needs to remove some code use a configuration that includes the PropertyGroup.
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'CompiledOutDebug|AnyCPU' ">
<DefineConstants>$(DefineConstants);MY_CONDITIONAL_COMPILATION_CONSTANT</DefineConstants>
</PropertyGroup>
Then use an MSBuild script that calls the project MSBuild script twice and uses the Properties attribute of the MSBuild task to specify the configuration to build:
<Target Name="Build">
<MSBuild Projects="MyProject.csproj;"
Targets="Build"
Properties="Configuration=Release" />
<MSBuild Projects="MyProject.csproj"
Targets="Build"
Properties="Configuration=CompiledOutDebug" />
</Target>
Hamish beat me to it.
Here's an alternate solution using the same concepts:
At the command line:
msbuild -t:Clean
msbuild
CopyOutputDirForWithoutDefine.cmd
msbuild -t:Clean
msbuild -property:DefineConstants=MY_CONDITIONAL_COMPILE_CONSTANT
CopyOutputDirForWithDefine.cmd
The 1st and 3rd 'msbuild -t:Clean' ensures that you don't have left over turds from previous builds. The 2nd 'msbuild' builds without the conditional define, while the 4rth builds with the conditional define.
If the above are just a couple on shot items, then a batch file maybe enough. I recommend learning a bit of MSBuild and actually scripting everything in a MSBuild file as Hamish has done.
If you don't want to create a separate target for the two compilations, you can do it by specifying the conditional define in the DefineConstants property when you call the build the second time:
<Target Name="Build">
<MSBuild Projects="MyProject.csproj;"
Targets="Build"
Properties="Configuration=Debug" />
<MSBuild Projects="MyProject.csproj"
Targets="Build"
Properties="Configuration=Debug;
AssemblyName=$(AssemblyName)_Conditional;
DefineConstants=$(DefineConstants);CONDITIONAL_DEFINE" />
</Target>
Note that if you do it this way, you need to also overwrite the AssemblyName, otherwise your second build might pick intermediate files from the first build.
You should also look at the MSBuild task docs on MSDN, there are some interesting tidbits there.