Since the release of Visual Studio 2010 we have received a few reports of crashing behavior which can be traced back to issues with MSBuild. We’ve analyzed all of these and there are several particular cases where a crash can occur. We’ve also added a notification to Windows Error Reporting to help guide those who hit these errors. You can determine you your error is one of these either by matching the problem description below, or looking in the Event Viewer as follows:
Fault bucket 1055654512, type 1 Event Name: APPCRASH Response: xxxxxxx Cab Id: 0
Fault bucket 1055654512, type 1
Event Name: APPCRASH
Response: xxxxxxx
Cab Id: 0
Problem: This can occur if the build process is missing a required target. This is normally due to an improperly customized build process. If you are using the .NET MicroFramework 4, which is not supported in Visual Studio 2010, you may also see this issue.
Solution: Provide the missing target. Try building the project/solution on the command-line. If MSBuild logs an error that a target is missing, that could be the problem.
Problem: COM registration requires the user have permission to certain registry keys, and lacking that permission the RegASM task crashes.
Solution: Ensure the registry keys needed to perform the registration are accessible to the account doing the registration. Look under HKCR\Record for the GUID matching the type (or types) associated with the COM components you are registering.
Problem: When building projects with Visual Studio 2010 and the .NET MicroFramework 4, the build would fail with an InvalidProjectFileException. The .NET MicroFramework 4 is not compatible with Visual Studio 2010.
Workaround: There is unfortunately no workaround for this. According to the .NET MicroFramework 4 team, the next version of the MicroFramework will support VS2010. Check out http://www.microsoft.com/netmf/default.mspx for updated information.
Problem: Building on the command-line or from Visual Studio displays an error that MSBuild could not find MSBuild.exe during a C++ or multiproc build. If your username is exactly 20 character long excluding your domain (the maximum allowed under Windows), there is a bug in the .NET Framework which will prevent us from authenticating the other MSBuild nodes.
Workaround: Build under an account with a name that is less than 20 characters. The bug should be fixed in the next version of the .NET Framework.
Problem: Your build in Visual Studio aborts with an OutOfMemory exception. It may or may not also do this when built from the command-line. This occurs typically when there are a very large number of projects with a lot of interdependencies, or when projects have an extremely large number of source files.
Workaround: Build your solution on the command-line, so that your process does not have Visual Studio’s initial memory foot print; or build on a 64-bit machine under a 64-bit command window so we can take advantage of the additional virtual memory spacel or split your solution into smaller chunks which can be built individually; or create a solution configuration in which only a subset of your projects build.
Problem: When building a solution which contains C++ and WiX projects, Visual Studio may crash.
Solution: This problem has been traced to a bug in the WiX project system. Please contact the WiX project for a newer version with the correct bits.
For some crashing issues we have set up Windows Error Reporting so that it will automatically request for you to send us additional information and contact us directly. If you see such a request, please consider providing us with the requested additional information so we can either determine that your issue is already known or address it in the next version of the product.
In my last two posts (here and here) I showed how to enable the unsupported MSBuild debugger to debug a build started on the command line with MSBuild.exe. In this final post, I'll mention some other variations.
Note that this blog is rather narrow, so some of the screenshots may be hard to see – you can click on them to see the full size version.
In the previous example, I launched msbuild.exe against a project file. You well might want to start with a solution file instead. If you do, you may get an error that looks like this:
Microsoft.Build.Shared.InternalErrorException: MSB0001: Internal MSBuild Error: Mismatched leave was C:\Users\danmose\Do cuments\visual studio 2010\Projects\WindowsFormsApplication1\WindowsFormsApplication1.sln.metaproj expected C:\Users\dan mose\Documents\visual studio 2010\Projects\WindowsFormsApplication1\WindowsFormsApplication1.csproj (2,1)
The workaround is as follows. First, set an environment variable MSBUILDEMITSOLUTION=1. Then do a build of the solution in the regular way: if you want, you can cancel it after it starts building projects. Next to the solution file, you should see a file with the extension ".sln.metaproj". This is essentially the solution file translated into MSBuild-format. Now do the usual debugging procedure, but this time launch msbuild.exe against this sln.metaproj file instead of the original solution file.
When you're debugging your build process or tasks, it's much easier to follow if only one project is building at a time, and you'll probably do it that way whenever you can. What's more, debugging slows down the build so much that it may not help you diagnose a timing problem anyway.
If however for some reason you do need to debug a multiprocessor build, it's possible.
As you probably know, MSBuild launches child processes to build more than one project at once, and they persist for a while to be ready for another build. The /debug switch doesn't propagate to them. To get this to work, first terminate any msbuild.exe processes that are still alive. Then in a command window set an environment variable MSBUILDDEBUGGING=1. That environment variable is equivalent to the /debug switch, but unlike the switch it will get propagated to any child processes.
From this command window now start msbuild.exe with the /debug switch as usual. Everything will work much the same as before, but you'll get a new JIT prompt as each child process starts to do its work, and you'll have to use a new instance of Visual Studio for each one of them.
For example, I'm building a solution here, using the .metaproj workaround I mentioned above. Attaching at the first JIT prompt, I can see I am starting in the .metaproj itself:
If I hit Continue (F5) I'll get to the top of the next project, and stop there as usual. In the callstack window, I can see that the solution has invoked that project, and I can double click on the lower frame in the callstack to see where it did that – it's an MSBuild task, of course:
While I'm stopped here, I get a JIT prompt again. This time it's for the other project in my solution, which has already started to load in parallel in another msbuild.exe process. I'll go through the JIT prompts as I did before, and select to start a new instance of Visual Studio. That will in turn break in at the top of that other project.
Here's what I see now:
Visual Studio supports debugging more than one process at the same time, which would be more convenient, but I don't think the JIT launcher will let you do that. If you have a lot of child processes, it could get rather cumbersome. Remember that the "/m" switch defaults to the same number of processes as you have CPU's, so you may want to cut it down with "/m:2".
When I wrote the prototype, it was also possible to debug the evaluation and building of projects loaded in Visual Studio.
Unfortunately in walking through this scenario to write this blog post, I was sorry to find that it's somewhat broken in the release version of Visual Studio 2010. In my experiments debugging works through the first evaluation, as the projects are loaded, but then it hits a bug and terminates. Since it's an untested feature there's always the chance something can break without detection and that's apparently what happened here.
Given that, you'll most likely have to stick with msbuild.exe. However, I'll go ahead and explain a little about how one would do this in Visual Studio, in case you have better luck than I do.
Start off by setting the registry key as described at the start of my first post and kill any lingering instances of MSBuild.exe as you did in the last scenario.
Make sure the environment variable MSBUILDDEBUGGING is not set and open your first Visual Studio to act as your debugger. You can do this from the start menu. As before make sure Just-My-Code is switched on in this instance.
Open a command prompt and set the environment variable MSBUILDDEBUGGING=1 again. Then launch Visual Studio from that command prompt -- most likely you'd start it with a command like "%ProgramFiles%\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe". This second instance is your debuggee, which you will load your projects into.
Go back to the debugger process, and attach to that debuggee, choosing the "Managed (v4.0)" engine as always. In this debugger process, open up the project or targets file you want to start debugging through. Make sure you open it with "Open File" into the XML editor, rather than loading it as an actual project.
Debugging may not start automatically on the first line this time, so set a breakpoint where you want to begin. I opened the "WindowsFormsApplication1.csproj" file I used before into the XML editor, and set a breakpoint on the first line to get hit when the project is first loaded.
Open up your project or projects in the normal way in the debuggee now and you should see your breakpoint is hit. Step a little further, and for me, Visual Studio terminates.
Now I've shown you all the features of the MSBuild debugger, I hope you'll try it out.
If you have feedback, do post it here. In particular, how important is it to be able to debug projects loaded inside Visual Studio? Also, as you've seen, MSBuild must be in "debugging mode" from launch -- it's not possible to walk up to a regular build that's in progress and attach to it. Is it important to be able to do that?
Most of all, how useful is this to you, and how problematic are the bugs and limitations you run into?
Thanks for reading
Dan
Visual Studio Project & Build Dev Lead
In my previous post, I showed how to enable the hidden Visual Studio debugger for MSBuild script, and demonstrated it by stepping through the evaluation of a C# project. In this post, I'll keep debugging into the actual build of that project.
Starting from where we left off last post, I'll set a breakpoint in Microsoft.CSharp.targets on the <Csc> task tag. That's where the compiler will run. Then hit F5 to run to it.
Ideally, I'd be able to set a breakpoint on the enclosing <Target> tag, but unfortunately there's a bug: you can't. As a workaround you could inspect the values of a target's attributes when you get to the first tag in the body of that target. If the target's condition is false, or if its inputs and outputs are up to date so that it skips, it's not so simple. You'd have to work around this by stepping up to the target before.
I'd like to be able to evaluate the condition on the task there, but because it's batchable it could have multiple results: the EvaluateCondition delegate I used before won't accept it. If this was a parameter on the task, I'd probably step into the task's code itself to see the value. Since it's a condition, I'd probably look through the metadata on the item list directly, or query the object model in some way.
Something like the value of Sources is easy to evaluate here, though:
Now I want to step into the task implementation.
You might think that at this point, you can simply Step In (F11). However, you can't – it happens that MSBuild will run this task on a different thread. To know to jump threads properly here, the debugger has to support what they call "causality" for this kind of debugging, and since it doesn't know anything about MSBuild, it doesn't.
It's easy to get the job done though – set a breakpoint in the task and run until it's hit.
I have the source code for the Csc task, so I set a breakpoint here on the setter of the WarningLevel property, and did Continue (F5). I can see the task is getting "4" as the value of that property here. I can debug this code just like any other C# code, stepping through methods and so forth.
To get out to the XML, I'll set a breakpoint in it and run – the same trick I used to get into the C#, but in reverse. Here I'm at the next tag after the task:
I used Csc as an example here, but you'll generally be debugging a custom task (or possibly, logger). Just make sure the assembly is not optimized: since you have Just-My-Code on, it won't be debuggable otherwise. If you only have access to an optimized one, you can switch off Just-My-Code temporarily.
There's a CallTarget tag here: you can step into those, and like imports they'll look like a new frame on the callstack – although unlike imports, that's correct for their semantics.
Probably the biggest limitation (bug) with the debugger right now is that you can't see item and property changes made inside a target. For example, at this point @(_CoreCompileResourceInputs) should be empty because of the line above, but the immediate window tells me it isn't:
When you get past that target, you can see the changes.
Typically there's more than one project in a build. I've added a project reference from this project to another. I've put a breakpoint at the top of that project, and run to it:
The bottom of the callstack is the point in Microsoft.Common.targets where, early in the build of WindowsFormsApplication1, it invoked WindowsFormsApplication2.
See you then!
Back when we started 4.0 development, I polled readers of the MSBuild blog to find out what features were most important to them. Debugging was #1 which was very surprising to us. Thinking about it more, it makes sense. In our team we've become so proficient ourselves at reading the XML and making sense of logs that it's easy to forget how difficult it is – especially for someone new. John Robbins, debugging guru, also requested a Visual-Studio-integrated debugger.
Fast forward to the 4.0 release earlier this year, and we addressed 7 out of 16 of the requests by my count. We had to balance the requests with what Visual Studio itself needed from MSBuild. There were two major requirements it had on MSBuild: to enable VC++ to move onto MSBuild (#5 request), and to help enable more powerful and fine grained multi-targeting.
It turned out that these two in turn required many other features, most of which were happily also popular requests on that blog poll. We added the ability to define a task with inline code (#7 – see powershell example) a new, comprehensive object model (#14; in three parts, one, two, three), improved performance and scalability in many cases (#8 -- and here), property and item functions (#9 – albeit not currently extensible) , and accurate automatic dependency checking by performing file system interception (#11), plus some small syntax additions (label, import group, import by wildcard) and a more configurable build engine (eg see here, here, and here), plus easier build extensibility and some performance diagnostics.
We didn't have time, unfortunately, to address converting the solution file to MSBuild (#3) – which we would dearly love to do – nor to add a Visual Studio integrated debugger (#1).
At least, not a supported one!
Mike Stall approached us to demonstrate an ingenious reflection-emit idea which made it considerably more feasible to create an MSBuild specific debugger with many of the features of the real managed code debugger. While on leave I wrote and checked-in the code to do it. Unfortunately we couldn't complete it in time to make the 4.0 schedule.
For that reason, it's in the product, but disabled by default. It does work, it's just not supported or documented, and has a few limitations and bugs: it may be slow, it's not always pretty, and in at least one case, it's a little inaccurate. This blog post is "unofficial" documentation of how to use it in the hope it will be useful. Although it's not supported we will welcome Connect feedback, but it will likely will be moved to our backlog rather than fixed immediately. It would also be a great idea to add any bug reports and feedback to the comments on this blog post.
I'm going to walk through each debugging scenario in turn.
Before you start, open Visual Studio briefly and make sure that "Just My Code" is enabled. It's essential for this to work properly:
There's a lot of screenshots here, but this blog is rather narrow, so some of them are distorted – you can click on them to see the full size version.
First, enable the undocumented "/debug" switch on MSBuild.exe by setting the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\4.0 key to have debuggerenabled=true, as I've done here with reg.exe in an elevated Visual Studio prompt:
You should now have these keys, assuming C: is your system drive.
Run MSBuild /? and you'll see the new switch has appeared.
We are now ready to debug.
Normally you'd be debugging some build process you've customized or authored, but for illustrative purposes I'm going to debug a brand new C# Windows Forms project. I'm going to build it with the /debug switch, and it will immediately stop:
In my case I get a prompt to elevate, and hit Yes:
Then I get the standard JIT debugging prompt. Make sure you check "Manually choose the debugging engines".
that causes a dialog to appear to choose the debugging engine: you want Managed only. (Mixed will work, is more clunky.)
And you are now debugging!
The first thing to notice is that we are right at the top of the first project file, the very first line MSBuild is evaluating. You are breaking in automatically at the very start, as if you started debugging a regular application with "F11". Well, almost the very start: MSBuild already read in the environment and its other initial settings:
Now hit F10 and you will step line by line:
As you step over properties, you'll see the locals window is updating:
As you probably know, MSBuild evaluates in passes. The first pass evaluates just properties, pulling in any imports as they're encountered. Try to set a breakpoint (F9) on an item tag right now – you can't! MSBuild is unaware of them at this point.
Set a breakpoint on the <Import> tag at the bottom and run to it (F5):
Now step in (F11). You'll enter the file that's being imported, which in this case is Microsoft.CSharp.targets.
The Callstack window shows that jump like a function call, including the location in the file:
Of course, <Import> does not have the semantics of a function call at all. Like an #include in C++, it simply logically inserts the content of another file. But I chose to make it work this way so that you can see the chain of imports in the Callstack window and figure out your context.
By setting some more breakpoints on Imports and doing step-into, I can go deeper to illustrate:
To get past the property pass, given that I can't set a breakpoint on items yet, I'll use a trick. I'll Step Out repeatedly (Shift-F11) until we get to the project file again, then step to get to the next pass, which is Item Definitions. The C++ build process uses Item Definitions a great deal, but they're not very interesting for C#, in fact there's only one:
Use the same trick to get to the Item pass, and we'll get to the first item. I've then set a breakpoint to illustrate that I can do that now.
Conditional Breakpoints work too, by the way as I believe do Trace Points.
Stepping a bit further, I can see items in the locals window, and also their metadata. A small bug here -- ignore the red message, and go into "Non-public members" to see the names and values:
Sometimes you'll want to figure what a condition evaluates to at the current moment. To do that, in the immediate window, pass the condition to the function EvaluateCondition:
It's much the same if you want to evaluate (expand) an expression, but the function is named EvaluateExpression:
This is also a convenient way to see what a property value is, or what's in an item list, without navigating through the locals window. Be sure to escape any slashes, as I've done here.
The Autos window doesn't work, but Watch does:
In the Immediate window you can change almost any project state during the build, using the new object model. For example, I'll modify this property while I'm stopped here:
You can do a lot through the new object model, so it's very useful to be able to call it here.
My Watch window updated to match:
That's the end of what I'm going to show for debugging MSBuild evaluation.
What's happening at the high level (you can find out more from Mike's blog) is that MSBuild is pretending the script is actually VB or C#. It's doing this by emitting IL on the fly that's semantically equivalent to what it's really doing as it goes through the XML. The code of MSBuild itself is of course optimized, so Just My Code hides it, but conveniently the IL isn't optimized, so it shows up. Inside the IL MSBuild emits line directives that point to the right place in the project file, completing the trick. As for the "locals", they're actually parameters passed to functions in the IL so that they appear. EvaluateCondition and EvaluateExpression are just delegates passed the same way.
As such, a large part of the basic features you get with the regular VB/C# debugger just work. Some that don't: hovering over an expression doesn't give you the result; you can't just use the "?" syntax in the immediate window; Threads and Processes windows don't make sense; I doubt Intellitrace works. Plus, there's some of our internals leaking out in the windows here and there. But by using this trick, it was vastly less work to get the basics of an integrated debugger. I believe I spent a day or two tidying up Mike's sample code, and another three days wiring it straightforwardly into MSBuild. Creating a real debugger engine would be much more costly; and something comparable with what you get for C# would be fantastically costly, so I expect that long term, this will be the MSBuild debugging story. I hope you'll agree it's a lot better than staring at XML and logs or adding <Message> tags.
In MSBuild 4 we introduced several performance improvements, particular for large interdependent builds. By and large they are automatic and you receive their benefit without making any changes to the way your build process in authored. However, there are still some cases where we are unable to make the best decision. One such case is when there is a particular external tool which is invoked as part of the build but which takes a significant amount of time. An example of such a tool would be cl.exe, the C++ compiler. This article discusses how to use the new yield mechanism for external tools to improve the performance of your builds.
There are a few ways MSBuild can be made to execute external, command-line tools:
All of these methods ultimately use the ToolTask class in Microsoft.Build.Utilities.v4.0.dll to handle executing a command-line task and deal with the output in the MSBuild way. Like all tasks, however, they block any other work from happening in MSBuild while they are executing. In cases where the task is very short, such as touching a log file or copying a file from one place to another this is perfectly acceptable. But in the original example of invoking the C++ compiler, the amount of time MSBuild itself sits idle can be lengthy and in some cases it may be a significant impediment to good parallelization of your build.
The problem has to do with the way MSBuild utilizes its worker nodes. Whenever a project is scheduled to be built, it is assigned to one of the worker nodes. This node will then execute that project from start to finish, and will not accept more work until the project is either finished or the project makes an MSBuild call (for instance to satisfy a project-to-project reference.) This is in large part because a node can only execute one task at a time, as tasks must be guaranteed their environment and current directory will not be modified during execution.
However, command-line tools do not execute in-process, and therefore their environment cannot be polluted by the running of additional tasks in parallel on the same node. We can take advantage of this behavior to let the MSBuild node execute tasks in other projects while our long-running tool completes its work. This is done using the YieldDuringToolExecution parameter.
In order to allow MSBuild to continue building other projects while a command-line tool in one project is running is simple. Just set the YieldDuringToolExecution parameter to ‘True’ on your long running command-line tool. This is a boolean parameter, so any valid MSBuild expression which resolves to a boolean value will work. Here’s an example:
<PropertyGroup> <YieldDuringToolExecution>true</YieldDuringToolExecution></PropertyGroup> <Exec CommandLine=”Sleep 10000” YieldDuringToolExecution=”$(YieldDuringToolExecution)”/>
When the Exec task executes, normally it would sleep for 10000 seconds during which no other work on the node can proceed. However, with yielding enabled, the Sleep command will still run but the MSBuild node will be free to do other work. Once the Sleep command is finished, the node will resume building the project which launched it as soon as the node is free to do so.
Whether or not you should enable yielding for your ToolTasks depends on what they do. Generally speaking if the task runs for less than one second, it’s probably not worth it to enable this since there is a small cost to give up the MSBuild node. However, for longer tools you may see some wins, and the wins will likely be larger the more complex your build is and the more long running tasks you have in it. Again, large interdependent C++ builds are a great example of this and they benefit tremendously from yielding being applied to the compiler. You can investigate your build’s performance using the Detailed Summary feature of MSBuild 4.
Yielding interacts well with the /m switch in MSBuild as well. For instance, if you have specified /m:4 to enable parallelization, MSBuild will ensure that no more than four parallel things are going on at once, whether they be regularly building projects or yielding tools. So enabling yielding will not cause your machine to become more overloaded. Instead your builds are likely to improve their parallelization and make better use of available CPU and I/O cycles that they would otherwise.
We have already enabled yield semantic for several tool tasks. These include:
It could also be enabled for the Vbc and Csc tasks since they are ToolTasks as well, but this support is not in the Microsoft.CSharp.targets and Microsoft.VisualBasic.targets shipped with .Net 4.0. You could easily add them yourself if you wished. More generally, if you include Microsoft.Common.targets the YieldDuringToolExecution property will be set to true unless it is overridden with the parameter /p:YieldDuringToolExecution=false being passed to MSBuild. We will continue to use this property as the basis for selecting the tool parameter value of the same name.
Unfortunately for MSBuild 4 we didn’t get the opportunity to make this system as automatic as we would like. In future versions we would like to automatically yield when ToolTasks are executing if they look like they will last longer than a certain threshold. This will also work together with additional automatic improvements in build analysis and scheduling we have planned.
Cliff Hudson - MSBuild Developer
Assembly references are an integral part of build process. When the assembly references passed to the compiler are correct everything works but when they are not projects stop building. When this happens It can be frustrating to try and figure out why a reference was resolved from one location rather than another thereby causing the problem. In this series we will be detailing what steps are taken to take a reference from the project file and turn it into the path on disk that is passed to the compilers.
This series will be focusing on the MSBuild task ResolveAssemblyReference. This task does the work of taking references declared in project files and turning them into paths on disk.
The reason we discuss this task is because this same task is used by both MSBuild on the commandline and Visual Studio to find the references. Internally Visual Studio uses MSBuild as its build engine, so even though this series focuses on the behavior in MSBuild, it behaves exactly the same way in Visual Studio.
Outline for the of the assembly resolution series.
Part 1
In part one we will discuss how references are represented inside of the project file. This will give a basic understanding when looking at a project file of the different forms a reference can take (e.g. file path, simple name, or fusion name) and the additional attributes that can be set on those references.
Part 2
In part two we will discuss some of the basic inputs to the ResolveAssemblyReference task. Why these inputs are important and how they affect how references are found is outlined. This post also goes into detail about how a reference is resolved and the different kinds of algorithms involved in turning what is represented in the project file into a path on disk.
Part 3
In part three we discuss the AssemblyFoldersEx registry location. This is just one of the places where references can be resolved from, however it is one of the most complicated locations due to how the location is searched. This section will discuss the layout of the registry keys and the algorithms used to find assemblies which are declared in this location.
Part 4
In part four we will discuss how conflicts between dependent assemblies arise and how they are dealt with. This section will provide an understanding of why conflict warnings occur and how they can be prevented or disabled. This part also discusses how the determination as to whether or not an assembly should be copied to the output directory is made. This is partially dependent on the resolution of conflicts between dependent assemblies and for this reason is in the same section.
Part 5
In part five we will discuss how the target framework moniker represented in the project file is used to generate a list of directories which represent the framework that the project is targeting. We also discuss the new multi-targeting rules that were introduced in MSBuild 4.0 to prevent users from referencing framework assemblies which are not part of the framework their project is targeting.
Part 6
In part six we will discuss the ResolveAssemblyReference task logging output. It logs a large amount of information about why it resolves references a certain way. This information is very useful when trying to determine why a reference was not resolved when it was expected to resolve or why one reference was picked from a certain location when it was expected to come from another.
Chris Mann – Developer, MSBuild
During the Visual Studio 2010 development cycle a push to make the build experience better on Cross compilation scenarios as well on making sure a build using 32-bit MSBuild was identical (in outputs) to a build using 64-bit MSBuild.
In most cases, 64-bit and 32-bit MSBuild will indeed produce the same output. However there are some cases, generally cross compilation scenarios, where this is not the case.
Note that since Visual Studio is a 32-bit application, if you build from Visual Studio, it is equivalent to running the 32-bit MSBuild.
If you have two assemblies whose identities differ only by the processor architecture, i.e.
myTypes, Version=1.0.1234.0, Culture=en-US, PublicKeyToken=b77a5c561934e089c, ProcessorArchitecture=msil myTypes, Version=1.0.1234.0, Culture=en-US, PublicKeyToken=b77a5c561934e089c, ProcessorArchitecture=x86
And you try to reference one of them specifically:
<Reference Include="myTypes, Version=1.0.1234.0, Culture=en-US, PublicKeyToken=b77a5c561934e089c, ProcessorArchitecture=x86"/>
You will notice that the first reference found will be picked up.
It will also cause the CopyLocal property being set to false.
Building with MSBuild 32-bit or 64-bit.
Add your affected references to the Global Assembly Cache. See KB315682 on how to do that.
You keep facing the following error:
Build FAILED."mysolution.sln" (Rebuild target) (1) ->(mcpplib1:Rebuild target) -> MSBUILD : error MSB3411: Could not load the Visual C++ component "VCBuild.exe". If the component is not installed, either 1) install the Microsoft Windows SDK for Windows Server 2008 and .NET Framework 3.5, or 2) install Microsoft Visual Studio 2008. 0 Warning(s) 1 Error(s)
Build FAILED.
"mysolution.sln" (Rebuild target) (1) ->(mcpplib1:Rebuild target) -> MSBUILD : error MSB3411: Could not load the Visual C++ component "VCBuild.exe". If the component is not installed, either 1) install the Microsoft Windows SDK for Windows Server 2008 and .NET Framework 3.5, or 2) install Microsoft Visual Studio 2008. 0 Warning(s) 1 Error(s)
Building with MSBuild 64-bit only.
In order to properly build solutions with MSBuild containing 3.5 and earlier VC++ project files (*.vcproj) the PATH environment variable should contain the path to VCBuild.exe, which happens to be a 32-bit only executable. To build with 64-bit MSBuild you should point to the location under “Program Files (x86)” path.
When building the AMD64 configuration of a solution, LC.exe is being picked up from %Program Files (x86)%\Microsoft SDKs\Windows\v7.0A\bin\NETFX 4.0 Tools\LC.exe instead of being picked of from %Program Files (x86)%\Microsoft SDKs\Windows\v7.0A\bin\NETFX 4.0 Tools\x64\LC.exe. Or if you are using Visual Studio 2008, from the directory %Program Files%\Microsoft SDKs\Windows\v6.0A\bin.
This will make you face an error like this:
LC : error LC0000: 'Could not load file or assembly 'MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. An attempt was made to load a program with an incorrect format.'
This issue is caused by the fact that LC.exe is not able to satisfy the Cross-Compilation scenarios because of some specific requirements on how it needs to load the referenced dynamic libraries.
NOTE: your build will succeed if you use 64-bit MSBuild on the command line.
Cross compilation scenarios. Building x64 platforms with 32-bit MSBuild or x86 platform with 32-bit MSBuild.
Your build will succeed if you use 64-bit MSBuild in the command line, however if you still want to build inside Visual Studio IDE you can use the following to your project file (by manually editing it):
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
<LCToolPath>C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\x64</LCToolPath>
If you have a project in your solution targeted to build an x64 platform and you:
You will face the following issue while building it:
Error 1 File "MyDll.dll" is not a valid assembly. C:\Windows\Microsoft.NET\Framework\v4.0.20904\Microsoft.Common.targets 3257 9 ClassLibrary3
MSBuild cannot register a library for COM Interop if its architecture does not match the architecture of the MSBuild.exe (or DevEnv.exe) hosting the build process.
So on a 64-bit OS, the following scenarios will not work when the RegisterAssembly task is invoked as part of the build:
If you have a COM object registered by using regsvr32.exe, consider that there is a 32-bit and 64-bit regsvr32.exe. If you used 32-bit regsvr32.exe to register your COM object and you are attempting to build a project targeting x86 platform but using 64-bit MSBuild. The build will fail, this issue is caused by the fact that the library was registered with a pure 32-bit regsvr32.exe and thus it only registers the component under the WOW registry section, that is invisible to 64-bit processes that do not attempt an explicit look up on the WOW nodes.
The opposite is also true, using the 64-bit regsvr32.exe to register the library and attempting to build a project targeting a x64 platform with 32-bit MSBuild. This process has no way to access the 64-bit part of the registry.
One manifestation of this issue would be if your build is failing with an AxImp error when building a project that consumes a registered PIA of an ActiveX control:
Build FAILED. "ActiveXWithPiaConsumer.csproj" (default target) (1) –> (ResolveComReferences target) -> C:\Windows\Microsoft.NET\Framework64\v4.0.21112\Microsoft.Common.targets(1543,9): warning MSB3283: Cannot find wrapper assembly for type library "AxActiveXControlLib". [ActiveXWithPiaConsumer.csproj] "ActiveXWithPiaConsumer.csproj" (default target) (1) –> (ResolveComReferences target) -> AXIMP : AxImp error : Did not find a registered ActiveX control in 'ActiveXWithPia\ActiveXControl.dll'. [ActiveXWithPiaConsumer.csproj]
Affected scenarios:
Mismatches between the architecture of the regsvr32.exe used to register the library and the architecture of MSBuild used to build:
NOTE: if you are using a 32-bit only COM object while trying to build a x64 platform the Interop assembly cannot be generated, and the same applies if you are using a 64-bit only COM object and you are trying to build the x86 platform.
Workaround:
Build using a matching MSBuild architecture with the architecture of regsvr32 and the platform to build:
You have a Silverlight project and you change the platform to x64. You might face one of the following errors:
The "ValidateXaml" task failed unexpectedly. System.BadImageFormatException: Could not load file or assembly 'obj\x64\Debug\SilverlightApplication1.dll' or one of its dependencies. An attempt was made to load a program with an incorrect format.
or if you are building using 64-bit MSBuild:
"SilverlightApplication1.csproj" (GetXapOutputFile target) (2:2) -> C:\Program Files (x86)\MSBuild\Microsoft\Silverlight\v3.0\Microsoft.Silverlight.Common.targets(101,9): error : The Silverlight 3 SDK is not installed. [SilverlightApplication1.csproj]
No workaround. Silverlight DOES NOT support x64 platforms. And Silverlight projects cannot be built by 64-bit MSBuild. You must use the 32-bit MSBuild and target x86 or AnyCPU platforms to build your Silverlight projects.
If you are using Team Build select x86 for the MSBuild platform setting.
If you have a class library project (for example) and you haven’t changed the platform of the project, it will be targeting the AnyCPU platform. However if you add a reference to a COM object you will find out that the generated Interop assembly is specifically targeting the x86 platform.
This is because Interop assemblies always have an explicit target platform, and in the absence of an explicit platform from the project consuming the Interop assembly this target platform is defaulted to the value of an Environment Variable named “PROCESSOR_ARCHITECTURE”, which inside Visual Studio IDE it evaluates to the x86 platform.
The effect of this is that if your application (targeting AnyCPU platform) is run in a 64-bit Operating System, it will run as a 64-bit process and the will fail to load the Interop assembly.
Note that applications built as AnyCPU will always run as 64-bit under a 64-bit Operating System, no matter if you launch them from a 64-bit or 32-bit command window.
Projects targeting the default platform and consuming Interop assemblies. This will happen either with 32-bit and 64-bit MSBuild.
Explicitly set the platform on your project or manually add it to the project by defining the PlatformTarget property to your configuration block in the project file:
<PlatformTarget>AnyCPU</PlatformTarget>
On a 64-bit OS you have a project targeting the x86 platform and it targets 3.5 .NET Framework or below. Your project has a reference to a 32-bit only assembly, and when you build you get the following error:
ResourceFrm.resx(1436,5): error RG0000: Could not load file or assembly '32bitOnlyAssembly.dll' or one of its dependencies. An attempt was made to load a program with an incorrect format. Line 1436, position 5.
This issue is caused by the fact that in the 3.5 .NET tools resgen.exe in both the x86 and x64 bin directories is marked as IL (architecture agnostic), causing it to run on a 64-bit Operating System as a64-bit executable no matter what. As a 64-bit process, resgen.exe is unable to load the 32-bit only library.
Also if you are targeting 4.0 .NET, MSBuild will fail in the same way if you are referencing a 32-bit only assembly while using 64-bit MSBuild and vice versa.
Cross targeting scenarios while building projects which contain resource files with MSBuild:
Make the library referred on the error target the AnyCPU platform
You have a SQL server project and you attempt to build it using 64-bit MSBuild, the following error is displayed:
SqlServerProject1.vbproj(149,3): error MSB4019: The imported project "C:\Windows\Microsoft.NET\Framework64\v4.0.xxxxx\SqlServer.targets" was not found. Confirm that the path in the <Import> declaration is correct, and that the file exists on disk.
Copy C:\Windows\Microsoft.NET\Framework64\v4.0.xxxxx\SqlServer.targets to C:\Windows\Microsoft.NET\Framework\v4.0.xxxxx\SqlServer.targets
Daniel Estrada
Software Development Engineer in Test, MSBuild Team
Some more information about this 4.0 feature. (I've also updated the first post with this, so everything's in one place for your reference.)
The full list of built-in [MSBuild] functions, like the one above, are in the MSDN topic here. They include arithmetic (useful, for example, for modifying version numbers), functions to convert to and from the MSBuild escaping format (on rare occasions, that is useful). Here's another example
$([MSBuild]::Add($(VersionNumber), 1))
And here's one other property function that will be useful to some people:
$([MSBuild]::GetDirectoryNameOfFileAbove(directory, filename)
Looks in the designated directory, then progressively in the parent directories until it finds the file provided or hits the root. Then it returns the path to that root. What would you need such an odd function for? It's very useful if you have a tree of projects in source control, and want them all to share a single imported file. You can check it in at the root, but how do they find it to import it? They could all specify the relative path, but that's cumbersome as it's different depending on where they are. Or, you could set an environment variable pointing to the root, but you might not want to use environment variables. That's where this function comes in handy – you can write something like this, and all projects will be able to find and import it:
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), EnlistmentInfo.props))\EnlistmentInfo.props" Condition=" '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), EnlistmentInfo.props))' != '' " />
The functions parser is pretty robust but not necessarily that helpful when it doesn't wokr. Errors you can get include
(1) It doesn't evaluate but just comes out as a string. Your syntax isn't recognized as an attempt at a function, most likely you've missed a closing parenthesis somewhere. That's easy to do when there's lots of nesting.
(2) error MSB4184: The expression "…" cannot be evaluated. It treated it as a function, but probably it couldn't parse it.
(3) error MSB4184: The expression "…" cannot be evaluated. Method '…' not found. It could parse it, but not find a member it could coerce to, or it was considered ambiguous by the binder. Verify you weren't calling a static member using instance member syntax. Try to make the call less ambiguous between overloads, either by picking another overload (that perhaps has a unique number of parameters) or using the Convert class to force one of the parameters explicitly to the type the method wants. One common case where this happens is where one overload takes an integer, and the other an enumeration.
(4) error MSB4184: The expression "[System.Text.RegularExpressions.Regex]::Replace(d:\bar\libs;;c:\Foo\libs;, \lib\x86, '')" cannot be evaluated. parsing "\lib\x86" - Unrecognized escape sequence \l. Here's an example where it bound the method, but the method threw an exception ("unrecognized escape sequence") because the parameter values weren't valid.
(5) error MSB4186: Invalid static method invocation syntax: "....". Method 'System.Text.RegularExpressions.Regex.Replace' not found. Static method invocation should be of the form: $([FullTypeName]::Method()), e.g. $([System.IO.Path]::Combine(`a`, `b`)).. Hopefully this is self explanatory, but more often than a syntax mistake, you called an instance member using static member syntax.
Arrays are tricky as the C# style syntax "new Foo[]" does not work, and Array.CreateInstance needs a Type object. To get an array, you either need a method or property that returns one, or you use a special case where we can force a string into an array. Here's an example of the latter case:
$(LibraryPath.Split(`;`))
In this case, the string.Split overload wants a string array, and we're converting the string into an array with one element.
Here I'm replacing a string in the property "LibraryPath", case insensitively.
<LibraryPath>$([System.Text.RegularExpressions.Regex]::Replace($(LibraryPath), `$(DXSDK_DIR)\\lib\\x86`, ``, System.Text.RegularExpressions.RegexOptions.IgnoreCase))</LibraryPath>
Here's how to do the same with string manipulation, less pretty.
<LibraryPath>$(LibraryPath.Remove($(LibraryPath.IndexOf(`$(DXSDK_DIR)\lib\x86`, 0, $(IncludePath.Length), System.StringComparison.OrdinalIgnoreCase)), $([MSBuild]::Add($(DXSDK_DIR.Length), 8))))</LibraryPath>
So far in my own work I've found this feature really useful, and far, far, better than creating a task. It can make some simple tasks that were impossible possible, and often, easy. But as you can see from the examples above, it often has rough edges and sometimes it can be horrible to read and write. Here's some ways we can make it better in future:
What do you think?
Dan MoseleyDeveloper Lead - MSBuild
Following extensive feedback on the decision to move the MSBuild blog to The Visual Studio Blog, a decision has been made to cross-post all MSBuild blog posts to this blog.
All current MSBuild posts to The Visual Studio Blog have now been posted here. Apologies if you have received RSS notifications on content you may already have known about.
Mike FourieMicrosoft Visual Studio ALM MVP
Have you ever wanted to do something simple in a build, like get a substring of a property value, and found that MSBuild didn't have syntax for it? You then had to write a task for it, which was tiresome to do for such a simple operation. What's more, if you wanted to do this during evaluation – outside of a target – you couldn't run a task there anyway.
In MSBuild 4.0 we addressed this by adding "property functions" which allow you to execute a variety of regular .NET API calls during evaluation or execution.
Here's an example. For the default VB or C# project, both the intermediate and final output directories are by default below the project's directory. Instead, I'm going to move the final outputs to c:\outputs\<some guid>\ followed by the usual path. You can see below how I did this. I removed the <OutputPath> property and replaced it with an expression that generated a guid for this project.
Now I reopen the project and hit build to show it worked:
There are two syntaxes, as follows. They're intended to be fairly close to the existing Powershell syntax for calling .NET types. The first is for calling static members:
$([Namespace.Type]::Method(..parameters…))
$([Namespace.Type]::Property)
$([Namespace.Type]::set_Property(value))
The second is for instance members on the String class. You write it as if the property itself is a string.
$(property.Method(..parameters...))
$(property.Property)
$(property.set_Property(value))
Notice that when setting a property, you must use CLR syntax for properties ("set_XXX(value)").
The neat part is that these can all be nested – be sure to match your parentheses correctly of course. We attempt to coerce parameters as far as possible in order to find a method or overload that will work.
If you want to pass strings, quote with back-ticks.
When you pass the result of one expression to another, the types are maintained along the chain. This helps the binder find the member you are trying to call. Only when the final result of the expression needs to go into the build do we coerce it to a string.
Some examples may help:
* You can't run instance methods on raw strings. For example $("c:\foo".get_Length()). They must go into a property first.
* Out parameters won't work – there are no intermediate values except for the return value. No delegates or generics either.
* If we coerce to the wrong overload, you may be able to use a Convert method to force the correct one.
* By default, you can only call certain members on certain types – selected to be free of side-effects. Here's the full list:
(1) All members on the following types:
System.Byte System.Char System.Convert System.DateTime System.Decimal System.Double System.Enum System.Guid System.Int16 System.Int32 System.Int64 System.IO.Path System.Math System.UInt16 System.UInt32 System.UInt64 System.SByte System.Single System.String System.StringComparer System.TimeSpan System.Text.RegularExpressions.Regex System.Version MSBuild (see below) Microsoft.Build.Utilities.ToolLocationHelper
(2) Selected members on certain other types:
System.Environment::CommandLine System.Environment::ExpandEnvironmentVariables System.Environment::GetEnvironmentVariable System.Environment::GetEnvironmentVariables System.Environment::GetFolderPath System.Environment::GetLogicalDrives System.IO.Directory::GetDirectories System.IO.Directory::GetFiles System.IO.Directory::GetLastAccessTime System.IO.Directory::GetLastWriteTime System.IO.Directory::GetParent System.IO.File::Exists System.IO.File::GetCreationTime System.IO.File::GetAttributes System.IO.File::GetLastAccessTime System.IO.File::GetLastWriteTime System.IO.File::ReadAllText
The reason we prevent this is to make it more safe to load Visual Studio projects. Otherwise, someone could give you a project that formatted your hard-disk during evaluation. Visual Studio load-time safety is actually more complicated than that – some targets will run and do arbitrary things – but we didn't want to make new opportunities for badness. We could have made this limitation only apply to Visual Studio, but then it would be possible to have your build work differently on the command line. I'd like to hear your feedback on this – is the list too constraining?
You can decide whether we made the correct call here. Meanwhile there is an unsupported way to call members on arbitrary types: set the environment variable MSBUILDENABLEALLPROPERTYFUNCTIONS=1. You can now use any type in any assembly. Of course, MSbuild has to know what assembly it is in (it knows them for the list above); and the CLR binder still has to be able to find it to load it.
To figure out the assembly, it tries to work up the name. So for this example (assuming the environment variable is set)
$([Microsoft.VisualBasic.FileIO.FileSystem]::CurrentDirectory)
it will look for Microsoft.VisualBasic.FileIO.dll, then Microsoft.VisualBasic.dll (which it will find and load from the GAC) and you will get the value of the current directory.
If that's not going to work for your assembly, it is possible to pass in a strong name. For example, the above could equivalently be written like this:
$([Microsoft.VisualBasic.FileIO.FileSystem, Microsoft.VisualBasic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a]::CurrentDirectory)
This means you can write your own functions for MSBuild to call – just put the assembly somewhere that the CLR can find it. By doing that, you can (if you set the environment variable) cause your build do do absolutely anything during property evaluation.
Here's a screenshot of these examples:
Have fun, and let me know what you think. I'd love to get suggestions on how we can improve this.
[Update] I'll post about this separately later, but here's one other property function that will be useful to some people: