Ubuntu系统下实现Android工程调用独立编译的C++程序和GMP、PBC库
目的:
实现使用C++编写代码供Android工程调用。C++代码中可以使用STL库,也可以使用常用的由源码编译生成的库,如PBC。因为PBC是基于GMP库的,所以这里只记录了GMP和PBC库的编译安装方法,其它库的方法类似。
特点:
不使用集成的ndk-build功能,不需要在jni目录下写c文件和mk文件,而是从NDK中提取出交叉编译toolchain,这样可以在CodeBlocks等环境中建立独立工程进行C++代码的开发,然后编译生成动态库交给Android工程来加载。
准备工作:
一个搭建好的Android开发环境(SDK),以及:
android-ndk-r9d-linux-x86_64.tar.bz2
gmp-6.0.0a.tar.bz2
pbc-0.5.14.tar.gz
这些都可以去各自的官网下载到。
一、搭建Android交叉编译环境
解压ndk开发包,并提取其中的toolchain到指定目录:
- $ cd android-ndk-r9d/
- $ build/tools/make-standalone-toolchain.sh --toolchain=arm-linux-androideabi-4.8 --platform=android-19 --system=linux-x86_64 --install-dir=$HOME/android-19-arm
参数说明:这里的toolchain参数指定的目标是基于ARM的Android设备,也可以根据需要改成基于x86或MIPS的Android设备,具体的参数名可以参见android-ndk-r9d/toolchains目录。参数platform设置为android-19,指生成的工具链是针对Android 4.4版本的,具体对应关系可以查看android-ndk-r9d/docs/STABLE-APIS.html文件。参数system指的是本机系统,即运行toolchain的环境。这里将提取出来的toolchain安装到了用户主目录下的android-19-arm文件夹,以后的工作都是在这个文件夹下进行,不再需要android-ndk-r9d目录了。
为toolchain添加环境变量,在文件/etc/profile的最后加上:
- # android toolchain
- export TOOLCHAIN_HOME=$HOME/android-19-arm
- export PATH=$TOOLCHAIN_HOME/bin:$PATH
然后最好注销一次,使环境变量生效(也可以用source /etc/profile,但好像只对本终端有效「注:elementary OS Luna」)
测试:
- $ arm-linux-androideabi-gcc --version
二、配置Codeblocks开发环境
打开Codeblocks,选择Settings--Compiler,选择GNU GCC Compiler,然后点Copy,这时会让填写新的编译器的名字,填写GCC Toolchain For Android。在Toolchain executables页中,编译器的安装目录选择在第一步中创建的目录(也就是$TOOLCHAIN_HOME所指向的目录,这里不能使用环境变量),然后将下面的gcc、g++、ar分别改成arm-linux-androideabi-gcc、arm-linux-androideabi-g++和arm-linux-androideabi-ar,Debugger和Make不用改动,保存。
现在已经配置好了codeblocks环境,创建工程时,需要选择刚才创建的编译器,编译出来的程序才能在Android中运行。
可以新建一个名为testToolchain的控制台程序来测试一下,选择GCC Toolchain For Android编译器,然后编译出来的可执行程序是Android系统上的原生C++程序,在x86平台上是不能运行的,可以传到手机上之后,使用adb shell或在手机上安装诸如BTEP终端来运行。在Ubuntu上用file命令也可以查看文件的信息:
- $ file testToolchain
- testToolchain: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped
可以看出,的确是生成了arm平台的目标程序。
三、使用Codeblocks来开发动态库并交给Android工程调用
Android工程:
在Android工程中(假设工程名为TestAndroidApp),在需要调用C函数的地方声明native函数,例如在MainActivity.java中声明:
- public native String function_in_c_code();
运行一下后生成对应的class文件,然后打开终端,切换到工程文件夹下的bin/classes目录,创建头文件:
- $ javah com.example.testandroidapp.MainActivity
然后会在当前目录下生成com_example_testapp_MainActivity.h头文件,里面有经过java改造的C++函数的声明方法。
Codeblocks中:
创建一个动态库工程(Shared library),假设工程名为cMainProc,编译器选择GCC Toolchain For Android,完成。这时应该先把刚才在Android中声明的接口函数实现,然后在接口函数中就可以随意调用自己写的其它函数或者库了。在CPP文件中,首先包含刚才使用javah命令生成的头文件。可以用相对路径引用它,也可以把头文件复制到当前工程中。然后按照头文件中的声明来创建接口函数,在刚才的例子中,应该创建这样一个函数:
- jstring JNICALL Java_com_example_testandroidapp_MainActivity_function_1in_1c_1code
- (JNIEnv *env, jobject)
- {
- // todo: your code here.
- return env->NewStringUTF("Hello world.");
- }
因为有返回值,所以在上面的代码中加了一个env变量,并调用java中的方法创建了一个jstring类型的字符串返回。
可以通过直接包含相应头文件来使用STL库。如果需要使用其他通过源码编译的库,那么需要先对其进行交叉编译,然后将编译后生成的头文件和库文件分别放到$TOOLCHAIN_HOME/sysroot/usr下的include和lib目录中,即可使用。头文件直接包含即可,库文件最好使用对应的静态库。例如,使用PBC库的话,首先在代码中#include <pbc/pbc.h>,然后在工程的Link libraries里添加libgmp.a和libpbc.a,注意要带上路径,这样才会链接静态库,否则会使用动态库。
编译这个工程,会在bin/Debug或bin/Release下生成对应的libcMainProc.so文件。将这个文件复制到Android工程的libs/armeabi文件夹下(也可以修改Codeblocks工程的输出目录,直接将编译出来的so文件放到Android工程中,这样更方便)。
Android工程:
在调用这个函数function_in_c_code()之前,先加载刚才编译的动态库文件:
- static
- {
- System.loadLibrary("cMainProc");
- }
注意库名中不带“lib”和扩展名,系统会自动寻找libcMainProc.so。然后就可以在java代码中调用这个函数了:
- TextView t = (TextView)findViewById(R.id.textView1);
- t.setText("String from c++: " + function_in_c_code());
运行效果示例:
四、编译安装GMP和PBC库
GMP库的编译稍复杂一些,因为在configure时要加上很多参数。解压gmp-6.0.0a.tar.bz2,并按下面给出的参数执行configure脚本。如果有缺少的依赖项,则用apt-get安装相应的项后,重新执行configure,直到出现下面提示:
- $ ./configure --prefix=$TOOLCHAIN_HOME/sysroot/usr --enable-cxx --build=x86_64-pc-linux-gnu --host=arm-linux-androideabi MPN_PATH="arm/v6t2 arm/v6 arm/v5 arm generic" CFLAGS="-O2 -g -pedantic -fomit-frame-pointer -Wa,--noexecstack -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64 -march=armv7-a -mfloat-abi=softfp -mfpu=vfp"
- ......
- ......
- configure: summary of build options:
- Version: GNU MP 6.0.0
- Host type: arm-unknown-linux-androideabi
- ABI: standard
- Install prefix: /home/user/android-19-arm/sysroot/usr
- Compiler: arm-linux-androideabi-gcc -std=gnu99
- Static libraries: yes
- Shared libraries: yes
然后再编译和安装:
- $ make -j8
- $ make install
PBC库相对比较简单,解压pbc-0.5.14.tar.gz,执行configure后编译并安装(在./configure阶段同样需要安装依赖项并重新./configure,直到显示成功):
- $ cd pbc-0.5.14
- $ ./configure --prefix=$TOOLCHAIN_HOME/sysroot/usr --host=arm-linux-androideabi
- ......
- ......
- global build variables
- -----------------------------------------
- Mon May 12 14:00:00 CST 2014
- host info: arm-unknown-linux-androideabi
- optimized build: no
- compiler (CC): arm-linux-androideabi-gcc
- LDFLAGS:
- CPPFLAGS:
- CFLAGS: -Wall -W -Wfloat-equal -Wpointer-arith -Wcast-align -Wstrict-prototypes -Wredundant-decls -Wendif-labels -Wshadow -pipe -ffast-math -U__STRICT_ANSI__ -std=gnu99 -fomit-frame-pointer -O3
- LEX: flex
- AM_LFLAGS:
- LFLAGS:
- YACC: bison -y
- AM_YFLAGS:
- YFLAGS:
- -----------------------------------------
- $ make -j8
- $ make install
在使用PBC库时,为了简洁,建议链接PBC的静态库,即libpbc.a,同时要注意以下事项:
1. 使用静态库时一定要链接所有用到的静态库。PBC库用到了GMP库,因此除了libpbc.a外,还应引用GMP的静态库,即libgmp.a
2. 链接多个静态库时,一定要注意顺序,即最底层的库排在最后面。在这里是PBC里用到了GMP的函数,因此需要先链接PBC,再链接GMP,否则会出错。
运行效果示例:
Ubuntu系统下实现Android工程调用独立编译的C++程序和GMP、PBC库的更多相关文章
- 〖Linux〗Android NDK调用已编译好的C/C++动态连接库(so文件)
一.背景:假定已有应用程序zigbeeclient.cpp,内容如下: ... extern "C" { int getresult(int argc, char **argv); ...
- Ubuntu环境下配置Android Studio【转】
本文转载自:https://www.jianshu.com/p/1f6295f9c955 之前学习Android开发的时候,一直跟各种教程一样,使用的是Eclipse+ADT,主要是比较方便,容易上手 ...
- Ubuntu系统下创建python数据挖掘虚拟环境
虚拟环境: 虚拟环境是用于创建独立的python环境,允许我们使用不同的python模块和版本,而不混淆. 让我们了解一下产品研发过程中虚拟环境的必要性,在python项目中,显然经常要使用不 ...
- 64位Ubuntu系统下ROP攻击
64位Ubuntu系统下ROP攻击 基础知识 ROP攻击 ROP全称为Retrun-oriented Programmming(面向返回的编程)是一种新型的基于代码复用技术的攻击,攻击者从已有的库或可 ...
- Ubuntu系统下OpenDaylight源码编译安装
操作系统:Linux x64 / Ubuntu 14.04 研究领域:软件定义网络SDN (Software-defined Networking) 开发组件:OpenDaylight 声明:转载请注 ...
- Ubuntu系统下安装并配置hive-2.1.0
说在前面的话 默认情况下,Hive元数据保存在内嵌的Derby数据库中,只能允许一个会话连接,只适合简单的测试.实际生产环境中不使用,为了支持多用户会话, 则需要一个独立的元数据库,使用MySQL作为 ...
- ubuntu系统下,gsl 库链接问题 -undefined reference to `cblas_xxx`
今天在ubuntu系统下进行程序调试的时候出现以下错误信息: [ %] Linking CXX executable ../test_coco /usr/local/lib/libgsl.so: un ...
- linux ubuntu系统下,adb不是内部命令 (如何才能让adb命令可以使用)
linux ubuntu系统下,adb不是内部命令 原文地址 linux ubuntu系统下,adb不是内部命令 解决方法: 1.sudo gedit ~/.bashrc 2.将下面的两句加到上面打开 ...
- Houdini 13在Ubuntu系统下流畅运行、不崩溃
至尊影视特效软件Houdini FX,当前最新版是13.0.547,经过试用在Ubuntu系统下可以完美运行,目前为止还没出现过崩溃的情况,之前在windows下使用Houdini 13简直就是噩梦, ...
随机推荐
- 主题:学习Spring必学的Java基础知识(9)----HTTP报文
转: 引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓“登高必自卑,涉远必自迩”.以下几项Java知识和Spring框架息息相关,不可不学(我将通过一个系列分别介绍这些 ...
- luogu3313 [SDOI2014]旅行
对每一个宗教建一棵线段树,然后树剖搞搞 #include <iostream> #include <cstdio> using namespace std; int n, m, ...
- 大数据学习——sqoop入门
下载地址 https://pan.baidu.com/s/1qWDl29L9I_KVU54c0ioNfQ fvfh 3.1 概述 sqoop是apache旗下一款“Hadoop和关系数据库服务器之间传 ...
- The 16th Zhejiang University Programming Contest-
Handshakes Time Limit: 2 Seconds Memory Limit: 65536 KB Last week, n students participated in t ...
- Codeforces603E - Pastoral Oddities
Portal Description 初始时有\(n(n\leq10^5)\)个孤立的点,依次向图中加入\(m(m\leq3\times10^5)\)条带权无向边.使得图中每个点的度数均为奇数的边集是 ...
- 【概率dp】C. Race to 1 Again
https://www.bnuoj.com/v3/contest_show.php?cid=9146#problem/C [题意] 给定一个数D,每次随机选取这个数的一个因子x得到新的数D=D/x,知 ...
- 同步OR异步?WebFlux开发真的比Servlet开发要快?顺便再科普下CompletableFuture
在看下文之前,先给大家科普一点基础知识 Runable:线程任务类接口,没有返回值 Callable:与上面的不同就是有返回值 Executor:定义了线程池执行任务的接口,不过只定义了Runable ...
- Codevs 2693 上学路线(施工)
时间限制: 2 s 空间限制: 16000 KB 题目等级 : 黄金 Gold 题目描述 Description 问题描述 你所在的城市街道好像一个棋盘,有a条南北方向的街道和b条东西方向的街道. 南 ...
- SQL SERVER 2012 第四章 连接 JOIN の INNER JOIN
所有JOIN语句的共同点是:将一个记录与另外一个或多个记录匹配,从而生成一个新记录,这个记录是由两个记录的合并列所产生的一个超集. 内部连接: 内部连接语法结构:SELECT <select l ...
- Wannafly挑战赛1
地址:https://www.nowcoder.com/acm/contest/15#question A(树形dp) 分析 dp[i][0],dp[i][1]分别表示以i为根的子树中,有多少个点到i ...