darkpoon 发表于 2015-10-10 13:30:10

Linux应用程序开发(三)---移植kvm到arm linux

Linux应用程序开发(三)---移植kvm到arm linux
  移植环境(红色粗字体字为修改后内容,蓝色粗体字为特别注意内容)
  1,主机环境:VMare下CentOS 5.5 ,1G内存。
  2,集成开发环境:Elipse IDE
  3,编译编译环境:arm-linux-gcc v4.4.3,arm-none-linux-gn?i-gcc v4.5.1。
  4,开发板:mini2440,2M nor flash,128M nand flash。
  5,u-boot版本:u-boot-2009.08
  6,linux 版本:linux-2.6.32.2
  7,参考文章:
Java虚拟机KVM在嵌入式Linux上的移植
  尽管前面基于php的嵌入式web服务器已经能够运行java脚本文件,而且也能够执行xajax运行库。但是还是有些系统用不到php那样复杂的功能,而且php作为嵌入式的移植也比较复杂。java技术在嵌入式领域的应用已经流行起来。下面就有关java在嵌入式方面的移植和应用问题做些探讨。
  移植kvm到arm-linux
  【1】安装jdk
  (1)检查系统中是否已经安装jkd,因为j2me_cldc/api目录下的源代码是用javac编译的,所以这里只需查询下javac的安装位置即可。
  # find / -name javac
/var/lib/alternatives/javac
/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0/bin/javac
/usr/lib/jvm/java-1.4.2-gcj-1.4.2.0/bin/javac
/usr/bin/javac
/etc/alternatives/javac
#
  查看下javac版本
  # java -version
java version "1.6.0_20"
OpenJDK Runtime Environment (IcedTea6 1.9.8) (rhel-1.22.1.9.8.el5_6-i386)
OpenJDK Client VM (build 19.0-b09, mixed mode)
#

如果系统中没有找到javac,可安装下面方式安装。
  方式1,j2me 1.4.2 版,这里不安装。
  j2sdk-1_4_2_19-linux-i586-rpm.bin.gz :http://file.ajava.org/tool/java/j2sdk-1_4_2_19-linux-i586-rpm.bin.gz

  方式2,jdk1.6.0_26版,可以是最新版,这里不安装。
  下载完解压
  
  (2)添加环境变量
  打开/etc/profile文件,定位到27行,确认如下修改:
  # Path manipulation
if [ "$EUID" = "0" ]; then
      pathmunge /sbin
      pathmunge /usr/sbin
      pathmunge /usr/local
      pathmunge /usr/local/bin
      pathmunge /usr/local/sbin
      pathmunge /usr/local/lib
      pathmunge /usr/local/arm/4.4.3/bin
      pathmunge /usr/local/CodeSourcery/Sourcery_G++_Lite/bin
      pathmunge /usr/local/JLink_Linux_V422
fi
  添加上面一行的目的是为了让编译器找到libiconv所在的路径。
  ... ...
#set to java jre
JAVA_HOME=/usr/local/jdk1.6.0_26
CLASSPATH=$JAVA_HOME/lib:/root/java
PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME PATH CLASSPATH

  根据你自己的实际解压后安装位置作适当的修改,我的解压后安装位置为/usr/local文件夹下,其中PATH是命令的搜索路径,比如说用javac去编译一个.java文件,直接在命令行中用javac就可以,而不要代绝对路径了。CALSSPATH中的$JAVA_HOME/lib 为你的java代码运行的类库路径,/root/JAVA 为编译你的java代码生成的class所放置的路径。
  文件修改并保持完以后,运行source etc/profile命令即可使修改操作立即生效。
  (3)运行测试
  在/root/java下新建一个文件名helloworld.java文件,并添加如下内容:
  class HelloWorldApp
{
p lic static void main(String args[])
{
System.out.println("welcome to java!");
}
}
  然后保存,并按下面操作编译后运行
  # javac helloworld.java
# java HelloWorldApp
welcome to java!
#
  【2】下载并解压kvm
  j2me_cldc-1_1-fcs-src-winunix:http://www.oracle.com/technetwork/java/javame/javamobile/download/overview/index.html
  在上面打开的页面左侧点击 REFERENCE IMPLEMENTATIONS->Connected Limited Device Configuration (CLDC) 1.1->download,如果您没有注册用户名,那么需要您注册一个并登录后才能下载。
  下载后解压
  #unzip /root/linux-test/j2me_cldc-1_1-fcs-src-winunix.zip -d ./
  【3】j2me_cldc文档结构
  j2me_cldc解压缩的目录有以下几个:
