In part of our code base, a big chunk of the library is done in F# and the rest in C#. Both F# and C# code are front facing.
We have a hellish batch file to take care of mergeing and what I see is that we are merging with this code:
echo merging %mergeapp% /keyfile:"%keyfile%" /target:library /attr:"%dstpath%%csharpdll%" /targetplatform:%targetplatform%,%targetlib% /lib:%sllib% /lib:%targetlib% /lib:"%libpath%lib" /out:"%mergedpath%..\%csharpdll%" "%dstpath%%csharpdll%" "%dstpath%%fsharpdll%"
%mergeapp% /keyfile:"%keyfile%" /target:library /attr:"%dstpath%%csharpdll%" /targetplatform:%targetplatform%,%targetlib% /lib:%sllib% /lib:%targetlib% /lib:"%libpath%lib" /out:"%mergedpath%..\%csharpdll%" "%dstpath%%csharpdll%" "%dstpath%%fsharpdll%"
and that does what we intend. However, we do not publish any extension methods nor do we do any AutoOpen. What we discovered was a bug in the F# compiler that, up until we started putting obfuscation in the mix, required us to run ildasm
on the F# assembly and rip out the offending code. The other issue is that F# doesn't properly support the protected modifier on members (F# makes them public) so we created an attribute that we could hang on class members that were meant to be protected. Then we wrote a tool that uses Cecil to blow the assembly apart, rip out our attribute and change the access to those members to protected (code is in the accepted answer here).
I didn't know about AutoOpen, but I had to do a similar task, so I created class called a registrant that did that kind of work like this:
type FSharpRegistrant() =
do
// do whatever I need to get going
Then in a static constructor within the C# module, I wrote some code that instantiates the F# registrant using reflection to find the class (since in my code base the C# code builds first and doesn't know there's F# code at all). This is ugly code with a lot of error checking, but it works.