Compiling .net projects with node-gyp

In order to actually use my custom msbuild logger, it must be compiled. Node has a native compiler that will be run during an npm install: node-gyp. All the documentation seems to indicate that this is only for c/c++ projects. I didn't like that answer, so I did a bit of research into projects I knew used c# in node. And I hit the jackpot with edge (which is itself really cool).

It turns out that you can specify a command line to run as an action. The difference is that instead of allowing node-gyp to create the visual studio project to build (and building it), you just have to specify a command line that will do the build. If using a .csproj file, this is how you'd do so:

{
  'targets': [{
    'target_name': 'my-project',
    'type': 'none',
    'actions': [{
      'action_name': 'compile',
      'inputs': [ 'all.cs', 'your.cs', 'files.cs' ],
      'outputs': [ 'path\to\result.dll' ],
      'message': 'msbuild myproject.csproj',
      'action': ['msbuild', 'myproject.csproj', '/p:Configuration=Release']
    }]
  }]
}

A couple of notes:

  • inputs and outputs must be specified, or node-gyp won't run your action during a build
  • inputs can be a blank array, but outputs must have at least one item, or node-gyp won't build it.
  • The project specified as the argument to msbuild will specify where to output the file, so outputs doesn't really matter.
  • Likewise, the project file specifies the files to build, so the contents of inputs isn't important.
  • outputs can be useful for other actions that wouldn't build your directory structure for you, as node-gyp will create it.
  • If your code exists in 1 file, consider calling csc (csharp compiler); you won't need a project file.

For my project, here is the resultant binding.gyp:

{
  'targets': [{
    'target_name': 'strider-msbuild-logger',
    'type': 'none',
    'actions': [{
      'action_name': 'compile',
      'inputs': [ ],
      'outputs': [ 'strider.msbuild.logger.dll' ],
      'message': 'msbuild Strider.MsBuild.Logger.csproj',
      'action': ['msbuild', 'Strider.MsBuild.Logger.csproj', '/nologo', '/tv:2.0', '/p:Configuration=Release']
    }]
  }]
}

I'm not using csc here, because I want to force the use of .NET 2.0. That way, all versions of msbuild can use my logger. As far as I'm aware, there is no way to force csc to do so.

I hope this quick tip is enough to get you started. There are more advanced scenarios, such as conditional actions (which would be great for building on linux with mono [in fact, edge does this]).

If you want to see how my project is using this, you can check it out on github.

-AH