C#编译基础知识(一)
2014-06-21 11:39 HaiZL 阅读(347) 评论(0) 收藏 举报1 准备工作
csc.exe是.net Framework提供的一个编译工具,对应的语言为C#,vb语言对应的编译器是vbc.exe。为了使用上的方便,我们需要把这个文件所在的路径放到环境变量path中,方便后面直接调用,这个文件位于C:\Windows\Microsoft.NET\Framework\v4.0.30319下,不同的版本最后一个文件夹会有差异。
2 一个简单的例子
源码如下,一个再简单不过的控制台命令程序。
using System;
///一个简单的demo public class a{
///应用程序的主入口Main方法 public static void Main(){ Console.WriteLine("Hi"); } }
编译命令很简单csc d:\a.cs,该源文件位于d盘根目录下。

该源码编译完成后将生成一个可执行的exe文件,就存在于C:\Users\liuzh下,执行之后的结果也是显而易见的

当然,生成的文件路径和文件名是可以随意修改的,显示的指定/out:开关即可,通过执行命令csc -?可以看到详细的描述

修改后的命令如下,执行之后生产的a.exe就会出现在d:\下面
csc /out:d:\a.exe d:\a.cs
有时候我们需要生成的可能不是exe,只是一个dll,那么需要显示的指定/target:开关,可以缩写成/t:,该开关的说明如下

那么修改后的命令如下
csc /out:d:\a.dll /target:library d:\a.cs
对于其他类型开关的一个说明
/t:module 生成的是一个托管模块,可用于将来合并到其他应用程序集
/t:winmdobj 将生成一个windows运行时中间文件,之所以叫做中间文件,是因为它必须被windows运行时元数据导出工具导出后才能使用。
/t:appcontainerexe 将生成一个windows应用商店里面的应用
/t:winexe将生成一个winform应用程序
下面给出一个/t:winexe的例子
源代码为
using System.Windows.Forms; using System; public class f{ public static void Main(){ Form f=new Form(); f.Text ="New Form"; f.Show(); Application.Run(); } }
编译命令为
csc /out:d:\f.exe /t:winexe d:\f.cs
最后运行的效果如下
如果我们想得到类的成员及注释信息,得加上/doc:开关

编译命令为
csc /out:d:\a.exe /doc:d:\a.xml /t:library d:\a.cs
最后生成的d:\a.xml文件是这个样子

3 类之间相互引用时的编译及响应文件
假如现在类a要引用类b的方法,但a和b都在一个程序集时,编译时则就需要把a.cs和b.cs都包含进来,就像这个样子
csc d:\a.cs d:\b.cs
如过b是一个应用程序集,如b.dll,类a需要引用b中的一个方法,那么编译时则需要加上/reference:开关,简写/r:,编译时的命令如下
csc d:\a.cs /r:d:\b.dll
当使用/reference:开关时,引用的应用程序集可以是一个特定的完整路径,如果不指定路径时(csc d:\a.cs /r:b.dll)编译器会从如下位置逐一进行寻找
1 工作目录 C:\Users\Liuzh
2 csc.exe本身所在的目录
3 使用/lib:开关指定的任何目录。
4 环境变量lib指定的任何目录
是时候来说说响应文件了,响应文件是一个文本文件,其中包含了编译器命令开关,执行csc.exe时,编译器会打开响应文件,并使用其中的所有开关,感觉就像是这些开关直接在命令行上传递给csc.exe一样,要在命令行中使用响应文件,在文件名前加上@。对于命令csc /out:d:\a.exe /doc:d:\a.xml /t:library d:\a.cs,假如我们的响应文件MyProgram.rsp内容为/out:d:\a.exe /doc:d:\a.xml /t:library,那么最后的编译命令为
csc @d:\MyProgram.rsp d:\a.cs
C#编译器允许同时制定多个响应文件,除了在命令行上显式制定文件,csc.exe在运行时还会自动寻找在csc.exe所在目录的CSC.RSP文件。
在安装.net framework时,默认就会在%SystemRoot%\Microsoft.NET\Framework\vX.X.X目录中安装一个CSC.RSP文件,4.0环境下的这个文件包含如下内容(部分截图)

4 生成调试信息及代码优化
示例代码如下
using System; public class c { public static void Main(){
Console.ReadLine(); if ("Aa"!="AA"){ Console.WriteLine("Really Different!"); } } }
控制调试信息和优化信息的两个开关分别是/optimize 和 /debug,csc帮助中的描述为

如果要生成一个可以用于调试的dll或exe,则需要使用命令 csc d:\c.cs /debug:full,运行后将会生成d:\c.exe和d:\c.pdb,使用vs可以直接附加进程调试

使用/debug:pdbonly时,生成的内容则不能进行调试,使用 /debug:full 时,编译器会发出 DebuggableAttribute,用于通知 JIT 编译器有可用的调试信息,比对它们生成的元数据的差异可以看出这一点

当使用/optimize+生成时,对比/debug生成的IL,可以发现很多NOP指令都消失了,代码行数也少了很多(如图左侧为debug生成,右侧为optimize)

这两个开关生成的代码其实还会影响到最后的JIT编译,他们组合起来时对IL和JIT编译的影响如下
| 编译器开关设置 | C#IL代码质量 | JIT本地代码质量 |
| /optimize- /debug-(默认) | 未优化 | 有优化 |
| /optimize- /debug(+/full/pdbonly) | 未优化 | 未优化 |
| /optimize+ /debug(-/+/full/pdbonly) | 有优化 | 有优化 |
5 总结
本文走马观花似的对C#的csc命令做了一个基本的介绍,这些内容在csc的帮助文档里面都有一个比较全面的介绍,了解这些命令有助于我们平常排查编译过程中遇到的各种错误,能为深入了解CLR执行模型打下良好的基础。
浙公网安备 33010602011771号