您的位置:首页 > 编程语言 > C语言/C++

Run c++ program with boost on Android

2013-10-20 16:06 281 查看
http://nick.luckygarden.org/

Android 很早就支持 NDK, 官方教程上说你可以把 native 代码编译成一个 .so, 在 java 代码中通过 jni 调用这个 .so.

现在在做一个 C++ 跨平台的库. 需要支持 Android. 为了在 Android 上测试, 自然可以按照教程里写 java, jni. 但其实也可以抛开 java. 直接将 c++ 代码编译成可执行文件. 下面将整个过程记录下来, 备忘, 也希望能帮助用这样的需求的人.

先下载 sdk, ndk. 解压缩就好, 然后设置好环境变量 ANDROID_SDKROOT, NDKROOT 指向这两个目录. 并将 $NDKROOT, $ANDROID_SDKROOT/platform-tools, $ANDROID_SDKROOT/tools 加入 PATH. 下面的操作使用的环境是 NDK r8, OS X 10.8.

开始啦:

#include <stdio.h>

int main(){printf("hello world.\n");return 0;}


把这个文件保存为 /tmp/hello.cpp. 要编译这个程序, 需要写一个 Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS) # mk 文件前面两句都这样, 不解释



LOCAL_MODULE := hello-world # 模块名, 必须唯一

LOCAL_SRC_FILES := ../hello.cpp # 要编译的源文件

include $(BUILD_EXECUTABLE) # 编译成可执行文件. 这个是关键.

# 其他的选项是 BUILD_SHARED_LIBRARY, BUILD_STATIC_LIBRARY 编译成 .so, .a


貌似还只能把这个 .mk 文件放到一个 jni 的文件夹里. 然后在 /tmp 目录执行 ndk-build. 如果环境都设置好了, 这个能够编译成功. 放到模拟器上试试吧.

执行

android - avd


打开 Android Virtual Device Manager (注意 – avd 之间有一个空格), 创建一个虚拟机, 然后启动它. 确保一切 ok. 然后执行

adb push libs/armeabi/hello-world /data/ && adb shell /data/hello-world

1372 KB/s (299852 bytes in 0.213s)

hello world.


push 到模拟器, 然后执行 hello-world.

继续. 修改一下代码, 试试 c++ 的库文件.

#include <iostream>

int main(){std::cout<<"hello world"; return 0;}


用 ndk-build 编译会发现有错误. 因为没有 stl 的支持.

nickx:/tmp $ ndk-build

Compile++ thumb : hello-world <= hello.cpp

jni/../hello.cpp:1:20: error: iostream: No such file or directory

jni/../hello.cpp: In function 'int main()':

jni/../hello.cpp:4: error: 'cout' is not a member of 'std'

make: *** [obj/local/armeabi/objs/hello-world/__/hello.o] Error 1


在 /tmp/jni 下建立 Application.mk, 加上下面一句:

APP_STL := gnustl_static # 另一个选项是 gnustl_shared


链接 gnustl. 再编译就 ok 了.

因为项目要链接 boost, 加上 boost header 试试吧.

#include <iostream>

#include <boost/thread.hpp>

void proc(){std::cout << "hello world\n";}

int main()

{

boost::thread thrd(proc);

thrd.join();

return 0;

}


首先是找不到 boost 头文件. 这里要做一些准备工作. 将需要编译的 boost 库在 android 编译好. 这里就不赘述了. 得到 libboost_thread.a, libboost_system.a, 将这些文件这样组织
/vendor
/boost
Android.mk
/boost
thread.hpp
..
/lib
libboost_thread.a
libboost_system.a


其中的 Android.mk 的内容是这样的:

LOCAL_PATH:= $(call my-dir)



include $(CLEAR_VARS)

LOCAL_MODULE:= boost_thread

LOCAL_SRC_FILES:= lib/android/lib$(LOCAL_MODULE).a

LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) # 导出头文件, 因为有这句, 在我们的程序中的 Android.mk 文件中就不需要 LOCAL_C_INCLUDES 来指定 boost 头文件所在位置了.

include $(PREBUILT_STATIC_LIBRARY) # 所谓的编译好的静态库

include $(CLEAR_VARS)

LOCAL_MODULE:= boost_system

LOCAL_SRC_FILES:= lib/android/lib$(LOCAL_MODULE).a

LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)



boost 库就准备好了. 现在修改程序的 Android.mk 文件:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)



LOCAL_MODULE := hello-world

LOCAL_SRC_FILES := ../hello.cpp

LOCAL_CPP_FEATURES := exceptions rtti # boost thread 库需要 exceptions 的支持. rtti 后面也会用到

LOCAL_STATIC_LIBRARIES := boost_thread boost_system # 要的就是这两个库.

include $(BUILD_EXECUTABLE)

$(call import-module,boost) # 导入 boost 库.


再次编译会提示 import-module 找不到 boost, 需要定义 NDK_MODULE_PATH

nickx:/tmp $ export NDK_MODULE_PATH=/vendor

nickx:/tmp $ ndk-build

Compile++ thumb : hello-world <= hello.cpp

Prebuilt : libboost_thread.a <= /vendor/boost/lib/android/

Prebuilt : libboost_system.a <= /vendor/boost/lib/android/

Executable : hello-world

Install : hello-world => libs/armeabi/hello-world


到这里差不多了.

文中提到的 .mk 文件中的宏 (LOCAL_..) 的具体含义参见 $NDKROOT/documentation.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: