• 如何移植library到Android


    一般来说,当你拿到一包library的source code,要按照如下的方式开始:
    1.请仔细仔细的阅读Readme,以及各种文档.这里面包含了绝大部分你想要的东西。
    2.尝试的编译一个可以运行的版本出来看看效果。
      a.这时候你应该了解你要移植的库,是怎么编译的了吧?没有?Goto 1:继续往下阅读
      b.一般来说,source code的编译会分成两种:
        <1>. 只有一个Makefile,或者是有configure文件的。
              这种的,最好是你阅读makefile文件,把这个makefile转换为Android.mk文件,使用ndk build system去编译。
        <2>. 另一种的是大型的源代码系统。这种的通常都会有自己的build system.比如android.
             碰到这种大型的,可能源代码太多了,一时半会根本不能写出一个Android.mk文件。可以酱紫,换成你要的目标平台的cross toolchain.
             举个通常的android例子:
              CC=$(Compile_Path)/arm-eabi-gcc
             STRIP=$(Compile_Path)/arm-eabi-strip
             AR=$(Compile_Path)/arm-eabi-ar
             LINK=&(Compile_Path)/arm-eabi-g++
             再配合上一些编译参数:比如,Compile_Flags = -fPIC, march = armv5t mno-thumb-interwork之类的。
      c.试试看能不能编译出来。
          能是最好的,不能,又要分几种情况了
          <1>.一般来说,source code的逻辑不太会错误.所以不要尝试大幅度修改源代码(除非你有能力推翻重写,都重写那干嘛还要移植?).
          <2>.Compile时,报语法错误,比如result = obj->func()->func2(),会说类似“XXX  can't find func2
            你可以该成: temp = obj->func(); result = temp->func2();这主要是编译器方面的差异。
          <3>.Compile时,报"can't find xxx.h" or "can't find xxx.cpp xxx.c"之类,请正确包含该文件;
             比如你可以写上:INCLUDE_PATH += -I/../......./include.或者放到编译下的include路径。比如ndk目录下的build/platforms/android-3/arch-arm/usr/include下面.不过这不是好方法就是了. 
         <4>.Link,"can't find reference XXX",基本是忘记添加库文件了。你可以写上:Library_Path +=-L/.../.../lib或者放到ndk下面的build/platforms/android-3/arch-arm/usr/lib下面。
         <5>.当你该加的library都加了,依然出现"can't find reference XXX",那多半就是你用的库不是标准的,这里面没有XXX函数的实现.
             比如androidbionic libc就没有ftime函数(应该没记错吧?!)那你只好自己去添上实现文件了。
        <6>.又报link error了?通常来说,使用android build system的人,不应该会遇到这类问题。只有直接使用toolchain才有可能会出现这类问题,这类link error比较棘手。
              解决的方法有:
              (I库之间有依赖,正确的链接库的顺序;比如libz.a依赖liby.a,那么链接顺序是:ld liby.a libz.a
              (II库版本不对,请仔细读documentation.这里要注意version的区别,debug & release的区别,是不是同一个编译器编译的库(ABI会不一致),static & shared的区别
              (IIICC++库之间的调用.要记得使用extern "C" {},和#ifdef __PLUSPLUS
              (IV我碰到这样一个问题,就是作者使用了#define OWNFUNC(Function) NEWNAME##Function字符拼接宏,把所有的函数名都转换了,dumpobj时候当然找不到函数签名啦.
              (V当你link成功了,运行的时候挂掉了.也可能是link的时候没有成功哦.举个列子来说明:
                    当你写了一个android  c 版本的helloworld,编译链接过了,但是运行的时候告诉你:"can't find _start symbol",这就是说android OS把执行权交个cruntime library的时候,找不到入口,而这个入口就是_start.解决的办法是:ld crtBegin_dynamic.o以及 crtEnd_android.o   
                  当然还有很多的问题不是上面说的这些,比如编译参数不对,-fPIC-fpic, 应该编译32bitarm指令,却用了16bit thumb指令...等等。
         <7>大部分的问题,你都解决了。剩下各种平时都没见过的问题了?去论坛上问吧。我就挺喜欢到国外的论坛上去问的。
         <8>.考虑使用ndk build system方式来编译。
          但不管怎么说,我推荐使用ndk build system方式。我曾经到google ndk group上去问过问题,得到过DavidTurner的回答:
          You should not be trying to use the toolchain directly like this ....省略....Really, youshould use the NDK build system instead.
    3.修改逻辑,添加逻辑适应自己的需要.

    先看看android ndk的目录layout大概长的怎么样.
    root
      |------apps,所有你要编译的Cc++code都放到这个目录下。
      |------build
      |        |----platforms 下面目前为止放了3sub fold,里面分别放了android 需要的include , library(提供的library有限)
      |                |------android 3 代表android 1.5
      |                |------android 4 代表android 1.6
      |                |------android 5 代表android 2.0
      |        |----prebuilt 该目录下存放toolchain的可执行档案,以及include & library.对于arm-eabi-4.4.0了解不多.
      |                |------arm-eabi-4.2.1
      |                          |------------bin 所有的toolchainexcute file
      |                          |------------arm-eabi
      |                                          |------include
      |                                          |------lib
      |        |----tools 这个目录下存放了很多有用的工具,包括下载,build toolchain
      |------docs必须仔细读的文档
      |------out生成的所有临时文件

    先从docs开始谈,这个也是非常重要的一步。
    1.纠正Android-mk.txt 中写的 ndk 只能编译出static library shared library,实际上他还提供了命令编译可执行程序.
       a.include $(BUILD_SHARED_LIBRARY)
       b.include $(BUILD_STATIC_LIBRARY)
       c.include $(BUILD_EXECUTABLE)
       理论上能编译出so文件,当然能编译出execute文件.只是ndk是否提供这个接口。
    2.apps目录下,新建一个目录,再建立project目录,这一级目录下建立Application.mk, 再建立一个sub foldjni, jni里面放的都是cc++源代码,还有Android.mk.Android.mk就必须仔细写了.
       常用的有LOCAL_PATH:=$(call my-dir)//访问当前path下的所有子目录,
           <1>.LOCAL_DEBUG:=no|yes
           <2>.LOCAL_OS:= linux  //目标平台
           <3>.LOCAL_ARCH:=arm   //目标平台cpu
           <4>.LOCAL_ARM_MODE:=arm  //CPU指令集
           <5>.COMMON_DEFINES += ISP=isp_arm9 -D_ARM_//这里通常会把要移植的library中的各种flag写在这里.(从待移植中的Configure或者Makefile中拷贝过来)
           <6>.ifeq($(DEBUG),no)
                 COMMON_FLAGS += --O2 -fno-strict-aliasing -DNDEBUG -fno-rtti//好像都采用O2优化,fno-rtti 告诉C++不要runtime 中的一些support.
           <7>.COMMON_COMPILE_FLAGS += -fPIC  += -msoft-float +=march=armv5t
              
        相对应的有了COMMON_XXX就有了LOCAL_XXX,
        我们可以定义相关的
           <1>.LOCAL_MODULE := libxxx  //定义要编译的moule         
           <2>.LOCAL_CFLAGS := -I$(LOCAL_PATH)/xxx/include以及局部FLAG(Configure或者Makefile中拷贝过来)//定义search .h fold
           <3>.LOCAL_CXXFILES := //和上面是相同的,只是这个是C++的,上面的是C
           <4>.LOCAL_SRC_FILES := XXX.c XXX.cpp XXX.hpp    //定义源代码          
           <5>.include $(BUILD_STATIC_LIBRARY定义该模块是静态的
        要编译到android上运行的excutable,还会依赖
            <1>.LOCAL_LDLIBS := -L library_path -lxx //定义库的路径,以及要的library, 这里其实用的都是动态库.
            android,有一个参数是:-dynamic-linker,/system/bin/linker ,采用的不是标准的linux下的ld.so.6(好像是这个数字,具体的不清楚了,而是/system/bin/linker来链接.这也是为什么我们用其他编译器(比如codesourcery)编译出来的东西不能在android上直接跑的原因,而一定要加上-static参数,也就是说用codesourcery编译出来的东西必须不依赖android的调度,而是靠编译时把所有的库全部加入.所以这时候写出来的helloworld都可能会有1~2Mb.提到了liner,就不得不提到android bionic,这个C runtime library设计并不是功能特别强大,并且有些gnu glic中的函数没有实现,这是移植时会碰到的问题.而且,这个C runtime library也并没有采用crt0.o,crt1.o,crti.o crtn.o,crtbegin.o crtend.o,而是采用了android自己的crtBegin_dynamic.o,crtBegin_static.o crtEnd_android.ocrt1.ocrt0.o的后续演进版本,crt1.o中会非常重要的.init段和.fini段以及_start函数的入口..init段和.fini段实际上是靠crti.o以及crtn.o来实现的. init段是main函数之前的初始化工作代码, 比如全局变量的构造. fini段则负责main函数之后的清理工作.crti.o crtn.o是负责C的初始化,C++则必须依赖crtbegin.ocrtend.o来帮助实现.
            So,在标准的linux平台下,link的顺序是:ld crt1.o crti.o [user_objects] [system_libraries]crtn.o
            而在android,link的顺序是:arm-eabi-g++ crtBegin_dynamic.o [user_objects][system_libraries] crtEnd_android.o
            所以这就是从另一个方面说明为什么不适合codesourcery之类编译来开发android底层东西的原因了,这里我不包括BSP之类.
           <2>.LOCAL_STATIC_LIBRARIES := //excute file 依赖的库
           <3>.include $(BUILD_EXCUTEABLE)
    在谈谈platform目录下的东西,这里面要说的是可能includelibrary中包含的头文件和library文件不太够,我们可以使用busybox for android把我们要的资料都给pull出来.或者编译android 源代码,需要的都东西都会有.
    prebuilt目录下,有我们编译器的可执行文件,但是很不幸android toolchain不支持STL.目前支持STL有两种方法:
      1.使用STLPort(据说这种方式不是太好)
      2.重新编译使android toolchain 支持STL.

  • 相关阅读:
    json python
    mysql存储json
    C#中使用Newtonsoft.Json序列化和反序列化自定义类对象
    IDEA 中的.iml文件和.idea文件夹 ( 隐藏方式 )
    C#中Newtonsoft.Json.dll 的使用 序列化 JsonConvert.SerializeObject(obj) Object 反序列 obji = JsonConvert.DeserializeObject<Object>(json数据);
    [python] JSON
    编程经验:分组条件查询having
    软件汉化:OllyDBG 入门之三简介及常用命令
    读书札记: [转] 失去目标的时候进来看看!
    软件汉化:OllyDBG 入门之二破解预备知识(转)
  • 原文地址:https://www.cnblogs.com/sardine/p/2100352.html
Copyright © 2020-2023  润新知