MSBUILD target outputs element is applied strangly [duplicate] - c#

I have customised an MSBuild project so that the default target is a new target named similarly to 'BuildWithExternalReference'. This new target calls two other targets; the first is a custom target called something like 'BuildExternalReference' which builds a DLL using an external tool. The DLL that is built is a reference for the main project, which is built using the normal 'Build' target. I have setup the Inputs and Outputs attributes for the 'BuildExternalReference' target so the Inputs reference the source files and the outputs reference the resulting DLL.
In both Visual Studio 2012 and Visual Studio 2010 the build works correctly the first time it is invoked. However, on subsequent builds if I change the external source files (referenced by the 'BuildExternalReference' target Inputs attribute) then Visual Studio 2012 simply reports 'Build: 0 succeeded, 0 failed, 1 up-to-date, 0 skipped'. Visual Studio 2010 continues to work perfectly. In addition, building from the command line with MSBuild.exe works perfectly.
I'm aware that the build system in Visual Studio 2012 has changed, but I can't find information about changes to the way incremental builds are performed.
Has anything changed in Visual Studio 2012 to cause incremental builds to change?
Here's a cut down version of the csproj file I'm using:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="BuildWithExternalTool" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ExternalSourceFiles Include="..\ExternalSourceFiles\\*\*.cs" />
<ExternalDll Include="..\ExternalSource\External.dll" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Target Name="BuildExternalTool" Inputs="#(ExternalSourceFiles);" Outputs="#(ExternalDll)">
<Exec Command="C:\External\Path\To\Tool.exe" />
</Target>
<Target Name="BuildWithExternalTool">
<CallTarget Targets="BuildExternalTool" />
<CallTarget Targets="Build" />
</Target>
</Project>
Update 1st of November 2012
Here's a complete self contained example which reproduces the issue:
https://skydrive.live.com/redir?resid=EA1DD6ACA92F9EFF!155&authkey=!ANhuqF_rrCgxpLE
This is a solution with one project. The MSBuildIssueExample\MSBuildIssueExample.csproj file has been customised so there is a custom default target. This default target calls a custom target (called 'ExternalTool') and then the default Build target.
The custom ExternalTool target writes out some messages to make sure it's working, and also copies the contents of the MSBuildIssueExample\ExternalTool\Input.txt file over the MSBuildIssueExample\ExternalTool\Output.txt file.
The Input.txt file is a input of the ExternalTool target, and Output.txt is an output.
To recreate the issue follow these steps:
1) Open the solution in the designated version of Visual Studio
2) Build the solution once to make sure the outputs are up to date with respect to the inputs
3) Modify MSBuildIssueExample\ExternalTool\Input.txt so its content does not match Output.txt
4) Build again
When you go through this process in Visual Studio 2010 the ExternalTool target will be invoked again, and the Input.txt file will be copied over Output.txt.
When you go through this process in Visual Studio 2012 the ExternalTool target will not be invoked, even though the inputs are newer than the outputs, and as a result the contents of Input.txt will not be written to Output.txt.
However, if you do Rebuild (rather than just Build) then both versions of Visual Studio work as expected.

This feedback from Microsoft answers the question:
This is due to a change in VS 2012 where C#/VB projects now do a "fast up-to-date check" that allows them to skip the build, rather than forcing the build all the time. One downside, however, is that fast up-to-date check does not take into account custom targets, which is why your incremental change was not detected. If you wish to disable the "fast up-to-date check" please set "DISABLEFASTUPTODATECHECK" to true either as an MSBuild property in the project file or as an environment variable in the environment you launch VS from.
So basically this is a breaking change in Visual Studio 2012 that unfortunately does not seem to be documented very well.

