How to fix Android project build failing with .so is not an ABI
Asked Answered
H

5

9

I have a project that was using Android Gradle Plugin 7.4.2, I used the upgrade assistant to update to 8.0.2 but now my project doesn't build with the following error:

Cause: jni extracted from path /Users/user01/.gradle/caches/transforms-3/4445827a66e5ef9b85054fadb96c8209/transformed/jetified-armnn.delegate-23.05/jni/arm64-v8.2-a/libarmnn_delegate_jni.so is not an ABI

Does anyone know if there is some way to specify in Gradle not to use the arm64-v8.2-a ABI versions of this library? I tried adding the following:

    ndk {
        // Specifies the ABI configurations of your native
        // libraries Gradle should build and package with your app.
        abiFilters 'arm64-v8a'
    }

and also

splits {
        abi {
            enable true
            reset()
            include "arm64-v8a"
        }
    }

but those didn't help. If I revert the upgrade the project builds fine, but I want to use the latest version of Gradle plugin.

Edit: For extra information, this dependency is coming in the form of a .AAR file and included within it is arm64-v8a and arm64-v8.2-a versions of the compiled native .so file. It looks like in older Android Gradle Plugin versions the v8.2 is just ignored but now it is getting automatically picked up and causing this issue?

Humoresque answered 24/7, 2023 at 10:34 Comment(0)
B
3

The code triggering the error resides in MergeNativeLibsTask.kt:

    /**
     * [file] is one of these two kinds:
     *    (1) /path/to/{x86/lib.so}
     *    (2) /path/to/x86/{lib.so}
     * Where the value in {braces} is the [relativePath] from the file visitor.
     * The first (1) is from tasks that process all ABIs in a single task.
     * The second (2) is from tasks the where each task processes one ABI.
     *
     * This function distinguishes the two cases and returns a relative path that always
     * starts with an ABI. So, for example, both of the cases above would return:
     *
     *    x86/lib.so
     *
     */
    private fun toAbiRootedPath(file : File, relativePath: RelativePath) : String {
        return if (abiTags.any { it == relativePath.segments[0] }) {
            // Case (1) the relative path starts with an ABI name. Return it directly.
            relativePath.pathString
        } else {
            // Case (2) the relative path does not start with an ABI name. Prepend the
            // ABI name from the end of [file] after [relativePath] has been removed.
            var root = file
            repeat(relativePath.segments.size) { root = root.parentFile }
            val abi = root.name
            if (!abiTags.any { it == abi }) {
                error("$abi extracted from path $file is not an ABI")
            }
            abi + separatorChar + relativePath.pathString
        }
    }

Based on the fact that your error starts with "jni", it appears that in your case, it picks the "jni" part of the path as the extracted ABI.

The code really looks like it requires a supported ABI name to be either the first segment of the relative path, or the name of the directory just outside of the relative path.

In your case, I surmise that you have a file value of /Users/user01/.gradle/caches/transforms-3/4445827a66e5ef9b85054fadb96c8209/transformed/jetified-armnn.delegate-23.05/jni/arm64-v8.2-a/libarmnn_delegate_jni.so and a relativePath arm64-v8.2-a/libarmnn_delegate_jni.so.

  • The first ("case 1") check will try to match "arm64-v8.2-a" with a known ABI, which apparently fails.
  • In the else path, we find the root by jumping upward two times (the number of elements in the relativePath), ending up with /Users/user01/.gradle/caches/transforms-3/4445827a66e5ef9b85054fadb96c8209/transformed/jetified-armnn.delegate-23.05/jni. The name of that dir is "jni", which also does not match any known ABI. Hence, the error.

I don't see any way to make this function pass except to make sure it is not called at all for this file. If that's possible, I don't know how (but I'm certainly no expert in the area). The other option is to remove the "bad" ABI from the dependency (if you have control over it) -- the list of accepted ones should be here.

This has previously been reported as a bug on the Google Issue Tracker, but there doesn't appear to be much (public) progress. Please do not post in those comments if you don't have anything new to add; mark the issue with the star icon or "+1" button instead.

Bernoulli answered 31/7, 2023 at 16:59 Comment(0)
W
3

I've experiencing the same issue recently with this error :

