在android上运行c编写的helloword
一般情况下Android系统应用程序都是java编写APK,如果要重用C代码,也是通过JNI,调用C库。
也许有人会和我有一样的想法既然android是基于linux的内核的,那应该也可以直接运行C编写的二进制呢?很显然是可以的。
当我们手机用USB线连接到电脑,电脑安装adb工具,手机也允许电脑调试就可以通过adb shell 进入android 。linux常用命令如:cd ls,也可以使用。这些程序就是android系统中C语言编写的程序了 。
我们在linux下编写一个hello.c如下:
#inlcude<stdio.h>
int main()
{
printf("hello world \n");
return 0;
}
在linux下通过gcc -o hello hello.c 编译生成hello的可执行文件,./hello打印出了hello world。
我假想它在andorid 也能运行,adb push到到手机上,chmod 755 hello修改可执行权限。执行./hello 出现了错误not executable: magic 7F45。原来我们编译环境是x86编出来的二进制只能在x86cpu上运行而android系统的是arm架构cpu的。所以我要编译arm架构二进制,编译环境和运行环境不同的编译,我们也叫做交叉编译。
废了九牛二虎的力气我下载arm的交叉编译,结果没有库文件 不能使用printf函数,编译不通过。遇到问题解决呗,本来可以直接下载一个标准库就行,为了方便我直接下载了一个arm-linux的交叉编译工具。
继续gcc -o hello hell.c 生成了arm下二进制文件,一波操作传输到android 修改权限,满怀希望的 ./hello 结果大失所望No such file or directory 这又是什么意思呢。百度一顿搜。
原来是这样啊。android下的c标准库的 linux下使用的C标准库和android下使用的库不是一样的。linux使用的glibc而在andorid下google没有使用linux的glib自己实现了一个比glib更小
更快的bionic C标准库,最重要的是android下linker链接器和linux的不一样。linker主要是用来加载库文件到内存的。
显然我知道了原因了执行程序的时候到去找库文件的时候没有找到就打印这句话。
这里有两种解决办法
1.直接将hello程序静态编译arm二进制让他不依赖库
gcc -o hello helllo.c -static
编译完成后我们发现二进制大了很多,printf函数编译二进制不再依赖库函数了 在android下执行成功打印hello world 真是不容易终于成功了 。
2.使用andorid下库和linker
下载android NDK 使用它来编译 用这个编译很多好处还可以使用android的日志模块
arm-linux-androideabi-gcc.exe -o hello hell.c –sysroot=”D:\NDK\platforms\android-19\arch-arm”
这样编译出来的二进制能使用andorid C标准库文件大小也最合适 目前google推荐的也是这种方式。
程序发布加上优化参数 在使用strip 来去掉调试信息减少二进制大小。
最后总结:虽然是个简单的hello的hello world程序,但让我加深了交叉编译理解,了解操作系统加载库的过程。