This is an old issue, but still relevant. Thank you very much for raising it here.
I would like to provide the results of my research.
The example you share shows the abnormal behavior both when built inside the Visual Studio GUI and by the devenv command line (devenv .\MSBuildIssueExample.sln /build)
However, if you replace your csproj file with the following:
MSBuildIssueExample.csproj
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{4EA8847D-262C-4937-8536-E526E9BAB1C7}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MSBuildIssueExample</RootNamespace>
<AssemblyName>MSBuildIssueExample</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Class1.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="Custom.Targets" />
</Project>
Custom.Targets
<?xml version="1.0" encoding="utf-8" ?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<CompileDependsOn>ExternalTool;$(CompileDependsOn)</CompileDependsOn>
<CleanDependsOn>CleanOutput;$(CleanDependsOn)</CleanDependsOn>
</PropertyGroup>
<ItemGroup>
<ExternalToolInputs Include="ExternalTool\Input.txt">
<InProject>false</InProject>
</ExternalToolInputs>
<ExternalToolOutputs Include="ExternalTool\Output.txt">
<InProject>false</InProject>
</ExternalToolOutputs>
</ItemGroup>
<Target Name="ExternalTool" Inputs="#(ExternalToolInputs)" Outputs="#(ExternalToolOutputs)">
<Message Text="ExternalTool target start, copying input file over output..." />
<Copy SourceFiles="#(ExternalToolInputs)" DestinationFiles="#(ExternalToolOutputs)" />
<Message Text="ExternalTool target end, copy successful" />
</Target>
<Target Name="CleanOutput">
<Delete Files="#(ExternalToolOutputs)" ContinueOnError="true" />
</Target>
</Project>
Then the behavior is different !
Visual Studio GUI continues to misbehave, however, the command line build with devenv does recognize the change in the input!
Also note, that running msbuild on the command line instead of devenv works correctly in both versions. Although msbuild has other problems ...
EDIT
There is a solution for the GUI build, which is only applicable when the amount of external files is small. You add them to the project as links and make sure the Build Action is None. Then it works fine in the GUI.
Although, I have only checked with the Custom.Targets, but I am pretty sure it is going to work with the original version as well.

To expand on mark's Edit, and since None-items didn't work for me, here's an example of a custom targets file that I can import in other projects, that reads a text file into a property (which I can then use in the DefineConstants property), and that will mark the text file as input for the CoreCompile target:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<CommonDefines>$([System.IO.File]::ReadAllText('$(SolutionDir)\_meta\definesFlags.txt'));$(CommonDefines)</CommonDefines>
</PropertyGroup>
<ItemGroup>
<CustomAdditionalCompileInputs Include="$(SolutionDir)\_meta\definesFlags.txt" />
</ItemGroup>
</Project>
CustomAdditionalCompileInputs-items is taken as an input by Microsoft.Csharp.Core.targets.

Related

New csproj re-generates files forever when Visual Studio is open

I'm generating some .cs files using node.exe before the compilation, which I then include in my project.
I call node.exe and define the steps for the generation via CSProj. After migrating the CSProj to the new format <Project Sdk="Microsoft.NET.Sdk"> the files are constantly being generated, erased and generated again while Visual Studio is open (tested with VS2017 and VS2019).
This is my targets file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
...
</PropertyGroup>
<Target Name="SetVariables">
<ItemGroup>
<_NodeJsExe Include="$(MSBuildThisFileDirectory)..\..\..\Node.js.redist\*\tools\win-x64\node.exe"/>
</ItemGroup>
<PropertyGroup>
<__NodeJsExe>#(_NodeJsExe);</__NodeJsExe>
<NodeJsExe>$(__NodeJsExe.Substring(0, $(__NodeJsExe.IndexOf(';'))))</NodeJsExe>
</PropertyGroup>
</Target>
<Target Name="ProblemHere" BeforeTargets="TransformDuringBuild;PrepareForBuild;CoreCompile" DependsOnTargets="SetVariables;CleanFilesBeforeBuild">
<Exec Command=""$(NodeJsExe)&quot..." />
</Target>
<Target Name="CleanFilesBeforeBuild">
<ItemGroup>
<Ts2LangFiles Include="$(GeneratedFolder)\**\*.cs" />
</ItemGroup>
<Delete Files="#(Ts2LangFiles)"/>
</Target>
</Project>
Anyone knows what the problem is?
Found out that Visual Studio is building some targets at design-time.
If I add this to my custom target, the files stop being constantly generated by MSBuild:
<Target Name="ProblemHere" Condition="$(DesignTimeBuild) != true And $(BuildingProject) == true" BeforeTargets="TransformDuringBuild;PrepareForBuild;CoreCompile" DependsOnTargets="SetVariables;CleanFilesBeforeBuild">
I just have yet to understand if this is a bug in Visual Studio or if the problem is mine and I'm using the targets like I'm not supposed to.

