2.4.2 使用程序集链接器
2011-11-22 21:30 iRead 阅读(399) 评论(0) 收藏 举报除了使用C#编译器,还可以使用“程序集链接器”使用程序AL.exe来创建程序集。如果要在创建的程序集中包含用不同编译器生成的模块(而且这些编译器不支持与C#编译器的/addmodule开关等价的机制),或者在生成时不清楚程序集的打包要求,那么程序集链接器就显得相当有用。还可用AL.exe来生成只含资源的程序集,也就是所谓的附属程序集(satellite assembly),它们通常用于本地化。本章稍后 会讨论附属程序集的问题。
AL.exe实用程序可生成一个EXE文件或者DLL PE文件(其中只包含对其他模块中的类型进行描述的一个清单)。为了理解AL.exe的工作原理,让我们改变一下JeffTypes.dll程序集的生成方式:
csc /t:module RUT.cs
csc /t:module FUT.cs
al /out:JeffTypes.dll /t:library FUT.netmodule RUT.netmodule
图2-3展示了执行上述语句所生成的文件。
这个例子首先创建了两个单独的模块,即RUT.netmodule和FUT.netmodule。两个模块都不是程序集,因为它们都不包含清单元数据表。然后生成了第三个文件:JeffTypes.dll,它是一个小的DLL PE文件(因为使用/t[arget]:library开关),其中不包含IL代码,但包含清单元数据表,指出RUT.netmodule和FUT.netmodule是程序集的一部分。最终的程序集由三个文件构成:JeffTypes.dll,RUT.netmodule和FUT.netmodule。程序集链接器不能将多个文件合并成一个文件。
AL.exe实用程序还可生成CUI和GUI PE文件,这是使用/t[arget]:exe或者/t[arget]:winexe命令行开关来实现的。但很少需要这样做,因为这意味着将得到一个EXE PE文件,其中的IL代码唯一能做的就是调用另一个模块中的一个方法。可指定将一个模块中的哪个方法作为入口使用。为此,需要在调用AL.exe时条件/main命令行开关。下面是一个例子:
csc /t:module /r:JeffTypes.dll Program.cs
al /out:Program.exe /t:exe /main:Program.Main Program.netmodule
第一行将Program.cs文件生成为一个Program.netmodule文件。第二行生成一个小的Program.exe PE文件,其中包含清单元数据表。除此之外,由于使用/main:Program.Main命令行开关,AL.exe还会生成一个小的全局函数,名为__EntryPoint。__EntryPoint函数包含以下IL代码:
.method privatescope static void __EntryPoint$PST06000001() cil managed
{
.entrypoint
// 代码大小 8 (0x8)
.maxstack 8
IL_0000: tail.
IL_0002: call void [.module Program.netmodule]Program::Main()
IL_0007: ret
} // end of method 'Global Functions'::__EntryPoint
可以看出,上述代码只是调用了Program.netmodule文件中定义的Program类型所包含的Main方法。AL.exe的/main开关实际上没有多大用处,因为假如一个应用程序的入口不在清单元数据所在的PE文件中,为它创建程序集有什么意义呢?开发人员只需知道存在这个开关就可以了。
在本书的配套代码中,我创建了一个Ch02-3-BuildMultiFileLibrary.bat文件,它封装了生成一个多文件程序集所需的所有步骤。作为一个预生成命令行步骤,Visual Studio项目Ch02-4-AppUsingMultiFileLibrary会调用这个批处理文件。卡参考这个项目来体会如何在Visual Studio中生成和引用一个多文件程序集。
浙公网安备 33010602011771号