api-目录下包含了java类库的代码
bin—包含了编译过的class文件以及一些常用的与平台相关的可执行文件
build---与平台相关的makefile文件存放目录
docs ---与开发或移植相关说明文档
jam---应用管理代码
kvm---kvm代码
samples--实例代码
tools---随kvm代码的工具
  说明:跟平台移植无关的代码都在kvm/vmcommon目录,平台有关的代码在kvm/vmextra目录下。
  【4】java在kvm中的执行流程
  在j2me中,程序流程从java源码(.java)开始的。Java源码被编译平台编译后生成与平台无关的Java字节码文件。该字节码文件经过一个外表校验器来验证字节码的合法性。当验证通过后,字节码会送到kvm中执行。其流程如下图所示。

  
  【5】修改j2me_cldc/kvm/VmUnix/build/Makefile文件
  (1)先改变其只读属性
  # cd j2me_cldc/kvm
  # chmod u+w VmUnix/build/Makefile
  (2)修改VmUnix/build下的Makefile,定位到文件开始处,修改如下:
  export PLATFORM=linux
TOP=../../..
incl? $(TOP)/build/Makefile.inc
  ifeq ($(PLATFORM), linux)
export GCC=tr
endif
  (3)定位到需要定位到95行,指定交叉编译器,修改如下:
  ifeq ($(GCC), tr)
   CC = arm-linux-gcc
   CFLAGS =-Wall $(CPPFLAGS) $(ROMFLAGS) $(OTHER_FLAGS)
   DEBUG_FLAG = -g
   OPTIMIZE_FLAG = -O2
   FP_OPTIMIZE_FLAG =
else
   CC = cc
   CFLAGS = -Xa $(CPPFLAGS) $(ROMFLAGS) $(OTHER_FLAGS)
   DEBUG_FLAG = -g -xsb
   OPTIMIZE_FLAG = -xO2
   FP_OPTIMIZE_FLAG =
endif
修改完后保存退出。
  【6】修改j2me_cldc/kvm/VmUnix/src/runtime_md.c文件
  (1)改变其只读属性
  # cd ../src
# chmod u+w runtime_md.c
  (2)把这个文件中void InitializeFloatingPoint()函数中的下面两句注释掉
# vim runtime_md.c
  定位到171行,修改如下:
  void InitializeFloatingPoint() {
#if defined(LINUX) && PROCESSOR_ARCHITECTURE_X86
    /* Set the precision FPU to do le precision */
   // fpu_control_t cw = (_FPU_DEFAULT & ~_FPU_EXTENDED) | _FPU_DO LE;
   // _FPU_SETCW(cw);
#endif
}
保存退出。
  【7】修改j2me_cldc/tools/preverifier/build/linux目录下的Makefile
  # cd linux-test/j2me_cldc/tools/preverifier/build/linux
# chmod u+w Makefile
# vim Makefile
  定位到39行附近,修改如下:
  CC = gcc
LD = gcc
  DEBUG_FLAG =
LDFLAGS = -l iconv
  ifeq ($(DEBUG), tr)
   DEBUG_FLAG = -g
endif
  加入上面一行的目的是引入iconv库,不然在编译是会出现如下错误:
  convert_md.o: In function `open_iconv':
convert_md.c:(.text+0x16): undefined reference to `libiconv_open'
convert_md.o: In function `native2utf8':
convert_md.c:(.text+0x239): undefined reference to `libiconv'
convert_md.c:(.text+0x276): undefined reference to `libiconv_close'
convert_md.o: In function `utf2native':
convert_md.c:(.text+0x365): undefined reference to `libiconv'
convert_md.c:(.text+0x3a2): undefined reference to `libiconv_close'
collect2: ld 返回 1
make: *** 错误 1
  【6】修改j2me_cldc/api目录下的Makefile,使其向下兼容1.4版本
  需要先改变其只读属性
  # chmod u+w Makefile
  然后打开j2me_cldc/api/Makefile,定位到16行,修改如下:
DEBUGFLAG=":none"
endif
  JAVAC   = javac -source 1.4
  ifneq ($(findstring win, $(PLATFORM)),)

这样修改的目的是使其向下兼容1.4版本,不然在编译时出现如下错误:
  src/java/lang/Object.java:132: cannot access java.lang.StringBuilder
class file for java.lang.StringBuilder not found
      return getClass().getName() + "@" + Integer.toHexString(hashCode());
  网上说问题是出在几个String相加原因是JDK1.5太新,wtk2.2只能用JDK1.4.2的。JDK1.5使用StringBuilder类来代替JDK1.4中的StringB?r类。
  【7】进入j2me_cldc/build/linux目录编译
  # cd build/linux
