Что такое Android.mk? |
![]() |
Добавил(а) microsin |
Android.mk - это специальный настроечный текстовый файл, предназначенный для автоматизации компиляции приложений Android на основе NDK. Это по сути так называемый файл makefile, но составленный по определенным правилам. Компиляция с участием файлов Android.mk делается под управлением утилиты-скрипта ndk-build. Файл Android.mk широко используется для компиляции модулей приложений (библиотек) как из командной строки, так и из среды разработки Eclipse. В статье использовался перевод документации Google [1]. [Основная концепция] Синтаксис файла Android.mk разработан так, чтобы позволить Вам группировать исходный код в "модули". Модуль в данном контексте - это специальный файл библиотеки, который создан из исходного кода на языке программирования C/C++ (native language). Модулем может быть либо статическая библиотека (static library), либо разделяемая общая (shared library, динамически загружаемая библиотека). Т. е. в модуле собраны функции, которые Вы можете использовать в приложении, и этот модуль может быть присоединен к приложению либо статически, на этапе компиляции, либо динамически, в процессе загрузки. В виде отдельных файлов в выходной пакет приложения (.apk) попадут только общие разделяемые библиотеки. Однако статическими библиотеками можно пользоваться, чтобы создать общие разделяемые библиотеки. Вы можете задать для компиляции один или большее количество модулей в каждом файле Android.mk. При этом можно использовать один и тот же исходный файл для нескольких модулей. Вот простой пример файла Android.mk: # Символом # всегда начинается строка комментария. # Файл Android.mk всегда должен начинаться с определения переменной LOCAL_PATH. # Она используется для указания размещения исходных файлов в дереве разработки. # В этом примере макро-функция 'my-dir', предоставляемая системой сборки, используется # для возврата пути текущей директории (т. е. директории, в которой находится сам # файл Android.mk). LOCAL_PATH := $(call my-dir) [Система именования (Naming convention)] Вы можете задать другие переменные для собственного использования, но система сборки NDK резервирует для себя следующие имена переменных: • Имена, начинающиеся с LOCAL_ (например LOCAL_MODULE). Если Вам нужно определить собственные переменные для удобства в файле Android.mk, то рекомендуется использовать префикс MY_ как в этом простом примере: MY_SOURCES := foo.c ifneq ($(MY_CONFIG_BAR),) MY_SOURCES += bar.c endif [Переменные, предоставляемые NDK] Эти переменные GNU Make определены системой сборки перед тем, как будет обработан Ваш файл Android.mk. Имейте в виду, что при определенных обстоятельствах NDK может сделать парсинг файла Android.mk несколько раз, причем каждый раз с разными значениями для некоторых из этих переменных. CLEAR_VARS BUILD_SHARED_LIBRARY include $(BUILD_SHARED_LIBRARY)
При этом будет сгенерирован библиотечный модуль с именем файла lib$(LOCAL_MODULE).so. BUILD_STATIC_LIBRARY include $(BUILD_STATIC_LIBRARY)
При этом будет сгенерирован файл lib$(LOCAL_MODULE).a. PREBUILT_SHARED_LIBRARY Вы можете обращаться к prebuilt library в другом модуле, используя переменную LOCAL_PREBUILTS (см. docs/PREBUILTS.html для получения дополнительной информации). PREBUILT_STATIC_LIBRARY TARGET_ARCH TARGET_PLATFORM TARGET_ARCH_ABI armeabi для ARMv5TE Примечание: до NDK 1.6_r1 эта переменная была просто задана как 'arm'. Однако значение было переназначено для лучшего соответствия используемой внутренней платформе Android. Для дополнительной информации по архитектуре ABI и соответствующим проблемам совместимости см. docs/CPU-ARCH-ABIS.html. Другое целевое ABI будет представлено в будущих релизах NDK, и будет иметь другое имя. Имейте в виду, что все ABI, основанные на ARM, имеют 'TARGET_ARCH' заданной как 'arm', но могут иметь разные 'TARGET_ARCH_ABI'. TARGET_ABI [Макрофункции, предоставленные NDK] Далее обсудим макросы-'функции' GNU Make, которые должны вызываться с помощью выражения '$(call < function >)'. Они возвращают текстовую информацию. my-dir LOCAL_PATH := $(call my-dir) Важное замечание: поскольку так работает GNU Make, это действительно возвратит путь *последнего* *подключенного* *Makefile* в процессе парсинга скриптов сборки. Не делайте вызов my-dir после подключения другого файла. К примеру: LOCAL_PATH := $(call my-dir) ... декларирование одного модуля Здесь может возникнуть проблема, что второй вызов 'my-dir' задаст LOCAL_PATH в значение $PATH/foo вместо $PATH, поскольку перед этим было выполнено включение include. По этой причине лучше сделать все включения после всех операций в Android.mk, вот так: LOCAL_PATH := $(call my-dir) ... декларирование одного модуля Если так делать неудобно, то сохраните первый вызов my-dir в другую переменную, например: MY_LOCAL_PATH := $(call my-dir) LOCAL_PATH := $(MY_LOCAL_PATH) ... декларирование одного модуля all-subdir-makefiles sources/foo/Android.mk Если sources/foo/Android.mk содержит одну строку: include $(call all-subdir-makefiles)
то к нему будут автоматически подключены также sources/foo/lib1/Android.mk и sources/foo/lib2/Android.mk. Эта функция может использоваться для предоставления системе сборки иерархии глубоко вложенных друг в друга директорий. Имейте в виду, что по умолчанию NDK будет просматривать файлы в sources/*/Android.mk. this-makefile parent-makefile grand-parent-makefile import-module $(call import-module, < name >) Эта строка вызовет просмотр в поиске модуля, помеченного именем < name > в списке каталогов, определенных Вашей переменной окружения NDK_MODULE_PATH, и автоматически подключит его в этот Android.mk. Подробности см. в docs/IMPORT-MODULE.html. [Переменные для описания модуля (Module-description variables)] Переменные, обсуждаемые в этом разделе, описывают Ваш модуль для системы сборки. Вы должны определить некоторые из них между 'include $(CLEAR_VARS)' и 'include $(BUILD_XXXXX)'. Как уже было упомянуто ранее, , $(CLEAR_VARS) является скриптом для очистки/удаления всех этих переменных, за исключением специально упомянутых в их описании. LOCAL_PATH LOCAL_PATH := $(call my-dir) Эта переменная НЕ очищается скриптом $(CLEAR_VARS), так что для неё нужно только одно определение на каждый файл Android.mk (в случае, если Вы определяете компиляцию нескольких модулей в одном файле Android.mk ). LOCAL_MODULE LOCAL_MODULE_FILENAME LOCAL_MODULE := foo-version-1 LOCAL_MODULE_FILENAME := libfoo Примечание: Вы не должны помещать путь или расширение имени файла в переменную LOCAL_MODULE_FILENAME, это будет обрабатываться автоматически системой сборки. LOCAL_SRC_FILES LOCAL_SRC_FILES := foo.c \ toto/bar.c Примечание: всегда используйте прямые слеши (/) для построения пути файлов в стиле Unix. Обратные слеши в стиле Windows будут некорректно обработаны. LOCAL_CPP_EXTENSION LOCAL_CPP_EXTENSION := .cxx Начиная с NDK r7 можно в этой переменной задавать список расширений: LOCAL_CPP_EXTENSION := .cxx .cpp .cc LOCAL_CPP_FEATURES LOCAL_CPP_FEATURES := rtti Чтобы показать, что Ваш код использует исключения C++ (exceptions), используйте: LOCAL_CPP_FEATURES := exceptions Вы можете также использовать несколько опций в одной строке (их порядок следования не имеет никакого значения): LOCAL_CPP_FEATURES := rtti features Эффект от использования этой переменной в том, чтобы разрешить правильные флаги компилятора/линкера, когда осуществляется сборка Ваших модулей из файлов исходного кода. Для предварительно собранного двоичного кода это также позволит помочь декларировать, какие фичи реализованы в двоичном коде, чтобы окончательная сборка работала корректно. Рекомендуется использовать эту переменную вместо разрешения -frtti и -fexceptions напрямую в определении LOCAL_CPPFLAGS. LOCAL_C_INCLUDES LOCAL_C_INCLUDES := sources/foo Или также: LOCAL_C_INCLUDES := $(LOCAL_PATH)/../foo Это должно быть размещено перед любым соответствующим флагом подключения в LOCAL_CFLAGS / LOCAL_CPPFLAGS. Путь LOCAL_C_INCLUDES также автоматически используется, когда запускается отладка (native debugging) через ndk-gdb. LOCAL_CFLAGS Важное замечание: не пытайтесь поменять уровень оптимизации/отладки в Вашем Android.mk, это может быть автоматически осуществлено для Вас путем указания соответствующей информации в Вашем файле Application.mk, и это позволит NDK генерировать полезные файлы данных для использования в отладке. Примечание: в android-ndk-1.5_r1 соответствующие флаги прикладываются только к файлам исходного кода C, но не к файлам C++. Это скорректировано для соответствия поведению полной системы сборки Android (Вы теперь также можете использовать LOCAL_CPPFLAGS для указания флагов только для исходного кода C++). Можно указать дополнительные пути включения (пути include) в опцией LOCAL_CFLAGS += -I< path >, однако лучше для этого использовать LOCAL_C_INCLUDES, поскольку пути подключения также используются при отладке (native debugging) через ndk-gdb. LOCAL_CXXFLAGS LOCAL_CPPFLAGS Примечание: в android-ndk-1.5_r1 соответствующие флаги будут применены и к файлам кода C, и к файлам кода C++. Это скорректировано для соответствия поведению полной системы сборки Android (Вы теперь также можете использовать LOCAL_CFLAGS для указания флагов и для C, и для C++). LOCAL_STATIC_LIBRARIES LOCAL_SHARED_LIBRARIES LOCAL_WHOLE_STATIC_LIBRARIES LOCAL_LDLIBS LOCAL_LDLIBS := -lz См. docs/STABLE-APIS.html для списка представленных системных библиотек, которые Вы можете линковать с этим релизом NDK. LOCAL_ALLOW_UNDEFINED_SYMBOLS LOCAL_ARM_MODE LOCAL_ARM_MODE := arm Обратите внимание, что Вы также можете инструктировать систему сборки компилировать только определенные исходники в режиме ARM, путем добавления суффикса '.arm' к имени этого исходного файла, например: LOCAL_SRC_FILES := foo.c bar.c.arm Эта команда указывает системе сборки всегда компилировать 'bar.c' в режиме ARM, и компилировать foo.c в соответствии со значением переменной LOCAL_ARM_MODE. Внимание: установка APP_OPTIM в значение 'debug' в Вашем Application.mk также будет принуждать генерировать бинарники ARM. Это происходит из-за багов в отладчике тулчейна, который не очень хорошо может обрабатывать код режима thumb. LOCAL_ARM_NEON Альтернативно Вы можете указать только отдельные исходные файлы, которые можно компилировать с поддержкой NEON, если будете использовать суффикс '.neon': LOCAL_SRC_FILES = foo.c.neon bar.c zoo.c.arm.neon В этом примере 'foo.c' будет скомпилирован в режиме thumb+neon, 'bar.c' будет компилироваться в режиме 'thumb', и 'zoo.c' будет компилироваться в режиме 'arm+neon'. Обратите внимание, что суффикс '.neon' должен идти после суффикса '.arm', если Вы используете их совместно (например foo.c.arm.neon будет работать, но только не foo.c.neon.arm!). LOCAL_DISABLE_NO_EXECUTE Внимание: эта фича не модифицирует ABI и будет разрешена только на ядрах, нацеленных на устройства с ARMv6+ CPU. Генерируемый машинный код с этой фичей, будет работать в немодифицированном виде на устройствах с более ранними архитектурами CPU. Для дополнительной информации см. [3, 4]. LOCAL_EXPORT_CFLAGS include $(CLEAR_VARS) LOCAL_MODULE := foo LOCAL_SRC_FILES := foo/foo.c LOCAL_EXPORT_CFLAGS := -DFOO=1 include $(BUILD_STATIC_LIBRARY) И в другом модуле с именем 'bar', который зависит от него: include $(CLEAR_VARS) LOCAL_MODULE := bar LOCAL_SRC_FILES := bar.c LOCAL_CFLAGS := -DBAR=2 LOCAL_STATIC_LIBRARIES := foo include $(BUILD_SHARED_LIBRARY) Тогда флаги flags '-DFOO=1 -DBAR=2' будут переданы компилятору, когда будет компилироваться bar.c. Экспортируемые флаги присоединяются к LOCAL_CFLAGS Вашего модуля, так что Вы можете легко перезадать их. Это также транзитивная особенность: если 'zoo' зависит от 'bar', который зависит от 'foo', то 'zoo' будет также наследовать все флаги, экспортируемые 'foo'. В заключение следует указать, что экспортируемые флаги НЕ используются, когда собирается модуль, который экспортирует их. В приведенном выше примере -DFOO=1 не будет передаваться компилятору, когда идет сборка foo/foo.c. LOCAL_EXPORT_CPPFLAGS LOCAL_EXPORT_C_INCLUDES LOCAL_EXPORT_LDLIBS Переменная обычно полезна, когда модуль 'foo' является статической библиотекой, и имеет код, который зависит от системной библиотеки. Тогда LOCAL_EXPORT_LDLIBS можно использовать для экспортирования зависимости. Пример: include $(CLEAR_VARS) LOCAL_MODULE := foo LOCAL_SRC_FILES := foo/foo.c LOCAL_EXPORT_LDLIBS := -llog include $(BUILD_STATIC_LIBRARY) Здесь libbar.so будет собран с -llog по окончании команды линкера, чтобы показать, что он зависит от системной библиотеки логгинга, потому что он зависит от 'foo'. LOCAL_SHORT_COMMANDS Примечание: не рекомендуется по умолчанию разрешать эту возможность, поскольку это замедляет процесс сборки. LOCAL_FILTER_ASM • Любой исходный файл C или C++ генерируется во временный файл ассемблера (вместо того, чтобы компилироваться в объектный файл). Другими словами, если у Вас: LOCAL_SRC_FILES := foo.c bar.S LOCAL_FILTER_ASM := myasmfilter foo.c --1--> $OBJS_DIR/foo.S.original --2--> $OBJS_DIR/foo.S --3--> $OBJS_DIR/foo.o Здесь "1" соответствует компилятору, "2" фильтру, и "3" ассемблеру. Фильтр должен быть отдельной командой шелла, которая принимает имя входного файла в качестве своего первого аргумента, и имя выходного файла в качестве второго аргумента, вот так: myasmfilter $OBJS_DIR/foo.S.original $OBJS_DIR/foo.S myasmfilter bar.S $OBJS_DIR/bar.S [Ссылки] 1. Android.mk site:docs.google.com. |