上一篇文章中,详细介绍gcc的编译流程,以及静态库和动态库的区别。接下来,就介绍什么是交叉编译,怎样进行交叉编译,也介绍Mac系统上怎样利用iterm2与服务器进行文件传输。
NDK系列文章
[TOC]
什么是交叉编译
介绍交叉编译之前,先介绍一下本地编译。
本地编译
本地编译可以理解为,在当前编译平台下,编译出来的程序只能放到当前平台下运行。比如我上一篇文章中,都是直接在Mac OS平台上编译的,那么就是本地编译,编译出来后也只能再Mac平台上使用,不能放到Android项目中。
交叉编译
交叉编译可以理解为,在当前编译平台下,编译出来的程序能运行在体系结构不同的另一种目标平台上,但是编译平台本身却不能运行该程序。比如接下来我们就要介绍在Mac平台上编写程序,然后编译能够运行在Android平台上的库,就是交叉编译。
为什么需要交叉编译
- 目标平台的运行速度往往比主机慢得多
- 整个编译过程是非常消耗资源的,目标平台往往没有足够的内存或磁盘空间
交叉编译Android项目
下载NDK并解压
在NDK官网下载NDK并进行解压,才能编译出Android平台上的库,否则直接用Mac OS上的gcc只能为本地编译,也可以直接通过Android Studio进行下载。
设置环境变量
定义了路径的变量,接下来编译的时候,就不用输入长长的路径
1
➜ export CC=NDK的路径
1
2
3
4
5我的设置如下,接下来就用指定路径的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创建并编写可执行文件
1
2
3
4
5
6
7
int main(){
printf("hello world\n");
return 0;
}交叉编译
1
2
3
4
5➜ $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中的,所以需要带上文件路径。设置文件路径并重新交叉编译
交叉编译基本的命令与上一篇文章的一样,区别就是把gcc、ar等换成下载的NDK中
生成动态库
1
2
3
4
5
6➜ $CC --sysroot=$NDK/platforms/android-21/arch-arm -isysroot $NDK/sysroot -isystem $NDK/sysroot/usr/include/arm-linux-androideabi -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生成静态库
1
2
3
4
5
6
7
8先生成.o文件(比动态库少了-shared)
➜ $CC --sysroot=$NDK/platforms/android-21/arch-arm -isysroot $NDK/sysroot -isystem $NDK/sysroot/usr/include/arm-linux-androideabi -fPIC main.c -o main.o
利用.o文件再生成静态库
➜ /Users/guidongyuan/Library/Android/android-ndk-r17c/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-ar r libmain.a main.o
/Users/guidongyuan/Library/Android/android-ndk-r17c/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-ar: creating libmain.a
查看文件信息
➜ file libmain.a
libmain.a: current ar archive参数说明
--sysroot=<directory>
设置编译需要的头文件与库文件的查找目录,会分别查找dir/usr/include
和dir/usr/lib
目录下的文件查找头文件
-isysroot directory
设置头文件的查找目录,会查找directory/usr/include
。注意,该查找只用于搜索头文件,而且会覆盖上面--sysroot
设置的路径。-isystem directory
与-isysroot
一样,都是设置头文件的查找路径查找库文件
-Ldirectory
指定库文件查找目录-lxx.so
指定需要链接的库名实例:链接ndk的liblog.so日志库
1
2
3-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
的错误,暂时找不到错误原因。
1 | 拷贝到手机sdcard中 |
执行的时候,如果提示上面的错误,可以参考adb “Permission denied” to run a “./configure” file,链接说到,如果确定该文件是可以执行的文件,拷贝到/data/local/tmp
目录下
1 | 退出手机的shell |
Mac使用iterm2上传、下载文件
使用Mac交叉编译的时候,也尝试用我的VPS的Linux系统进行编译测试,但怎样把编译好的文件发送回我的Mac上呢?解决后顺便在此记录下来
在Mac上安装Iterm2和lrzsz
1
2➜ brew install iterm2
➜ brew install lrzsz下载github上的脚本,然后copy到
/usr/local/bin
中1
2
3
4➜ 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拷贝iterm2
具体配置,可以参考上面下载文件夹中的README.MD
1
2
3
4
5
6
7
8
9Regular 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利用ssh连接vps
1
ssh 用户名@IP地址 -p 端口号
Linux上安装lrzsz
1
root@localhost:~# apt-install lrzsz
然后就可以利用sz、rz上传下载文件了
1
2如,下载main.c文件到Mac上,执行后选择文件夹保存就可以了
root@localhost:/home/studyndk# sz main.c