# make
... ...
  src/java/lang/Object.java:132: cannot access java.lang.StringBuilder
class file for java.lang.StringBuilder not found
      return getClass().getName() + "@" + Integer.toHexString(hashCode());
                                          ^
1 error
94 warnings
make: *** Error 1
make: Leaving directory `/root/linux-test/j2me_cldc/api'
make: *** 错误 1

  
  【8】在/usr/lib目录下建立libiconv库文件
  因为gcc默认的库文件路径为/usr/lib,需要将/usr/local/lib目录下的libiconv.so,libiconv.so.2,libiconv.so.2.5.0三个文件复制到此目录下或者在此目录先建立到/usr/local/lib/libiconv.so的软连接。不然会出现下面错误:
  ... ...
../tools/preverifier/build/linux/preverify -d classes tmpclasses
../tools/preverifier/build/linux/preverify: error while loading shared libraries: libiconv.so.2: cannot open shared object file: No s h file or directory
make: *** Error 1
make: Leaving directory `/root/linux-test/j2me_cldc/api'
make: *** 错误 1

  【9】修改j2me_cldc/tools/jcc/src/util目录下ClassReader.java
  需要先改变其只读属性
  # chmod u+w Makefile
  然后打开其目录下的ClassReader.java,定位到85行修改如下:
  p lic int
    readZip (String fileName, Vector done) throws IOException
    {
    int i = 0;
  ZipFile zf = new ZipFile(fileName);
      Enumeration myenum = zf.entries();
      while (myenum.hasMoreElements()) {
            ZipEntry ent = (ZipEntry)myenum.nextElement();
      String name = ent.getName();
      if (!ent.isDirectory() &&
不然会出现如下错误:
  ... ...
  src/util/ClassReader.java:85: as of release 5, 'enum' is a keyword, and may not be used as an identifier
(use -source 1.4 or lower to use 'enum' as an identifier)
      Enumeration enum = zf.entries();
                  ^
src/util/ClassReader.java:86: as of release 5, 'enum' is a keyword, and may not be used as an identifier
(use -source 1.4 or lower to use 'enum' as an identifier)
      while (enum.hasMoreElements()) {
               ^
src/util/ClassReader.java:87: as of release 5, 'enum' is a keyword, and may not be used as an identifier
(use -source 1.4 or lower to use 'enum' as an identifier)
            ZipEntry ent = (ZipEntry)enum.nextElement();
... ...
  【10】参考Memo for Explanting KVM to ARM-Linux,针对如下错误需要安装低版本的编译器。
  ... ...
  ../../../kvm/VmCommon/src/verifierUtil.c: In function 'verifyClass':
../../../kvm/VmCommon/src/verifierUtil.c:547: error: invalid storage class for function 'Vfy_verifyMethod'
../../../kvm/VmCommon/src/verifierUtil.c:571: warning: implicit declaration of function 'Vfy_verifyMethod'
../../../kvm/VmCommon/src/verifierUtil.c: At top level:
../../../kvm/VmCommon/src/verifierUtil.c:1595: error: static declaration of 'Vfy_verifyMethod' follows non-static declaration
../../../kvm/VmCommon/src/verifierUtil.c:571: note: previous implicit declaration of 'Vfy_verifyMethod' was here
../../../kvm/VmCommon/src/verifierUtil.c: In function 'Vfy_verifyMethod':
../../../kvm/VmCommon/src/verifierUtil.c:1598: error: invalid storage class for function 'Vfy_checkNewInstr tions'
../../../kvm/VmCommon/src/verifierUtil.c:1633: warning: implicit declaration of function 'Vfy_checkNewInstr tions'
../../../kvm/VmCommon/src/verifierUtil.c: At top level:
../../../kvm/VmCommon/src/verifierUtil.c:1671: error: conflicting types for 'Vfy_checkNewInstr tions'
../../../kvm/VmCommon/src/verifierUtil.c:1633: note: previous implicit declaration of 'Vfy_checkNewInstr tions' was here
make: *** Error 1
make: Leaving directory `/root/linux-test/j2me_cldc/kvm/VmUnix/build'
make: *** 错误 1
#
  (1)下载arm-linux-gcc-3.3.2.tar.bz2 : http://code.google.com/p/mini4020/downloads/detail?name=3.3.2.tar.bz2&can=2&q=label%3AMini4020
  (2)修改第【4】中的Makefile,修改如下:
  ifeq ($(GCC), tr)
   CC = /usr/local/arm/3.3.2/arm-linux/bin/gcc
   CFLAGS =-Wall $(CPPFLAGS) $(ROMFLAGS) $(OTHER_FLAGS)
   DEBUG_FLAG = -g
   OPTIMIZE_FLAG = -O2
   FP_OPTIMIZE_FLAG =
  【11】进入j2me_cldc/kvm/VmUnix/build编译
  # cd ../build
# make
... ...
Linking ... kvm
make: Leaving directory `/root/linux-test/j2me_cldc/kvm/VmUnix/build'
<<<Finished Recursively making ../../kvm/VmUnix/build all.
#
  OK,编译成功。
  【12】查看下面两个重要文件
  # file /root/linux-test/j2me_cldc/kvm/VmUnix/build/kvm
/root/linux-test/j2me_cldc/kvm/VmUnix/build/kvm: ELF 32-bit LSB executable, ARM, version 1 (ARM),for GNU/Linux 2.0.0, dynamically linked (uses shared libs), for GNU/Linux 2.0.0, not stripped
# file /root/linux-test/j2me_cldc/tools/preverifier/build/linux/preverify
/root/linux-test/j2me_cldc/tools/preverifier/build/linux/preverify: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.9, dynamically linked (uses shared libs), for GNU/Linux 2.6.9,not stripped
#
可以看到,生成的kvm可执行文件是用来在目标板上运行java程序的,生成的preverify是用来预校验用。
  【13】kvm验证测试
  (1)进入到/root/java目录下,在linux主机上编译上面【1】jdk的测试文件helloworld.java
  # cd /root/java
# javac helloworld.java

  (2)将编译生成的j2me_cldc/tools/preverifier/build/linux/preverify文件复制到linux主机/bin目录下
# cp linux-test/j2me_cldc/tools/preverifier/build/linux/preverify/bin
  将linux-test/j2me_cldc/tools/jcc目录下classes.zip 和classesUnix.zip 分别解压到/root/java目录的classes 和classesUnix目录下
  # cd linux-test/j2me_cldc/tools/jcc
# unzip classes.zip -d /root/java/classes/
  # unzip classesUnix.zip -d /root/java/classesUnix/

  用下面命令进行预校验
  preverify -classpath classesdir myclass
  # cd java
# preverify -classpath classes/classes classes/classesUnix HelloWorldApp
段错误
#
参考http://www.cnblogs.com/oomusou/archive/2008/06/14/j2me_cpld_preverify.html,知是使用的语系问题。Solution如下:
  <1>显示目前使用的语系
  # echo $LANG
zh_CN.UTF-8
  不管目前使用的中文还是英文,只要是UTF-8就会出现上面错误。
  <2>暂时修改成en_US.ISO8859-1语系
# export LANG=en_US.ISO8859-1
# echo $LANG
en_US.ISO8859-1
  <3>再次执行preverify
  # preverify -classpath classes/classes classes/classesUnix HelloWorldApp
#
  执行成功。
  (3)在目标板上运行测试
  先将/root/linux-test/j2me_cldc/kvm/VmUnix/build目录下的kvm复制到开发板根目录即nfsboot/rootfs/usr/local/sbin目录下
  # cp linux-test/j2me_cldc/kvm/VmUnix/build/kvm /nfsboot/rootfs/usr/local/sbin
#
  然后将校验后生成的Java/output目录下HelloWorldApp.class复制到开发板的/root目录下
  # cp /root/java/output/HelloWorldApp.class /nfsboot/rootfs/root/
#
  (4)在开发板串口终端运行
  在执行之前先确认开发板/etc/profile文件中的PATH系统变量有如下路径:
  PS1='[\u@\h \W]\$'
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH
HOSTNAME='/bin/hostname'
export USER LOGNAME PS1 PATH
然后再串口终端中执行
  #kvm
-/bin/sh: kvm: not found
#
  问题分析:kvm是用arm-linux-gcc-3.3.2编译的,而内核是用arm-linux-gcc-4.4.3编译的。在【12】中用file指令查看结果是&quot;for GNU/Linux 2.0.0 ”,显然出现了兼容问题。
  由此,我突然想到一个问题,之前用arm-linux-gcc-4.4.3编译应用程序时,通过file查看,可以看到如&quot;for GNU/Linux 2.6.32&quot; 之类的信息,而编译kvm则是出现的&quot;for GNU/Linux 2.0.0 ”这样的信息,arm-linux-gcc是如何知道内核版本信息的呢?
页: [1]
查看完整版本: Linux应用程序开发(三)---移植kvm到arm linux