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!
20.01.2015 14:40

У вас есть код, который использует библиотеки Boost C++? Вы хотите максимально простым способом портировать этот код под Android? Или, может быть, вы просто начинаете новый проект под Android и хотите использовать Boost с самого начала? С CrystaX NDK 10.1.0 вы получаете возможность разрабатывать под Android на C++ с использованием Boost прямо "из коробки".

Давайте посмотрим, как это можно сделать.

Для простоты изложения, будем считать, что вы используете систему сборки проекта из NDK, основанную на файлах Application.mk и Android.mk. Вот структура каталога простейшего проекта, который не содержит Java-части, и результатом сборки которого является один исполняемый файл:

.
└── 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. В этом примере мы будем использовать библиотеку Boost Serialization. Демонстрируемый подход работает для любой библиотеки из проекта Boost, единственное, что нужно изменить - это собственно имя библиотеки в файле Android.mk.

Сначала добавим в проект файлы, использующие библиотеку Boost Serialization (мы используем официальный пример из Boost):

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 код, использующий классы и методы из gps.hpp:

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

Конечный результат

Готово! Можно проверить, как это все работает. Заметьте, что мы использовали параметр APP_ABI при вызове ndk-build только для того, чтобы уменьшить вывод на консоль; тем не менее, приведенный код работает для всех возможных ABI.

$ 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

Как вы могли заметить, Boost в Crystax NDK просто работает без каких-либо модификаций - это означает, что вы сможете использовать один и тот же код как для мобильных, так и для всех остальных платформ. Более того, Boost в Crystax NDK работает для всех поддерживаемых версий Android, т.е. начиная с версии 2.3 (API level 9).

Впечатляет? Тогда скачайте CrystaX NDK и попробуйте его прямо сейчас!

Back
Home
Map
Back
Home
Map

Наши авторы: