Подтвердить что ты не робот

Система сборки Android, сборки NEON и не-NEON

Я хочу создать свою библиотеку для armv6, и есть некоторый неоновый код, который я включаю во время выполнения, если устройство поддерживает его. Неоновый код использует неонные функции, и чтобы скомпилировать его, я должен включить armeabi-v7a, но это влияет на обычный c-код (он разбивается на некоторых младших устройствах).

Итак, если система сборки android не была чрезмерно навязчивой, мне не пришлось бы задавать вопросы, но мне кажется, что мне не удалось скомпилировать один файл для armv6 и другого файла для arm7-neon.

Может ли кто-нибудь дать какие-либо подсказки, если это выполнимо?

Edit
Прежде чем пытаться ответить и растрачивать интернет-чернила, должно быть ясно, что это основные моменты:
  1) сделать только ОДИН lib.
  2) сделать сборку, которая работает на armv6 (неонные устройства, например armeabi).
  3) позволяют этой сборке также содержать код NEON (который может быть выполнен на основе обнаружения времени выполнения cpu, обнаружение cpu выходит за рамки вопроса).
  4) Код NEON поступает из файла c/cpp и написан с использованием неонных функций.

Опускание любой части этих требований полностью теряет смысл вопроса

4b9b3361

Ответ 1

Недавно я нашел другой способ обойти ограничения NDK. Мое дело не было связано с NEON, но для вас тот же хак мог бы выполнить эту работу.

Хитрость заключается в использовании существующего механизма тега NDK для указания специального CFLAGS для кучи файлов. Вот как вы это делаете:

Сначала перечислите источники, относящиеся к неона. Вы не можете использовать суффикс .neon, как описано в docs/CPU-ARM-NEON.html, потому что build-binary.mk обнаруживает, что вы не нацеливаете armeabi-v7a. Я использую следующий метод:

LOCAL_NEON_SRC_FILES := imgproc/neon_utils.c \
                        videoproc/usingneon.cpp
LOCAL_SRC_FILES := main.c \
                   imgproc/img.c \
                   videoproc/video.cpp

LOCAL_SRC_FILES += $(LOCAL_NEON_SRC_FILES)

Теперь определите CFLAGS для NEON:

LOCAL_NEON_CFLAGS := -mfloat-abi=softfp -mfpu=neon -march=armv7

Наконец, добавьте следующую магическую строку в ваш Android.mk:

TARGET-process-src-files-tags += $(call add-src-files-target-cflags, $(LOCAL_NEON_SRC_FILES), $(LOCAL_NEON_CFLAGS))

Если у вас есть несколько двоичных файлов для сборки, вы, вероятно, захотите $(LOCAL_NEON_SRC_FILES) быть reset на

include $(CLEAR_VARS)

Для этого добавьте следующее к Android.mk или Application.mk:

modules-LOCALS += NEON_SRC_FILES

Примечание: Я не пробовал эту магию для NEON, мне она была нужна для совершенно разных целей. Возможно, вам понадобится адаптация для достижения желаемых параметров компиляции для ваших файлов и для вашего проекта. Я использую NDK r.8b, и я не проверял, будет ли это работать на более ранних (или более поздних) версиях.

Ответ 2

Если вы поместите код NEON в отдельный модуль (статическая библиотека или общая библиотека), вы можете вручную настроить CFLAGS для этого модуля в Android.mk на свой желая.

Если у вас есть файлы C, которые используют #ifdef __ARM_NEON __ вокруг встроенных функций, лучшим выбором было бы поместить эти файлы в разделяемые библиотеки - один скомпилирован для v6, другой для неона.

Я обычно загружаю такие "дополнительные" библиотеки непосредственно из Java, так что основной нативный код вообще не заботится об этих изменениях.


Обновление: Вот простой пример, который использует статическую библиотеку:

Android.mk

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE    := neon_utils
LOCAL_SRC_FILES := neon_add.c
LOCAL_CFLAGS += -mfloat-abi=softfp -mfpu=neon -march=armv7
include $(BUILD_STATIC_LIBRARY)

NDK_PATH:=$(call my-dir)/../..

include $(CLEAR_VARS)
LOCAL_MODULE    := test_conditional_load
LOCAL_C_INCLUDES := $(NDK_PATH)/sources/cpufeatures
LOCAL_SRC_FILES := main.c
LOCAL_STATIC_LIBRARIES  :=  neon_utils cpufeatures

