解释型语言移植-Java

1.实验目

对于以Java语言为代表的解释型语言来说,应用迁移相对简单一 些,因为Java的虚拟机JVM屏蔽了不同处理器之间指令集架构的区 别,所以,纯Java语言编写的程序不需要重新编译,而对于调用了编 译型语言so库的应用来说,需要重新编译。通过具体的实验案例,掌握纯java语言编写的程序如何迁移,以及调用so库的解决方案。

2.实验环境

基于X86架构的麒麟操作系统V10。

基于Arm架构(鲲鹏920)的麒麟操作系统V10。

3.实验步骤

查询本地的java环境

分别在X86架构的麒麟操作系统V10,Arm架构(鲲鹏920)的麒麟操作系统V10环境下执行以下命令

步骤1 查看本机已经安装的java版本。
#yum search java

麒麟默认提供了java1.8,java-11两套java开发环境。可以依据实际情况自行确定。

我们这里选用java1.8作为开发环境

yum install java-1.8.0-openjdk java-1.8.0-openjdk-devel java-1.8.0-openjdk-headless -y
本地安装java1.8的环境

yum remove java-11-openjdk-devel java-11-openjdk java-11-openjdk-headless -y
删除java-11
步骤3 验证java,javac的版本
[root@jd4 tmp]# java -version
openjdk version "1.8.0_292"
OpenJDK Runtime Environment Bisheng (build 1.8.0_292-b10)
OpenJDK 64-Bit Server VM Bisheng (build 25.292-b10, mixed mode)
[root@jd4 tmp]# javac -version
javac 1.8.0_292

在两台主机上均完成以上操作,则可以进入下一步骤。

纯java代码迁移

x86架构下完成以下操作,配套代码可以在java_demo目录中查找

步骤1 编写java测试代码

mkdir -pv /usr/local/src/code/java_demo
cd /usr/local/src/code/java_demo
vim Demo.java

import java.util.Scanner;

public class Demo{
    public static void main(String[] args){
      Scanner sc = new Scanner(System.in);
      String input = sc.nextLine();
      System.out.println(input);
      sc.close();
    }
}

步骤2 编译并执行

[root@node1 java_demo]#javac Demo.java
[root@node1 java_demo]# ls
Demo.class  Demo.java
java Demo

你输入什么,就会显示什么,如下图

在x86架构下编译及运行没问题了,把这个编译好的.class文件 复制到鲲鹏架构的服务器上。

步骤3 移植java代码

把x86架构下环境下编写的java代码拷贝到Arm架构环境。在Arm 环境完成以下操作:

先确认环境

[root@jd4 tmp]# java -version
openjdk version "1.8.0_292"
OpenJDK Runtime Environment Bisheng (build 1.8.0_292-b10)
OpenJDK 64-Bit Server VM Bisheng (build 25.292-b10, mixed mode)
[root@jd4 tmp]# javac -version
javac 1.8.0_292

拷贝java代码

在x86主机执行
[root@node1 java_demo]# scp Demo.class 179.119.224.2:/tmp
The authenticity of host '179.119.224.2 (179.119.224.2)' can't be established.
ECDSA key fingerprint is SHA256:QBfezyONvuiNbSmao2ml3MjaZX/BMllINTtPJ4TetJk.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '179.119.224.2' (ECDSA) to the list of known hosts.

Authorized users only. All activities may be monitored and reported.
root@179.119.224.2's password:
Demo.class

这里的ip地址请根据实际情况修改

步骤4 执行java代码,并验证

在arm主机执行

[root@jd4 ~]# cd /tmp/
[root@jd4 tmp]# java Demo
hello java
hello java

Java 依赖So库迁移

对于大型项目来说,很多时候不仅仅使用一种语言来开发应用, 有时候会使用多种语言进行混合编程,例如著名的开源项目Netty, 主体开发语言是Java,但是在部分项目里还使用了C语言。出现这种 情况的一个原因是Netty在Linux下的异步/非阻塞网络传输中,使用 了Epoll——一个基于I/O事件通知的高性能多路复用机制。Netty是 通过JNI方式提供Native Socket Transport的,在Netty的 transport-native-epoll项目中,有相关调用的C代码。除此之外,在Netty的依赖项目netty-tcnative-parent中,也有 JNI方式提供的C语言调用。

Netty是开源的项目,在获得所有的源代码后,可以通过对代码 进行重新编译的方式来执行迁移。因为代码里有Java和C语言,并且 Netty项目是通过Pom进行项目组织管理的,在迁移时不但要安装C的 编译环境,还要安装openjdk和Maven。

