java源代码
前言
本文为javac 源码解析的第一篇,主要介绍了如下内如:
重要说明: javac是java的编译器,内容高深,非常人所能参透,本人也同样,写本文只为了交流,因此,诸位看客发现纰漏,请指出,点拨一下小弟,不甚感激.
阅读javac源代码的好处
阅读javac的好处如下:
- 能接触java的真实面貌
- 能更早的进入到java大神的行列
- 能够获取到更多面试机会
阅读javac源代码的储配知识
按照官方的说法是: javac读取按照java语法写成的源文件,同时生产字节码文件.其中java语法被The Java Language Specification (JLS) 所定义,字节码文件则被The Java virtual Machine Specification (JVMS) 所定义. 同时,该编译器会处理注解,这是被Pluggable Annotation Processing API (JSR 269). 所定义的. 同样,该编译器还支持 the Java Compiler API (JSR 199). 因此,阅读javac所需要的知识也就很明白了:
- JLS
- JVMS
- (option) JSR 269
- (option) JSR 199
另外,既然是一个编译器,自然逃不过编译原理的范畴.
build javac
javac的源代码可以在如下地址中找到: javac源代码.下载下来后,按照 官方说明build说明 进行build即可.
不过,我这里采用的是build jdk的方式构建的.现说明如下:
- 在 下载链接 中下载openjdk 8 的源代码.
由于本人是在mac 上进行构建的,因此需要对源码做如下修改:
在hotspot/src/share/vm/code/relocInfo.hpp 中,将 datalen = 0 改为 datalen. 如图所示:
搜索 int datalen, 第 462 行,改为 int datalen = 0.如图所示:
在hotspot/src/share/vm/opto/loopPredicate.cpp中,将 _igvn.type(rng)->is_int() >= 0 改成 _igvn.type(rng)->is_int()->_lo >= 0 如图所示:
在hotspot/src/share/vm/runtime/virtualspace.cpp中,将 base() > 0 改成 base() != 0 如图所示:
修改 nashorn/make/BuildNashorn.gmk 中的 第 80 行 -cp 修改为 -Xbootclasspath/p . 如图所示:
然后,创建一个 envsetup.sh, 内容如下:
\# 设定语言选项,必须设置 export LANG=C \# Mac平台,C编译器不再是GCC,是clang export CC=gcc \# 跳过clang的一些严格的语法检查,不然会将N多的警告作为ERROR export COMPILER_WARNINGS_FATAL=false \# 链接时使用的参数 export LFLAGS='-Xlinker -lstdc++' \# 是否使用clang export USE_CLANG=true \# 使用64位数据模型 export LP64=1 \# 告诉编译平台是64位,不然会按32位来编译 export ARCH_DATA_MODEL=64 \# 允许自动下载依赖 export ALLOW_DOWNLOADS=true \# 并行编译的线程数,编译时间长,为了不影响其他工作,我选择为2 export HOTSPOT_BUILD_JOBS=2 export ALT_parallel_COMPILE_JOBS=2 \# 是否跳过与先前版本的比较 export SKIP_COMPARE_IMAGES=true \# 是否使用预编译头文件,加快编译速度 export USE_PRECOMPILED_HEADER=true \# 是否使用增量编译 export INCREMENTAL_BUILD=true \# 编译内容 export BUILD_LANGTOOLS=true export BUILD_JAXP=false export BUILD_JAXWS=false export BUILD_CORBA=false export BUILD_HOTSPOT=true export BUILD_JDK=true \# 编译版本 export SKIP_DEBUG_BUILD=true export SKIP_FASTDEBUG_BUILD=false export DEBUG_NAME=debug \# 避开javaws和浏览器Java插件之类的部分的build export BUILD_DEPLOY=false export BUILD_INSTALL=false \# 加上产生调试信息时需要的 objcopy export OBJCOPY=gobjcopy
然后,执行 source envsetup.sh
进行build。
执行如下命令:
bash ./configure \ --with-target-bits=64 \ --with-debug-level=slowdebug --enable-debug-symbols \ ZIP_DEBUGINFO_FILES=0
执行命令:
make all
至此,就会看到build 成功的输出
进行测试,如图所示:
添加编译的jdk到Eclipse中,如图所示:
创建一个java 项目,使用我们自己build的jdk.然后将javac的源代码赋值到该项目中, javac的源代码在 openjdk/langtools/src/share/classes/com/sun/tools 下.导入后,如图所示:
写两个类进行测试,代码如下:
import com.sun.tools.javac.main.Main; public class DebugEntryPoint { public static void main(String[] args) { Main m = new Main("fx_debug"); m.compile(asArray("/Users/xxxxx/Documents/2017-03-22-brabch/javac-test/src/Demo.java")); } private static <T> T[] asArray(T... args) { return args; } }
public class Demo { public void foo() { char a = 'a'; a += 32; // 可以通过 } }
执行后,就可以看到会生成 Demo.class
javac源代码结构说明
用官方的一张图进行说明:
在com.sun.tools.javac下有如下几个包,现说明如下:
1. api –> 实现了JavaCompiler 和javax.tools中其他的api
2. code –> 定义了Java程序的语义元素的表示,如符号、作用域和类型,在javax.lang.model.*.中实现.
3.comp –> 编译器的主要处理阶段,如标记、流分析、“解语法糖”和擦除
4. file –> 使用java.nio.file 的api来访问本地的文件系统.
5. jvm –> 读取和写class文件,生成字节码
6. main –> 编译的主要驱动代码,提供了多样的编译步骤选项
7.model –> javax.lang.model.*. 的额外实现类
8.parser –> 读取java源文件生成语法树
9.processing –> 实现了在javax.annotation.processing.*定义的api
10.resources –> 信息本地化和版本信息的资源文件
11. tree –> 编译器的语法树的表示和实用类,实现了com.sun.source.*.中定义的api
12. util –> 工具类
参考链接
compiler-package-overview
compiler-README.html#build
compiler-index
在 macOS 上编译 OpenJDK 8
如何构建javac的调试环境
相关阅读
一、简述: cmd中,执行java命令与javac命令的区别: javac:是编译命令,将java源文件编译成.class字节码文件。 例如:javac hello.java 将
Javac编译器是把 *.java 文件转换为 *.class 文件,是一个前端编译器;对应着有一种把字节码转变为机器码的编译器,称为JIT编译器(Jus
简述 在学着使用Java的命令行来编译java文件的时候,遇到了这个问题Windows操作系统“‘javac’不是内部或外部命令,也不是可运行的