How to set SGEN toolpath in Msbuild to target 3.5 framework
Asked Answered
S

5

18

I've just upgraded a project from VS2008 to VS2010 but I'm still targeting the 3.5 framework.

In my project file I have a custom task to run SGEN to generate my XmlSerializers.dll. However the version of sgen being run targets the 4.0 framework. As a result, when I run my application I get the error message:

"Could not load file or assembly 'XXXX.XXXX.XmlSerializers' or one of its dependencies. This assembly is built by a runtime newer than the currently loaded runtime and cannot be loaded."

The Sgen task looks like this:

  <Target Name="AfterBuild" DependsOnTargets="AssignTargetPaths;Compile;ResolveKeySource" Inputs="$(MSBuildAllProjects);@(IntermediateAssembly)" Outputs="$(OutputPath)$(_SGenDllName)">
    <!-- Delete the file because I can't figure out how to force the SGen task. -->
    <Delete Files="$(TargetDir)$(TargetName).XmlSerializers.dll" ContinueOnError="true" />
    <SGen BuildAssemblyName="$(TargetFileName)" BuildAssemblyPath="$(OutputPath)" References="@(ReferencePath)" ShouldGenerateSerializer="true" UseProxyTypes="false" KeyContainer="$(KeyContainerName)" KeyFile="$(KeyOriginatorFile)" DelaySign="$(DelaySign)" ToolPath="$(SGenToolPath)">
      <Output TaskParameter="SerializationAssembly" ItemName="SerializationAssembly" />
    </SGen>
  </Target>

There's the ToolPath="$(SGenToolPath)". How do I make it run the version that targets 3.5?

There's a similar question here but it doesn't help me much.

Sukey answered 1/5, 2010 at 5:12 Comment(2)
Quick note to others who end up here based on the exception message: if you don't need the XmlSerializers assembly you can simply disable it's creation on the project's build tab.Nonet
P.S. if you do set Generate serialization assembly to 'off' remember to do it for both release and debug (or relevant) configurations.Nonet
S
18

I have solved this by manually configuring the ToolPath to point to the old (version 2.0.50727.3038) version of sgen.exe

On my machine, this is in: C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin

I changed the ToolPath attribute to be:

ToolPath="C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin"

and this solved the problem.

It seems, by default, it's running the new 4.0 framework version in: C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools

Hope this helps somebody else.

Sukey answered 2/5, 2010 at 10:26 Comment(3)
I set it in the project file as follows: <GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies><SGenToolPath>C:\Program Files\Microsoft SDKs\Windows\v7.0\bin</SGenToolPath>Diella
MSBuild will use the 4.0 tools in "NETFX 4.0 Tools" for 3.5 projects if it can't find the 3.5 tools. My answer might help to resolve the root cause of the problem, avoiding the need for a workaround in individual project files.Courlan
I tried this and I still couldn't get it to work. I found out that it was because my project was on a network share. After I moved it onto my local hard drive everything worked perfectly.Epicycle
C
17

MSBuild uses the registry to get the path to the v3.5 tools. The MSBuild tasks that require v3.5 SDK tools will fall back to the v4.0 path if the path to the 3.5 tools can't be identified - look at the logic used to set the TargetFrameworkSDKToolsDirectory property in C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.NETFramework.props if you're really interested.

You can diagnose and fix this problem as follows:

Install Process Monitor and set up a filter to monitor registry access by msbuild (Event class: Registry, Process Name: msbuild.exe, all types of result).

Run your build.

Search Process Monitor for a RegQueryValue access matching "MSBuild\ToolsVersions\4.0\SDK35ToolsPath". Note that this could be be under either "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft" or "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft".

If you have a look at this key in the registry, you'll see that it aliases another registry value, e.g. "$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1\WinSDK-NetFx35Tools-x86@InstallationFolder)" Shortly after this, you'll probably see a "NAME NOT FOUND" result. If you look at where the expected key should be, you'll see that they don't match the key being requested (missing hyphens and possibly no key ending with "-86").

It should be clear what you need to correct. I chose to export the incorrect keys, edit the .reg file and run it to create the correct keys.

One cause of invalid registry entries could be a bug with the Microsoft SDK v7.1 installation:

http://connect.microsoft.com/VisualStudio/feedback/details/594338/tfs-2010-build-agent-and-windows-7-1-sdk-targeting-net-3-5-generates-wrong-embedded-resources

Courlan answered 18/4, 2011 at 10:43 Comment(4)
@DanMalcom That's a really thorough answer, but in my case, and possibly this users case, the real issue was not setting ToolPath to $(TargetFrameworkSDKToolsDirectory). If you could edit your answer based on that. I will delete my answer below.Eldoraeldorado
@Justin If you have the registry problem that I described, then $(TargetFrameworkSDKToolsDirectory) will end up being incorrect, e.g. 4.0 Tools (v4 runtime) for a build targeting 3.5 framework (v2.0 runtime). If the SDK tools are installed correctly, you shouldn't have to set $(ToolPath), either to $(TargetFrameworkSDKToolsDirectory) or to a hard-coded path.Courlan
This happened again on another project 3 years on. Glad I wrote this up!Courlan
Thank you for investigation. I've had the same issue building native addons for Node.js with node-gyp and was able to find a proper solution after reading your reply. The issue is tracked here if anybody is interested: code.google.com/p/gyp/issues/detail?id=457Procrastinate
U
7

I found this to be the easiest way and it works with: <GenerateSerializationAssemblies>On</ GenerateSerializationAssemblies>

<SGenToolPath>C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin</SGenToolPath>
Unvarnished answered 14/12, 2010 at 21:19 Comment(1)
Worked great for us - in my opinion, this is better because it lets you specify the sgen version to use PER PROJECT. Note that Visual Studio doesn't have UI for this setting and, if you open the project file in VS, it shows it as invalid. However, it does work. Another reminder, specify it for BOTH RELEASE AND DEBUG!Vtehsta
E
7

The problem is $(SGenToolPath) isn't set by MSBuild. If you use $(TargetFrameworkSDKToolsDirectory) then it will attempt to resolve the path based on $(TargetFrameworkVersion).

Its helpful to make use of tags for printf() style debugging. Add the following temporally.

<Target Name="AfterBuild" DependsOnTargets="AssignTargetPaths;Compile;ResolveKeySource" Inputs="$(MSBuildAllProjects);@(IntermediateAssembly)" Outputs="$(OutputPath)$(_SGenDllName)">
  <Message Text="SGenPath: $(SGenPath)" Importance="high"/>
  <Message Text="TargetFrameworkVersion: $(TargetFrameworkVersion)" Importance="high"/>
  <Message Text="TargetFrameworkSDKToolsDirectory : $(TargetFrameworkSDKToolsDirectory )" Importance="high"/>
Eldoraeldorado answered 12/7, 2012 at 14:43 Comment(0)
S
5

@Craig - Did you manually install the 7.0A framework on your build machine. If so, your problem may be your registry settings and not msbuild. Take a look at LocalMachine -> Software -> Microsoft -> MSBuild -> ToolsVersions -> 4.0 -> SDK35ToolsPath and make sure the reg key that is referenced there is valid. (Hint: Make sure the -x86 is there only if the -x86 key exists.)

Sulfanilamide answered 30/6, 2010 at 19:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.