步骤1 通过yum 安装依赖环境
#yum install gcc gcc-c++ make cmake3 libtool autoconf automake ant wget git openssl openssl-devel apr-devel ninja-build -y
步骤2 安装Maven

下载Maven

#cd /usr/local/src
#wget http://archive.apache.org/dist/maven/maven-3/3.5.4/binaries/apache-maven-3.5.4-bin.tar.gz

解压缩

#cd /usr/local/src
#tar fvxz apache-maven-3.5.4-bin.tar.gz
#mv apache-maven-3.5.4 /opt/maven

修改环境变量

vim /etc/profile
MAVEN_HOME=/opt/maven
PATH=$MAVEN_HOME/bin:$PATH
export MAVEN_HOME PATH

#执行下面的命令更新环境变量

source /etc/profile

查看版本

mvn -version

修改maven的配置文件,更改镜像仓库网址为国内的镜像网址。

vim /opt/maven/conf/settings.xml
     <mirror>
      <id> huawei </id>
      <name>huawei maven</name>
      <url>https://mirrors.huaweicloud.com/repository/maven/</url>
      <mirrorOf>central</mirrorOf>
    </mirror>

步骤3 修改gcc、g++ 默认编译选项

鲲鹏架构中char类型问题

设置gcc和g++的编译选项来处理,也就是把这两个编译器的编译 加上-fsigned-char的选项。

给gcc加一个壳

[root@jd4 src]# which gcc
/usr/bin/gcc
[root@jd4 src]# mv /usr/bin/gcc /usr/bin/gcc_bak  cp
[root@jd4 src]# vim /usr/bin/gcc
#!/usr/bin/env bash
/usr/bin/gcc_bak -fsigned-char "$@"
[root@jd4 src]# chmod +x /usr/bin/gcc
[root@jd4 src]# gcc --version
gcc_bak (GCC) 7.3.0
Copyright © 2017 Free Software Foundation, Inc.

看到下图,就代表gcc 加壳替换成功了。

步骤4 下载netty相关的安装包

cd  /usr/local/src/
wget https://mirrors.tuna.tsinghua.edu.cn/apache/apr/apr-1.6.5.tar.gz
wget https://mirrors.tuna.tsinghua.edu.cn/OpenBSD/LibreSSL/libressl-3.1.1.tar.gz
wget https://www.openssl.org/source/openssl-1.1.1g.tar.gz
wget https://GitHub.com/netty/netty-tcnative/archive/netty-tcnative-parent-2.0.34.Final.tar.gz

步骤5 移植

通过编译安装,在arm 环境下完成以下操作

 tar fvxz netty-tcnative-parent-2.0.34.Final.tar.gz

  cd netty-tcnative-netty-tcnative-parent-2.0.34.Final/

  vim pom.xml

  因为我们之前已经手动下载了apr的安装包,不需要重复下载,所以注释474

  <!-- <get src="http://archive.apache.org/dist/apr/${aprTarGzFile}"     dest="${project.build.directory}/${aprTarGzFile}" verbose="on" /> -->

  

  

cd libressl-static/

  vim pom.xml

  同样的理由,libssl已经下载,不需要重复下载,所以注释263

  <!-- <get src="https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/${libre    sslArchive}" dest="${project.build.directory}/${libresslArchive}" verbose="on" /> -->

  cd ../openssl-static/

  vim pom.xml

  同样的理由,openssl已经下载,不需要重复下载,所以注释334行和338

  <!-- <get src="https://www.openssl.org/source/openssl-${opensslVersion}.tar.gz" dest="${project.build.directory}/openssl-${opensslVersion}.tar.gz" verbose="on" /> -->

                         

  <!-- <get src="https://www.openssl.org/source/old/${opensslMinorVersion}/openssl-${opensslVersion}.tar.gz" dest="${project.build.directory}/openssl-${opensslVersion}.tar.gz" verbose="on" /> -->

  

  cd ..

  vim pom.xml

  注释掉对boringssl-static的编译(在第603),因为 boringssl-static需要从谷歌服务器获取资源,由于无法获取成功,

这里就取消对它的编译,但不影响后续的使用

  <!-- <module>boringssl-static</module> -->

纯文本

创建openssl-static,libressl-static项目的target目录

[root@jd4 netty-tcnative-netty-tcnative-parent-2.0.34.Final]# pwd

/usr/local/src/netty-tcnative-netty-tcnative-parent-2.0.34.Final

在此目录下执行一下命令

[root@jd4 netty-tcnative-netty-tcnative-parent-2.0.34.Final]# mkdir -pv openssl-static/target

