Get the current logging verbosity level in my MSBuild script - msbuild

Our MSBuild scripts use the Exec task to call a few command line applications. Most of these applications have their own output verbosity settings which I would like to have be the same as the verbosity level of the MSBuild script calling them.
Is there a way for me to get the logging verbosity level of my MSBuild process?
I thought I could write a custom task to handle this, but poking around the MSBuild API, I couldn't find any properties or classes that would give me the verbosity level.

Shortly after asking my questions, I noticed that MSBuild 4 exposes System.Environment.CommandLine as a property function, which should include any verbosity arguments. With the following bit of parsing, you can create several boolean properties that will tell you the current logging level:
<PropertyGroup>
<CommandLine>$([System.Environment]::CommandLine.Trim().ToLower())</CommandLine>
<IsQuietVerbosity>False</IsQuietVerbosity>
<IsMinimalVerbosity>False</IsMinimalVerbosity>
<IsNormalVerbosity>True</IsNormalVerbosity>
<IsDetailedVerbosity>False</IsDetailedVerbosity>
<IsDiagnosticVerbosity>False</IsDiagnosticVerbosity>
</PropertyGroup>
<PropertyGroup Condition="'$(CommandLine.Contains("/v"))' == 'True'">
<IndexOfLastVerbosityArg>$(CommandLine.LastIndexOf("/v"))</IndexOfLastVerbosityArg>
<IndexOfVerbosityArg>$(CommandLine.IndexOf(":", $(IndexOfLastVerbosityArg)))</IndexOfVerbosityArg>
<IndexOfVerbosityArg>$([MSBuild]::Add($(IndexOfVerbosityArg), 1))</IndexOfVerbosityArg>
<IndexOfEndOfVerbosityArg>$(CommandLine.IndexOf(" ", $(IndexOfVerbosityArg)))</IndexOfEndOfVerbosityArg>
<IndexOfEndOfVerbosityArg Condition="'$(IndexOfEndOfVerbosityArg)' == '-1'">$(CommandLine.Length)</IndexOfEndOfVerbosityArg>
<LengthOfVerbosityArg>$([MSBuild]::Subtract($(IndexOfEndOfVerbosityArg), $(IndexOfVerbosityArg)))</LengthOfVerbosityArg>
<VerbosityLevel>$(CommandLine.Substring($(IndexOfVerbosityArg), $(LengthOfVerbosityArg)).Trim())</VerbosityLevel>
<IsQuietVerbosity>$(VerbosityLevel.StartsWith('q'))</IsQuietVerbosity>
<IsMinimalVerbosity>$(VerbosityLevel.StartsWith('m'))</IsMinimalVerbosity>
<IsNormalVerbosity>$(VerbosityLevel.StartsWith('n'))</IsNormalVerbosity>
<IsDiagnosticVerbosity>$(VerbosityLevel.StartsWith('di'))</IsDiagnosticVerbosity>
<IsDetailedVerbosity Condition="'$(IsDiagnosticVerbosity)' == 'False'">$(VerbosityLevel.StartsWith('d'))</IsDetailedVerbosity>
</PropertyGroup>
Remember, this will only work in MSBuild 4+.
Ugly? Yup. Kludgy? Maybe. Does it work. Yup!

You can't : http://social.msdn.microsoft.com/Forums/en-US/msbuild/thread/510f07b4-c5f7-43a8-b7cb-e3c398841725/
Instead, you can set a property of yours (passing it with the command line for example) which contains the verbosity level.

Related

MSBuild overrides properties while building VC++ project

I'm trying to build my vcxproj with different properties through command line base on MSBuild. I tested WarningLevel property since it is on MSDN MSBuild introduction page.
My project originally sets WarningLevel as 3. I kicked off:
msbuild myproj.vcxproj /p:Configuration=Debug /p:Platform=Win32 /p:WarningLevel=4;OutDir=test\Debug
I checked tracker log to see what the executing command is, it turned out "/W3" is still there other than "/W4" as expected. However, "OutDir" was set correctly and I could find target files in bin\Debug directory.
Is there anything incorrect I did with WarningLevel? How to override properties correctly? Please teach me the right way, I will be fully grateful.
Regards,
SL
This is in essence a duplicate of this question, but that one is for adding items to the list of PreProcessorDefinitions which is not exactly the same as overriding WarningLevel, which can only have one value. So here it goes: WarningLevel isn't a global property, like OutDir, but it's part of the ClCompile ItemDefinitionGroup so you cannot set it directly. It looks somewhat like this in the project file:
<PropertyGroup>
<!-- global property, can be overridden on commandline -->
<OutDir>$(ProjectDir)$(Configuration)$(Platform)</OutDir>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<!-- not a global property -->
<WarningLevel>Level4</WarningLevel>
</ClCompile>
<ItemDefinitionGroup>
Two ways to deal with this, see answers for the linked question:
First option is to set the WarningLevel to another property which you then define on the commandline. Go to Project Properties->Configuration Properties->C/C++->General->Warning Level and enter $(MyWarningLevel). In the project file, this looks like
<ItemDefinitionGroup>
<ClCompile>
<!-- gets it's value from a global property now -->
<WarningLevel>$(MyWarningLevel)</WarningLevel>
</ClCompile>
<ItemDefinitionGroup>
and it's set using msbuild myproj.vcxproj /p:MyWarningLevel=Level3. If not set explicitly the default value will be used.
Second option is to use one of the msbuild/C++ extension points. Create a file named override.props or so containing
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemDefinitionGroup $(PUT_IN_YOUR_CONDITION)>
<ClCompile>
<WarningLevel>Level4</WarningLevel>
</ClCompile>
</ItemDefinitionGroup>
</Project>
and have msbuild pick it up with msbuild myproj.vcxproj /p:ForceImportBeforeCppTargets=/path/to/override.props

