[Mono-dev] mono merge

Bart Masschelein masschel at gmail.com
Sun Nov 16 08:34:30 EST 2008


> Indeed, the merger needs some tweaking ;-). It creates an assembly,  
> and a project that uses this assembly compiles, but gives a runtime  
> exception, saying that it cannot find certain assemblies, which  
> should be in the merged assembly.
>
> I'll see what I can do...

(warning: long mail ahead, questions at the end)

... and I did. I created a solution containing two library projects,  
Lib1 and Lib2, and an application project, App. I compiled the App in  
several ways:

App1: Using the seperately included Lib1 and Lib2
App2: Merge the two libs in a MergedLib, and use that one as reference
App3: Merge all seperate libraries into the App.
App4: Merge the MergedLib into the App.

We can already forget about App1 (obviously), App3 and App4. Those  
work fine. So merging all libraries into an application works as  
expected, at least for this small solution. The problem arises when  
using a merged lib as reference in an application. The raised error is:

** (/Users/masschel/development/MonoMergeStuff/MonoMergeTestSolution/ 
Application2UsingMergedAssembly/bin/Release/ 
Application2UsingMergedAssembly.exe:48092): WARNING **: The following  
assembly referenced from /Users/masschel/development/MonoMergeStuff/ 
MonoMergeTestSolution/Application2UsingMergedAssembly/bin/Release/ 
Application2UsingMergedAssembly.exe could not be loaded:
      Assembly:   Library1    (assemblyref_index=1)
      Version:    1.0.3241.38976
      Public Key: (none)
The assembly was not found in the Global Assembly Cache, a path listed  
in the MONO_PATH environment variable, or in the location of the  
executing assembly (/Users/masschel/development/MonoMergeStuff/ 
MonoMergeTestSolution/Application2UsingMergedAssembly/bin/Release).

So I went on... I used Mono.Cecil to analyze the MergedLib, and App3,  
and this is what I found:

**** Merged library
Assembly
NET_2_0
Number of modules: 1
Name of MainModule: Library1.dll
Number of references: 1
/Users/masschel/development/MonoMergeStuff/MonoMergeTestSolution/Merge/ 
MergedLibrary.dll
AssemblyReferences:
    mscorlib, Version=2.0.0.0, Culture=neutral,  
PublicKeyToken=b77a5c561934e089 mscorlib
<Module>
Library1.MyClass
Library2.MyClass

**** Application (merged)
Assembly
NET_2_0
Number of modules: 1
Name of MainModule: Application2UsingMergedAssembly.exe
Number of references: 2
/Users/masschel/development/MonoMergeStuff/MonoMergeTestSolution/ 
Application2UsingMergedAssembly/bin/Release/ 
Application2UsingMergedAssembly.exe
AssemblyReferences:
    mscorlib, Version=2.0.0.0, Culture=neutral,  
PublicKeyToken=b77a5c561934e089 mscorlib
    Library1, Version=1.0.3241.38976, Culture=neutral,  
PublicKeyToken=null Library1
Library1, Version=1.0.3241.38976, Culture=neutral, PublicKeyToken=null
<Module>
Application2UsingMergedAssembly.MainClass

As you can see, there are two peculiar issues: the merged library has  
as name for the MainModule Library1.dll instead of MergedLibrary.dll,  
and the Application references Library1, which obviously cannot find.  
I thought these problems were related, eg. the application knows it  
needs Library1 because the Name of the MainModule is Library1.dll. So  
Cecil to the rescue, I changed the Name to MergedLibrary.dll, saved  
the assembly. Recompiling and running my walker again now results in

**** Merged library
Assembly
NET_2_0
Number of modules: 1
Name of MainModule: MergedLibrary.dll
Number of references: 1
/Users/masschel/development/MonoMergeStuff/MonoMergeTestSolution/Merge/ 
MergedLibrary.dll
AssemblyReferences:
    mscorlib, Version=2.0.0.0, Culture=neutral,  
