Как включить существующий файл make с Android NDK

Итак, у меня есть огромный существующий проект C, который я поместил в каталог $PROJECT/jni. Этот проект обычно выполняется путем запуска configure script, который создает Makefiles, который затем позволяет скомпилировать проект через make.

Этот проект довольно большой и содержит много каталогов, содержащих исходные файлы и файлы заголовков.

Я предполагаю, что мне не хватает фундаментального понимания того, как Android.mk должен работать. Предполагается ли заменить файл конфигурации и makefile, который в настоящее время используется для компиляции проекта? Или я бы включил созданный make файл из моей конфигурации script в Android.mk? Примеры, которые они предоставляют, довольно тривиальны только с несколькими исходными файлами. Мой каталог jni больше похож:

jni/
  folder1/subfolder1
  folder1/subfolder2
  folder1/source
  folder2/source
  .....
  foldern/source
  configure/
  configure/configure.sh
  Makefile
  Android.mk

Сгенерированные make файлы довольно обширны (хороший объем конфигурации и есть один в каждой директории), поэтому я немного потерял, как подойти к этому.

EDIT:

Основная проблема заключается в том, что примеры, которые поставляются с NDK, являются тривиальными примерами. У них есть 3-5 исходных файлов в каталоге jni верхнего уровня. Моя проблема в том, что это огромный проект со сложной конфигурацией с 4 папками верхнего уровня, каждый со многими подкаталогами. Я не могу просто переместить источник в jni-папку и запустить компилятор ndk.

Ответ 1

Чтобы ответить на ваш вопрос, да Android.mk - это система сборки Android. Google едва упоминает, что "язык" этого файла реализован как макросы GNU make. Документы хотят, чтобы вы описали свой проект с точки зрения этих макросов. Они справляются со всеми деталями кросс-компиляции. Я уверен, что Google применил этот подход для улучшения переносимости файлов Android.mk по мере развития средств разработки.

Результат заключается в том, что (и я знаю, что вы не захотите это услышать) лучший ответ - это, вероятно, написать правильный NDK Android.mk для вашего большого проекта с нуля.

В этой статье излагаются те же наблюдения, которые я сделал портированием библиотеки около 800 файлов и 300 КБ SLOC. К сожалению, я сжег почти две недели, достигнув такого же вывода: кросс-компиляция приводит к сбою хотя бы некоторых сценариев configure (приводят к ошибочным файлам config.h). Я "придумал" почти те же методы, которые он использовал в статье. Но даже после того, как я получил чистую сборку, полученная статическая библиотека не работала полностью. Часы отладки нет полезной информации. [Предостережение: я не специалист по настройкам. Гуру, вероятно, заметила бы мою ошибку. Так оно и есть.] Мне понадобилось пару дней, чтобы создать чистый Android.mk. В результате библиотека впервые провела все тесты. И он портировал чисто через несколько оборотов инструментов разработки.

К сожалению, создание библиотеки, использующей configure без использования автоматических инструментов, означает создание собственного config.h вручную для целевой среды. Это может быть не так плохо, как кажется. Системы IME имеют тенденцию определять гораздо больше в своих средах configure, чем они фактически используют. Получение четкого представления о реальных зависимостях может погасить утомительные усилия во время будущего рефакторинга.

В сводном заявлении из статьи говорится все:

Autotool хорош только для систем GNU, и использование его для кросс-компиляции может быть действительно утомительным, запутанным, подверженным ошибкам или даже невозможным. Метод, описанный здесь, является взломом и должен использоваться на свой страх и риск.

Извините, у меня нет более позитивного предложения.

Ответ 2

Мой ответ лучше всего работает в тандеме с ответом Gene.

./configure Создание файла конфигурации основано на компиляции (и, возможно, запуске) небольших фрагментов кода C для каждого теста. Тестирование только для компиляции может быть успешно протестировано в среде кросс-компиляции. Тем не менее, тесты компиляции и запуска невозможно запускать в среде кросс-компиляции. Успех каждого теста устанавливает соответствующую переменную в шаблоне config.h.in для создания config.h.

Таким образом, чтобы начать процесс преобразования, вам нужно установить CPP, CC, LD и другие инструменты в набор инструментов кросс-компилятора (возможно, те из NDK) и затем запустите ./configure. Как только это будет сделано, вам нужно исправить config.h в соответствии с целевой средой. Это наиболее важный и наиболее подверженный ошибкам шаг.

Как и для Android.mk, он следует формату, близкому к Makefile.am, который может быть легко преобразован в него. Вы можете игнорировать Makefile.in и Makefile, поскольку они генерируются из Makefile.am.

Чтобы взять пример file (версия 5.11), я запустил configure со следующими параметрами,

