Included in the CLI is the specification of the CIL output from a source language compiler, usually an assembly. In addition to the CIL instructions themselves, an assembly includes a manifest that is made up of the following components:
The manifest is essentially a header to the assembly, providing all the information about what an assembly is composed of, along with the information that uniquely identifies it.
Assemblies can be class libraries or the executables themselves, and one assembly can reference other assemblies (which, in turn, can reference more assemblies), thereby establishing an application composed of many components rather than existing as one large, monolithic program. This is an important feature that modern programming frameworks take for granted, because it significantly improves maintainability and allows a single component to be shared across multiple programs.
In addition to the manifest, an assembly contains the CIL code within one or more modules. Generally, the assembly and the manifest are combined into a single file, as was the case with HelloWorld.exe in Chapter 1. However, it is possible to place modules into their own separate files and then use an assembly linker (al.exe) to create an assembly file that includes a manifest referencing each module.4 This approach not only provides another means of breaking a program into components but also enables the development of one assembly using multiple source languages.
Casually, the terms module and assembly are somewhat interchangeable. However, the term assembly is predominant when talking about CLI-compatible programs or libraries. Figure 24.2 depicts the various component terms.
Note that both assemblies and modules can also reference files such as resource files that have been localized to a particular language. Although it is rare, two different assemblies can reference the same module or file.
Even though an assembly can include multiple modules and files, the entire group of files has only one version number, which is placed in the assembly manifest. Therefore, the smallest versionable component within an application is the assembly, even if that assembly is composed of multiple files. If you change any of the referenced files—even to release a patch—without updating the assembly manifest, you will violate the integrity of the manifest and the entire assembly itself. As a result, assemblies form the logical construct of a component or unit of deployment.
Even though an assembly (the logical construct) could consist of multiple modules, most assemblies contain only one. Furthermore, Microsoft now provides an ILMerge.exe utility for combining multiple modules and their manifests into a single file assembly.
Because the manifest includes a reference to all the files an assembly depends on, it is possible to use the manifest to determine an assembly’s dependencies. Furthermore, at execution time, the runtime needs to examine only the manifest to determine which files it requires. Only tool vendors distributing libraries shared by multiple applications (e.g., Microsoft) need to register those files at deployment time. This makes deployment significantly easier. Often, deployment of a CLI-based application is referred to as xcopy deployment, after the Windows xcopy command that simply copies files to a selected destination.
Unlike Microsoft’s COM files of the past, CLI assemblies rarely require any type of registration. Instead, it is possible to deploy applications by copying all the files that compose a program into a particular directory and then executing the program.