include $(BUILD_EXECUTABLE)

include $(NDK_PATH)/sources/cpufeatures/Android.mk

main.c

#include <stdio.h>
#include <cpu-features.h>

void neon_add(int32_t * ptr);

int main()
{
    int32_t int32_4[] = {2,3,4,5};

    if (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON)
    {
        neon_add(int32_4);
        printf("neon\n");
    }
    else
    {
        printf("not neon\n");
    }
    printf("values = %d, %d, %d, %d\n", int32_4[0], int32_4[1], int32_4[2], int32_4[3]);
    return 0;
}

neon_add.c

#include <arm_neon.h>

void neon_add(int32_t * ptr)
{
    int32x4_t vin = vld1q_s32(ptr);
    int32x4_t vout = vaddq_s32(vin, vin);
    vst1q_s32(ptr, vout);
}

Ответ 3

Используя эту ссылку http://www.kandroid.org/ndk/docs/CPU-ARM-NEON.html

Вы можете выборочно создавать определенные исходные файлы с поддержкой NEON, используя суффикс файла .neon. Надеюсь, вы сможете решить, относится ли это к выбору ABI...

Возможно, вы сможете поместить свой путь кода NEON в один файл и использовать условный файл make, как показано выше, для создания правильного файла, на основе которого вы нацеливаете ABI

Ответ 4

Этот фрагмент из документации, вероятно, поможет:

   # define a static library containing our NEON code
   ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
      include $(CLEAR_VARS)
      LOCAL_MODULE    := mylib-neon
      LOCAL_SRC_FILES := mylib-neon.c
      LOCAL_ARM_NEON  := true
      include $(BUILD_STATIC_LIBRARY)
   endif # TARGET_ARCH_ABI == armeabi-v7a

Это только компилирует mylib-neon при использовании armeabi-v7a, даже если вы используете тот же файл Android.mk для различных ABI. Для armeabi v6 он полностью пропустит его.

Ответ 5

Если вы ищете более простую реализацию:

Во-первых, убедитесь, что весь код, совместимый с NEON, условно скомпилирован только для ABI armeabi-v7a и дополнительно будет выполняться только в том случае, если во время выполнения он работает в реализации ARMv7, которая включает NEON:

/* 
   bar_better_on_neon.c
 */

#ifdef HAVE_ARMV7
#  include <arm_neon.h>
#  ifdef ANDROID
#    include "cpu-features.h"
#  endif
#endif

#ifdef HAVE_ARMV7 
static int check_for_neon(void)
{
#  ifdef ANDROID
    // Not all Android devices with ARMv7 are guaranteed to have NEON, so check.
    uint64_t features = android_getCpuFeatures();
    return (features & ANDROID_CPU_ARM_FEATURE_ARMv7) && (features & ANDROID_CPU_ARM_FEATURE_NEON);
#  elif defined(__APPLE__)
    return 1;
#  else
    return 0;
#  endif
}
#endif

void bar(void)
{
#ifdef HAVE_ARMV7
    if (check_for_neon()) {

        /* here put neon code */

    } else {
#endif

        /* here put non-neon code */

#ifdef HAVE_ARMV7
    }
#endif
}

Здесь check_for_neon() использует библиотеку cpufeatures NDK. Затем в вашем файле Android.mk:

LOCAL_SRC_FILES := foo.c bar_better_on_neon.c
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
  # Compile the one file in NEON mode.
  LOCAL_SRC_FILES := $(subst bar_better_on_neon.c, bar_better_on_neon.c.neon,$(LOCAL_SRC_FILES))
  LOCAL_CFLAGS += -DHAVE_ARMV7=1
endif

Ответ 6

Да, в вашем файле Application.mk добавьте:

APP_ABI := armeabi armeabi-v7a
LOCAL_ARM_NEON := true

NDK не добавит поддержку NEON к libe armeabi, поскольку они являются взаимоисключающими, просто добавляя эти строки и компилируя, как вы обычно делаете, создадут два отдельных файла. Вы включаете их как в свой apk в структуре каталогов, в которую они были экспортированы, так и при загрузке устройство автоматически загружает неоновый файл.