mkdir: 已创建目录 'openssl-static/target'

[root@jd4 netty-tcnative-netty-tcnative-parent-2.0.34.Final]# mkdir -pv libressl-static/target

mkdir: 已创建目录 'libressl-static/target'

纯文本

拷贝之前下载的软件包到target目录

# cp /usr/local/src/apr-1.6.5.tar.gz /usr/local/src/netty-tcnative-netty-tcnative-parent-2.0.34.Final/openssl-static/target/

# cp /usr/local/src/openssl-1.1.1g.tar.gz /usr/local/src/netty-tcnative-netty-tcnative-parent-2.0.34.Final/openssl-static/target/

# cp /usr/local/src/apr-1.6.5.tar.gz /usr/local/src/netty-tcnative-netty-tcnative-parent-2.0.34.Final/libressl-static/target/

# cp /usr/local/src/libressl-3.1.1.tar.gz /usr/local/src/netty-tcnative-netty-tcnative-parent-2.0.34.Final/libressl-static/target/

纯文本

进入主目录执行编译

#cd /usr/local/src/netty-tcnative-netty-tcnative-parent-2.0.34.Final

#mvn install

看到如图中所示的输出,代表编译成功

在你执行mvn install的过程中,背后其实调用了make

[root@jd4 netty-tcnative-netty-tcnative-parent-2.0.34.Final]# find ./ -name Makefile

./libressl-static/target/apr-1.6.5/test/internal/Makefile

./libressl-static/target/apr-1.6.5/test/Makefile

./libressl-static/target/apr-1.6.5/Makefile

./libressl-static/target/native-build/Makefile

./openssl-dynamic/target/native-build/Makefile

./openssl-static/target/apr-1.6.5/test/internal/Makefile

./openssl-static/target/apr-1.6.5/test/Makefile

./openssl-static/target/apr-1.6.5/Makefile

./openssl-static/target/openssl-1.1.1g/demos/bio/Makefile

./openssl-static/target/openssl-1.1.1g/demos/evp/Makefile

./openssl-static/target/openssl-1.1.1g/Makefile

./openssl-static/target/native-build/Makefile

纯文本

编译netty-all-4.1.52

先查询jni.h与jni_md.h的位置

[root@jd4 netty-netty-4.1.52.Final]# find / -name jni.h

/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.292.b10-8.ky10.aarch64/include/jni.h

/opt/hyper_tuner/tool/bisheng-jdk-11.0.12/include/jni.h

[root@jd4 netty-netty-4.1.52.Final]# find / -name jni_md.h

/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.292.b10-8.ky10.aarch64/include/linux/jni_md.h

/opt/hyper_tuner/tool/bisheng-jdk-11.0.12/include/linux/jni_md.h

纯文本

#cd /usr/local/src

#wget https://GitHub.com/netty/netty/archive/netty-4.1.52.Final.tar.gz

#tar fvxz netty-4.1.52.Final.tar.gz

#cd netty-netty-4.1.52.Final/

#vim /usr/local/src/netty-netty-4.1.52.Final/transport-native-unix-common/pom.xml

198

<env key="CFLAGS" value="-O3 -Werror -Wno-attributes -fPIC -fno-omit-frame-pointer -Wunused-variable -fvisibility=hidden -I/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.292.b10-8.ky10.aarch64/include/ -I/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.292.b10-8.ky10.aarch64/include/linux/" />

263

 <env key="CFLAGS" value="-O3 -Werror -Wno-attributes -fPIC -fno-omit-frame-pointer -Wunused-variable -fvisibility=hidden -I/usr/lib/jvm/java-1.8.0-openjdk-1.8.    0.292.b10-8.ky10.aarch64/include/ -I/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.292.b10-8.ky10.aarch64/include/linux/" />

#mvn install -DskipTests

看到类似输出代表编译成功

可以到相关的target目录查看编译产生的jar包

在你执行mvn install的过程中,背后其实调用了make

[root@jd4 netty-netty-4.1.52.Final]# find ./ -name Makefile

./transport-native-epoll/target/native-build/Makefile

./transport-native-unix-common/Makefile

总结:

在一个Java程序执行时,首先通过javac把java文件编译为虚拟机可以识别的class文件。 然后由JVM解释器解释class文件中的字节码,通过JVM把解释结果转变为机器码执行。 这是我们通常所说的解释执行。所以,纯Java语言编写的程序不需要重新编译。有依赖的So库需要迁移,可以先安装好编译需要的GCC与Maven,然后在新平台下重新编译So库。

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值