تو مطلب «اسمبلی های چند فایله»، روش تولید یه اسمبلی چند فایله با استفاده از کامپایلر سی شارپ نشون داده شد. علاوه بر این روش، راه دیگه ای هم برای تولید چنین اسمبلی هایی وجود داره و اون استفاده از ابزار AL.exe یا Assembly Linker هست. این ابزار رو هم مثل ابزار ILDasm.exe میشه تو SDKهای ویندوز پیدا کرد که به همراه ویژوال استودیو نصب میشه.
مسیر نصب این SDKها معمولا به این صورته (تو سیستم 64 بیتی):
و مسیر نصب این ابزارها (ILDasm.exe و AL.exe) هم بصورت زیره:
یا
بصورت خلاصه، از این ابزار برای تولید یه فایل حاوی مانیفست اسمبلی استفاده میشه. این مانیفست با استفاده از یک یا چند فایل که ممکنه ماژول های مدیریت شده یا فایلهای ریسورس باشن، تولید میشه.
این ابزار وقتیکه بخوایم یه اسمبلی رو با استفاده از ماژولهایی که توسط کامپایلرهای مختلف تولید شده بسازیم (و اون کامپایلرها امکانی مثل سوییچ addmodule/ کامپایلر #C ندارن)، میتونه مفید باشه. همچنین برای مواردی که در زمان تولید ماژول ها، از نیازهای دقیق برنامه و طراحی نهایی اون برای توزیع و انتشار، اطلاع دقیقی نیست، میشه از این ابزار برای تهیه اسمبلی نهایی در زمان مناسب استفاده کرد.
درضمن با استفاده از این ابزار امکان تولید اسمبلی هایی که فقط حاوی ریسورس های برنامه هستند (resource-only assembly) هم میشه استفاده کرد. به این اسمبلیها اصطلاحا اسمبلی های ماهواره ای یا «satellite assembly» گفته میشه که معمولا برای برنامه های چندزبانه استفاده میشن.
ابزار AL.exe توانایی تولید فایلهایی از نوع exe یا dll داره که تنها حاوی مانیفست اسمبلی هستن (برای توصیف فایلهای تشکیل دهنده اون اسمبلی). برای اینکه با این ویژگی بیشتر آشنا بشیم، مثال مطلب قبلی که تماما با استفاده از کامپایلر سی شارپ انجام شده بود رو بصورت زیر و با کمک ابزار AL.exe انجام میدیم:
- ابتدا هر دو فایل سورس کد توسط کامپایلر #C به فایلهای ماژول مدیریت شده کامپایل میشن:
اگه این دو سورس کد کاملا مستقل از هم باشن، دستورات بالا بدون مشکل اجرا میشن. اما نکته ای که اینجا باید بهش دقت بشه اینه که تو این مثال، ماژول دوم به ماژول اول وابستگی داره و با اجرای دستور دوم کامپایلر سی شارپ خطایی مبنی بر ناشناس بودن نوع IWriter صادر میکنه. با توجه به اینکه این نوع تو ماژول source1.netmodule تعریف شده بنابراین باید این موضوع رو یه جوری به کامپایلر بفهمونیم. برای اینکار هم میشه از سوییچ addmodule/ استفاده کرد. پس دستور دوم باید بصورت زیر تغییر کنه:
در اینجا ماژول جدید source2.netmodule هم تولید میشه. بررسی این ماژول تو ابزار ILDasm.exe نتیجه زیر رو دربر داره:
با دابل کلیک بر روی گره MANIFEST پنجره زیر نمایش داده میشه:
همونطور که مشاهده میشه، این ماژول هم مثل ماژول source1.netmodule جداول مانیفست نداره و صرفا بصورت یه ماژول مدیریت شده که در ادامه تو تشکیل یه اسمبلی کامل استفاده میشه، تولید شده.
متادیتای این ماژول هم، که با استفاده از کلید ترکیبی Ctrl+M نشون داده میشه، بصورت زیره:
===========================================================
ScopeName : source2.netmodule
MVID : {3A785CBB-F3EF-443C-B458-9F73D29FD7EC}
===========================================================
Global functions
-------------------------------------------------------
Global fields
-------------------------------------------------------
Global MemberRefs
-------------------------------------------------------
TypeDef #1 (02000002)
-------------------------------------------------------
TypDefName: DataContext (02000002)
Flags : [Public] [AutoLayout] [Class] [AnsiClass] [BeforeFieldInit] (00100001)
Extends : 01000001 [TypeRef] System.Object
Field #1 (04000001)
-------------------------------------------------------
Field Name: _logger (04000001)
Flags : [Private] (00000001)
CallCnvntn: [FIELD]
Field type: Class IWriter
Method #1 (06000001)
-------------------------------------------------------
MethodName: .ctor (06000001)
Flags : [Public] [HideBySig] [ReuseSlot] [SpecialName] [RTSpecialName] [.ctor] (00001886)
RVA : 0x00002050
ImplFlags : [IL] [Managed] (00000000)
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
1 Arguments
Argument #1: Class IWriter
1 Parameters
(1) ParamToken : (08000001) Name : logger flags: [none] (00000000)
Method #2 (06000002)
-------------------------------------------------------
MethodName: Save (06000002)
Flags : [Public] [HideBySig] [ReuseSlot] (00000086)
RVA : 0x00002062
ImplFlags : [IL] [Managed] (00000000)
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
No arguments.
TypeRef #1 (01000001)
-------------------------------------------------------
Token: 0x01000001
ResolutionScope: 0x23000001
TypeRefName: System.Object
MemberRef #1 (0a000002)
-------------------------------------------------------
Member: (0a000002) .ctor:
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
No arguments.
TypeRef #2 (01000002)
-------------------------------------------------------
Token: 0x01000002
ResolutionScope: 0x1a000001
TypeRefName: IWriter
MemberRef #1 (0a000003)
-------------------------------------------------------
Member: (0a000003) Write:
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
1 Arguments
Argument #1: String
TypeRef #3 (01000003)
-------------------------------------------------------
Token: 0x01000003
ResolutionScope: 0x23000001
TypeRefName: System.Runtime.CompilerServices.RuntimeCompatibilityAttribute
MemberRef #1 (0a000001)
-------------------------------------------------------
Member: (0a000001) .ctor:
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
No arguments.
TypeRef #4 (01000004)
-------------------------------------------------------
Token: 0x01000004
ResolutionScope: 0x23000001
TypeRefName: System.Runtime.CompilerServices.AssemblyAttributesGoHere
CustomAttribute #1 (0c000001)
-------------------------------------------------------
CustomAttribute Type: 0a000001
CustomAttributeName: System.Runtime.CompilerServices.RuntimeCompatibilityAttribute :: instance void .ctor()
Length: 30
Value : 01 00 01 00 54 02 16 57 72 61 70 4e 6f 6e 45 78 > T WrapNonEx<
: 63 65 70 74 69 6f 6e 54 68 72 6f 77 73 01 >ceptionThrows <
ctor args: ()
ModuleRef #1 (1a000001)
-------------------------------------------------------
ModuleRef: (1a000001) source1.netmodule:
AssemblyRef #1 (23000001)
-------------------------------------------------------
Token: 0x23000001
Public Key or Token: b7 7a 5c 56 19 34 e0 89
Name: mscorlib
Version: 4.0.0.0
Major Version: 0x00000004
Minor Version: 0x00000000
Build Number: 0x00000000
Revision Number: 0x00000000
Locale:
HashValue Blob:
Flags: [none] (00000000)
User Strings
-------------------------------------------------------
70000001 : (17) L"DataContext Saved"
Coff symbol name overhead: 0
===========================================================
===========================================================
===========================================================
در اینجا هم خبری از داده های جداول مانیفست نیست.
- تو گام بعدی با استفاده از ابزار AL.exe از این دو ماژول برای تولید یه اسمبلی تو فایل سومی با نام asm.dll استفاده میشه:
مشاهده میشه که ابزار AL.exe سوییچهایی شبیه به کامپایلر #C داره. اما ورودیهای اصلی این ابزار به جای فایلهای سورس کد، فایلهای ماژول یا اسمبلی هست. این دستور باید مثل تصویر زیر اجرا بشه:
فایل asm.dll تولید شده رو با استفاده از ابزار ILDasm مورد بررسی قرار میدیم که نتیجه تو تصویر زیر نشون داده شده:
واضحه که این اسمبلی تنها حاوی داده های مانیفسته. با دابل کلیک بر روی گره MANIFEST پنجره زیر نمایش داده میشه:
معلومه که داده های مانیفست اسمبلی تو این فایل ذخیره شده. حالا کل داده های متادیتای این فایل رو مورد بررسی قرار میدیم:
===========================================================
ScopeName : asm.dll
MVID : {ECCADD91-67D9-4DFF-AFE4-53439C42ED0E}
===========================================================
Global functions
-------------------------------------------------------
Global fields
-------------------------------------------------------
Global MemberRefs
-------------------------------------------------------
TypeRef #1 (01000001)
-------------------------------------------------------
Token: 0x01000001
ResolutionScope: 0x23000001
TypeRefName: System.Runtime.CompilerServices.RuntimeCompatibilityAttribute
MemberRef #1 (0a000001)
-------------------------------------------------------
Member: (0a000001) .ctor:
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
No arguments.
Assembly
-------------------------------------------------------
Token: 0x20000001
Name : asm
Public Key :
Hash Algorithm : 0x00008004
Version: 0.0.0.0
Major Version: 0x00000000
Minor Version: 0x00000000
Build Number: 0x00000000
Revision Number: 0x00000000
Locale:
Flags : [none] (00000000)
CustomAttribute #1 (0c000001)
-------------------------------------------------------
CustomAttribute Type: 0a000001
CustomAttributeName: System.Runtime.CompilerServices.RuntimeCompatibilityAttribute :: instance void .ctor()
Length: 30
Value : 01 00 01 00 54 02 16 57 72 61 70 4e 6f 6e 45 78 > T WrapNonEx<
: 63 65 70 74 69 6f 6e 54 68 72 6f 77 73 01 >ceptionThrows <
ctor args: ()
AssemblyRef #1 (23000001)
-------------------------------------------------------
Token: 0x23000001
Public Key or Token: b7 7a 5c 56 19 34 e0 89
Name: mscorlib
Version: 4.0.0.0
Major Version: 0x00000004
Minor Version: 0x00000000
Build Number: 0x00000000
Revision Number: 0x00000000
Locale:
HashValue Blob:
Flags: [none] (00000000)
File #1 (26000001)
-------------------------------------------------------
Token: 0x26000001
Name : source1.netmodule
HashValue Blob : 1f bc 2d cb b2 3b 74 57 12 f8 77 78 71 d5 94 86 c7 64 f8 b8
Flags : [ContainsMetaData] (00000000)
File #2 (26000002)
-------------------------------------------------------
Token: 0x26000002
Name : source2.netmodule
HashValue Blob : 21 94 0c 30 17 c4 86 2f 82 0a cc 91 e7 bb a9 59 ed a1 7a bc
Flags : [ContainsMetaData] (00000000)
ExportedType #1 (27000001)
-------------------------------------------------------
Token: 0x27000001
Name: IWriter
Implementation token: 0x26000001
TypeDef token: 0x02000002
Flags : [Public] [AutoLayout] [Interface] [Abstract] [AnsiClass] (000000a1)
ExportedType #2 (27000002)
-------------------------------------------------------
Token: 0x27000002
Name: ConsoleWriter
Implementation token: 0x26000001
TypeDef token: 0x02000003
Flags : [Public] [AutoLayout] [Class] [AnsiClass] [BeforeFieldInit] (00100001)
ExportedType #3 (27000003)
-------------------------------------------------------
Token: 0x27000003
Name: DataContext
Implementation token: 0x26000002
TypeDef token: 0x02000002
Flags : [Public] [AutoLayout] [Class] [AnsiClass] [BeforeFieldInit] (00100001)
User Strings
-------------------------------------------------------
70000001 : ( 1) L" "
Coff symbol name overhead: 0
===========================================================
===========================================================
===========================================================
مشاهده میشه که این اسمبلی فقط حاوی داده های مانیفسته و از سایر جداول معروف متادیتا خبری نیست. تو تصویر زیر نمای کلی فایلهای تولیدشده و محتوای اونا نشون داده شده:
در این مثال، همونطور که تو تصویر بالا مشخصه، یه اسمبلی 3 فایله تولید شد. با استفاده از دو ماژولی که کامپایلر #C تولید کرد و یه فایل اصلی اسمبلی که ابزار AL.exe تولید کرد، درنهایت یه اسمبلی کامل که قابلیت بارگذاری تو CLR رو داره تولید شد. البته نکته ای که باید بهش توجه کرد اینه که ابزار AL.exe هیچ راهی برای ترکیب این فایلها و تولید یه اسمبلی تک فایله کامل نداره.