How to run MSBuild from Powershell without spawning msbuild.exe process?

谁都会走 提交于 2019-12-30 00:35:33

问题


I am considering running MSBuild from a Powershell script by tapping directly to the MSBuild assemblies (as opposed to looking up MSBuild install path and starting msbuild.exe as a child process).

Has anyone done this? What would be the simplest, most straightforward way to run the build? Are there any pros/cons to either technique you'd like to point out? (I'm especially interested in any issues that might arise from running msbuild in the same process/appdomain as the rest of the script).

Currently my thinking is something along these lines:

[void][System.Reflection.Assembly]::Load('Microsoft.Build.Engine, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a')
[void][Microsoft.Build.BuildEngine.Engine]::GlobalEngine.BuildProjectFile("path/main.proj")

回答1:


The simplest embedded-build invocation that worked and produced output was:

[void][System.Reflection.Assembly]::Load('Microsoft.Build.Engine, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a')
$engine = New-Object Microsoft.Build.BuildEngine.Engine
$engine.RegisterLogger((New-Object Microsoft.Build.BuildEngine.ConsoleLogger))
$engine.BuildProjectFile('fullPath\some.proj')

However, it turns out embedding MSBuild directly in Powershell (V1) is problematic:

'MSBUILD : warning MSB4056: The MSBuild engine must be called on
a single-threaded-apartment. Current threading model is "MTA".
Proceeding, but some tasks may not function correctly.'

Why oh why are we still paying COM tax in 2009 while working in a managed environment?

My conclusion is that embedding MSBuild in Powershell (V1) is not a good idea. For reference, I'm also including the process-based approach I ended up using:

[void][System.Reflection.Assembly]::Load('Microsoft.Build.Utilities.v3.5, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a')
$msbuild = [Microsoft.Build.Utilities.ToolLocationHelper]::GetPathToDotNetFrameworkFile("msbuild.exe", "VersionLatest")
&$msbuild fullPath\some.proj



回答2:


I would very highly suggest looking at PSake.

Let me quote a portion of that page:

Remember that psake is syntactic sugar around PowerShell. So anything you can do in PowerShell, you can do in psake. That means that you can run MSBuild, NAnt, or other scripts. There is no need to completely replace your current build system. You can use psake to automate and extend it!

psake automatically adds the appropriate version of .NET Framework to its path. So you can access MSBuild, csc.exe, vbc.exe, or any other tools installed in $env:windir\Microsoft.NET\Framework\$version\ without the fully qualified path.




回答3:


A different and potentially more usable approach would be to make an msbuild cmdlet. MsBuild has a nice API and there are many samples out there on how to use it from a compiled language such as C#/VB. It would be very easy to build a cmdlet that would provide a much nicer syntax to your powershell scripts.




回答4:


I was looking for this same thing. Following JaredPar's lead I found the following:

This is a how-to on making a cmdlet.

http://bartdesmet.net/blogs/bart/archive/2008/02/03/easy-windows-powershell-cmdlet-development-and-debugging.aspx

The MSBuild API is part of these namespaces:

Microsoft.Build.Framework

Microsoft.Build.BuildEngine

And the MSBuild documentation can be found here (this is more for completeness than in response to your question):

http://msdn.microsoft.com/en-us/library/wea2sca5.aspx




回答5:


Once upon a time I've been playing with running augmented MSBuild build processes (like, skip some parts of the build more aggressively).

There were two choices:

  1. Host MSBuild in your own process by loading its DLLs.
  2. Spawn MSBuild.exe the regular way and then inject into it (e.g. loggers provide a decent way in).

I've implemented both and had to abandon #1 because it wasn't flexible enough.

For instance, MSBuild has a load of assembly binding redirections in its .config file.

The Visual Studio process (devenv.exe) which also hosts MSBuild with its API ends up copypasting these into its devenv.exe.config. Mine .exe.config had also to have these, but it adheres you to a specific MSBuild version. And, of course, you have to modify the config. Which is not an option with PS actually, so I doubt if you could get a really stable solution.



来源:https://stackoverflow.com/questions/472038/how-to-run-msbuild-from-powershell-without-spawning-msbuild-exe-process

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!