本篇博客并不会详细介绍如何使用Androidstudio来编写Native层代码,因为这部分内容在Androidstudio官网文档中已经被详细描述过了。然而移植c/c++现有库到Android平台是什么意思呢,其实就是把那些现有的c/c++库的源码按照Android平台的架构重新编译一遍。目前Androidstudio支持两种编译原生库的工具,CMake和ndk-build,默认工具是CMake,而且推荐使用的工具也是CMake。Androidstudio官网文档中的向项目中添加c/c++代码小节详细介绍了如何使用CMake工具编译原生库,但是我在移植的过程中还是碰到一个坑,这篇博客主要是记录一下这个坑。
不知大家对c++中的extern “C”{}有多少了解,其实百度百科对这个关键字的说明也已经比较详细了,在此也不再介绍,这个坑就是和这个关键字相关的。我先来简述一下问题出现的过程:我想要移植一个c/c++的MD5库到Android平台,从网上找了一个MD5的源码,该源码是c语言代码,由头文件md5.h和源代码文件md5c.c组成。然后使用Androidstudio创建一个空的带有c++支持的项目,会自动生成一个native-lib.cpp文件,该文件定义了jni接口,注意这是c++语言代码。然后我简单的在native-lib.cpp文件中#include "md5.h"
之后,就开始调用了md5.h中声明的函数,比如MD5Init。Build没问题,但是Link却报错了,提示MD5Init未定义:error: undefined reference to 'MD5Init(MD5Context*)'
。经过多种尝试终于找到了错误所在,那就是native-lib.cpp文件中的#include "md5.h"
这行代码,由于是在c++文件中include头文件,所以编译器会把该md5.h当做c++代码来解析,特别是会把其中声明的函数当做c++函数来解析,然而那些函数其实是c函数,这些c函数在编译md5c.c时会被编译,但是编译器认为的c++函数却没有被定义,所以才会出现未定义的错误。
解决方法也很简单,即把native-lib.cpp文件中的#include "md5.h"
改为
extern "C" {
#include "md5.h"
}
即可,当编译器遇到extern “C”{}时,会把大括号中的内容当做c语言编译,这样就能链接到md5c.c中的c函数了,也就填上了这个坑。总结一下,遇到c/c++混合时需要格外小心和注意!!!