تو مطلب «اسمبلی های چند فایله»، روش تولید یه اسمبلی چند فایله با استفاده از کامپایلر سی شارپ نشون داده شد. علاوه بر این روش، راه دیگه ای هم برای تولید چنین اسمبلی هایی وجود داره و اون استفاده از ابزار 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 هیچ راهی برای ترکیب این فایلها و تولید یه اسمبلی تک فایله کامل نداره.