在 wind_jvm 上的即时编译器在今年的 4 月 4 日完成了。并不打算放在 github 上。
学到了很多的东西,对 JIT 有了新的认识。
毕设答辩前夕,不由得唏嘘不已。
从 HIR 到 LIR,从静态单赋值的建立到解构。
Cliff Click 大神的 GCM 算法,简直是拯救了这个编译器,哈哈。它让我的 HIR 能够成功编译成 LIR。当时琢磨怎样将一个图形态的 IR 编译到混合形态的低层 IR,也是挺痛苦的,哈哈。头发掉了一斤。
线性寄存器分配也是非常有意思,让人难受的有意思。可能是自己的功力不够吧。还是要多努力啊。Christian Wimmer 大神真的是强啊。人家的硕士论文。比不了啊。
生成 X86 平台的机器码也非常的有趣。
过几天看看心情,把论文的东西发一部分上来。心情不好就算了。
哎呀。真是不错的一段时光。
虽然不知道以后会如何,但是还是乐观些吧。
突然想到,博客不设置评论才是最好的。邮件才是交流的好方式。
还是非常期待的。就先这样吧。
编译 hsdis mac 版本,打印 jvm 执行时汇编信息
wget 一下,然后把 hsids-amd64.dylib 放到 /Library/Java/JavaVirtualMachines/jdk1.8.0_161.jdk/Contents/Home/jre/lib/server/
目录下,用 java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly <Java Main Class Name(no suffix)>
即可。
以及放在 debug 版本:~/jvm/jdk8_mac/build/macosx-x86_64-normal-server-slowdebug/images/j2sdk-bundle/jdk1.8.0.jdk/Contents/Home/jre/lib/server
目录下,但是这时候要指定:export LD_LIBRARY_PATH=~/jvm/jdk8_mac/build/macosx-x86_64-normal-server-slowdebug/images/j2sdk-bundle/jdk1.8.0.jdk/Contents/Home/jre/lib/server
才行,要不链接找不到。之后 java1 -XX:+PrintAssembly <Java Main Class Name(no suffix)>
即可。详见:http://yueyemaitian.iteye.com/blog/2042772。
唉……其实在我的机器上并没有编译成功,错误信息比较诡异。所以请用上边取巧的办法。https://www.chrisnewland.com/building-hsdis-amd64dylib-on-mac-osx-376
最后需要加一个参数 ARCH=amd64…… 要不一直默认编译 i386 的……
用 clang 编译的,不会有问题。
虚拟机完成~
前言
首先甩仓库:wind jvm
一开始只是想写一个 java 的 class file parser。后来把这东西变成了一个 tool,请左转我的javap。后来看到 @racaljk 同学用 java 实现了一个小虚拟机,感觉很有意思,遂学习了一波规范,然后写了个 C++ 的。大三下准备实习,但是还没什么能拿出手的。所以正好现在大三上有点时间,于是花了两个月写了一个。
类似项目:
@racaljk 的 YVM。不过 @racaljk 学习貌似很忙,一直没有更新QAQ。最初知道你是因为你的 hosts,实在是帮了不少忙,非常感激。而且 programming 也很强,实在佩服。
@lfkdsk 学长的 JustVM。学长实在很强,看到一堆的个人项目就五体投地了。当时我也因为 Jar 文件解包比较麻烦,看到 @lfkdsk 是直接文件读取 zip 的。因为没有现成的 zip 库也不想在上边花太多时间,所以我就采取直接把 rt.jar 全部解压的省事策略了。话说回来,大工和我们还是邻居(,而且 @lfkdsk 学长貌似也是哈尔滨人OWO。
以及 @zxh0 大大的 jvm.go。虽然没学过 go 语言,不过还是能看懂一些,也参考了部分思路。
不过最重点的还是 openjdk 的 hotspot…… 虽然管中窥豹,不过也可以略见一斑了,学到了非常多的东西~
具体
我的 wind jvm 也就是个小玩具。代码总量用 cloc 去一下水分,也就 15k 左右。一共花了两个月代码时间,其实还有一个月是在学习各种乱七八糟的支持项目的知识。还 reference 了各种东西,列举如下:
- jvm8 spec
- 周志明大大的《深入理解 java 虚拟机》
- 陈涛大大的《HotSpot 实战》
- (日)中村成洋先生的《垃圾回收的算法与实现》(中译)
- 等等。重要的还有一堆网络资源。比如 R大的 hllvm 论坛:hllvm论坛~
那么说下打开方式
我的 README 上都有写,在这里重写一遍。
- 首先我只支持 linux 和 mac。因为底层用了各种操作系统函数,pthread,stat 啥的。我的机器是 mac,所以就不支持 Windows 了。然后呢,我们需要 boost 库。用 brew 安装和 apt-get 啥的,yum 啥的都行。mac 就是
brew install boost
,然后 ubuntu 应该是sudo apt-get install libboost-all-dev
。 - 这样我们就有了 boost 支持了。于是我们应该去 Makefile 修改一下,因为我配置的是我机器的环境,而且没用 cmake。所以要手动修改,把我机器上的 boost 路径目录换成你的就可以了。比如如果是 mac 的话,把 ifeq 中的
$(CC) $(LINK_FLAGS) -L/usr/local/Cellar/boost/1.60.0_2/lib/ ....
里边的目录换成你自己的就行。如果是 linux,就把 else 中的$(CC) $(LINK_FLAGS) -L/usr/lib/x86_64-linux-gnu/
换成你自己的。不过如果是 ubuntu,八成不需要改,因为目录的版本无关。其他的 linux 就不知道了。 - 然后呢,你需要知道你的 jdk class 文件路径。mac 上,一般在
/Library/Java/JavaVirtualMachines/jdk1.8xxx.jdk/Contents/Home/jre/lib/
下的 rt.jar 文件。如果是 linux,一般在/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/
下。配置到 config.xml 中相应位置就可以了。 - 于是应该就完事了。直接跑 make -j 8 啥的 8 线程编译就可以。当然如果你是虚拟机,虚拟内存没配置够的话就算了,直接跑 make -j 2 或者 make -j 3 这种就行了。
- 之后
bin
目录会出现wind_jvm
这个 executable file。注意:一定要在wind_jvm/
目录运行./bin/wind_jvm Test1
这样的命令。因为内部我的 system lib path 是通过当前路径来获取的。如果不在wind_jvm/
目录下跑,就应该会报错。然后我给了十几个 TestX.java 文件,执行make test
就能编译。有一个 Test7.java 是不行的。那个只有 debug version jvm 的工具才能编译。所以我编译好了直接放上去了。然后运行./bin/wind_jvm Test1
这种命令就好。不加.class
后缀,参数必须有且仅有一个。 - 然后就可以玩了。不过只支持特定实现好的库,你要 socket 什么的都是没有的。不过日后实现看情况可以往上加,你也可以来 pull request 哦。
- 如果有 issue 请在 github 上上传 issue。
特性支持
- 完整的 ClassFileParser。那个 tool 的地址我已经刚才写过了。这东西才 3k 行多一点而已。
- 支持大部分常用反射机制。其他的是我没写的。因为太多了……不过想写的话肯定是有的。具体在
src/native/sun_reflect_Reflection.hpp(cpp)
,src/native/sun_reflect_NativeConstructorAccessorImpl.hpp(cpp)
等等文件中。 - 支持底层的 Unsafe 类中的大部分。如果想要支持 jdk 类库,这个类是必须要写且必须实现的。这个类可以添加 java 不能而 C++ 能的指针操作。必须强行交换两个对象什么的。当然,还需要有少量 CAS support。并发非常必要。
- 支持简单多线程。Thread 类的底层方法是通过操作系统级别的线程支持的。比如 pthread 库。
- 支持异常机制。stack unwind 栈回溯,athrow 以及可以 catch 字节码已经处理好的异常表。Test7.java 就是测试多线程异常的。
- 支持 GC。parallel GC 支持的保证是 stop-the-world (调 bug 可是好长好长时间好痛苦哇),使用了 GC-Root 算法,以及 GC 复制算法。见:gc.cpp……虽然代码量不大确是调试时间最长最难受的部分……毕竟这不是单线程 GC,是多线程的……不过我的实现肯定也是 too young 的,因为并没有各种菊苣的 paper 的支持。
- 部分支持 lambda,比如简单的 invokedynamic 类似
Thread t = new Thread(() -> System.out.println("hello world"));
,Test4,5,6,8,11,13 是测试 lambda 和 invoke(MethodHandle) 的。不过很遗憾这一部分理解有些跟不上,虽然支持是比较容易,但是想要理解类库究竟是怎么实现 lambda,还需要积累和进一步研究。因此只能支持部分。[注:部分测试用例 from network]。具体实现代码请见:invokedynamic。当然不可能只有这点。这里是核心部分。还有待支持更多。 - 字节码方面,支持绝大多数,没用到的就没写(怕写错),wide 指令这种,我是没加的。
实现细节
- 和 openjdk 一样的,klass oop 二分模型。
- 解释型。完全在解释 bytecode。因此效率上肯定差强人意。
- 按照真正的 jvm 跑 class 文件的流程运行(几乎)。初始化 mirror,初始化基础类,使用 C++ 实现的 bootstraploader,进而调用 java 的 AppClassLoader 来加载 main class。
- 每个线程配上了不同的颜色(,方便观看(其实更重要的是方便调试哇。(笑)
- 等等。细节太多了。如果你想看更多的细节,下文有字节码执行的流程输出。
糟粕
- 一开始什么也不会的时候,用字符串查找类……这是特别悲伤的设计。严重拖慢速度,历史遗留问题。
- 有时跑 Test7 这种多线程测试用例碰到异常的时候,最后会段错误。其实是完全可以解决的。用 pthread_cancel 配上 pthread_join 就可以完全解决。不过一开始的设计是没考虑到这么多,直接把所有线程 detach 了。如果要改,势必代码的形状会特别悲伤。所以左思右想还是维持原状,并不影响运行结果。其实这样是并不对的,java 要求某一线程抛异常,不会影响其他线程的执行。其实真正的实现是要用 join 的。
- 等等。
输出细节
如果想要开启更多的细节,可以在 Makefile 中修改,原本是 CPP_FLAGS := -std=c++14 -O3 -pg
,我在后边写了一个加上 -DBYTECODE_DEBUG -DDEBUG
的,启用这个就可以启用所有的字节码调试代码。引用一张月初放在博客上的图:
如果还要看 classfile 的文件 parse,运行时常量池的解析,以及字符串池的常量字符串,可以打开 -DKLASS_DEBUG -DPOOL_DEBUG -DSTRING_DEBUG
宏,然后重新编译就好。
不过!如果这么打开,由于一开始初始化虚拟机,需要加载各种类,需要跑各种字节码,输出会是巨量的。没记错的话跑一个 hello world 貌似就要上十w的字节码执行量吧。因为我是解释型,自然执行的机器码比这还多;如果是编译型,那就快了。所以如果发现终端吃不消,请及时关闭。后期由于字节码输出量巨大,我从来都是关闭这些宏的,只看结果忽略执行过程。
写文章的目的
为了骗 star(,同时也是为了交友(。希望有同样爱好和兴趣的童鞋能够一起偷(yu)税(yue)地交流。那么就写到这吧。同时发到博客和知乎。
最终的感谢
感谢这个领域的先驱们,感谢各种热心的回复,感谢给我思路和灵感的人们。(热泪盈眶)
尤为感谢《spec》《深入java虚拟机》《hotspot实战》的作者们,以及R大的论坛和R大在知乎上传播的各种深入的虚拟机知识。实在是感激不尽!
另:
就是一个区区玩具,就不胡乱@了。供学习和交流~随便乱加了一个开源协议,虽然没什么用处就是了。
纪念伟大的 hello world!
截图留念!
2017.12.2
以上这句话由伟大的 System.out.println
提供技术支持~
在我的机器上 ./hotspot 会出现错误
RT。错误是:
通过查找 Makefile 中 hotspot.script 文件中此错误位置发现需要引用环境变量 ALT_JAVA_HOME
。因而只要 export ALT_JAVA_HOME=<YourOpenJDK>/build/macosx-x86_64-normal-server-slowdebug/images/j2sdk-bundle/jdk1.8.0.jdk/Contents/Home
即可。
VSCode cpp 检索 include 路径的问题
问题
碰到了一个 VSCode include 路径的问题。我的项目路径在 {workspaceRoot}/include 下,一开始想要以 -I./include
的方式来编译的。不过在 VSCode 中遇到了些麻烦。
解决
使用的是 Microsoft C/C++ Extension。这个插件非常棒,但是在 mac 上因为 bug 的原因之前经常烫烫烫。好在已经 fix 了。在项目路径下的 .vscode 的文件夹下一般而言有四大金刚:c_cpp_properties.json
,launch.json
,settings.json
以及 tasks.json
。其中 $1 用于配置 path……我都没怎么碰过这东西……还以为没啥用呢(。一般配置的都是 $2 和 $4。$3 是自动生成的用户配置,不用管就好。$2 launch.json
用于调试,而 tasks.json
用于 build && run。
查了半天,在 VSCode 的官方博客上找到了:应该在 $1 c_cpp_properties.json
中配置路径。所以变成了现在这样:
emmmm。虽然我不知道 browse 那是什么东西。不过还是加上吧。
然而鬼畜的来了:特么竟然还是报错!!按官博说的,应该已经好了!!
痛苦地找了一个晚上。。。。。。
现在已经是第二天中午了QAQ。
正当我打开 issue,想要像 vscode-cpptools 官方 repository 上报 issue 的时候,看到了官方的提示:上报 issue 之前,请关闭其他插件。看看是否是其他插件的影响。
上报 issue 之前,请关闭其他插件。看看是否是其他插件的影响。
上报 issue 之前,请关闭其他插件。看看是否是其他插件的影响。
上报 issue 之前,请关闭其他插件。看看是否是其他插件的影响。
卧槽,其实这个时候我都没怎么在意……因为另一个插件是我非常喜欢的 clang 的插件啊!虽然不是 clang 官方的(,叫 C/C++ Clang Command Adapter。是五星的插件啊!而且是个霓虹开发者开发的!OWO
然后我关了它。
竟然好了!!可以索引了!!
于是我看了下介绍……
这插件里边写的:
于是我跑到 settings.json
,加了一行这个:"clang.cxxflags": ["-std=c++11", "-I${workspaceRoot}/include"]
然后就好了……QAQ
然而这就比较诡异了……在点击头文件跳转的时候,关了微软官方的插件就不能跳转;关了 clang 插件,还是能够跳转。说明 clang 插件不对跳转有任何的作用;但是,只要没有配置 args,头文件就会出现红线报错,这时微软的插件检测到错误,也不会帮你跳转……卧槽。这是插件冲突的玄学吗……
emmmm。下次一定要注意,别因为印象好就单独开小灶……因为真正的错误往往藏在你放心的位置,然后耽误你大量的时间……QAQ。
Native 方法的探究有了小进展~~
卧槽。痛苦的一天。
因为需要读取 jar 文件,还用 C++ 语言QAQAQAQ,没有现成的库……我又不可能直接去解析……QAQ,于是就想到直接调用 Hotspot 写好的现成的 jar 文件库(我好聪明,逃。
然后就开始了日狗的一天。啥都没干,就一直在干动态库(。mac 的动态库 dylib 实在是气死了。但是这个设计也真是让人眼前一亮啊。学到了不少东西。
一开始只想要调用 Java 的 Native 方法
想写一个小型 jvm 的话,(虽然是玩具,不过我是不可能仅仅局限于只是跑一个 hello world 这种的。自然,想要打造一个运行时环境,那么就必须能够和原生java挂钩。这是目标,同样也是底线。不能让步,如果写完了之后连 java 的类库都不能调,可以狗带了。比如说日后我要是想要实现一个 C 语言的玩具编译器的话,那么不可能仅仅调用我自己底层写的 printf,一定要调用 stdio.h 中的 printf 才好啊。但是这样的话,就肯定涉及解释执行 C 宏了。因为 stdio.h 全都是宏,大家也不是不知道。当然……就我这辣鸡水平估计是要弃坑了……不过这是一年以后的话题了。我们先放着。和这一样,如果要写一个小型 jvm,那么就必须要支持 java 类库的调用才行。要不然就只能跑自己 XJB 写的不带任何库的 java 文件,一点意义也没有。因而,必须要调用 Native 方法。但是,这时就产生了一个问题啊。这个 Native 方法,每个 Native 是不是都是纯函数呢?这是个很重要的话题呢。如果不纯,我即使强行从动态库中把他们扒出来,调用也一定会出错。因为可能这个 Native 方法还涉及到他周边的上下文环境,而我只调用了这个方法,那么肯定会出错的。这个 blog 就是一个栗子。。因为要拆包 jar 文件,我模仿 hotspot 的调用方式调用了一波 jre lib,于是代码如下:
emmm。然后 mac 的动态库给我报错
|
|
这一段非常恶心。本质上原因是:由于你这个调用的动态库引用了别的动态库,如图:
我们能够发现这个动态库 libzip.dylib 引用了一堆动态库,有两个 libz.1.dylib 和 libSystem.B.dylib 是绝对路径,那么系统绝对不可能找不着。关键在于另三个:前边都有个 @rpath。
这个 @rpath 是执行的路径。貌似没法直接输出,只能通过强行指定才行。有的大神用 otool -l libzip.dylib
(注意 l 小写) 然后得到了如下:
大概能看出来后边的 LC_RPATH 的指定位置,是 @loader_path。也就是,应该是你的可执行文件调用这个库所在的位置。比如说,我在 /usr/tmp/haha
这个可执行文件中调用 <YourOpenJdk>/build/macosx-x86_64-normal-server-slowdebug/images/j2sdk-bundle/jdk1.8.0.jdk/Contents/Home/jre/lib/libzip.dylib
,那么八成这个 @loader_path
只是 /usr/tmp/haha
。然后由于 @rpath
是 @loader_path/.
,那么就一样。于是 libzip.dylib 引用的 libjvm.dylib 等共三个的目录变成了 /usr/tmp/libjvm.dylib
……应该是这样。为啥说是应该,因为我也没有验证过,存在错误的可能。不过八成是真的(逃。但是总之你是肯定索引不到真正的 libjvm.dylib 就是了,哈哈。
于是我们要引入 mac 的一个工具:install_name_tool
。这个工具可以在可执行文件/动态库中加入 @rpath。由于我们正在写程序,所以不可能通过程序把自己设置 rpath。。。所以,我们只能在程序内去修改 libzip.dylib 的 rpath 了。那么我们在刚才的 [1] 处添加几行代码:
这样就可以成功了 QAQ。我说的比较容易,其实花了我将近半天才弄完QAQ。
调用不纯的 Native 方法是一个巨坑。
到这一步能够解析动态库了,那么我们就开始搜刮里边的 sun 公司写好的函数了~于是加入下边的代码来 get 那个 ZIP_Open 函数~
然后就开始了:
|
|
Oh my god。
试了无数遍都这样,我是崩溃的!!
卧槽,后来仔细想了想……这一段错误提示是不是在 jvm 中的啊???
然后我在 hotspot/src/share/vm/utilities/debug.cpp
下……
然而!然而!!
我调用的 ZIP_Open 函数分明是 jdk 中的 Native 函数啊!!jdk 和 hotspot 是两个模块互不干扰,而且我就是写了一段 cpp 代码,根本没用到 jvm 啊!!
emmmm。细心的小伙伴肯定发现了。刚才的 libzip.dylib 引用了 libjvm.dylib。
那只能说明一点!!
(双眼一亮)
ZIPOpen 函数内部肯定检测了 JVM 的启动!!
是的就是这样。查阅源码之后我们能看到内部的各种检测自家的 JVM 启没启动的代码……
所以我们必须启动一个虚拟机才行。调用 JNI:
在整个代码的前部加上:
然后就可以了!输出就是正常的了。不过我们在编译的时候也要用 install_name_tools:
这说明,如果要自己写的话,Native 方法也要自己实现,不能调用人家的啊……(
解析 dylib 文件并且找到 java native 方法的源代码
参见博客
Native 方法在 Oracle Java 是不让看的。我们只能从 Openjdk 中看。我在编译好的 openjdk 源码的 build.log 中找到了一大堆 native 方法的编译 log,但是却没有发现它们到底最后被编译到哪了。而且挨个翻 Makefile 也是不太可能的(看不懂哈哈)。于是只能暴力一些了。找到 Openjdk 目录下的各种 libs,首先我的 jdk 在前一个博客也说过是 openjdk8。在 <yourjdk>/build/macosx-x86_64-normal-server-****/jdk/lib
下,有一大堆的 libs。我估计就是他们(逃)。但是怎么确认呢?请参加上方的 blog。执行那两个命令之中的任意一个。然后你就会得到一大堆的输出。然后随便找一个函数,直接在源码目录 yourjdk/jdk/src/share/native
目录下使用 grep -rn <method_name> .
就好了!然后发现确实能查到的!虽然不能一一对应就是了。不过这样也是大有进展,这样就可以直接调用人家写好的 Native 方法了~
外赠一个 shell 脚本来检查到底某个 native 方法被放到哪个 dylib 中去了:
|
|
随后我还是查看了 Makefile……
比如 libjava 的 output 指定的 Makefile 脚本在:
嗯嗯。还想要继续找的话,请各种使用 grep 命令会方便很多~
Mac 环境使用 clang 编译 OpenJDK8
经历
搞了 3 个晚上,终于搞定了。在 mac 上各种版本不适配,也是很有意思的~需要折腾,需要折腾~
参看博客:
主要参照
主要参照的补充: 编译 debug 版 openjdk
R大的答案
很好的博客
重点!对 mac 下 libiconv 的操作
调试你的 openjdk
历程
按照主要参照
的 github 上边的过程一步步来,注意要使用 clang 而不是 gcc。其实在 mac 就应该使用 clang,因为 gcc 不知道会引发什么潜在的隐患那…… 而且 clang 生成的调试信息貌似要比 gcc 好些吧。但是要注意:如果你想要调试的话,就要看看主要参照的补充
那个博客了。因为 sh configure
后边需要有参数。我将会列在下边。
各种版本:
|
|
- 以上即是各种 tools 的信息。注意,最好开着 VPN 进行 hg 的 pull 操作。因为这样下载速度会飙得很快~ 而且用 hg 貌似易于更新的话说。
- 其中,XQuartz 请下载最新的官网版本。不要用
主要参照
给出的链接,请自行使用brew cask install XQuartz
来进行 brew 安装。因为链接给出的 XQuartz 版本太老了,是 SnowLeopard 版本的 mac 才适配的。 xcode-select -install
在我这里已经没用了。不过貌似工具链完整,也不需要安装了。- 编译开始之前,请一定要把
/usr/bin/gcc
和/usr/bin/g++
改成clang
和clang++
!因为./configure
的时候会搜索这两个路径确认编译器gcc
以及g++
。当然,如果你原先没有做过交叉编译啥的修改过/usr/bin/gcc
和/usr/bin/g++
的话,那么请忽略我这些话。 - 我的 shell 脚本,参照了一堆人的脚本,列举如下。我自己略加修改:1234567891011121314151617181920212223242526272829303132333435363738394041# 设定语言选项,必须设置export LANG=C# Mac平台,C编译器不再是GCC,是clangexport CC=gcc# 跳过clang的一些严格的语法检查,不然会将N多的警告作为Errorexport COMPILER_WARNINGS_FATAL=false# 链接时使用的参数export LFLAGS='-Xlinker -lstdc++'# 是否使用clangexport USE_CLANG=true# 使用64位数据模型export LP64=1# 告诉编译平台是64位,不然会按32位来编译export ARCH_DATA_MODEL=64# 允许自动下载依赖export ALLOW_DOWNLOADS=true# 并行编译的线程数,编译时间长,为了不影响其他工作,我选择为2export HOTSPOT_BUILD_JOBS=6export ALT_PARALLEL_COMPILE_JOBS=6# 是否跳过与先前版本的比较export SKIP_COMPARE_IMAGES=true# 是否使用预编译头文件,加快编译速度export USE_PRECOMPILED_HEADER=true# 是否使用增量编译export INCREMENTAL_BUILD=true# 编译内容export BUILD_LANGTOOLS=trueexport BUILD_JAXP=falseexport BUILD_JAXWS=falseexport BUILD_CORBA=falseexport BUILD_HOTSPOT=trueexport BUILD_JDK=true# 编译版本export SKIP_DEBUG_BUILD=trueexport SKIP_FASTDEBUG_BUILD=falseexport DEBUG_NAME=debug# 避开javaws和浏览器Java插件之类的部分的buildexport BUILD_DEPLOY=falseexport BUILD_INSTALL=false# 加上产生调试信息时需要的 objcopy# export OBJCOPY=gobjcopy
把它命名为 jvm.sh
的话,我们只需要执行 source ./jvm.sh
即可把临时环境变量设置好。
主要参照
的所有问题都遇到了。不得不说这是十分良心的经验~- 不过,如果你要进行调试的话,需要把一开始的
sh configure
变成:sh configure --with-target-bits=64 --with-debug-level=slowdebug --enable-debug-symbols ZIP_DEBUGINFO_FILES=0
。这样就会产生足够多数量的调试信息,方便调试~ - 如果你遵循了第 6 条,那么最后会提示你缺少
objcopy
。那么请使用brew install binutils
来安装 GNU 的组件,并且把jvm.sh
的最后一行取消注释才行! - 然后愉快地 make all 即可!
坑们
在我这里只出现了一个大坑,然而弄到了半夜QAQ。就是当编译 make all
的时候,到了编译 jdk 的时候,编译了一半出现了诡异的
这种狗血的错误。然后一看名就知道了……分明应该是 libiconv 的问题……然而特么一查,电脑中有各种 libiconv.dylib
包,还有各种花式的 libiconv.2.dylib
以及 libiconv.2.4.0.dylib
…… 而且散布在不同目录下……我都不知道链接哪个才是正确的……于是不得不上网查,谷歌谷不出来还是百度百出来的(逃,(因为可能是谷歌不支持特殊字符的原因吧……),然后就查到了有一个回答支持,链接也贴出来了:重点!对 mac 下 libiconv 的操作。这个回答只要做第一步就好。即,把 /usr/lib/libiconv.dylib
变成 /usr/lib/libiconv1.dylib
即可,让链接库找不到就 ok。结果链接的是 /usr/bin
目录下的这个文件……其实 /usr/local/bin/
里边还有同名的一套 libiconv 呢……
不过改完之后就能碰到 主要参照
的第三个错误了,照改不误就可以。对于这份 github 的经验实在是感激不尽!帮了大忙。
世界的终结
打开你自己的 build/macosx-x86_64-normal-server-slowdebug/jdk/bin
目录,然后 ./java
,出现
就算大功告成!
但是,如果没有出现这,而是出现什么类似 某个文件800行有问题,提示你编译不完全
的错误提示的话,那你怕是要返工了。当时在 Docker 下 的 ubuntu 虚拟机编译的(其实我就把它当轻量的虚拟机来用HAHA,当时就出现了这个错误。而且错误信息中显示时间戳不对,肯定是编译的过程中出了些岔子吧。
如果你产生了调试信息,那么可以参见 调试你的 openjdk
的最后方,有调试的方法,很简单~
Enjoy it!
使用 mac 同步 Markdown 的方法......
用 Quiver 写完之后,导出为 Markdown 然后放在一个文件夹下,然后用 MWeb 进行导入,但是导入后的图片格式会有 Quiver 自动生成的xxx = 380x300
这种图片格式,需要用正则替换:\s=[0-9]+x[0-9]+
替换成全空字符即可,这样图片格式就只剩下原先的xxx
了,而后边由 Quiver 自动生成的图片尺寸格式就会被正则删除了。然后,用 MWeb 直接发布到 wordpress 上,由于 MWeb 会直接转成 wordpress 的图片地址,所以直接就可以发布上去;但是,如果仅仅正常发布的话,我们就只能看到最后的结果,但是却并不能得到 Markdown 的格式。所以最后我们需要勾选:发布为 Markdown 格式 这个选项!然后发布到 wordpress 上,之后直接复制粘贴所有的,然后本地 hexo new 之后复制粘贴即可……关键问题是我特别喜欢用 Quiver 写,但是 Quiver 还没有一键发布的功能……所以只能采用这样间接迂回的方案了……不过这样也特别快速,不过唯一的缺点就是最后要手动清理发布的 wordpress 版本和本地由 Quiver 导出的 Markdown 了……但是其他的使用体验还是相当棒的!欢迎来尝试~其实如果你用 MWeb 这种就可以的话,那么 MWeb 一键就可以上传~不过我更喜欢 Quiver 的界面~