先说一下为什么写这一篇小文章,最近不少同事是在问一个问题,为什么Ant编译出的代码在日志里的出错异常栈看不到行号信息,每次如果在定位问题,都需要用eclipse重新将相应的jar包编译一下,再放到问题环境上重现一下,这样再看日志才可以。而且使用ant生成的包就算是远程调试也不可用,断点总是打不上。
一般的开发都会有一套持续集成的环境,用作每日构建,用ant或是其他工具,开发人员一般用Eclipse或其他的IDE做开发,所以经常会遇见上面的问题。
原因ant的Javac任务里有对debug信息输出的设置,不过默认是不输出。
javac中设置调试信息级别的选项为-g,其详细含义如下,英文太简单,偶会详细介绍一下:
-g Generate all debugging information, including local variables. By default, only line number and source file information is generated. 在Class文件中生成所有调试信息。也就是将会包含下面介绍的3类调试信息的所有。 -g:none Do not generate any debugging information. Class文件中不包含任何调试信息,这个是Ant在编译时默认使用的。 -g:{keyword list} Generate only some kinds of debugging information, specified by a comma separated list of keywords. Valid keywords are: source Source file debugging information Class文件中固定长度的SourceFile属性,编译时如果选择了生成此属性,则会将它写到Class文件中。它用来提供产生Class文件的源文件名称。 如果不生成此属性,那么在调试时就会提示“Source not found.”。有图有真像,我们用Eclipse来演示一下此调试开关的作用,帮助大家理解。 先设置一下eclipse编译时的选项,关闭Source file属性开关,编译选项的修改只针对此测试用的工程,所以在我们测试的工程右键->properties,在弹出的对话框中,按下图进行选择:
Java代码
public class Main { public static void main(String[] args) { Test t = new Test(); t.sayHello(); } } class Test { public Test() { } public void sayHello() { <SPAN style="COLOR: #ff0000">int a = 10; // 断点将打在此行</SPAN> int b = a++; System.out.println("b:" + b); String hello = "Test say"; hello += " hello"; System.out.println(hello); } } public class Main { public static void main(String[] args) { Test t = new Test(); t.sayHello(); } } class Test { public Test() { } public void sayHello() { int a = 10; // 断点将打在此行 int b = a++; System.out.println("b:" + b); String hello = "Test say"; hello += " hello"; System.out.println(hello); } } 好了,我们在Eclipse中启动调试Main.java,你将会得到下图中的信息:lines Line number debugging information 将源文件中的行号信息写到Class文件中,此属性用于在Class文件中生成方法字节码流偏移量和源代码行号之间的映射关系。就像我们引子中所看到的,打印出的异常栈中看不到行号,就是因为生成Class中没有此属性导致,而远程调试时打不上断点也是这个原因。 同样的,我们在Eclipse中测试此调试选项的含义,其设置位置跟Source file属性在同一个界面,也在我们图1中设置,图1位置2的第2行,就是此选项,去选中此项,其他选项均选中,重新编译。还是用上面的Main.java来调试,看一下,会出现什么。