Caused by: java.lang.IllegalStateException: out extracted from path C:\dev\androidStudioProject\myApp\core\build\intermediates\merged_jni_libs\apiaryGoogleDebug\out\core\arm64-v8a\lib-core.so is not an ABI
        at com.android.build.gradle.internal.tasks.MergeNativeLibsTask$Companion.toAbiRootedPath(MergeNativeLibsTask.kt:375)
        at com.android.build.gradle.internal.tasks.MergeNativeLibsTask$Companion.access$toAbiRootedPath(MergeNativeLibsTask.kt:330)
        at com.android.build.gradle.internal.tasks.MergeNativeLibsTask$doTaskAction$fileVisitor$1.visitFile(MergeNativeLibsTask.kt:132)
        at org.gradle.api.internal.file.collections.ReproducibleDirectoryWalker.walkDir(ReproducibleDirectoryWalker.java:68)
        at org.gradle.api.internal.file.collections.ReproducibleDirectoryWalker.walkDir(ReproducibleDirectoryWalker.java:83)
        at org.gradle.api.internal.file.collections.ReproducibleDirectoryWalker.walkDir(ReproducibleDirectoryWalker.java:83)
        at org.gradle.api.internal.file.collections.DirectoryFileTree.walkDir(DirectoryFileTree.java:148)
        at org.gradle.api.internal.file.collections.DirectoryFileTree.visitFrom(DirectoryFileTree.java:126)
        at org.gradle.api.internal.file.collections.DirectoryFileTree.visit(DirectoryFileTree.java:111)

and after some trial and error, the error gone after moving my jni source dir to default.

Note: Keep in mind, that this temporary solution only work if you own the related jniLibs configuration, which from your stacktrace I assume that you use 3rd party library (.aar) that contain jniLibs configuration. Because in my finding, the issue is related to the new AGP that incorrectly select root.name to check .so file ABI type

Here's what I've done :

Before

sourceSets {
        getByName("main") {
            ...
            jniLibs.srcDir("src/main/jniLibs/core")
        }
}

lib path:

:core
   src/
        main/
               jniLibs/
                        core/
                           arm64-v8a/
                           armeabi-v7a/
                           x86/
                           x86_64/

After

sourceSets {
        getByName("main") {
            ...
            jniLibs.srcDir("src/main/jniLibs")
        }
}

and then move relative .so path to:

:core
   src/
        main/
               jniLibs/
                     arm64-v8a/
                     armeabi-v7a/
                     x86/
                     x86_64/

it seems the new AGP have some issue regarding to select / filtering relative root path

Woods answered 10/8, 2023 at 12:12 Comment(0)
D
1

I believe Davin solution is correct, but I'll just expand on it based on my observations.

In my case I built a Kotlin/Native library that targeted "AndroidNativeX64". That project built an so library.

In a separate project, I built a Kotlin Multiplatform project in Android Studio that used that so library.

The mistake I made was that I put the so library in an "src/jniLibs/x64" directory. What resolved the problem was moving the so library to the "src/jniLibs/x86_64" directory instead. In other words, there are specific names for the directories in the jniLibs directory. For some reason I was under the impression that you would put targeted "AndroidNativeX64" libraries in an x64 directory. It would have probably been better if the predefine target "AndroidNativeX64" was named "AndroidNativeX86_64" and perhaps I wouldn't have made that mistake.

Dystrophy answered 10/2 at 19:54 Comment(0)
A
0

I have faced similar issue during AGP migration from 7.5.1 to 8.4

My .so files were under

core
   src/
        main/
               jniLibs/
                     arm64-v8a/
                     armeabi-v7a/
                     x86/
                     x86_64/

and core.gradle was

sourceSets {
        debug {
            jniLibs.srcDirs = ["src/main/jniLibs/debug"]
        }
        release {
            jniLibs.srcDirs = ["src/main/jniLibs/release"]
        }
}

then i had change it to

for debug buildType

core
   src/
        debug/
               libs/
                     arm64-v8a/
                     armeabi-v7a/
                     x86/
                     x86_64/

and for release buildType

core
   src/
        release/
               libs/
                     arm64-v8a/
                     armeabi-v7a/
                     x86/
                     x86_64/

and inside core.gradle

sourceSets {
        debug {
            jniLibs.srcDir 'src/debug/libs'
        }
        release {
            jniLibs.srcDir 'src/release/libs'
        }
    }

then it worked.

Allain answered 9/9 at 8:0 Comment(0)
S
0

Try to go to you gradle cache folder /Users/user01/.gradle/caches/transforms-3/4445827a66e5ef9b85054fadb96c8209/transformed/jetified-armnn.delegate-23.05/jni and delete arm64-v8.2-a folder then build again

Also, would you mind using Configure multiple APKs for ABIs to target specific ABI listings in the Google tracker issue link if it works?

public static final String ABI_ARMEABI = "armeabi";
public static final String ABI_ARMEABI_V7A = "armeabi-v7a";
public static final String ABI_ARM64_V8A = "arm64-v8a";
public static final String ABI_INTEL_ATOM = "x86";
public static final String ABI_INTEL_ATOM64 = "x86_64";
Surtax answered 11/9 at 19:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.