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.
Related
We can define a target in a csproj file and then specify that target when we call msbuild from the command line. That looks like this:
my.csproj
<Target Name="CopyFiles">
<Copy
SourceFiles="#(MySourceFiles)"
DestinationFolder="c:\MyProject\Destination" />
</Target>
msbuild
msbuild my.csproj /t:CopyFiles
The CopyFiles targets asks msbuild to run the Copy task.
What if we don't want to edit the csproj file. How can we define a target just from the command line? Alternatively, using only the command line, how can we ask msbuild to run just one or maybe two tasks?
Pseudo-Code
msbuild my.csproj /t:"Copy SourceFiles=#(MySourceFiles) DestinationFolder=..."
Based on the MSBuild Command-Line Reference, this isn't possible exactly as you describe it, i.e. MSBuild will not take Target definitions from the command-line input. They have to be defined in a file somewhere.
But, you can have a script (maybe even a .bat?) that does something like:
Create a new, essentially empty, project file.
Import the .csproj, with <Import Project="foo.csproj" />
Add the targets
Call MSBuild with the new project file with the targets you want. Multiple targets can be specified by multiple /t: switches. Properties can be specified with /p:
The final, programmatically/script generated project file might look something like:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="foo.csproj" />
<Target Name="CopyFiles">
<Copy
SourceFiles="#(MySourceFiles)"
DestinationFolder="$(Destination)" />
</Target>
</Project>
The actual MSBuild command called might then be:
msbuild temp.proj /t:CopyFiles /p:"Destination=c:\MyProject\Destination"
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/
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.
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>
I'd like to have a different verbosity for the msbuild project invoked from the commandline, and those invoked by the MSBuild task from within the project. For example:
Inside my.proj:
<Target Name=Foo>
<MSBuild Projects="a.csproj;b.csproj;c.csproj"/>
</Target>
On the commandline:
msbuild /v:d my.proj
now when the MSBuild task builds the .csproj files, it does it with detailed verbosity as well. However I'd want to build it with minimal verbosity.
I know it is possible to invoke msbuild manually like so:
<Target Name=Foo>
<Exec Command="msbuild /v:m a.csproj"/>
<Exec Command="msbuild /v:m b.csproj"/>
<Exec Command="msbuild /v:m c.csproj"/>
</Target>
or in practice
<Target Name=Foo>
<Exec Command="msbuild /v:m %(Projectlist.Identity)"/>
</Target>
and this works well off course, but then I cannot get the functionality of the BuildInParallel switch anymore (I do not think it is possible to invoke msbuild from the commandline with multiple projects without them being contained in a solution?)
Update
I went with Ludwo's option: basically create a custom logger that holds two ConsoleLoggers as a member. One has the verbosity passed at command line, the other one is 'minimal'. The logger registers for all events and passes them to one of the loggers depending on whether a csproj file is currently being built or not. Output looks exactly like normal, except it doesn't include thousands of lines from the csproj files.
You have two options (at least) :)
Create one additional msbuild script for building abc projects
"BuildABC.proj"
<Target Name="BuildABC">
<MSBuild Projects="a.csproj;b.csproj;c.csproj" BuildInParallel="true"/>
</Target>
In your parent script execute MSBuild using Exec task and call
"BuildABC.proj" with minimal verbosity
<Target Name=Foo>
<Exec Command="msbuild /v:m /m:2 BuildABC.proj"/>
</Target>
You have to pass explicitly all parent properties needed in the BuildABC project to msbuild /p parameter.
Use custom logger. See this how to do it. In this case you can use your original script:
<Target Name=Foo>
<MSBuild Projects="a.csproj;b.csproj;c.csproj"/>
</Target>
In your custom logger do not log anything related to e.g. "a.csproj" project between ProjectStarted and ProjectFinished events where e.ProjectFile == "a.csproj" (to disable diagnostic logging on "a.csproj" project while building parent project with diagnostic verbosity)