美文网首页性能优化
NDK(四):交叉编译

NDK(四):交叉编译

作者: 亦猿非猿 | 来源:发表于2019-01-02 08:32 被阅读33次

    上一篇文章中,详细介绍gcc的编译流程,以及静态库和动态库的区别。接下来,就介绍什么是交叉编译,怎样进行交叉编译,也介绍Mac系统上怎样利用iterm2与服务器进行文件传输。

    NDK系列文章

    什么是交叉编译

    介绍交叉编译之前,先介绍一下本地编译。

    本地编译

    本地编译可以理解为,在当前编译平台下,编译出来的程序只能放到当前平台下运行。比如我上一篇文章中,都是直接在Mac OS平台上编译的,那么就是本地编译,编译出来后也只能再Mac平台上使用,不能放到Android项目中。

    交叉编译

    交叉编译可以理解为,在当前编译平台下,编译出来的程序能运行在体系结构不同的另一种目标平台上,但是编译平台本身却不能运行该程序。比如接下来我们就要介绍在Mac平台上编写程序,然后编译能够运行在Android平台上的库,就是交叉编译。

    为什么需要交叉编译

    • 目标平台的运行速度往往比主机慢得多
    • 整个编译过程是非常消耗资源的,目标平台往往没有足够的内存或磁盘空间

    交叉编译Android项目

    1. 下载NDK并解压

      NDK官网下载NDK并进行解压,才能编译出Android平台上的库,否则直接用Mac OS上的gcc只能为本地编译,也可以直接通过Android Studio进行下载。

      image-20190101202815344
    2. 设置环境变量

      定义了路径的变量,接下来编译的时候,就不用输入长长的路径

      ➜  export CC=NDK的路径
      
      # 我的设置如下,接下来就用指定路径的gcc去编辑
      ➜  export NDK=/Users/guidongyuan/Library/Android/android-ndk-r17c
      ➜  export CC=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-gcc
      # 输出NDKPATH变量的内容,可以验证是否设置成功
      ➜  echo $CC
      
    3. 创建并编写可执行文件

      # mian.c文件
      
      #include <stdio.h>
      int main(){
          printf("hello world\n");
          return 0;
      }
      
    4. 交叉编译

      ➜  $CC -fPIC main.c -o main
      main.c:1:19: fatal error: stdio.h: No such file or directory
       #include <stdio.h>
                         ^
      compilation terminated.
      

      上面编译运行错误,提示找不到.h文件。因为gcc是用ndk中的,所以.h也需要用ndk中的。所以需要带上文件路径

    5. 设置文件路径并重新交叉编译

      # 生成静态库
      ➜  $CC --sysroot=$NDK/platforms/android-21/arch-arm -isysroot $NDK/sysroot -isystem $NDK/sysroot/usr/include/arm-linux-androideabi -pie -fPIC main.c -o libmain.so
      ➜  ls
      libmain.so main.c
      # 查看文件信息,为executable
      ➜  file libmain.so
      libmain.so: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /system/bin/linker, not stripped
      
      # 生成动态库(添加-shared参数)
      ➜  $CC --sysroot=$NDK/platforms/android-21/arch-arm -isysroot $NDK/sysroot -isystem $NDK/sysroot/usr/include/arm-linux-androideabi -pie -fPIC -shared main.c -o libmain.so
      ➜  ls
      libmain.so main.c
      # 查看文件信息,为shared object
      ➜  file libmain.so
      ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /system/bin/linker, not stripped
      

      参数说明

      --sysroot=<directory>
      设置编译需要的头文件与库文件的查找目录,会分别查找dir/usr/includedir/usr/lib目录下的文件

      查找头文件

      -isysroot directory
      设置头文件的查找目录,会查找directory/usr/include。注意,该查找只用于搜索头文件,而且会覆盖上面--sysroot设置的路径。

      -isystem directory
      -isysroot一样,都是设置头文件的查找路径

      查找库文件

      -Ldirectory
      指定库文件查找目录
      -lxx.so
      指定需要链接的库名

      实例:链接ndk的liblog.so日志库

      # -L需要指定到bin目录
      gcc -L/Users/guidongyuan/Library/Android/android-ndk-r17c/platforms/android-21/arch-arm/usr/bin -llog
      gcc --sysroot=/Users/guidongyuan/Library/Android/android-ndk-r17c/platforms/android-21/arch-arm -llog
      

    在Android平台上测试验证

    注意:发送到Android平台上,为上面交叉编译出来的so文件,而且为静态库,尝试发送动态库执行,最后提示Illegal instruction的错误,暂时找不到错误原因。

    # 拷贝到手机sdcard中
    ➜  adb push libmain.so /sdcard/
    # 进入手机路径执行
    ➜  adb shell
    ➜  cd /sdcard/
    # 执行可执行文件
    ➜  ./libmain.so
    # 如果提示该错误,则需要更改到其他路径
    can't execute: Permission denied
    

    执行的时候,如果提示上面的错误,可以参考adb “Permission denied” to run a “./configure” file,链接说到,如果确定该文件是可以执行的文件,拷贝到/data/local/tmp目录下

    # 退出手机的shell
    ➜  exit
    # 重新拷贝到手机sdcard中
    ➜  adb push libmain.so /data/local/tmp
    ➜  adb shell
    ➜  cd /data/local/tmp
    ➜  ./libmain.so
    hello world
    # 成功输出hello world
    

    Mac使用iterm2上传、下载文件

    使用Mac交叉编译的时候,也尝试用我的VPS的Linux系统进行编译测试,但怎样把编译好的文件发送回我的Mac上呢?解决后顺便在此记录下来

    1. 在Mac上安装Iterm2和lrzsz

      ➜  brew install iterm2
      ➜  brew install lrzsz
      
    2. 下载github上的脚本,然后copy到/usr/local/bin

      ➜  cd /tmp
      ➜  git clone https://github.com/mmastrac/iterm2-zmodem.git
      ➜  mv /tmp/iterm2-zmodem/iterm2-recv-zmodem.sh /usr/local/bin/iterm2-recv-zmodem.sh
      ➜  mv /tmp/iterm2-zmodem/iterm2-send-zmodem.sh /usr/local/bin/iterm2-send-zmodem.sh
      
    3. 拷贝iterm2

      具体配置,可以参考上面下载文件夹中的README.MD

      image-20180904082334235 image-20180904082531465
      Regular expression: rz waiting to receive.\*\*B0100
      Action: Run Silent Coprocess
      Parameters: /usr/local/bin/iterm2-send-zmodem.sh
      Instant: checked
       
      Regular expression: \*\*B00000000000000
      Action: Run Silent Coprocess
      Parameters: /usr/local/bin/iterm2-recv-zmodem.sh
      Instant: checked
      
    4. 利用ssh连接vps

      ssh 用户名@IP地址 -p 端口号
      
    5. Linux上安装lrzsz

      root@localhost:~# apt-install lrzsz
      
    6. 然后就可以利用sz、rz上传下载文件了

      # 如,下载main.c文件到Mac上,执行后选择文件夹保存就可以了
      root@localhost:/home/studyndk# sz main.c
      

    参考资料

    相关文章

      网友评论

        本文标题:NDK(四):交叉编译

        本文链接:https://www.haomeiwen.com/subject/buyalqtx.html