背景

最近公司项目需要适配arm64架构机器,特意整了两台arm64架构的CentOS7/8的机器来构建。
x86、x64架构下的应用在arm64下面需要解决各种环境和依赖问题。

环境

Linux internal 4.18.0-147.8.1.el7.aarch64 #1 SMP Wed Apr 15 18:13:44 UTC 2020 aarch64 aarch64 aarch64 GNU/Linux

CentOS Linux release 7.8.2003 (AltArch)

编译

在 Linux - CentOS / RHEL 环境下编译,可以选择安装官方完整的依赖或者只安装自己需要的部分。有什么区别?

环境准备:

  • gcc升级到至少7的版本,以获得C++17的支持

获取 RocksDB

1
get clone https://github.com/facebook/rocksdb.git

安装插件

这些插件可以选择性安装,你需要哪个,在使用时自行安装,也可以一次性装好。

Install gflags:

1
2
3
4
git clone https://github.com/gflags/gflags.git
cd gflags
git checkout v2.0
./configure && make && sudo make install

Install snappy:

1
sudo yum install snappy snappy-devel

Install zlib:

1
sudo yum install zlib zlib-devel

Install bzip2:

1
sudo yum install bzip2 bzip2-devel

Install lz4:

1
sudo yum install lz4-devel

Install ASAN (optional for debugging):

1
sudo yum install libasan

Install zstandard:

With EPEL:

1
sudo yum install libzstd-devel

编译静态库

编译使用make,如果直接使用makemake install编译出来的会是debug模式的程序,会打印一堆日志。
真正需要是一个RocksDB的静态库librocksdb.a
make static_lib将编译librocksdb.a,RocksDB静态库。当前是 arm 架构下直接使用 make 是编译出不来的,需要加上跨平台参数PORTABLE=1

1
2
cd rocksdb
PORTABLE=1 make static_lib

正常输出日志,截取部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
GEN      util/build_version.cc
GEN util/build_version.cc
CC cache/clock_cache.o
CC cache/lru_cache.o
CC cache/sharded_cache.o
CC db/builder.o
CC db/c.o
CC db/column_family.o
CC db/compacted_db_impl.o
CC db/compaction.o
CC db/compaction_iterator.o
CC db/compaction_job.o
CC db/compaction_picker.o
CC db/compaction_picker_universal.o
CC db/convenience.o
CC db/db_filesnapshot.o
CC db/db_impl.o
CC db/db_impl_compaction_flush.o

查看一下这个库的结构,这些对应上面的的插件,如果少装一个,这里查看就会少一个。

1
2
3
4
5
6
7
8
9
10
11
12
linux-vdso.so.1 =>  (0x0000ffff973d0000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x0000ffff96d40000)
librt.so.1 => /lib64/librt.so.1 (0x0000ffff96d10000)
libsnappy.so.1 => /lib64/libsnappy.so.1 (0x0000ffff96ce0000)
libz.so.1 => /lib64/libz.so.1 (0x0000ffff96ca0000)
libbz2.so.1 => /lib64/libbz2.so.1 (0x0000ffff96c80000)
liblz4.so.1 => /lib64/liblz4.so.1 (0x0000ffff96c50000)
libstdc++.so.6 => /lib64/libstdc++.so.6 (0x0000ffff96b20000)
libm.so.6 => /lib64/libm.so.6 (0x0000ffff96a60000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x0000ffff96a20000)
libc.so.6 => /lib64/libc.so.6 (0x0000ffff96890000)
/lib/ld-linux-aarch64.so.1 (0x0000ffff973e0000)

编译 rocksdbjni

命令

1
PORTABLE=1 DEBUG_LEVEL=0 make -j8 rocksdbjava

获得: librocksdbjni-linux64.so

1
2
3
4
5
6
drwxr-xr-x. 3 root root 4.0K 3月  10 10:44 apidocs
drwxr-xr-x. 3 root root 17 3月 10 10:44 classes
-rwxr-xr-x. 1 root root 140M 3月 10 10:45 librocksdbjni-linux64.so
-rw-r--r--. 1 root root 140M 3月 10 10:50 librocksdbjni.tar.gz
-rw-r--r--. 1 root root 49M 3月 10 10:46 rocksdbjni-5.15.10-linux64.jar
drwxr-xr-x. 3 root root 17 3月 10 10:44 test-classes

报错处理

编译 rocksdbjni,执行编译PORTABLE=1 DEBUG_LEVEL=0 make -j8 rocksdbjava 命令报错

jni.h: No such file or directory

修改/etc/profile 或者 ~/.bashrc,添加 :

1
2
3
export CPATH=$CPATH:$JAVA_HOME/include:$JAVA_HOME/include/linux
export C_INCLUDE_PATH=$C_INCLUDE_PATH:$JAVA_HOME/include:$JAVA_HOME/include/linux
export CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH:$JAVA_HOME/include:$JAVA_HOME/include/linux

精简库文件

编译出来的 librocksdb.a 文件,发现有140兆,业务程序都没这么大,这个整这么大。
由于刚编译出来的 librocksdb.a 库文件,包含 debug信息,需要手动给他瘦身一下,提取关键部分:
先看一段 strip 命令的介绍:

strip 命令从 XCOFF 对象文件里有选择地除去行号信息、重定位信息、调试段、typchk 段、凝视段、文件头以及全部或部分符号表。 一旦您使用该命令,则非常难调试文件的符号;因此,通常应该仅仅在已经调试和測试过的生成模块上使用 strip 命令。使用 strip 命令降低对象文件所需的存储量开销。

查看文件概要

1
file librocksdbjni-linux64.so

librocksdbjni-linux64.so: ELF 64-bit LSB shared object, ARM aarch64, version 1 (GNU/Linux), dynamically linked, BuildID[sha1]=43a90c7ba9000ef6a27ba47ac786b7d00d703d83, not stripped

文件瘦身

1
strip librocksdbjni-linux64.so

librocksdbjni-linux64.so: ELF 64-bit LSB shared object, ARM aarch64, version 1 (GNU/Linux), dynamically linked, BuildID[sha1]=43a90c7ba9000ef6a27ba47ac786b7d00d703d83, stripped

瘦射后,140M的文件就只剩下6M!!!!

总结

在 arm 架构通常是在移动端下面使用的比较多,由于苹果M1架构也是基于arm64上构建,所以带动了一波arm架构的热潮,社区开发者纷纷要求提供arm版本的程序,有M1本的程序员就是任性。当然间接带动了linux arm架构下的应用。

RocksDB静态库
PORTABLE=1 make static_lib

RocksDB的共享库
PORTABLE=1 make shared_lib

RocksDB JNI
PORTABLE=1 DEBUG_LEVEL=0 make -j8 rocksdbjava

官方文档

https://github.com/facebook/rocksdb/blob/main/INSTALL.md
https://github.com/facebook/rocksdb/wiki