[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