Can MSBuild ItemGroup's be chunked?

I've got an ItemGroup that includes source files from my project:
<ItemGroup>
<SourceFiles Include=".\**\*.h;.\**\*.cpp"/>
</ItemGroup>
There are a few hundred source files. I want to pass them to a command line tool in an Exec task.
If I call the command line tool individually for each file:
<Exec Command="tool.exe %(SourceFiles.FullPath)" WorkingDirectory="."/>
Then, it runs very slowly.
If I call the command line tool and pass all of the files in one go:
<Exec Command="tool.exe #(SourceFiles -> '"%(FullPath)"', ' ')" WorkingDirectory="."/>
Then, I get an error if there are too many files (I'm guessing the command line length exceeds some maximum).
Is there a way I can chunk the items so that the tool can be called a number of times, each time passing up to a maximum number of source file names to the tool?
I'm not aware of any mechanism to do that with well known item metadata. What you could do is load all those paths into their own item group and write a custom task that calls the exec task. Writing a custom task is pretty simple, it can be done inline:
http://msdn.microsoft.com/en-us/library/vstudio/dd722601(v=vs.100).aspx

MSBuild batch updating ItemGroup MetaData with output from a custom task

I am trying to use MSBuild 4.0 to Uninstall\install a set of windows services I have defined in an ItemGroup using the MSBuild extensions. The problem I am running into is if the service does not exist the uninstall TaskAction will error out. I want to be able to use the CheckExists TaskAction to set a flag in my metadata that I can evaluate on the condition statement.
However, I cannot figure out how to batch over the list of services, calling the CheckExist task and updating the flag in my metadata. See sample below:
<ItemGroup>
<ServiceName Include="Service1">
<ExeName>Service1.exe</ExeName>
<ServicePath>$(LocalBin)\Service1.exe</ServicePath>
<User>LocalSystem</User>
<Exists></Exists>
</ServiceName>
<ServiceName Include="Service2">
<ExeName>Service2.exe</ExeName>
<ServicePath>$(LocalBin)\Service2.exe</ServicePath>
<User>LocalSystem</User>
<Exists></Exists>
</ServiceName>
</ItemGroup>
<Target Name="UninstallServices">
<!--how can I batch over this command to set %(ServiceName.Exist)-->
<MSBuild.ExtensionPack.Computer.WindowsService TaskAction="CheckExists" ServiceName="%(ServiceName.Identity)">
<Output TaskParameter="Exists" PropertyName="DoesExist"/>
</MSBuild.ExtensionPack.Computer.WindowsService>
<MSBuild.ExtensionPack.Computer.WindowsService TaskAction="Uninstall" ServiceName="%(ServiceName.Identity)" User="%(ServiceName.User)" ServicePath="%(ServiceName.ServicePath)" Condition="%(ServiceName.Exists) = 'True'" />
</Target>
I have done some searching and have not found an example where metadata is being updated based on an Output result of a Task. Is this something that is possible? Should I be taking a different approach?
My current solution for this problem has been to set ContinueOnError to true on the call for the uninstall, but I do not like this approach because I could be hiding other errors.
Any help would be appreciated.
Thanks,
Tyson Moncrief

Pass property value from TFS Build Definition to proj file

I have a build definition set up in my TFS 2012 instance. In this Build Definition I want to pass in a custom argument and access said argument in my .csproj file. For example:
MSBuild Arguments: /p:MyFoo=1
In my .csproj file I want to do this:
<ItemGroup Condition=" '$(MyFoo)' == '1' ">
Is this possible, or am I going about this incorrectly?
This is more than possible, it's very easy to do. Edit your build definition, under the process tab expand the "advanced" section and you will see a property called "MSbuild Arguments" add the argument in the format in the question. e.g. /p:MyFoo=1
e.g.
You can also enter the arguments when you queue a build

Commandline override the /Out paramter of a vcbuild task of msbuild

Is there a way to specify the output like
msbuild zlibvc.sln /t:zlibvc /p:OUT=$(OutDir)\zlib1.dll
by example, changing the output from the standard zlibwapi.dll to zlib1.dll ?
In case of C# projects, we do modify csproject file in the following two places like this:
Before:
<AssemblyName>zlibwapi.dll</AssemblyName>
and
<OutputPath>bin\</OutputPath>
After:
<ZLibAssemblyName Condition="$(ZLibAssemblyName) == '' ">zlibwapi.dll</ZLibAssemblyName>
<AssemblyName>$(ZLibAssemblyName)</AssemblyName>
and
<ZLibOutputPath Condition="$(ZLibOutputPath) == '' ">bin\</ZLibOutputPath>
<OutputPath>$(ZLibOutputPath)</OutputPath>
Then call your msbuild command like below:
msbuild zlibvc.sln /t:zlibvc /p:ZLibOutputPath=$(OutDir)\ /p:ZLibAssemblyName=zlib1.dll
Hope this or a similar thing works in vcbuild task as well.