Сборка open-source библиотек на Android NDK

    Привет, Хабралюди!

    В процессе работы с Android NDK я столкнулся с проблемой сборки уже существующих Linux библиотек на Android NDK. Так как материала не слишком много в этой статье поделюсь своим опытом. В Андроиде я новичек, так что если найдете ошибки — пишите:)

    Чтобы пример был не самым простым и при том полезным — возьмём библиотеку libFLAC. Этот даст возможность декодировать .flac файлы. По данному мануалу, я надеюсь, соберутся большинство других библиотек.

    Кроме неё нам понадобится:
    • Android NDK, r5b (http://developer.android.com/sdk/ndk/index.html)
    • libOgg (http://www.xiph.org/downloads/)
    • libVorbis (там же, где и libOgg).

    Создание проекта


    Создаём стандартный Android проект, в нем создаём папку jni и распаковываем туда libogg, libvorbis, libflac.

    Сборка



    Приступим к первому этапу. Для сборки я использовал такой скрипт:

    PREBUILT=/home/user/android-ndk-r5b/toolchains/arm-eabi-4.4.0
    PLATFORM=/home/user/android-ndk-r5b/platforms/android-3/arch-arm
    
    export CC="/home/user/android-ndk-r5b/toolchains/arm-eabi-4.4.0/prebuilt/linux-x86/bin/arm-eabi-gcc"
    export CFLAGS="-fPIC -DANDROID -nostdlib"
    export ANDROID_ROOT="/home/user/android-ndk-r5b"
    export LDFLAGS="-Wl,-rpath-link=$ANDROID_ROOT/platforms/android-3/arch-arm/usr/lib/ -L$ANDROID_ROOT/platforms/android-3/arch-arm/usr/lib/"
    
    export CPPFLAGS="-I$ANDROID_ROOT/platforms/android-3/arch-arm/usr/include/"
    export LIBS="-lc "
    ./configure --host=arm-eabi 


    Для libVorbis придется его немного изменить:
    LDFLAGS будет таким:
    export LDFLAGS="-Wl,-rpath-link=$ANDROID_ROOT/build/platforms/android-3/arch-arm/usr/lib/ -L$ANDROID_ROOT/build/platforms/android-3/arch-arm/usr/lib/ -L../../libs/armeabi/"

    а LIBS:
    export LIBS="-lc -logg"


    Для libflac изменим добавим в libs -lvorbis.

    Рассмотрим структуру скрипта по порядку. Строка export CC — путь к компилятору Android NDK. Тут: export LDFLAGS можем задавать директории, где искать библиотеки, а в LIBS подключать их. В этой строке: export CPPFLAGS подключаем headers дополнительных библиотек.

    Выполняете нужные скрипты в корне каждой из библиотек. После сборки, если все прошло успешно вы получаете библиотеки, которые уже можно компилировать на NDK.

    Подготовка Android.mk



    Итак, для начала создадим Android.mk, вида:
    include $(all-subdir-makefiles)
    В папках: jni, jni/libogg, jni/libflac, jni/libvorbis
    Этот скрипт означает, что будут подключены все Android.mk в поддиректориях.

    Для создания Android.mk в папках jni/libogg/src, jni/libvorbis/lib, jni/libflac/src будем использовать все Makefile.am в тех же папках.
    jni/libogg/src

    В Makefile.am ищем строки:
    libogg_la_SOURCES = framing.c bitwise.c — это все что нам надо. Получаем стандартный Android.mk вида:
    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    
    LOCAL_MODULE := libogg
    
    LOCAL_C_INCLUDES := $(LOCAL_PATH) \
    $(LOCAL_PATH)/../include/
    
    LOCAL_SRC_FILES := framing.c bitwise.c
    
    include $(BUILD_SHARED_LIBRARY)
      #В данном примере собираем динамические библиотеки

    Думаю тут объяснять ничего не надо. Идём дальше.
    jni/libvorbis/lib

    Тут тоже все просто. Находим строку: libvorbis_la_SOURCES и подулючаем все файлы, что там есть. Получаем такой Android.mk:
    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    
    LOCAL_MODULE := libvorbis
    
    LOCAL_C_INCLUDES := $(LOCAL_PATH) \
    $(LOCAL_PATH)/../include \
    $(LOCAL_PATH)/../../libogg/include
      #Подключаем headers libogg
    
    LOCAL_SRC_FILES := mdct.c smallft.c block.c envelope.c window.c lsp.c \
    			lpc.c analysis.c synthesis.c psy.c info.c \
    			floor1.c floor0.c\
    			res0.c mapping0.c registry.c codebook.c sharedbook.c\
    			lookup.c bitrate.c\
    
    LOCAL_SHARED_LIBRARIES := libogg	#Тут подключаем требуемые библиотеки
    
    
    LOCAL_LDLIBS := -ldl -lGLESv1_CM -llog
    
    include $(BUILD_SHARED_LIBRARY)

    jni/libflac/src

    Процесс тот же, но файлов намного больше и они в поддиректориях. Я решил все что есть собрать в одну библиотеку, чтоб было проще, поэтому получил такой скрипт:
    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    
    LOCAL_MODULE := libFLAC
    
    LOCAL_C_INCLUDES := $(LOCAL_PATH)/libFLAC/include/ \
    $(LOCAL_PATH)/../include/ \
    $(LOCAL_PATH)/../../libogg/include/ \
    $(LOCAL_PATH)/../../vorbis/include/ \
    $(LOCAL_PATH)/share/include/ \
    $(LOCAL_PATH)/share/utf8/ \
    $(LOCAL_PATH)/../include/ \
    $(LOCAL_PATH)/../include/share/ \
    $(LOCAL_PATH)/share/replaygain_synthesis/include/ \
    $(LOCAL_PATH)/../../libogg/include/ \
    $(LOCAL_PATH)/../../vorbis/include/ \
    $(LOCAL_PATH)/metaflac/include/ \
    $(LOCAL_PATH)/../include/ \
    $(LOCAL_PATH)/../include/share \
    $(LOCAL_PATH)/../../libogg/include/ \
    $(LOCAL_PATH)/../../vorbis/include/ \
    $(LOCAL_PATH)/flac/ \
    $(LOCAL_PATH)/../include/ \
    $(LOCAL_PATH)/../../libogg/include/ \
    $(LOCAL_PATH)/../../vorbis/include/ \
    
    LOCAL_SRC_FILES := libFLAC/bitmath.c \
    	libFLAC/bitreader.c \
    	libFLAC/bitwriter.c \
    	libFLAC/cpu.c \
    	libFLAC/crc.c \
    	libFLAC/fixed.c \
    	libFLAC/float.c \
    	libFLAC/format.c \
    	libFLAC/lpc.c \
    	libFLAC/md5.c \
    	libFLAC/memory.c \
    	libFLAC/metadata_iterators.c \
    	libFLAC/metadata_object.c \
    	libFLAC/stream_decoder.c \
    	libFLAC/stream_encoder.c \
    	libFLAC/stream_encoder_framing.c \
    	libFLAC/window.c \
                  libFLAC/ogg_decoder_aspect.c \
    	libFLAC/ogg_encoder_aspect.c \
    	libFLAC/ogg_helper.c \
    	libFLAC/ogg_mapping.c \
                  share/getopt/getopt.c share/getopt/getopt1.c  \
                  share/grabbag/cuesheet.c \
    	share/grabbag/file.c \
    	share/grabbag/picture.c \
    	share/grabbag/replaygain.c \
    	share/grabbag/seektable.c \
                  share/replaygain_analysis/replaygain_analysis.c \
                  share/replaygain_synthesis/replaygain_synthesis.c \
                  share/utf8/charset.c share/utf8/iconvert.c share/utf8/utf8.c \
                  metaflac/main.c \
    	metaflac/operations.c \
    	metaflac/operations_shorthand_cuesheet.c \
    	metaflac/operations_shorthand_picture.c \
    	metaflac/operations_shorthand_seektable.c \
    	metaflac/operations_shorthand_streaminfo.c \
    	metaflac/operations_shorthand_vorbiscomment.c \
    	metaflac/options.c \
    	metaflac/usage.c \
    	metaflac/utils.c \
                  flac/analyze.c \
    	flac/decode.c \
    	flac/encode.c \
    	flac/foreign_metadata.c \
    	flac/local_string_utils.c \
    	flac/utils.c \
    	flac/vorbiscomment.c \
    
    LOCAL_SHARED_LIBRARIES := libogg libvorbis
    
    LOCAL_LDLIBS := -ldl -lGLESv1_CM -llog
    
    include $(BUILD_SHARED_LIBRARY)

    И последнее:

    NDK BUILD



    Выполняем ndk-build (этот скрипт находится в папке NDK) и видим что все компилируется, но flac даёт следующую ошибку:
    /home/user/workspace/w/testOGG/jni/flac-1.2.1/src/libFLAC/format.c:60: error: 'VERSION' undeclared here (not in a function)
    /home/user/workspace/w/testOGG/jni/flac-1.2.1/src/libFLAC/format.c:66: error: expected ',' or ';' before 'VERSION'
    make: *** [/home/user/workspace/w/testOGG/obj/local/armeabi/objs/FLAC/libFLAC/format.o] Ошибка 1

    Проблема в том, что константа VERSION определена в makefile, который мы не подключали. Самым простым выходом я вижу создать эту константу в самом format.c вот так:
    #define VERSION "1.2.1"
    Все теперь ошибок нет. При компиляции получаем:
    Install : libFLAC.so => libs/armeabi/libFLAC.so
    Install : libogg.so => libs/armeabi/libogg.so
    Install : libvorbis.so => libs/armeabi/libvorbis.so

    В каталогах должны появится такие файлы и папки:
    image
    Теперь осталось последнее — протестировать все ли работает. Я переделал на скорую руку из стандартных примеров декодирования аудио через libflac. Декодировал из flac файла в wav. Так как код скрипт великоват вы можете протестировать работу на этом apk:тестовый apk файл
    (чтоб все сработало, надо чтоб в sdcard был файл output.flac с:
    05-20 14:18:42.783: INFO/FLAC(427): sample rate: 44100 Hz
    05-20 14:18:42.783: INFO/FLAC(427): channels: 2 Hz
    05-20 14:18:42.783: INFO/FLAC(427): bits: 16 Hz, он будет перекодирован в test2.wav. При работе программы ничего писать не будет (только в логи). Протестировано на эмуляторе, HTC Wildfire и Samsung galaxy tab (везде Android 2.2). Процесс занял не более минуты при работе с 20 мегабайтным flac файлом. По окончанию работы отобразится Hello world.
    Вот исходники всего проекта:
    исходники
    Удачи!

    Похожие публикации

    Средняя зарплата в IT

    110 000 ₽/мес.
    Средняя зарплата по всем IT-специализациям на основании 8 431 анкеты, за 2-ое пол. 2020 года Узнать свою зарплату
    Реклама
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее

    Комментарии 7

      +2
      Может, кому-то будет интересно — есть такая вещица, www.crystax.net/android/ndk.php
      Используется в запуске Haxe приложений на андроиде, примеры на gamehaxe.com/
        0
        Это не шутка? std???
          0
          А почему бы нет?
          +1
          Не вижу особого смысла сейчас использовать сборку от crystax'а, эксепшны и STL появились в r5 официального NDK.
          Может переубедите?
            0
            Насколько я помню, это результат сотрудничества CrystaX'a с гуглом, нет?
          +2
          А ещё есть android-cmake.
            +1
            А статическую библиотеку можно создать, если вместо include $(BUILD_SHARED_LIBRARY) поставить include $(BUILD_STATIC_LIBRARY). Иногда это может быть полезно.

            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

            Самое читаемое