闲来无事,看到方舟编译器完整开源,于是打算拿来试着编译一个东西来,接下来把踩过的一些坑记录一下。
参考文档
方舟编译器的官网是
OpenArkCompilerwww.openarkcompiler.cn但是这个网站上的文档其实是过时的,没有更新过的,应该去查阅的文档是开源代码里的文档部分,也就是下面链接里的doc部分
方舟编译器/OpenArkCompilergitee.com编译环境如下:
CPU:R9-3900X 其中虚拟机给了16核
内存:64G 其中虚拟机给了32G 后面会讲为什么给了这么多。
磁盘:虚拟机250G机械硬盘,实际编译过程中操作系统比较吃硬盘,建议用固态。
操作系统:ubuntu 20.10
jdk:openjdk-8
首先是文档部分,需要用到两个文档,分别是开发者指南和环境配置,也就是
doc/cn/DeveloperGuide.md · 方舟编译器/OpenArkCompiler - Gitee.comgitee.comdoc/cn/DevelopmentPreparation.md · 方舟编译器/OpenArkCompiler - Gitee.comgitee.com根据开发者指南头部,下载源码到本地。这里需要注意的是,不要使用开发者指南中的地址,要用gitee的地址,也就是本文的第二个链接,真正的“官网”
懒人复制版:
git clone https://gitee.com/openarkcompiler/OpenArkCompiler.git
下载完以后是环境搭建。官方的推荐是
硬件推荐配置
2 GHz 双核处理器或者更高等级CPU
2 GB 系统内存及以上
200GB 可用磁盘空间
CPU不必多说,人有多大胆,机有多大产,钱包多大,电脑就多6
内存的需求其实只能满足方舟编译器这个本体的编译,而实际的编译过程其实还需要编译安卓的AOSP,这个需要耗费大量的磁盘和内存,只是为了编译出一个8.6M的java基础库
这个文件可以从网上下载到:
Gitee 极速下载/java-coregitee.com但是为了照着文档来,而且这是两年前的文件,不知道靠不靠谱,这次手动去编译。
如果你不打算编译这个文件,则不需要200G磁盘,100G就绰绰有余。如果你打算像我一样自己编译,那么恭喜你,噩梦开始。首先2G内存远远不够,可以通过改脚本的编译线程数来降低内存占用,脚本默认是32线程编译,我一路增加到了32G才堪堪完成编译。
实际上在32G的情况下依旧出现了一次out of memory然后进程被kill掉的情况。这种情况下其实再make一次接着之前的编译就好。要是每次都超内存再给虚拟机加内存。
适当降低编译线程数量应该可以降低内存占用,不过我没试过。降低方法后面会提到。
文档中推荐安装的gcc5和g++5在本系统源里已经不能使用,因此忽略该部分,改为使用gcc10和g++10,嗯,跨步很大,不过问题不大。
按照文档cd 到tools目录,准备执行setup.sh。这里建议打开setup.sh脚本,有一些内容我们可以提前修改,加快编译速度,还可以定制一些东西。以下修改是我个人修改,请酌情参考,单纯编译的话,仅建议加速相关的修改。
ANDROID_VERSION=android-10.0.0_r35
ANDROID_SRCDIR=$MAPLE_ROOT/../android/$ANDROID_VERSION
这里我把ANDROID_VERSION替换为了android-10.0.0_r47。不换安卓11的原因是官方说暂不支持安卓11。
ninja跟gn
相关内容没有修改,体积不大,不会下载很长时间。
clang编译器
if [ ! -f $TOOLS/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-16.04/bin/clang ]; thencd $TOOLSwget https://releases.llvm.org/8.0.0/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xzecho unpacking clang+llvm ...tar xf clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xzecho Downloaded clang+llvm.
fi
这里我修改了下载的llvm clang为clang+llvm-11.0.0-x86_64-linux-gnu-ubuntu-20.04
https://github.com/llvm/llvm-project/releases/download/llvmorg-11.0.0/clang+llvm-11.0.0-x86_64-linux-gnu-ubuntu-20.04.tar.xzgithub.com同样的,根据文档里做对应修改
解压并放置到openarkcompiler/tools
目录
修改openarkcompiler/build/config.gni
文件,将CLANG_PATH
变量配置为clang编译器所在路径,例如:
CLANG_PATH = "${MAPLE_ROOT}/tools/clang+llvm-11.0.0-x86_64-linux-gnu-ubuntu-20.04"
修改openarkcompiler/build/core/maple_variables.mk
文件,将CLANG_PATH
配置为clang编译器所在路径,例如:
CLANG_PATH := ${MAPLE_ROOT}/tools/clang+llvm-11.0.0-x86_64-linux-gnu-ubuntu-20.04
其中${MAPLE_ROOT}为openarkcompiler源码根目录。
修改之后setup.sh会重新下载8.0的文件,可以通过touch一个tools/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-16.04/bin/clang文件来跳过,也可以直接修改setup.sh中的文件名。
加速:该文件体积较大,建议提前下载,然后放到tools目录里,原版下载地址在setup.sh中,如果你下载原版的话就不需要修改这些参数,只需要tar xf解压即可。
linaro gcc编译器
if [ ! -f $TOOLS/gcc-linaro-7.5.0/bin/aarch64-linux-gnu-gcc ]; thencd $TOOLSwget https://releases.linaro.org/components/toolchain/binaries/latest-7/aarch64-linux-gnu/gcc-linaro-7.5.0-2019.12-i686_aarch64-linux-gnu.tar.xzecho unpacking gcc ...tar xf gcc-linaro-7.5.0-2019.12-i686_aarch64-linux-gnu.tar.xzmv gcc-linaro-7.5.0-2019.12-i686_aarch64-linux-gnu gcc-linaro-7.5.0echo Downloaded gcc aarch64 compiler.
fi
这次我没改版本,直接用的7.5.0,日后有兴趣再用10.2编译一次。但是架构需要变更,我的电脑是64位,对应的下载文件应该变成gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar
https://releases.linaro.org/components/toolchain/binaries/latest-7/aarch64-linux-gnu/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xzreleases.linaro.org加速:该文件体积较大,建议提前下载,然后放到tools目录里,原版下载地址在setup.sh中,tar xf解压,然后按照官方文档重命名
解压并放置到openarkcompiler/tools
目录,并将文件夹更名为gcc-linaro-7.5.0
。
NDK
if [ ! -f $TOOLS/android-ndk-r21/ndk-build ]; thencd $TOOLSwget https://dl.google.com/android/repository/android-ndk-r21d-linux-x86_64.zipecho unpacking android ndk ...unzip android-ndk-r21d-linux-x86_64.zip > /dev/nullmv android-ndk-r21d android-ndk-r21echo Downloaded android ndk.
fi
加速:该文件体积较大,建议提前下载,然后放到tools目录里,原版下载地址在setup.sh中,unzip解压,然后按照官方文档重命名
解压并放置到openarkcompiler/tools目录,并将文件夹更名为android-ndk-r21
。
d8
相关内容没有修改,体积不大,不会下载很长时间。
下载编译AOSP
这步可选,编译安卓源码,重头戏。
# download and build andriod source
if [ ! -d $ANDROID_DIR/out/target/product/generic_arm64/obj ]; thenmkdir -p $ANDROID_SRCDIRcd $ANDROID_SRCDIRrepo init -u https://android.googlesource.com/platform/manifest -b $ANDROID_VERSIONrepo sync. ./build/envsetup.shlunch 2make -j32ln -s $ANDROID_SRCDIR $ANDROID_DIRecho Downloaded and built AOSP.
fi
首先提前安装好repo,根据谷歌官方的开源环境安装所需组件:
sudo apt-get install git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z-dev ccache libgl1-mesa-dev libxml2-utils xsltproc unzip
这里建议根据实际环境可选择性的安装,需要卸载gcc 10,g++10的组件可以不安。这里需要使用openjdk-8,如果用11会大概率报错。
附安卓官方编译环境搭建指南地址
https://source.android.com/source/initializingsource.android.com这一步强烈建议手动操作,按照脚本里的自己一步一步执行,容易排错。ANDROID_DIR变量和ANDROID_VERSION变量可以在脚本头部找到。
然后按照脚本,创建$ANDROID_SRCDIR的目录,然后进到这个目录。
repo在同步的时候会检查repo是否有更新,这里在repo init之前添加一个环境变量
export REPO_URL='https://mirrors.tuna.tsinghua.edu.cn/git/git-repo'
修改代码同步地址,这里选择了清华大学的镜像,对应的repo命令行改为,后面安卓版本号根据你自己的设计修改:
repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest -b android-10.0.0_r35
make -j32这一行就是编译线程的修改,根据你电脑的配置进行修改,我头铁32线程死扛,所以耗了32G内存,一般这个数量选择为虚拟机里CPU核心数的2倍即可。
ok,开始漫长的编译吧。
在编译过程中可能会遇到一个报const指针转换的错误,打开对应的代码去掉const标志即可。
找不到某.so缺lib库就安装对应的lib库。
遇到killed就
sudo dmesg
看看是不是内存溢出了,重新开始编译,或者加内存。
在make完之后,使用ln命令创建软链接,这里要注意目录层级不要搞错。
重点:在创建完软链接之后务必执行来生成libjava-core文件
make core-all
创建java-core.jar
# create java-core.jar
if [ ! -f $MAPLE_ROOT/libjava-core/libart.jar ]; thenmkdir -p $MAPLE_ROOT/libjava-coreJLIBDIR=$ANDROID_DIR/out/target/product/generic_arm64/obj/JAVA_LIBRARIEScp -f $JLIBDIR/core-libart_intermediates/javalib.jar $MAPLE_ROOT/libjava-core/libart.jarcp -f $JLIBDIR/core-oj_intermediates/javalib.jar $MAPLE_ROOT/libjava-core/oj.jarcd $MAPLE_ROOT/libjava-core$MAPLE_ROOT/build/d8 --min-api 39 --output . libart.jar oj.jarmv classes.dex libcore-all.dexecho Copied jar files.
fi
这一步是有坑的,代码应该是还没同步完整,少了一步,在两个cp后面还需要执行:
DevelopmentPreparation.md documentation:
116 * 将`openarkcompiler/android/out/target/product/generic_arm64/obj/JAVA_LIBRARIES/core-all_intermediates/javalib.jar`拷贝到`openarkcompiler/libjava-core`目录,
并命名为`java-core.jar`, 同时码云> 上也提供了编译好的libcore的jar文件,你可以下载直接使用,下载链接`https://http://gitee.com/mirrors/java-core/`;
即:
cp -f $JLIBDIR/core-all_intermediates/javalib.jar $MAPLE_ROOT/libjava-core/java-core.jar
参考issue:
Problem making OpenArkCompiler libcore and running sample programs. · Issue #I29K2F · 方舟编译器/OpenArkCompiler - Gitee.comgitee.comgcc、clang-r353983c
相关内容没有修改,正常跑脚本即可。
libicuuc.so
if [ ! -f $MAPLE_ROOT/third_party/icu/lib/aarch64-linux-gnu/libicuuc.so ]; thencd $TOOLSwget https://github.com/unicode-org/icu/archive/release-56-1.tar.gztar zxf release-56-1.tar.gzDIR=$TOOLS/icu-release-56-1/icu4cexport CROSS_BUILD_DIR=$DIR/linuxexport ANDROID_NDK=$MAPLE_ROOT/tools/android-ndk-r21export ANDROID_TOOLCHAIN=$DIR/toolchainexport PATH=$ANDROID_TOOLCHAIN/bin:$PATHmkdir -p $DIR/linux $DIR/aarch64(cd $DIR/linux; ../source/runConfigureICU Linux --prefix=$DIR/prebuilts; make -j16)(cd $DIR; $ANDROID_NDK/build/tools/make-standalone-toolchain.sh --platform=android-21 --install-dir=$ANDROID_TOOLCHAIN --toolchain=aarch64-linux-android-clang3.6)(cd $DIR/aarch64; ../source/configure --prefix=$DIR/prebuilt --host=aarch64-linux-android CFLAGS='-Os' CXXFLAGS='--std=c++11' --enable-shared=yes -with-cross-build=$CROSS_BUILD_DIR CC=aarch64-linux-android-clang CXX=aarch64-linux-android-clang++ AR=aarch64-linux-android-ar RINLIB=aarch64-linux-android-ranlib --with-data-packaging=archive; make -j16)AARCH64DIR=$MAPLE_ROOT/third_party/icu/lib/aarch64-linux-gnumkdir -p $AARCH64DIRcd $AARCH64DIRcp -f $DIR/aarch64/lib/libicuuc.so libicuuc.so.56cp -f $DIR/aarch64/stubdata/libicudata.so libicudata.so.56ln -s libicuuc.so.56 libicuuc.soln -s libicudata.so.56 libicudata.soecho Downloaded icu.
fi
加速:这一步里release-56-1.tar.gz文件体积较大,建议提前下载,注释掉wget一行
#wget https://github.com/unicode-org/icu/archive/release-56-1.tar.gz
然后手动下载这个文件,放到tools目录,注意文件名字得是release-56-1.tar.gz,不然后面的tar zxf会找不到文件。
libz.so.1.2.8
相关内容没有修改,体积不大,不会下载很长时间。
到此为止,环境搭建部分结束,环境配置文档DevelopmentPreparation.md后面的内容就不需要看了,都包含在setup.sh了。setup.sh这个文件本身可以重复执行,前面执行好的部分也不会重复执行,如果你发现重复执行了,说明你手动执行的过程还有纰漏,需要手动修正。
编译方舟编译器
参考开发者指南DeveloperGuide.md,开始编译。
首先编译生成OpenArkCompiler及maple runtime部分的Release版本:
在OpenArkCompiler目录下执行
source build/build.sh
生成libjava-core.mplt文件
cd libjava-core
jbc2mpl -injar java-core.jar -out libjava-core
编译Sample
cd samples/helloworld/
make
这里我吧helloworld.java中末尾的感叹号改成了问号,来确认确实是执行了自己编译的代码。编译完成后执行:
java HelloWorld
执行结果:
完事。
结语
编译的最重要的工作都在编译AOSP上和找官方文档上,官方文档得互相凑,还得参考社区issue才能凑齐完整的编译方法。然后真正的方舟编译器编译只有几分钟,真的是何苦来哉。
编译出来的jar文件是直接在x86平台上跑的,应该是跨平台支持的,不知道前面搭建armv8的交叉编译环境目的是什么,只是为了编译AOSP么。方舟编译器真的只是一个编译器,想要编译完整的安卓app需要一套ide,暂时没空搞了,就先这样吧,给大家一些踩过的坑的经验,文中有错误的地方希望大家可以及时指出。
关于方舟编译器的深入学习可以移步中科院软件所 智能软件研究中心大佬 @小乖他爹 的文章,比我的水文干货质量高多了。
参考资料:上面都有。