Компилировать отдельные файлы с NDK 13

с выпусками NDK 10 я использовал ndk-build для компиляции автономных двоичных файлов для многих различных ABIs и нескольких уровней API. Эти файлы должны быть включены в приложение. Тем не менее, я установил NDK на новую машину разработки как описанные в этой статье. Это привело к папке ndk-bundle в моем каталоге Android SDK. Я использовал для компиляции кода из командной строки, а затем скопировать двоичные файлы на ресурсы моего проекта Android Studio, но я не мог понять как это сделать с NDK 13, поэтому я попытался следовать учебник для включения моего собственного кода в проект Android Studio. Однако почти все последние инструкции предполагают, что нужно построить библиотеку, а не автономный двоичный файл, поэтому я не ушел далеко.

Я бы переключился на CMake, если бы понял, как заставить его работать. Мой родной проект имеет следующее (упрощенный) структура:

  • уроженца

    • Android.МК

      LOCAL_PATH := $(call my-dir)/my_tool/src
      include $(CLEAR_VARS)
      LOCAL_MODULE    := my_tool
      LOCAL_SRC_FILES := main.c
      include $(BUILD_EXECUTABLE)
      
    • применение.МК

      APP_ABI := all
      APP_PLATFORM := android-21
      
    • my_tool

      • src
        • main.c

как я могу скомпилировать это с помощью Android Studio или NDK из командной строки в нашей разработке Windows 10 машины?

Edit:

Я использую это в build.Gradle в:

externalNativeBuild {
    ndkBuild {
        path "../native/Android.mk"
    }
}

Gradle создает каталог .externalNativeBuild который содержит конфигурации сборки, но я не могу узнать, как на самом деле построить собственный код. При запуске gradle двоичные файлы не создаются.

Я не могу найти любой информация о конфигурации gradle для ndk-build.

2 ответов


Я старался следовать вашей упрощенной структуре как можно ближе.

вот файл app / build.Gradle в:

apply plugin: 'com.android.library'

android {
    compileSdkVersion 24
    buildToolsVersion "25.0.1"
    defaultConfig {
        minSdkVersion 21
        targetSdkVersion 24
        externalNativeBuild {
            ndkBuild {
                targets "my_tool"
                abiFilters "armeabi-v7a"
            }
        }
    }
    externalNativeBuild {
        ndkBuild {
            path "../native/Android.mk"
        }
    }
}

файл родной / Android.МК идентично вашему:

LOCAL_PATH := $(call my-dir)/my_tool/src
include $(CLEAR_VARS)
LOCAL_MODULE    := my_tool
LOCAL_SRC_FILES := main.c
include $(BUILD_EXECUTABLE)

у меня также есть файлы уроженца/главная.c и минимальный app / src / main / AndroidManifest.в XML:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="my.tool" />

Я не трогал корень построить.Gradle в скрипт, созданный Мастер Android Studio:

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.0-alpha3'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

теперь я могу построить проект и вот что я получаю:

$> file ./app/build/intermediates/ndkBuild/debug/obj/local/armeabi-v7a/my_tool
ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked (uses shared libs), not stripped

Android Studio показывает мой main.c на cpp папка в представлении по умолчанию:

enter image description here

обновление: иметь исполняемый раздели и упаковываются в APK, уроженца/Андроид.МК надо менять:

LOCAL_PATH := $(call my-dir)/my_tool/src

install: LIB_PATH := $(call my-dir)/libs

include $(CLEAR_VARS)
LOCAL_MODULE    := my_tool
LOCAL_SRC_FILES := main.c
include $(BUILD_EXECUTABLE)

install: $(LOCAL_INSTALLED)
    -mkdir $(LIB_PATH)
    -rm -r $(LIB_PATH)
    mv $< $(<:my_tool=lib-my_tool-.so)
    mv $(realpath $(dir $<)..) $(LIB_PATH)

.PHONY: install

и app / build.Gradle в нуждается в некоторой настройке:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 24
    buildToolsVersion "25.0.1"
    defaultConfig {
        minSdkVersion 21
        targetSdkVersion 24
        externalNativeBuild {
            ndkBuild {
                targets "my_tool"
                abiFilters "armeabi-v7a"
                arguments 'V=1', 'install'
            }
        }
    }
    externalNativeBuild {
        ndkBuild {
            path "../native/Android.mk"
        }
    }
    sourceSets {
        main {
            jniLibs.srcDirs = ['../native/libs']
        }
    }
}

это зависит от старый Хак который зависит от недокументированного поведения NDK и может сломаться без уведомления о будущем обновлении NDK.


если все, что вы делаете, это изменение версий NDK, то я считаю, что это довольно просто, и что нам не хватает чего-то простого. Я думаю, что вам нужно обновить переменную среды PATH, чтобы указать на новый ndk-bundle путь и попробуйте запустить ndk-build снова.

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

обновление

вот как создать исполняемый файл c++ с помощью Android Studio и NDK. Это без использования CMake, и это даже если у вас нет кода JNI.

app / build.Gradle в

sourceSets.main {
    // Do not run default ndkbuild
    jni.srcDirs = []
    // Place where .so libs are available
    jniLibs.srcDir 'src/main/libs'
}

task buildNative(type: Exec, description: 'Compile JNI source via NDK') {
    def ndkDir = android.ndkDirectory
    commandLine "$ndkDir/ndk-build.cmd", 'V=1',
            '-C', file('src/main/jni').absolutePath,
            '-j', Runtime.runtime.availableProcessors(),
            'all',
            'NDK_DEBUG=1'
}

task cleanNative(type: Exec, description: 'Clean JNI object files') {
    def ndkDir = android.ndkDirectory
    commandLine "$ndkDir/ndk-build.cmd",
            '-C', file('src/main/jni').absolutePath,
            'clean'
}

структура каталогов

вам нужно иметь папку с именем app/src/main/jni. Как вы можете видеть, приведенный выше код gradle просто звонки ndk-build против этого каталога. Вот как я рекомендую вам настроить каталоги:

  • JNI, у

    • Android.МК

      LOCAL_PATH := $(call my-dir)
      include $(call all-subdir-makefiles)
      
    • применение.МК

      APP_ABI := all
      APP_PLATFORM := android-21
      
    • уроженца

      • my_tool
        • src
          • main.c
      • Android.МК

        include $(CLEAR_VARS)
        LOCAL_C_INCLUDES := my_tool/src
        LOCAL_PATH := $(call my-dir)
        LOCAL_MODULE := my_tool
        LOCAL_SRC_FILES := my_tool/src/main.c
        include $(BUILD_EXECUTABLE)
        

здание

для build, вы можете либо запустить ndk-build С или gradle buildNative из корневого каталога проекта. Вы можете видеть, что в коде gradle, который я показал выше, есть задача с именем buildNative, так что это код gradle, который будет выполнен.

топ-уровня Android.mk файл помогает в том случае, если вы когда-либо добавляете больше модулей, которые будут построены под app/src/main/jni, он пересекает все подкаталоги в этом каталоге и вызывает любой другой Android.mk файлы, которые он находит.