Build target used by Visual Studio to do Incremental Build via msbuild command line

I created a task in our C# Projects to auto-version projects when they are built (changes are made) in release mode. The versioning part works perfectly. However, all the projects are being built regardless if the project actually changed when done from command line. This causes projects to be versioned unnecessarily. Building in Visual Studio works, unchanged projects are not built, however we made a tool to do automated build using msbuild.exe and are using this as a temporary fix while we work on Bamboo and that method always does a blind build, even if there are no changes to the project. I need to be able to identify if changes were made to the project.
Something like
'$(wasSourceUpdated)' == 'true' or some kind of target condition to use on my custom versioning target.
Here is a sample of my versioning task in our projects
<Import Project="..\..\DXT.BuildTasks\Targets\DXTAutoIncrementVersion.targets" Condition="Exists('..\..\DXT.BuildTasks\Targets\DXTAutoIncrementVersion.targets') And '$(Configuration)|$(Platform)' == 'Release|AnyCPU' And '$(DeployOnBuild)' != 'true'" />
I also checked this and this articles to no avail.
EDIT
I need the task to run before the build is actually executed in order to stamp the generated assemblies with the new versions
EDIT 2
What I'm really looking for is the condition to run CoreCompile or to run CoreCompile again when I detect that the assembly was updated
What I've tried so far:
<Project>
<PropertyGroup>
<RunPostBuildEvent>OnOutputUpdated</RunPostBuildEvent>
</PropertyGroup>
<PropertyGroup>
<_AssemblyTimestampBeforeCompile>%(IntermediateAssembly.ModifiedTime)</_AssemblyTimestampBeforeCompile>
</PropertyGroup>
<PropertyGroup>
<_AssemblyTimestampAfterCompile>%(IntermediateAssembly.ModifiedTime)</_AssemblyTimestampAfterCompile>
</PropertyGroup>
<PropertyGroup>
<_ProjectVersioned Condition="'$(_ProjectVersioned)'==''">false</_ProjectVersioned>
</PropertyGroup>
<Target Name="IncrementVersionBeforeBuild" AfterTargets="CoreCompile" Condition="'$(_AssemblyTimestampBeforeCompile)'!='$(_AssemblyTimestampAfterCompile)' and '$(_ProjectVersioned)' == 'false'">
<Message Text="Before $(_AssemblyTimestampBeforeCompile) After $(_AssemblyTimestampAfterCompile)" Importance="High"/>
<IncrementVersion
ProjectPath="$(MSBuildProjectFullPath)"
VersionRule="3.3.0.+"
FileName="Properties\AssemblyInfo.cs">
</IncrementVersion>
</Target>
<PropertyGroup>
<TaskPath>$(MSBuildThisFileDirectory)..\Tasks\AutoVersionTask\AutoVersionTask\bin\Debug</TaskPath>
</PropertyGroup>
<!-- Sample import for projects
<Import Project="..\..\DXT.BuildTasks\Targets\DXTAutoIncrementVersion.targets" Condition="Exists('..\..\DXT.BuildTasks\Targets\DXTAutoIncrementVersion.targets') And '$(Configuration)|$(Platform)' == 'Release|AnyCPU' And '$(DeployOnBuild)' != 'true'" />
-->
<UsingTask AssemblyFile="$(TaskPath)\AutoVersionTask.dll" TaskName="AutoVersionTask.IncrementVersion" />
<PropertyGroup>
<_ProjectVersioned>true</_ProjectVersioned>
</PropertyGroup>
Thanks in advance
So Thanks to Lance for getting me to understand MSBuild to the point that I understand the issue way better.
After a long time researching the default task, I ran upon this question that had the perfect solution to my issue. After applying the fix the versioning task now only runs when changes are made to the msbuild code.
The inputs and outputs are the same as the CoreCompile target and ensures that the task is only run if there were changes to the source
Here is the target I ran that works:
<?xml version="1.0" encoding="utf-8"?>
<Project>
<PropertyGroup>
<CoreCompileDependsOn>
$(CoreCompileDependsOn);
IncrementVersionBeforeBuild
</CoreCompileDependsOn>
</PropertyGroup>
<Target Name="IncrementVersionBeforeBuild"
Inputs="$(MSBuildAllProjects);
#(Compile);
#(_CoreCompileResourceInputs);
$(ApplicationIcon);
$(AssemblyOriginatorKeyFile);
#(ReferencePath);
#(CompiledLicenseFile);
#(EmbeddedDocumentation);
$(Win32Resource);
$(Win32Manifest);
#(CustomAdditionalCompileInputs)"
Outputs="#(DocFileItem);
#(IntermediateAssembly);
#(_DebugSymbolsIntermediatePath);
$(NonExistentFile);
#(CustomAdditionalCompileOutputs)"
>
<Message Text="Version Task running" Importance="High"/>
<IncrementVersion
ProjectPath="$(MSBuildProjectFullPath)"
VersionRule="3.3.0.+"
FileName="Properties\AssemblyInfo.cs">
</IncrementVersion>
</Target>
<PropertyGroup>
<TaskPath>$(MSBuildThisFileDirectory)..\Tasks\AutoVersionTask\AutoVersionTask\bin\Debug</TaskPath>
</PropertyGroup>
<UsingTask AssemblyFile="$(TaskPath)\AutoVersionTask.dll" TaskName="AutoVersionTask.IncrementVersion" />
<PropertyGroup>
<_ProjectVersioned>true</_ProjectVersioned>
</PropertyGroup>
</Project>
Normaly, we can add the script below into .csproj file:
<PropertyGroup>
<RunPostBuildEvent>OnOutputUpdated</RunPostBuildEvent>
</PropertyGroup>
<Target Name="AutoVersionWhenBuild" AfterTargets="CoreBuild"
Condition="'$(_AssemblyTimestampBeforeCompile)'!='$(_AssemblyTimestampAfterCompile)'">
<Message Importance="high" Text="Auto-version begins when changes are made!"/>
<!--<AutoVersionTask>Do your auto-version task here.</AutoVersionTask>-->
</Target>
It will be called during the build when changes are really made to the project. See this similar issue.
As for your situation:
It seems your tasks and target comes from the targets file DXTAutoIncrementVersion.targets,you can open that file and change the target in it to the format above.
In addition: Please check the relationship between tasks, targets and .targets file.
1.MSBuild uses tasks to perform these actions.
2.Targets group tasks together.
3.MSBuild includes several .targets files that contain items, properties, targets, and tasks for common scenarios.
So you can either modify your auto-version target in the xx.targets file, or use the script above, and call the auto-version task in the AutoVersionWhenBuild target. Hope it helps:)