./configure --host arm-toshiba-linux-androideabi --build x86_64-linux-gnu \
            --prefix=/data/local/ host_alias=arm-linux-androideabi \
           "CFLAGS=--sysroot=~/ndk/platforms/android-8/arch-arm  -Wall -Wextra" \
           "CPPFLAGS=--sysroot=~/ndk/platforms/android-8/arch-arm" \
            CPP=arm-linux-androideabi-cpp

Следующим шагом было взять src/Makefile.am, как показано ниже:

MAGIC = $(pkgdatadir)/magic
lib_LTLIBRARIES = libmagic.la
include_HEADERS = magic.h

bin_PROGRAMS = file

AM_CPPFLAGS = -DMAGIC='"$(MAGIC)"'
AM_CFLAGS = $(CFLAG_VISIBILITY) @[email protected]

libmagic_la_SOURCES = magic.c apprentice.c softmagic.c ascmagic.c \
        encoding.c compress.c is_tar.c readelf.c print.c fsmagic.c \
        funcs.c file.h readelf.h tar.h apptype.c \
        file_opts.h elfclass.h mygetopt.h cdf.c cdf_time.c readcdf.c cdf.h
libmagic_la_LDFLAGS = -no-undefined -version-info 1:0:0
if MINGW
MINGWLIBS = -lgnurx -lshlwapi
else
MINGWLIBS =
endif
libmagic_la_LIBADD = $(LTLIBOBJS) $(MINGWLIBS)

file_SOURCES = file.c
file_LDADD = libmagic.la
CLEANFILES = magic.h
EXTRA_DIST = magic.h.in
HDR= $(top_srcdir)/src/magic.h.in
BUILT_SOURCES = magic.h

magic.h:        ${HDR}
        sed -e "s/X.YY/$$(echo @[email protected] | tr -d .)/" < ${HDR} > [email protected]

И создайте Android.mk из этого.

Последний и самый важный шаг - изменить config.h, чтобы точно отразить состояние целевой системы. Это будет ручной процесс, который я не могу дать обходным путем, в основном, заглядывая в configure.log, просматривая заголовки и "вызывая" Google. Плоды этого труда доступны в XDA.

Ответ 3

Здесь решение для того, чтобы делать вещи наоборот: построение как внешняя библиотека, так и пакет Android из стандартных Make файлов.

В качестве предварительного условия вам необходимо установить все необходимое для выполнения командной строки Разработка Android:

  • Отдельная инструментальная цепочка, см. документацию, включенную в Android NDK;
  • ant.

Структура примера: каталог для внешней библиотеки и каталог для Android-источников на одном уровне с Makefile в каждом каталоге и рекурсивном Makefile верхнего уровня:

Makefile
mylib/
    Makefile
android/
    Makefile

mylib/Makefile создает статическую библиотеку:

AR=/path/to/standalone/bin/arm-linux-androideabi-ar
CC=/path/to/standalone/bin/arm-linux-androideabi-gcc

libmylib.a: mylib.o
    $(AR) rcs libmylib.a mylib.o

mylib.o: mylib.c
    $(CC) -c mylib.c -o mylib.o

android/Makefile предоставляет правила для сборки пакета Android:

  • нам нужна зависимость для копирования mylib при ее изменении;
  • мы используем файл jni/ndkmake.c для переноса вызовов на mylib и предоставляем специфичные для Android файлы;
  • пакет android зависит от источников Java и общей библиотеки.

Makefile предоставляет две цели: release (по умолчанию) и debug для создания пакета выпуска или отладочного.

NDK_BUILD=/path/to/ndk-build
JAVASRC=src/com/example/ndkmake/NdkMake.java

release: bin/NdkMake-release-unsigned.apk

debug: bin/NdkMake-debug.apk

bin/NdkMake-release-unsigned.apk: libs/armeabi/libndkmake.so $(JAVASRC)
ant release

bin/NdkMake-debug.apk: libs/armeabi/libndkmake.so $(JAVASRC)
ant debug

libs/armeabi/libndkmake.so: jni/ndkmake.c jni/libmylib.a
$(NDK_BUILD)

jni/libmylib.a: ../mylib/libmylib.a
cp ../mylib/libmylib.a jni/libmylib.a

Файл Android.mk предоставляет правила для включения статической библиотеки в сборку в качестве готовой. Мы включаем заголовки из библиотеки mylib, используя LOCAL_EXPORT_C_INCLUDES.

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := ndkmake
LOCAL_SRC_FILES := ndkmake.c
LOCAL_STATIC_LIBRARIES := mylib-prebuilt
include $(BUILD_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := mylib-prebuilt
LOCAL_SRC_FILES := libmylib.a
LOCAL_EXPORT_C_INCLUDES := ../mylib/
include $(PREBUILT_STATIC_LIBRARY)

Теперь нам нужен только Makefile верхнего уровня для создания двух подкаталогов:

all: libmylib package

libmylib:
    cd mylib && $(MAKE)

package:
    cd android && $(MAKE)

Любое изменение в библиотеке, источниках jni или источниках Java приведет к восстановлению пакета.