1.
C# Compiler - CSC.exe
csc.exe /out:Program.exe /t:exe /r:MSCorLib.dll
Program.cs
This command line tells the C# compiler to emit an executable file
called Program.exe (/out:Program.exe). The type of file
produced is a Win32 console
application (/t[arget]:exe).
csc.exe /out:Program.exe /t:exe Program.cs
The C# compiler automatically references the MSCorLib.dll
assembly.
csc.exe Program.cs
Furthermore, the /out:Program.exe and the /t:exe command-line
switches also match what the C# compiler would choose as defaults.
/nostdlib switch
The C# compiler doesn‘t reference the
MSCorLib.dll assembly.
Windows supports two types of applications, those with a
console user interface (CUI) and those with a graphical
user interface (GUI). Because I specified
the /t:exe switch, the C#
compiler produced a CUI application. You’d use
the /t:winexe switch to
cause the C# compiler to produce a GUI application.
/t:exe
/t:winexe
/t:library
The C# compiler produces an assembly when you specify any of the
following command-line switches: /t[arget]:exe,
/t[arget]:winexe, or /t[arget]:library. All of these
switches
cause
the compiler to generate a single PE file that contains the manifest metadata
tables. The resulting file is either a CUI executable, a GUI executable, or
a DLL, respectively.
/t:module
This switch tells the compiler to produce
a PE file that doesn’t contain the manifest metadata
tables. The PE file produced is always a DLL PE file,
and this file must be added to an assembly before the CLR can access any
types within it. When you use the /t:module switch, the C# compiler, by
default, names the output file with an extension
of .netmodule.
e.g csc /t:module RUT.cs
This will produce a standard DLL PE file named RUT.netmodule. But,
the CLR can‘t load it.
/addmodule
This switch is used to add a module to an assembly.
e.g csc /out:JeffTypes.dll /t:library /addmodule:RUT.netmodule
FUT.cs
This line tells the C# compiler to compile the FUT.cs file to
produce the JeffTypes.dll
file. Because /t:library is
specified, a DLL PE file containing the manifest metadata tables is emitted
into the JeffTypes.dll file.
The /addmodule:RUT.netmodule switch
tells the compiler that RUT.netmodule is a file that should be considered
part of the assembly. Specifically,
the /addmodule switch tells the compiler
to add the file to the FileDef manifest metadata table and to add
RUT.netmodule’s publicly exported types to the ExportedTypesDef
manifest metadata table.
Any client code that consumes the JeffTypes.dll assembly’s types
must be built using
the /r[eference]:JeffTypes.dll compiler
switch. This switch tells the compiler to load
the JeffTypes.dll assembly and all of the files listed in its FileDef
table when searching for an external
type. The compiler requires all of the assembly’s
files to be installed and accessible.
/resource
The
C#
compiler’s /resource switch embeds
the specified resource file into the resulting assembly PE file,
updating the ManifestResourceDef table.
/linkresource
The
compiler’s /linkresource switch adds an entry to the
ManifestResourceDef and the FileDef manifest tables to refer to a
stand-alone resource file.
2. MSCorLib.dll
MSCorLib.dll is a special file in that it contains all
the core types: Byte, Char, String,
Int32, and many more. In fact, these types are so frequently
used that the C# compiler
automatically references the MSCorLib.dll assembly.
3. Respone File
A response
file is a text file that contains a set of
compiler commandline switches. When you execute CSC.exe, the compiler opens
response files and uses any switches that are specified in them as though
the switches were passed to CSC.exe on the command line. You instruct the
compiler to use a response file by specifying its name on the command line
prepended by
an @ sign.
For example: you could have a response file
called MyProject.rsp that contains the
following text:
/out:MyProject.exe
/target:winexe
To cause CSC.exe to use these settings, you’d invoke it as
follows:
csc.exe @MyProject.rsp CodeFile1.cs
CodeFile2.cs
The C# compiler supports multiple response files. In addition to
the files you explicitly specify on the command
line, the compiler automatically looks for files
called CSC.rsp. When you
run
CSC.exe, it looks in the current directory for a local
CSC.rsp file—you should place any project-specific settings in
this file. The compiler also looks in the directory
containing the CSC.exe file for a global CSC.rsp
file. Settings that you want applied to all of your
projects should go in this file. The compiler aggregates and uses the
settings in all of these response files. If you have conflicting settings
in the local and global response files, the settings in the local file
override the settings in the global file. Likewise, any settings explicitly
passed on the command line override the settings taken from a local
response file.
When you install the .NET Framework, it installs
a default global CSC.rsp file in the
%SystemRoot%\Microsoft.NET\Framework\vX.X.Xdirectory (where
X.X.X is the version of the .NET Framework you have installed).
You can tell the compiler to ignore both local and global CSC.rsp
files by specifying
the /noconfig command-line
switch.
4.
Metadata
A managed PE file has four main parts: the PE32(+) header,
the CLR header, the metadata, and the IL.
The PE32(+)
header is the standard information that Windows
expects.
The CLR header is
a small block of information that is specific to modules that require the CLR
(managed modules). The header includes the major and minor version number
of the CLR that the module was built for: some flags, a MethodDef token
indicating the module’s entry point method if this module is a CUI or GUI
executable, and an optional strong-name digital signature. Finally, the
header contains the size and offsets of certain metadata tables contained
within the module. You can see the exact format of the CLR header by
examining the IMAGE_COR20_HEADER defined in the CorHdr.h header file.
The metadata is
a block of binary data that consists of several tables. There are three
categories of tables: definition tables,
reference tables, and manifest tables.
Method Flag [HideBySig] hidebysig is supplied for the
use of tools and is ignored by the VES. It specifies that the declared method
hides all methods of the base class types that have a matching method signature;
when omitted, the method should hide all methods of the same name, regardless of
the signature.
上面的英文摘自ECMA关于CLI的标准。用hidebysig修饰的方法会隐藏掉基类中具有相同签名的方法,这么看来相当于在方法前加上了new关键字
Method Flag [ReuseSlot] Indicates that the method
will reuse an existing slot in the vtable. This is the default behavior.
Method Flag [NewSlot] Indicates that the
method always gets a new slot in the vtable.
For the curious, metadata tokens are
4-byte values. The high byte indicates the
type of token (0x01=TypeRef, 0x02=TypeDef, 0x23=AssemblyRef, 0x26=FileRef,
0x27=ExportedType). For the complete list, see
the CorTokenType enumerated
type in the CorHdr.h file included with the .NET Framework SDK. The three
lower bytes of the token simply identify the row in the corresponding
metadata table. For example, the implementation token 0x26000001 refers
to the first row of the FileRef table. For most tables, rows are numbered
starting with 1, not 0. For the TypeDef table, rows actually start with
2.
typedef enum CorTokenType
{mdtModule = 0x00000000, //mdtTypeRef = 0x01000000, //mdtTypeDef = 0x02000000, //mdtFieldDef = 0x04000000, //mdtMethodDef = 0x06000000, //mdtParamDef = 0x08000000, //mdtInterfaceImpl = 0x09000000, //mdtMemberRef = 0x0a000000, //mdtCustomAttribute = 0x0c000000, //mdtPermission = 0x0e000000, //mdtSignature = 0x11000000, //mdtEvent = 0x14000000, //mdtProperty = 0x17000000, //mdtModuleRef = 0x1a000000, //mdtTypeSpec = 0x1b000000, //mdtAssembly = 0x20000000, //mdtAssemblyRef = 0x23000000, //mdtFile = 0x26000000, //mdtExportedType = 0x27000000, //mdtManifestResource = 0x28000000, //mdtGenericParam = 0x2a000000, //mdtMethodSpec = 0x2b000000, //mdtGenericParamConstraint = 0x2c000000,mdtString = 0x70000000, //mdtName = 0x71000000, //mdtBaseType = 0x72000000, // Leave this on the high end value. This does not correspond to metadata table} CorTokenType;
5.
Assembly Linker - AL.exe
The Assembly Linker
is useful if you want to
create an assembly consisting of modules built from
different compilers (if your compiler doesn’t support
the equivalent of C#’s /addmodule switch) or perhaps if you
just don’t know your assembly
packaging requirements at build time.
The AL.exe utility can produce an EXE or a DLL PE file that
contains only a manifest describing the types in other
modules. The
Assembly Linker has no way to
combine multiple files into a single file.
e.gcsc /t:module RUT.cscsc /t:module FUT.csal /out:JeffTypes.dll /t:library FUT.netmodule RUT.netmodule
The AL.exe utility can also produce CUI
and GUI PE files by using the /t[arget]:exe or /t[arget]:winexe command-line
switches. But this is very unusual since it would
mean that you’d have an EXE PE file with just enough IL code in it to call
a method in another module. You can specify which method in a module should
be used as an entry point by adding the /main command-line switch when
invoking AL.exe. The following is an example of how to call the Assembly
Linker, AL.exe, by using the /main command-line switch:
e.gcsc /t:module /r:JeffTypes.dll Program.csal /out:Program.exe /t:exe /main:Program.Main Program.netmodule
When using AL.exe to create an assembly, you can add a file as a
resource to the assembly by using
the /embed[resource] switch.
This switch takes a file (any file) and embeds the file’s
contents
into the resulting PE file. The manifest’s ManifestResourceDef table is updated
to reflect the existence of the resources.
AL.exe also supports a /link[resource] switch, which also takes a
file containing resources. However,
the /link[resource] switch
updates the manifest’s ManifestResourceDef and FileDef tables, indicating
that the resource exists and identifying which of the assembly’s
files contains it. The resource file is not embedded into the assembly PE
file; it remains separate and must be packaged and deployed with the other
assembly files.
/c[ulture]:<text>
This switch will add culture infromation.
Like
AL.exe, CSC.exe also allows
you to combine resources into an assembly produced by the C# compiler. The
C#
compiler’s /resource switch
embeds the specified resource file into the resulting assembly PE file,
updating the ManifestResourceDef table. The
compiler’s /linkresource switch adds an
entry to the ManifestResourceDef and the FileDef manifest tables to refer
to a stand-alone resource file.
6.
Satellite assembly
Resource-Only Assembly
Assemblies that are marked with a culture are called
satellite assemblies.
You’ll usually use
the AL.exe tool to build a
satellite assembly. You won’t use a compiler because the satellite assembly
should have no
code contained within it. When using AL.exe, you
specify the desired culture by using the /c[ulture]:text switch, where text is a
string such as “en-US,” representing U.S. English. When
you deploy a satellite assembly, you should place it in a subdirectory
whose name matches the culture text. For example, if the application’s base
directory is C:\MyApp, the U.S. English
satellite assembly should be placed in the C:\MyApp\en-US
subdirectory. At runtime, you access a satellite assembly’s resources
by using the System.Resources.ResourceManager class.
Note: It is possible to create a satellite
assembly that contains code, though this practice is discouraged. If you
prefer, you can specify the culture by using
the System.Reflection.AssemblyCultureAttribute custom
attribute instead of using AL.exe’s /culture switch, for example, as shown
here:
e.g
// Set assembly‘s culture to Swiss German[assembly:AssemblyCulture("de-CH")]
7. Assembly
Version Resources
e.g
using System.Reflection;
// FileDescription version information:[assembly: AssemblyTitle("JeffTypes.dll")]// Comments version information:[assembly: AssemblyDescription("This assembly contains Jeff‘s types")]// CompanyName version information:[assembly: AssemblyCompany("Wintellect")]// ProductName version information:[assembly: AssemblyProduct("Wintellect (R) Jeff‘s Type Library")]// LegalCopyright version information:[assembly: AssemblyCopyright("Copyright (c) Wintellect 2010")]// LegalTrademarks version information:[assembly:AssemblyTrademark("JeffTypes is a registered trademark of Wintellect")]// AssemblyVersion version information:[assembly: AssemblyVersion("3.0.0.0")]// FILEVERSION/FileVersion version information:[assembly: AssemblyFileVersion("1.0.0.0")]// PRODUCTVERSION/ProductVersion version information:[assembly: AssemblyInformationalVersion("2.0.0.0")]// Set the Language field (discussed later in the "Culture" section)[assembly:AssemblyCulture("")]
You can use AL.exe‘s
command-line switches to set this information instead of using the custom
attributes.
Version Resource AL.exe Switch
Custom Attribute/Comment
FILEVERSION /fileversion System.Reflection.AssemblyFileVersionAttribute.PRODUCTVERSION /productversion System.Reflection.AssemblyInformationalVersionAttribute.FILEFLAGSMASK (none) Always set to VS_FFI_FILEFLAGSMASK (defined in WinVer.h as 0x0000003F).FILEFLAGS (none) Always 0.FILEOS (none) Currently always VOS__WINDOWS32.FILETYPE /target Set to VFT_APP if /target:exe or /target:winexe is specified; set to VFT_DLL if /target:library is specified.FILESUBTYPE (none) Always set to VFT2_UNKNOWN. (This field has no meaning for VFT_APP and VFT_DLL.)AssemblyVersion /version System.Reflection.AssemblyVersionAttribute.Comments /description System.Reflection.AssemblyDescriptionAttribute.CompanyName /company System.Reflection.AssemblyCompanyAttribute.FileDescription /title System.Reflection.AssemblyTitleAttribute.FileVersion /version System.Reflection.AssemblyFileVersionAttribute.InternalName /out Set to the name of the output file specified (without the extension).LegalCopyright /copyright System.Reflection.AssemblyCopyrightAttribute.LegalTrademarks /trademark System.Reflection.AssemblyTrademarkAttribute.OriginalFilename /out Set to the name of the output file (without a path).PrivateBuild (none) Always blank.ProductName /product System.Reflection.AssemblyProductAttribute.ProductVersion /productversion System.Reflection.AssemblyInformationalVersionAttribute.SpecialBuild (none) Always blank.
8. Version
Numbers
Version numbers have the format: each consists of four
period-separated parts.
The first two
numbers make
up the public perception of the version.
The public will think of this example as version 2.5 of the assembly. The
third number, 719, indicates the build of the assembly. If your company
builds its assembly every day, you should increment the build number each
day as well. The last number, 2, indicates the revision of the build. If
for some reason your company has to build an assembly twice in one day,
maybe to resolve a hot bug that is halting other work, the revision number
should be incremented.
9.
Culture
Like version numbers, assemblies also have a culture as part of
their identity.
e.g
In general, if you create an assembly that contains code, you don’t
assign a culture to it. This is because code doesn’t usually have any
culture-specific assumptions built into it. An assembly that isn’t assigned
a culture is referred to as being culture
neutral.
10.
Simple Application Deployment
Assemblies deployed to the same directory as the application are
called privately
deployed assemblies because the assembly files
aren’t shared with any other application (unless the other application is
also deployed to the same directory). Privately deployed assemblies are
a big win for developers, end users, and administrators because they can
simply be copied to an application’s base directory, and the CLR will load them
and execute the code in them. In addition, an application can be
uninstalled by simply deleting the assemblies in its directory. This allows
simple backup and restore as well.
This
simple install/move/uninstall scenario
is possible because each assembly has metadata indicating which referenced
assembly should be loaded; no registry settings are required. In addition,
the referencing assembly scopes every type. This means that an application
always binds to the same type it was built and tested with; the CLR can’t
load a different assembly that just happens to provide a type with the same
name. This is different from COM, in which types are recorded in the
registry, making them available to any application running on
the machine.
11.
Simple Administrative Control (Configuration)
To allow administrative control over an application, a
configuration file can be placed in the application’s directory.
e.g
<configuration><runtime><assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"><probing privatePath="AuxFiles" /></assemblyBinding></runtime></configuration>
The name and location of this XML configuration file is different
depending on the application type:
For executable
applications (EXEs), the configuration file must be in the
application’s base directory, and it must be the name of the EXE file with
“.config” appended to it.
For Microsoft
ASP.NET Web Form applications, the file must be in the Web
application’s virtual root directory and is always named Web.config. In
addition, subdirectories can also contain their
own Web.config file, and
the configuration settings are inherited. For example, a Web application
located at http://Wintellect.com/Training would use the settings in the
Web.config files contained in the virtual root directory and in
its Training subdirectory.
Configuration settings apply to a particular application and
to the machine. When you install the .NET Framework, it creates a Machine.config
file. There is one Machine.config file per version of the CLR you have installed
on the machine.
The Machine.config file
is located in the following directory:
%SystemRoot%\Microsoft.NET\Framework\version\CONFIG
Of
course, %SystemRoot% identifies your Windows directory (usually C:\WINDOWS),
and version is a version number identifying a specific version of the .NET
Framework (something like v4.0.#####).
CLR via C# 3rd - 02 - Building, Packaging, Deploying, and Administering Applications and Types