【问题标题】:How to Exclude Duplicate C Shared Libraries (.so) in a Multi-Project Android Build?如何在多项目 Android 构建中排除重复的 C 共享库 (.so)?
【发布时间】:2014-08-10 11:40:21
【问题描述】:

在构建具有两个库模块的父项目时遇到“重复文件”冲突,这两个库模块使用相同的 libc++_shared.so 共享库。

(注意:请不要认为这是一个“重复的问题”。我已经阅读了几篇相关的帖子,这些帖子帮助我走到了这一步。但是,没有帖子提供适用于我的案例涉及 NDK 工件。)

当我只有 1 个这样的库模块时,构建工作正常。添加第二个库模块现在正在产生冲突。

考虑以下项目结构:1 个父项目,2 个“子”项目 - 但每个项目都位于同一目录级别(即不分层嵌套)

ProjectA/   (Parent)
    LibraryModuleA1/
        build/exploded-aar/com.package.name/
            LibraryModuleB1/<version>/jni/armeabi-v7a/libc++_shared.so
            LibraryModuleC1/<version>/jni/armeabi-v7a/libc++_shared.so
        build.gradle    (bgA1)
    Test_APK_Module A1T/
        build.gradle    (bgA1T)
    build.gradle    (bgPA)

ProjectB/
    LibraryModuleB1/  (Uses NDK)
        build/lib/armeabi-v7a/libc++_shared.so
        build.gradle    (bgB1)
    build.gradle    (bgPB)

ProjectC/
    LibraryModuleC1/  (Uses NDK)
        build/lib/armeabi-v7a/libc++_shared.so
        build.gradle    (bgC1)
    build.gradle    (bgPC)

库模块 A1 依赖于库模块 B1 和 C1。
A1 -> B1
A1 -> C1

项目 B 和 C 都具有基于 NDK 的代码并且可以正确构建/测试。两者都依赖于libc++_shared.so 共享库。

但是,在构建项目 A 时,我在 :LibraryModuleA1:packageDebugTest 任务期间收到以下错误:

Error: duplicate files during packaging of APK   /ProjectA/LibraryModuleA1/build/apk/LibraryModuleA1-debug-test-unaligned.apk
    Path in archive: lib/armeabi-v7a/libc++_shared.so
    Origin 1:  /ProjectA/LibraryModuleA1/build/exploded-aar/com.package.name/LibraryModuleB1/<version>/jni/armeabi-v7a/libc++_shared.so
    Origin 2:  /ProjectA/LibraryModuleA1/build/exploded-aar/com.package.name/LibraryModuleC1/<version>/jni/armeabi-v7a/libc++_shared.so
You can ignore those files in your build.gradle:
    android {
      packagingOptions {
        exclude 'lib/armeabi-v7a/libc++_shared.so'
      }
    }

* What went wrong:
Execution failed for task ':LibraryModuleA1:packageDebugTest'.
> Duplicate files copied in APK lib/armeabi-v7a/libc++_shared.so
    File 1: /ProjectA/LibraryModuleA1/build/exploded-aar/com.package.name/LibraryModuleC1/<version>/jni/armeabi-v7a/libc++_shared.so
    File 2: /ProjectA/LibraryModuleA1/build/exploded-aar/com.package.name/LibraryModuleC1/<version>/jni/armeabi-v7a/libc++_shared.so

:LibraryModuleA1:packageDebugTest FAILED

到目前为止我的尝试

  1. 我试图将建议的闭包添加到我的build.gradle 文件中,但是我应该将它添加到哪个build.gradle 文件中?我已将闭包添加到bgA1bgB1bgC1(一次一个),但没有成功。
  2. 建议的关闭表示使用exclude 'lib/armeabi-v7a/libc++_shared.so'。每个“子”库模块在build/lib 路径下构建libc++_shared.so 文件。但是,我注意到父库模块复制了build/exploded-aar 目录结构内jni/armeabi-v7a/libc++_shared.so 下的libc++_shared.so 文件。 (见上文)闭包应该改为exclude 'jni/armeabi-v7a/libc++_shared.so(即jni vs.lib)吗?
  3. 由于我使用的是 Gradle 插件 0.9.1,因此我尝试使用 pickFirst 代替 exclude,但这也没有成功。

有人可以帮助确定我应该如何为我的给定案例配置 `packagingOptions' 闭包吗?

感谢您的帮助!

【问题讨论】:

    标签: android c++ android-ndk android-gradle-plugin


    【解决方案1】:

    我遇到了同样的问题,但没有使用 exclude 或 pickFirst。所以我使用了一个有点丑陋的解决方法。想法是在主项目的构建目录中创建一个“native-libs”文件夹,从那里复制所有必需的 *.so 文件从 ndk 库项目中,然后告诉构建系统将这些库打包到 apk 中。

    在我的主项目(app 项目)中,我明确定义了包含我所依赖的 ndk 代码的模块列表

    // Ndk stuff. We have to explicitely manage our NDK dependencies
    ext.jniProjects = [project(':ndklib1'), project(':ndklib2'), project(':ndklib3')]
    apply from: '../depend_ndk.gradle'
    

    然后,'depend_ndk.gradle' 是一个 gradle 外部脚本,包含

    // Build helper for projects that depends on a native library with a NDK part
    // Define the list of ndk library you depend on in project main file :
    //   ext.jniProjects = [project(':ndklib1')]
    //   apply from : 'depend_ndk.gradle'
    buildscript {
        repositories {
            jcenter()
            mavenCentral()
        }
        dependencies {
            classpath 'com.android.tools.build:gradle:0.12.+'
        }
    }
    import com.android.build.gradle.tasks.PackageApplication
    
    // As a workaround, we create a new 'native-libs' folder in the current project and
    // copy all the .so we depend on into it
    def ndkLibsDir = new File(buildDir, 'native-libs')
    ndkLibsDir.mkdir()
    
    task copyDependingNativeLibs(type: Copy) {
        // Doc for copy http://www.gradle.org/docs/current/dsl/org.gradle.api.tasks.Copy.html
        println 'jniProjects ' + jniProjects
        jniProjects.each {
            from(new File(it.buildDir, 'native-libs')) {
                include '**/*.so'
            }
        }
        into ndkLibsDir
    }
    
    tasks.withType(PackageApplication) { pkgTask ->
        pkgTask.jniFolders = new HashSet<File>()
        pkgTask.jniFolders.add(ndkLibsDir)
        pkgTask.dependsOn copyDependingNativeLibs
    }
    

    【讨论】:

    • PackageApplication 如何被触发?在应用程序中 - 我在调试版本中没有看到它......所以我的调试 APK 包括......谢谢。
    • 你说得对,我无法让 copyDependingNativeLibs 自动运行。我认为将其添加为 pk​​gTask 的依赖项不是正确的做法。我真的没有时间找到解决方案,所以现在我只是在更改一些原生部分时运行'./gradlew app:copyDependingNativeLibs'。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-02
    • 1970-01-01
    • 1970-01-01
    • 2016-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多