1

I am using Gradle 3.0.1 in Android studio (3) trying to compile FFMPEG and armeabi-v7a has two shared libraries one with neon and one without. Typically in the old days before gradle, ndkbuild would compile my project without any issues, now with gradle and new ndkbuild, a bunch of issues showed up. The below isn't exactly how my code is but you can checkout my code in https://github.com/matthewn4444/VPlayer_lib. I have 3 questions about building in gradle with ndk.

I prebuilt 2 versions of libffmpeg.so, one for armeabi-v7a in neon and other without. I have a module for application-neon and application in the Android.mk file. I am not sure if there is a way to have just 1 .so file but since FFMPEG is complex I didn't want to wrap neon calls just to create one shared library.

My first question is, is it possible to just have 1 shared library in ndk to import into java with neon and non-neon support that links to larger 3rd party libraries or is having 2 separate libraries easier?


If I try to compile other architectures like arm64-v8a I will get an error:

* What went wrong:
Execution failed for task ':VPlayer_library:externalNativeBuildDebug'.
> Unexpected native build target application-neon. Valid values are: <projects>

This is because in my Android.mk file I have a module for non-neon and one for neon mainly for armeabi-v7a. I get the error above because the neon module is only available for armeabi-v7a, arm 64 will not have one so that error pops up on compile. If i create a dummy neon build it will allow the project to compile but then it bundles that fake neon shared library into the apk. I was thinking of building it like this and then having all dummy shared libraries removed from arm64, x86 etc from the build section before merging the shared libraries into the apk.

My second question is, is there a way to bypass this error or have special targets for specific architectures when building (abiFilters) without all this hacking? Code is below.

Android.mk

... <the module for normal application project>

ifdef FEATURE_NEON
include $(CLEAR_VARS)
LOCAL_ALLOW_UNDEFINED_SYMBOLS=false
LOCAL_MODULE := application-neon
LOCAL_SRC_FILES := application.c
LOCAL_C_INCLUDES := $(LOCAL_PATH)/ffmpeg/$(TARGET_ARCH_ABI)/include \
                    $(LOCAL_PATH)/application
LOCAL_SHARED_LIBRARY := application-neon
LOCAL_LDLIBS    += -landroid
LOCAL_LDLIBS += -llog -ljnigraphics -lz -lm -g $(LOCAL_PATH)/ffmpeg-build/$(TARGET_ARCH_ABI)/libffmpeg-neon.so
include $(BUILD_SHARED_LIBRARY)
else
# This is the dummy app to get the project to compile.
include $(CLEAR_VARS)
LOCAL_MODULE := application-neon
LOCAL_ALLOW_UNDEFINED_SYMBOLS=false
include $(BUILD_SHARED_LIBRARY)
endif

-------------------------------------------------------

build.gradle

externalNativeBuild {
    ndkBuild {
        targets "application", "cpufeatures", "application-neon" // fails for 'arm64-v8a' without that dummy module
    }
}

Next, when I change the abiFilters, it will include all the architectures that I built before besides the ones I selected. For example, if I built

ndk { 
    abiFilters 'armeabi-v7a', 'arm64-v8a'
}

then....

ndk { 
    abiFilters 'arm64-v8a'
}

and made an apk and then decided to only build arm64-v8a and built an apk, all the armeabi-v7a shared libraries are also in the apk. Android studio does not delete the other architectures compiled data from the build folder but bundles them into the apk as well. So for now I have a gradle task to remove them from build folder (the code is at the end).

My third question is if I did something wrong or if there is something easier I can do that does not require the gradle code below?

 def deleteOtherArchFromFolder(config, path) {
    new File(path).listFiles().each { folder ->
        if (!config.ndk.abiFilters.contains(folder.name)) {
            delete {
                delete folder
            }
        }
    }
}

task prebuildTask() {
    doLast {
        def config = android.defaultConfig

        // delete the obj files in build directory
        deleteOtherArchFromFolder(config, project.buildDir.absolutePath + '/intermediates/ndkBuild/debug/obj/local')
    }
}
preBuild.dependsOn(prebuildTask)

Thanks in advance!

user654628
  • 1,429
  • 1
  • 17
  • 37
  • Even before I finished reading your question, I have an advice for you: do your really need armeabi-v7a w/o NEON binary? What is the chance that your app will be run on a Tegra2 device? – Alex Cohn Jan 23 '18 at 08:16
  • regarding separate apps for different architectures, you can use [splits](https://developer.android.com/studio/build/configure-apk-splits.html#configure-abi-split). – Alex Cohn Jan 23 '18 at 13:37
  • to set different parameters for externalNativeBuild, you can use [flavors](https://stackoverflow.com/a/47361259/192373). – Alex Cohn Jan 23 '18 at 13:42
  • Since I was writing a library that other people use, I was including arm7 without neon, my other app (gaming) that use this library I am not sure how many people still play on their device without neon. Is it rare now a days to have a non-neon capable device? If you use splits then you get multiple apks for each arch? My app isn't that large (all arch about 60mb, 10mb per arch). – user654628 Jan 24 '18 at 04:38
  • The only armv7 chip without neon that I heard of, was Tegra2 from Nvidia, circa 2010. Have fun reading this discussion: https://groups.google.com/forum/m/#!topic/mozilla.dev.platform/F2rZrwyNSmQ – Alex Cohn Jan 24 '18 at 05:02
  • Ok. Do you know the answer of my 3rd question? – user654628 Jan 24 '18 at 07:03
  • The 3rd question can be resolved easier with splits. You split the APK not only to reduce the size (even though 60 MB is not too small), but also to hide all the unused binaries. – Alex Cohn Jan 24 '18 at 10:09

0 Answers0