Visual Studio C# project in Monodevelop - Errors for GenerateSatelliteAssemblies and GenerateTargetFrameworkMonikerAttribute

I am trying to setup a C# project that is compatible with both Windows 10 / Visual Studio 2015 and Ubuntu 16.04 / MonoDevelop.
In the MonoDevelop project options, I set the target framework to Mono / .NET 4.5 and configuration to Debug|x86.
The .csproj file now looks like this:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProjectGuid>{myprojectsguid}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>myproject</RootNamespace>
<AssemblyName>myproject</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<DebugType>full</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>
When I build, I get this message:
Erzeuge Projektmappe: myproject (Debug|x86)
myproject (Debug|x86) wird erzeugt
Build started 26.05.2016 22:05:49.
__________________________________________________
Project "pathto/myproject.csproj" (Build target(s)):
Target PrepareForBuild:
Configuration: Debug Platform: x86
Target GenerateSatelliteAssemblies:
No input files were specified for target GenerateSatelliteAssemblies, skipping.
Target GenerateTargetFrameworkMonikerAttribute:
Skipping target "GenerateTargetFrameworkMonikerAttribute" because its outputs are up-to-date.
Done building project "pathto/myproject.csproj".-- FAILED
Build FAILED.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:00.0785520
--------------------- Fertig ---------------------
Erzeugung erfolgreich.
The message seems to contradict itself. The English part says "build failed", while the localized/German part says "build successful". But no executable was created.
I did not find any applicable information about GenerateSatelliteAssemblies or GenerateTargetFrameworkMonikerAttribute.
Do I need to change the project settings even further? Do I need to supply some missing files?
Update:
Apparently, some packages were missing. So I ran sudo apt-get install mono-complete. Now the project builds successfully.
Though, the notifications about GenerateSatelliteAssemblies and GenerateTargetFrameworkMonikerAttribute are still there. Looks like they don't break the build. I still wonder what they mean.
(I'm just posting the answer that the asker wrote in the question.)
For the asker, it turned out that some packages were missing. The asker ran sudo apt-get install mono-complete, and then the project would build successfully.

Visual Studio Online Error parsing solution file at *.xproj

I am working on an AspNet5 project and trying to use VSO to build the project. I am following the article here but when I build the xproj file I get "Error parsing solution file at {ProjectPath}.xproj: Exception has been thrown by the target of an invocation." How can I get the MsBuild step to run without throwing this error?
Edit:
My xproj file nearly identically matches the xproj here
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>06d62522-2dad-4393-9b90-17d70e275587</ProjectGuid>
<RootNamespace>ProjectNamespace</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
<DevelopmentServerPort>2645</DevelopmentServerPort>
</PropertyGroup>
<ItemGroup>
<DnxInvisibleContent Include="bower.json" />
<DnxInvisibleContent Include=".bowerrc" />
<DnxInvisibleContent Include="package.json" />
</ItemGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>
I found the answer to this problem and it is due to VSO automatically doing a NuGet restore. After I unchecked NuGet restore it works fine. In the tutorial there is a step that adds 'dnu restore' which is where the packages are being restored.
Ah, found it. It is a property of the VS Build step.

Implementing StyleCop MSBUILD From NuGet Package

A quick precursor to say that I've done the usual searching around the forums and net in general, and I've tried a multitude of suggestions found on this forum and elsewhere to no avail.
The problem I'm having is that my company is looking to implement internal automated peer-reviews (to an extent of course) with the use of tools such as StyleCop, ReSharper and JSLint (etc etc).
We're using a custom NuGet package against our internal NuGet Package Repository (feed) so that our developers get an administered release of tools (i.e. they cannot download the latest StyleCop when it comes out until its been reviewed and released) with the addition of our custom rules (StyleCop Settings file). Because we want to use StyleCop MSBUILD tasks to highlight errors at build time, the assemblies for StyleCop need to be exact and therefore we're ruling out installations of the C:\Program Files\ version in favour of a NuGet release.
I've managed to create a NuGet package that installs to a project (class library, web site, etc), copies the approved StyleCop assemblies (StyleCop.dll, StyleCop.CSharp.dll and StyleCop.CSharpRules.dll), Settings.StyleCop and StyleCop.Targets to the package folder, and modifies the .csproj file to include the following nodes (this just a snippet of course):
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition=" '$(Configuration)' != 'Debug' ">
<StyleCopTreatErrorsAsWarnings>false</StyleCopTreatErrorsAsWarnings>
</PropertyGroup>
<Import Project="$(SolutionDir)\packages\NuGetPackageName.1.0.0\StyleCop.Targets" />
</Project>
If I have StyleCop installed as C:\Program Files\ and in C:\Program Files\MSBUILD then everything works, but using this method the StyleCop.Targets doesn't seem to work correctly. It is being used as Visual Studio 2010 throws errors if the file is removed and it creates a StyleCop.Cache file. The StyleCop.Targets file has been changed to point at the local DLL in the NuGet package folder, and I have tried a couple of different .Targets files including the standard StyleCop one (with relative filepath changes). Even if I override the MSBUILD properties locally it doesn't work, such as OverrideSettingsFile.
The StyleCop.Targets file looks like this currently:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Specify where tasks are implemented. -->
<UsingTask AssemblyFile="$(SolutionDir)\packages\NuGetPackageName.1.0.0\lib\net40\StyleCop.dll" TaskName="StyleCopTask"/>
<PropertyGroup>
<BuildDependsOn>$(BuildDependsOn);StyleCop</BuildDependsOn>
<RebuildDependsOn>StyleCopForceFullAnalysis;$(RebuildDependsOn)</RebuildDependsOn>
</PropertyGroup>
<!-- Define StyleCopForceFullAnalysis property. -->
<PropertyGroup Condition="('$(SourceAnalysisForceFullAnalysis)' != '') and ('$(StyleCopForceFullAnalysis)' == '')">
<StyleCopForceFullAnalysis>$(SourceAnalysisForceFullAnalysis)</StyleCopForceFullAnalysis>
</PropertyGroup>
<PropertyGroup Condition="'$(StyleCopForceFullAnalysis)' == ''">
<StyleCopForceFullAnalysis>false</StyleCopForceFullAnalysis>
</PropertyGroup>
<!-- Define StyleCopCacheResults property. -->
<PropertyGroup Condition="('$(SourceAnalysisCacheResults)' != '') and ('$(StyleCopCacheResults)' == '')">
<StyleCopCacheResults>$(SourceAnalysisCacheResults)</StyleCopCacheResults>
</PropertyGroup>
<PropertyGroup Condition="'$(StyleCopCacheResults)' == ''">
<StyleCopCacheResults>true</StyleCopCacheResults>
</PropertyGroup>
<!-- Define StyleCopTreatErrorsAsWarnings property. -->
<PropertyGroup Condition="('$(SourceAnalysisTreatErrorsAsWarnings)' != '') and ('$(StyleCopTreatErrorsAsWarnings)' == '')">
<StyleCopTreatErrorsAsWarnings>$(SourceAnalysisTreatErrorsAsWarnings)</StyleCopTreatErrorsAsWarnings>
</PropertyGroup>
<PropertyGroup Condition="'$(StyleCopTreatErrorsAsWarnings)' == ''">
<StyleCopTreatErrorsAsWarnings>true</StyleCopTreatErrorsAsWarnings>
</PropertyGroup>
<!-- Define StyleCopEnabled property. -->
<PropertyGroup Condition="('$(SourceAnalysisEnabled)' != '') and ('$(StyleCopEnabled)' == '')">
<StyleCopEnabled>$(SourceAnalysisEnabled)</StyleCopEnabled>
</PropertyGroup>
<PropertyGroup Condition="'$(StyleCopEnabled)' == ''">
<StyleCopEnabled>true</StyleCopEnabled>
</PropertyGroup>
<!-- Define StyleCopOverrideSettingsFile property. -->
<PropertyGroup Condition="('$(SourceAnalysisOverrideSettingsFile)' != '') and ('$(StyleCopOverrideSettingsFile)' == '')">
<StyleCopOverrideSettingsFile>$(SourceAnalysisOverrideSettingsFile)</StyleCopOverrideSettingsFile>
</PropertyGroup>
<PropertyGroup Condition="'$(StyleCopOverrideSettingsFile)' == ''">
<StyleCopOverrideSettingsFile> </StyleCopOverrideSettingsFile>
</PropertyGroup>
<!-- Define StyleCopOutputFile property. -->
<PropertyGroup Condition="('$(SourceAnalysisOutputFile)' != '') and ('$(StyleCopOutputFile)' == '')">
<StyleCopOutputFile>$(SourceAnalysisOutputFile)</StyleCopOutputFile>
</PropertyGroup>
<PropertyGroup Condition="'$(StyleCopOutputFile)' == ''">
<StyleCopOutputFile>$(IntermediateOutputPath)StyleCopViolations.xml</StyleCopOutputFile>
</PropertyGroup>
<!-- Define all new properties which do not need to have both StyleCop and SourceAnalysis variations. -->
<PropertyGroup>
<!-- Specifying 0 will cause StyleCop to use the default violation count limit.
Specifying any positive number will cause StyleCop to use that number as the violation count limit.
Specifying any negative number will cause StyleCop to allow any number of violations without limit.
-->
<StyleCopMaxViolationCount Condition="'$(StyleCopMaxViolationCount)' == ''">0</StyleCopMaxViolationCount>
</PropertyGroup>
<!-- Define target: StyleCopForceFullAnalysis -->
<Target Name="StyleCopForceFullAnalysis">
<CreateProperty Value="true">
<Output TaskParameter="Value" PropertyName="StyleCopForceFullAnalysis" />
</CreateProperty>
</Target>
<!-- Define target: StyleCop -->
<Target Name="StyleCop" Condition="'$(StyleCopEnabled)' != 'false'">
<Message Text="Forcing full StyleCop reanalysis." Condition="'$(StyleCopForceFullAnalysis)' == 'true'" Importance="Low" />
<!-- Determine what files should be checked. Take all Compile items, but exclude those that have set ExcludeFromStyleCop=true or ExcludeFromSourceAnalysis=true. -->
<CreateItem Include="#(Compile)" Condition="('%(Compile.ExcludeFromStyleCop)' != 'true') and ('%(Compile.ExcludeFromSourceAnalysis)' != 'true')">
<Output TaskParameter="Include" ItemName="StyleCopFiles"/>
</CreateItem>
<Message Text="Analyzing #(StyleCopFiles)" Importance="Low" />
<!-- Show list of what files should be excluded. checked. Take all Compile items, but exclude those that have set ExcludeFromStyleCop=true or ExcludeFromSourceAnalysis=true. -->
<CreateItem Include="#(Compile)" Condition="('%(Compile.ExcludeFromStyleCop)' == 'true') or ('%(Compile.ExcludeFromSourceAnalysis)' == 'true')">
<Output TaskParameter="Include" ItemName="StyleCopExcludedFiles"/>
</CreateItem>
<ItemGroup>
<StyleCopFiles Remove="#(ExcludeFromStyleCop)" />
</ItemGroup>
<Message Text="Excluding #(StyleCopExcludedFiles)" Importance="Normal" />
<!-- Run the StyleCop MSBuild task. -->
<StyleCopTask ProjectFullPath="$(MSBuildProjectDirectory)" SourceFiles="#(StyleCopFiles)"
AdditionalAddinPaths="#(StyleCopAdditionalAddinPaths)" ForceFullAnalysis="$(StyleCopForceFullAnalysis)"
DefineConstants="$(DefineConstants)" TreatErrorsAsWarnings="$(StyleCopTreatErrorsAsWarnings)"
CacheResults="$(StyleCopCacheResults)" OverrideSettingsFile="$(StyleCopOverrideSettingsFile)"
OutputFile="$(StyleCopOutputFile)" MaxViolationCount="$(StyleCopMaxViolationCount)" />
<!-- Make output files cleanable -->
<CreateItem Include="$(StyleCopOutputFile)">
<Output TaskParameter="Include" ItemName="FileWrites"/>
</CreateItem>
<!-- Add the StyleCop.cache file to the list of files we've written - so they can be cleaned up on a Build Clean. -->
<CreateItem Include="StyleCop.Cache" Condition="'$(StyleCopCacheResults)' == 'true'">
<Output TaskParameter="Include" ItemName="FileWrites"/>
</CreateItem>
</Target>
</Project>
Does anyone know how I can get this working? Visual Studio 2010 doesn't show any messages in the Output window.
Cheers all!
I'm posting the solution I came across for anyone in a similar position.
Firstly I followed this excellent guide on debugging MSBuild operations, which helped me to iron out some of the logic and variables:
http://blogs.msdn.com/b/visualstudio/archive/2010/07/06/debugging-msbuild-script-with-visual-studio.aspx
Following this I checked the StyleCopViolations.xml which was in my /obj/Debug/ folder. This however always returned 0 results, with just the following XML:
<StyleCopViolations/>
I did some research on this and found that I needed to include StyleCop.CSharpRules.dll in to my NuGet/lib/net40/ folder with the StyleCop.dll, StyleCop.CSharp.dll and StyleCop.Settings files.
My project didn't needed references to any of the aforementioned assemblies, but I realised that my NuGet package had a dependency on the StyleCop NuGet package which did not include StyleCop.CSharpRules.dll.
After adding this assembly I was still seeing 0 results, so I did a manual override of all 3 assemblies and the .Settings file from a fresh install of the StyleCop C:\Program Files\StyleCop\ installer (from CodePlex). After overwriting the NuGet package assemblies this started working!
So to wrap up, debug your MSBuild (with the link at the top of this post) and don't use the NuGet package just yet!
Cheers
Use StyleCop.MSBuild instead of StyleCop as suggested by Dmitry Lobanov.
i.e use the command install-package stylecop.msbuild in the package manager console.
You can use combination of nuget packages StyleCop.MSBuild and StyleCop.Error.MSBuild to enable stylecop warnings as errors.
Go to Turn Windows features on and off, and make sure that .Net Framework is checked
Then rebuild your project.

Categories