PublicKeyToken=b77a5c561934e089 mscorlib
<Module>
Library1.MyClass
Library2.MyClass

**** Application (merged)
Assembly
NET_2_0
Number of modules: 1
Name of MainModule: Application2UsingMergedAssembly.exe
Number of references: 2
/Users/masschel/development/MonoMergeStuff/MonoMergeTestSolution/ 
Application2UsingMergedAssembly/bin/Release/ 
Application2UsingMergedAssembly.exe
AssemblyReferences:
    mscorlib, Version=2.0.0.0, Culture=neutral,  
PublicKeyToken=b77a5c561934e089 mscorlib
    Library1, Version=1.0.3241.38976, Culture=neutral,  
PublicKeyToken=null Library1
Library1, Version=1.0.3241.38976, Culture=neutral, PublicKeyToken=null
<Module>
Application2UsingMergedAssembly.MainClass

So the name was changed correctly, but apparently that is not how the  
Application knows which assembly to use: it still references Library1.  
The next thing I tried was changing the AssemblyReference in the  
Application from Library1 to MergedLibrary (and verify with the walker  
that the changes were done). I ran the application without  
recompilation. And this works! I get the expected results. If however  
I recompile, the Application again references the Library1. And  
anyway, we don't want to hack the Application, it should find out  
itself where to find the assembly. So what I thought was that maybe it  
is the first module that is used in the Application to know where to  
find it. So I created another project, namely MergedLibrary, without  
anything special, compiled it, and included this in the merge process  
to create a MergedLibrary. My walker results in this:

**** Merged library
Assembly
NET_2_0
Number of modules: 1
Name of MainModule: MergedLibrary.dll
Number of references: 1
/Users/masschel/development/MonoMergeStuff/MonoMergeTestSolution/Merge/ 
MergedLibrary.dll
AssemblyReferences:
    mscorlib, Version=2.0.0.0, Culture=neutral,  
PublicKeyToken=b77a5c561934e089 mscorlib
<Module>
Library1.MyClass
Library2.MyClass
MergedLibrary.MyClass

**** Application (merged)
Assembly
NET_2_0
Number of modules: 1
Name of MainModule: Application2UsingMergedAssembly.exe
Number of references: 2
/Users/masschel/development/MonoMergeStuff/MonoMergeTestSolution/ 
Application2UsingMergedAssembly/bin/Release/ 
Application2UsingMergedAssembly.exe
AssemblyReferences:
    mscorlib, Version=2.0.0.0, Culture=neutral,  
PublicKeyToken=b77a5c561934e089 mscorlib
    MergedLibrary, Version=1.0.3241.41055, Culture=neutral,  
PublicKeyToken=null MergedLibrary
MergedLibrary, Version=1.0.3241.41055, Culture=neutral,  
PublicKeyToken=null
<Module>
Application2UsingMergedAssembly.MainClass

As you can see, the MergedLibrary.dll now contains a MergedLibrary  
Type, and, although MergedLibrary is not the first Type, the  
Application recognizes it for use as reference. This looked good, so I  
recompiled everything, and indeed, I got the correct result!

So here are the questions:

*  How exactly does an application know what assembly to reference,  
when it is given an assembly, eg. how is it that in the first  
examples, Application used Library1 as reference?
* Why does the last hack works, eg. by adding a class library with the  
exact name as merged library? Has this anything to do with the Primary  
Assembly, as I have seen it called when using ILMerge?
* If this is correct, a work-around would be to always add such a  
dummy class library, with the same name as the merged library, and a  
more profound solution would be to have the merger create a dummy Type  
if no library with the corresponding name is found.

If you think the latter is ok, I will try to implement such a addition  
to mono-merge.

Any ideas, or someone that can shed a light on these inner workings of  
mono?

Bart



More information about the Mono-devel-list mailing list