F# Powerpack's Metadata doesn't recognize FSharp.Core as an F# library
Here's my test code to isolate the problem:
open Microsoft.FSharp.Metadata
[<EntryPoint>]
let main args =
let core = FSharpAssembly.FromFile @"C:\Program Files\FSharp-2.0.0.0\\bin\FSharp.Core.dll"
let core2 = FSharpAssembly.FSharpLibrary
let core3 = System.AppDomain.CurrentDomain.GetAssemblies()
|> Seq.find (fun a -> a.FullName.Contains "Core")
|> FSharpAssembly.FromAssembly
core.Entities |> Seq.iter (printfn "%A")
0
All three let
s should give me the same FSharpAssembly. Instead, all 3 throw an exception that FSharp.Core is not an F# assembly (details below, re-formatted for readability). Two more clues:
- Using the
core3
method, I get the same error for the test F# assembly itself - I don't get the error at FSI after doing
#r "@C:\Program Files...\FSharp.Powerpack.Metadata.dll"
.
Any ideas? I'm using Visual Studio 2008, F# 2.0 and F# Powerpack 2.0.0.0 (May 20, 2010) release on an oldish XP VM, I think it's updated to SP3 though.
(I got the error this morning with Powerpack 1.9.9.9, so I upgraded to 2.0.0.0. I thought that if 1.9.9.9 doesn't recognise F#'s 2.0.0.0's assemblies, then maybe bugfixes in Powerpack 2.0.0.0 would help.)
Unhandled Exception: System.TypeInitializationException:
The type initializer for 'Microsoft.FSharp.Metadata.AssemblyLoader' threw an
exception.
---> System.TypeInitializationException: The type initializer for
'<StartupCode$FSharp-PowerPack-Metadata>.$Metadata' threw an exception.
---> System.ArgumentException: could not produce an FSharpAssembly
object for the assembly 'FSharp.Core' because
this is not an F# assembly
Parameter name: name
at Microsoft.FSharp.Metadata.AssemblyLoader.Add(String name,Assembly assembly)
at <StartupCode$FSharp-PowerPack-Metadata>.$Metadata..cctor()开发者_JAVA百科
--- End of inner exception stack trace ---
at Microsoft.FSharp.Metadata.AssemblyLoader..cctor()
--- End of inner exception stack trace ---
at Microsoft.FSharp.Metadata.AssemblyLoader.Get(Assembly assembly)
at Microsoft.FSharp.Metadata.FSharpAssembly.FromAssembly(Assembly assembly)
at Program.main(String[] args) in
C:\Documents an...\FSMetadataTest\Program.fs:line 11
Press any key to continue . . .
Nathan, great investigation, the version number was indeed not updated in original May2010 release, see http://fsharppowerpack.codeplex.com/workitem/4548 We have uploaded binaries with corrected version number.
I found the immediate cause of the problem by reading the Powerpack source on Codeplex. Powerpack.Metadata always loads FSharp.Core before any other assembly, so if it's broken, it blocks the rest.
From my research, most other F# assemblies carry their metadata with them in a manifest resource stream named "FSharpSignatureData.Package.Name"--that's where the Metadata library looks first. But FSharp.Core doesn't. (At least, on my XP VM the 2.0.0.0 download for VS 2008 does not.) So the Powerpack Metadata looks for a file called FSharp.Core.sigdata in the same directory it expects to find FSharp.Core.dll.
The code looks four places for this directory name:
- ConfigurationSettings.AppSettings.["fsharp-core-referenceassembly-location"].
- The registry key
@"SOFTWARE\Microsoft\.NETFramework\" + MSCorLibRunningRuntimeVersion + @"\AssemblyFoldersEx\Microsoft Visual F# 4.0"
, where MSCorLibRunningRuntimeVersion is determined by reflection--in my case it's "v2.0.50727". I think this only applies if you have VS 2010 and hence F# 4.0 - The registry key
@"Software\Microsoft\.NETFramework\AssemblyFolders\Microsoft.FSharp-" + FSharpTeamVersionNumber
, where FSharpTeamVersionNumber is hard-coded as "1.9.9.9", at least in the codeplex version. I don't have the source for the May 2010 release installed on my machine. - System.AppDomain.CurrentDomain.BaseDirectory. This is the "bin/Debug" directory of your local project, unless you are in fsi. Then it's some variant of C:\Program Files\FSharp-2.0.0.0\bin.
For me, all four fail:
- I don't have an app config file. I don't know the .NET ecosystem very well, so I don't know how to create one.
- I don't have VS 2010 installed.
- I have a "Microsoft.FSharp-2.0.0.0" key in the right place, but no "Microsoft.FSharp-1.9.9.9" key.
- My local project doesn't have a copy of FSharp.Core.sigdata in the bin/Debug directory.
Now that I know what's going on, I have a number of fixes (besides using a real Windows machine instead of an ancient VM, which I plan to fix in about a month). I should probably learn about .NET's config files at some point anyway, so that's probably the best medium-term solution. Creating the registry key "Microsoft.FSharp-1.9.9.9" or copying FSharp.Core.sigdata to the bin/Debug directory is a super easy short-term fix.
I still don't know if this bug should be widespread or if it's just caused by my upgrades from VS 2005->2008 and multiple F# previews. From reading the codeplex source, it seems to me that other people without VS 2010 should also have this problem, just because FSharpTeamVersionNumber is hard-coded as 1.9.9.9, and hasn't been updated to match the registry key, 2.0.0.0. But maybe the order that I upgraded to F# 2.0 and the F# Powerpack 2.0 was incorrectly intermingled to produce this condition. Or maybe there aren't enough people using the Metadata library to expose the bug.
This is really confusing - I tried running the code using the exact scenario you described (F# 2.0 in Visual Studio 2008, with the latest PowerPack 2.0 from CodePlex) and it works without any exceptions.
You could also make sure that you have the latest release of F# for Visual Studio 2008 (that was released shortly after final version of Visual Studio 2010), because FSharp.Core.dll
that you're loading needs to be compatible with FSharp.PowerPack.Metadata.dll
. Also, is the Metadata
library able to load other dll
libraries that you compile with the current version of F# compiler?
EDIT
If this doesn't work then (I'd think) the Metadata
library is probably out of sync with the F# compiler:
let a = System.Reflection.Assembly.GetExecutingAssembly()
|> FSharpAssembly.FromAssembly
printf "%A" a.Entities.Count
If the following doesn't work then that would be really confusing - no matter what version, the library should be able to read itself!
let a = FSharpAssembly.FromFile @"C:\...\bin\FSharp.PowerPack.Metadata.dll"
printf "%A" a.Entities.Count
精彩评论