如何修复Android项目构建失败,提示“.so不是ABI”

huangapple go评论112阅读模式
英文:

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

问题

我有一个项目,之前使用的是Android Gradle插件7.4.2版本,我使用升级助手更新到了8.0.2版本,但现在我的项目无法构建,出现以下错误:

> 原因:从路径中提取的jni
> /Users/user01/.gradle/caches/transforms-3/4445827a66e5ef9b85054fadb96c8209/transformed/jetified-armnn.delegate-23.05/jni/arm64-v8.2-a/libarmnn_delegate_jni.so
> 不是ABI

有人知道是否有办法在Gradle中指定不使用该库的arm64-v8.2-a ABI版本吗?我尝试添加以下内容:

    ndk {
        // 指定Gradle应该构建并与您的应用程序一起打包的本地库的ABI配置。
        abiFilters 'arm64-v8a'
    }

还有

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

但这些都没有帮助。如果我恢复升级之前的版本,项目就能正常构建,但我想使用最新版本的Gradle插件。

编辑:额外信息,此依赖项以.AAR文件的形式提供,并在其中包含了编译后的本地.so文件的arm64-v8a和arm64-v8.2-a版本。在较旧的Android Gradle插件版本中,v8.2版本似乎被忽略了,但现在它被自动检测到并引发了这个问题?

英文:

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?

答案1

得分: 2

错误触发的代码位于MergeNativeLibsTask.kt文件中:

/**
 *  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  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
    }
}

根据您的错误以"jni"开头,似乎在您的情况下,它选择了路径的"jni"部分作为提取的ABI。

代码看起来要求受支持的ABI名称要么是相对路径的第一个段落,要么是相对路径之外的目录的名称。

在您的情况下,我猜测您有一个文件值为/Users/user01/.gradle/caches/transforms-3/4445827a66e5ef9b85054fadb96c8209/transformed/jetified-armnn.delegate-23.05/jni/arm64-v8.2-a/libarmnn_delegate_jni.so,以及一个相对路径arm64-v8.2-a/libarmnn_delegate_jni.so

  • 第一个("case 1")检查将尝试匹配"arm64-v8.2-a"与已知ABI,显然失败。
  • 在else路径中,我们通过向上跳两次(相对路径中的元素数)找到了根,最终得到/Users/user01/.gradle/caches/transforms-3/4445827a66e5ef9b85054fadb96c8209/transformed/jetified-armnn.delegate-23.05/jni。该目录的名称是"jni",这也不匹配任何已知的ABI。因此,出现错误。

我看不到使此函数通过的方法,除非确保不会为此文件调用它。如果可能的话,我不知道如何做到这一点(但我绝对不是该领域的专家)。另一种选择是从依赖项中删除"不良" ABI(如果您有控制权),接受的ABI名称列表应该在这里

这曾被报告为Google问题跟踪器上的一个错误,但似乎没有太多(公开的)进展。如果您没有新的信息要添加,请不要在这些评论中发布;请使用星形图标或"+1"按钮标记问题。

英文:

The code triggering the error resides in MergeNativeLibsTask.kt:

    /**
     *  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  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.

答案2

得分: 0

我最近遇到了相同的问题,出现了以下错误:

由于路径 C:\dev\androidStudioProject\myApp\core\build\intermediates\merged_jni_libs\apiaryGoogleDebug\out\core\arm64-v8a\lib-core.so 中提取的 out 不是 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)

经过一些试验后,移动我的 jni 源目录到默认位置后错误消失了。

注意:请记住,这个临时解决方案只在您拥有相关的 jniLibs 配置时有效,从您的堆栈跟踪中我假设您使用了包含 jniLibs 配置的第三方库(.aar)。因为根据我的发现,问题与新的 AGP 相关,它错误地选择 root.name 来检查 .so 文件的 ABI 类型。

以下是我所做的:

之前

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

库路径:

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

之后

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

然后将相对的 .so 路径移动到:

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

看起来新的 AGP 在选择/过滤相对根路径方面存在一些问题。

英文:

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

huangapple
  • 本文由 发表于 2023年7月24日 18:34:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/76753627.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定