Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I treat MSB3245 (could not resolve reference) warning as an error?

Tags:

msbuild

My question is based on another one, but I want to do the opposite: tell msbuild to treat the warning as an error instead of suppressing a specific msbuild warning.

However, all I see so far says /p:WarningsAsErrors only takes in csc warnings and errors. I tried just dropping the MSB and googling for what number might go in there to work, but no luck.

Is there any way to treat an "assembly reference not found" warning from msbuild (command line) as an error?

like image 856
Maslow Avatar asked Jul 05 '13 18:07

Maslow


2 Answers

Recently I needed something similar (acting on certain log events) but I couldn't find a clean solution mainly because I haven't figured out how to programmatically access the loggers in the msbuild process. I did come up with this though, adapted to your problem the principle is:

  • install a custom logger scanning for the warning
  • build
  • set a static flag if the warning occurs
  • have a custom task check that flag and raise an error if it's on

Might sound hard, but the code is simple enough:

using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

namespace Foo
{
  public static class Common
  {
    public static bool errorsOccurred = false;
  }

  public class ScanLogger : Logger
  {
    public override void Initialize( IEventSource eventSource )
    {
      eventSource.MessageRaised += ( s, e ) =>
        Common.errorsOccurred |= e.Message.Contains( "MSB3245" );
    }
  }

  public class CheckErrors : Task
  {
    public override bool Execute()
    {
      if( Common.errorsOccurred == false )
        return true;
      Log.LogError( "errorsOccurred = true" );
      return false;
    }
  }
}

Here's a sample msbuild script using it:

<UsingTask TaskName="Foo.CheckErrors" AssemblyFile="Foo.dll"/>

<Target Name="MyBuild">
  <Message Text="MSB3245"/> <!-- simulate the build warning -->
  <Foo.CheckErrors /> <!-- this will trigger an error -->
</Target>

And you invoke it like this:

msbuild /logger:Foo.dll my.proj

edit I just needed this again but couldn't find the original dll nor project file etc anymore - I figured storing just the code and simplest build instructions in git and building it on the fly when needing it is probably cleaner. So basically store the code above in a file customlogger.cs and then somewhere in your build process, before effectively invoking msbuild with the custom logger, build it using

<Target Name="BuildCustomLoggerDll">
  <Csc Sources="$(MSBuildThisFileDirectory)customlogger.cs"
       References="System.dll;mscorlib.dll;Microsoft.Build.Framework.dll;Microsoft.Build.Utilities.v4.0.dll"
       TargetType="Library" OutputAssembly="$(MSBuildThisFileDirectory)CustomLogger.dll"/>
</Target>

update In response to comments: trying this again today I'm not sure the original code actually ever worked (well, it does for the sample message shown but not for actual warning MSB3245), since it hooks message events only whereas the ResolveAssemblyReference emits an actual warning event and moreover the warning number isn't typically contained contained in the message. This does the trick though:

public class ScanLogger : Logger
{
  public override void Initialize( IEventSource eventSource )
  {
    eventSource.WarningRaised += ( s, e ) => Common.errorsOccurred |= e.Code == "MSB3245";
  }
}
like image 93
stijn Avatar answered Nov 13 '22 09:11

stijn


It seems that the message associated with this warning that's not a warning:

If this reference is required by your code, you may get compilation errors

, is not quite correct. If the missing reference is a WPF theme, you'll get a run-time error (System.IO.FileNotFoundException) instead.

As an aside, if you specifically look for MSB3245 you'll get:

CSC : warning CS1691: 'MSB3245' is not a valid warning number

like image 44
Michael J. Avatar answered Nov 13 '22 10:11

Michael J.