This project has been on hold since 2016.
All the data on this site is still available (and will stay available) but not actual anymore.
You might be interested in checking out Dmitry Moskalchuk's portfolio website to learn about his other projects.
Boost + Android? CrystaX NDK!
2015.01.20 14:40

你是否代码中使用了Boost C++库? 你是否想轻松移植这些代码到Android? 或者你只是想使用Boost开始创建一个Android平台的新项目? 通过CrystaX NDK 10.1.0, 你就可以同时拥有Android原生开发套件和Boost C++库!

接下来看看如何实现.

首先我假设你使用标准的NDK build方式, 包括使用Application.mkAndroid.mk文件. 以下是一个最简单的项目,只有native部分的运行程序:

.
└── jni
    ├── Android.mk
    ├── Application.mk
    └── test.cpp

初始化文件
Application.mk
# Application.mk
APP_ABI := all
Android.mk
# Android.mk
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE    := test-boost
LOCAL_SRC_FILES := test.cpp
include $(BUILD_EXECUTABLE)
test.cpp
// test.cpp
#include <iostream>

int main()
{
    return 0;
}

添加Boost

现在来扩展成一个简单的Boost-enabled项目. 这里使用Boost序列化库示例; 其他库类似. 唯一区别是Android.mk中的引用库名称.

首先,添加源文件 (使用 official Boost example):

gps.hpp
// gps.hpp
#ifndef GPS_HPP_7D5AF29629F64210BE00F3AF697BA650
#define GPS_HPP_7D5AF29629F64210BE00F3AF697BA650

// include headers that implement a archive in simple text format
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

/////////////////////////////////////////////////////////////
// gps coordinate
//
// illustrates serialization for a simple type
//
class gps_position
{
private:
    friend class boost::serialization::access;
    friend std::ostream &operator<<(std::ostream &, gps_position const &);
    // When the class Archive corresponds to an output archive, the
    // & operator is defined similar to <<.  Likewise, when the class Archive
    // is a type of input archive the & operator is defined similar to >>.
    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    {
        ar & degrees;
        ar & minutes;
        ar & seconds;
    }
    int degrees;
    int minutes;
    float seconds;
public:
    gps_position(){}
    gps_position(int d, int m, float s) :
        degrees(d), minutes(m), seconds(s)
    {}

    bool operator==(gps_position const &g) const
    {
        return degrees == g.degrees &&
            minutes == g.minutes &&
            seconds == g.seconds;
    }

    bool operator!=(gps_position const &g) const
    {
        return !(*this == g);
    }
};

void save(gps_position const &g);
void load(gps_position &g);

#endif // GPS_HPP_7D5AF29629F64210BE00F3AF697BA650
gps.cpp
// gps.cpp
#include <fstream>

#include "gps.hpp"

const char *FILENAME = "gps.dat";

std::ostream &operator<<(std::ostream &s, gps_position const &g)
{
    s << "GPS(" << g.degrees << "/" << g.minutes << "/" << g.seconds << ")";
    return s;
}

void save(gps_position const &g)
{
    // create and open a character archive for output
    std::ofstream ofs(FILENAME);
    boost::archive::text_oarchive oa(ofs);
    // write class instance to archive
    oa << g;
    // archive and stream closed when destructors are called
}

void load(gps_position &g)
{
    // create and open an archive for input
    std::ifstream ifs(FILENAME);
    boost::archive::text_iarchive ia(ifs);
    // read class state from archive
    ia >> g;
    // archive and stream closed when destructors are called
}

其次, 修改test.cpp做点实际的事情:

test.cpp
// test.cpp
#include <iostream>
#include <iomanip>
#include "gps.hpp"

int main()
{
    // create class instance
    const gps_position g(35, 59, 24.567f);
    std::cout << "Initial value: " << g << std::endl;
    save(g);

    // ... some time later restore the class instance to its orginal state
    gps_position newg;
    load(newg);
    std::cout << "After load: " << newg << std::endl;

    if (g != newg)
    {
        std::cerr << "ERROR: Loaded object differs from the saved one" << std::endl;
        return 1;
    }

    std::cout << "Congratulations! GPS object was successfully saved and then loaded" << std::endl;
    return 0;
}

最后,修改Android.mk包含以上文件,启用Boost Serialization:

Android.mk
# Android.mk
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE           := test-boost
LOCAL_SRC_FILES        := test.cpp gps.cpp
LOCAL_STATIC_LIBRARIES := boost_serialization_static
# Or, if you need to link with Boost Serialization library dynamically:
#LOCAL_SHARED_LIBRARIES := boost_serialization_shared
include $(BUILD_EXECUTABLE)

$(call import-module,boost/1.57.0)

现在这个示例项目如下所示:

.
└── jni
    ├── Android.mk
    ├── Application.mk
    ├── gps.cpp
    ├── gps.hpp
    └── test.cpp

最终结果

Ok, 完成了! 来看看如何编译运行. 注意这里ndk-build使用了APP_ABI参数armeabi-v7a; 只是示例,其他所有ABIs都一样可用.

$ ndk-build APP_ABI=armeabi-v7a
[armeabi-v7a] Compile++ thumb: test-boost <= test.cpp
[armeabi-v7a] Compile++ thumb: test-boost <= gps.cpp
[armeabi-v7a] Prebuilt       : libgnustl_shared.so <= <NDK>/sources/cxx-stl/gnu-libstdc++/4.9/libs/armeabi-v7a/thumb/
[armeabi-v7a] Executable     : test-boost
[armeabi-v7a] Prebuilt       : libboost_atomic.so <= <NDK>/sources/boost/1.57.0/libs/armeabi-v7a/
[armeabi-v7a] Install        : libcrystax.so => libs/armeabi-v7a/libcrystax.so
[armeabi-v7a] Install        : test-boost => libs/armeabi-v7a/test-boost
[armeabi-v7a] Install        : libgnustl_shared.so => libs/armeabi-v7a/libgnustl_shared.so

$ adb push libs/armeabi-v7a/libcrystax.so /data/local/tmp
1231 KB/s (537036 bytes in 0.425s)

$ adb push libs/armeabi-v7a/libgnustl_shared.so /data/local/tmp
1234 KB/s (718448 bytes in 0.568s)

$ adb push libs/armeabi-v7a/test-boost /data/local/tmp
840 KB/s (50536 bytes in 0.058s)

$ adb shell 'cd /data/local/tmp && LD_LIBRARY_PATH=/data/local/tmp ./test-boost'
Initial value: GPS(35/59/24.567)
After load: GPS(35/59/24.567)
Congratulations! GPS object was successfully saved and then loaded

如你所见,不用修改任何代码就可用了 - 代码跟其他桌面和移动平台完全一样. 而且在所有平台的运行表现也一样. Android从2.3 (API level 9)开始支持.

印象深刻吧? 现在就来体验 CrystaX NDK 吧!

Back
Home
Map
Back
Home
Map

Our contributors: