【问题标题】:How to prevent from C++ to recompile all files in Android NDK?如何防止 C++ 重新编译 Android NDK 中的所有文件?
【发布时间】:2018-08-08 01:20:55
【问题描述】:

您好,

我在一个包含大量 C++ 文件的项目中使用带有 NDK 和 JNI 的 Android Studio。当我在单个 C++ 文件中进行更改时 除非我重建整个项目并刷新整个项目,否则它将不适用于代码 C++ 文件,因此它们必须重新编译。每次小改动编译过程都需要 3 多分钟,一天做 20 次,你就损失了一个小时。

根据今天,在我对文件进行更改后,我会去

构建 >> 刷新链接的 C++ 项目,

然后运行项目,从而对所有文件进行完整、冗余的编译。

我正在寻找方法让编译器仅刷新更改的文件,从而缩短构建过程。

注意:这个问题只出现在windows中,当我在Mac上运行Android Studio时,编译器只重新编译相关文件。

这是我的 CMakeLists.txt 文件:

cmake_minimum_required(VERSION 3.4.1)

FILE(GLOB CPP_SRC
     "src/main/cpp/*.c"
     "src/main/cpp/*.h"
     "src/main/cpp/*.cpp"
     "src/main/cpp/*.hpp"
 )


add_library(MyLib

             SHARED
             ${CPP_SRC} )

find_library(
              log-lib
              log )

target_link_libraries(
                       MyLib

                       ${log-lib} )

target_link_libraries(MyLib
                      android
                      log
                      EGL
                      GLESv2)

还有我的 gradle.build 文件:

apply plugin: 'com.android.library'

android {
    signingConfigs {
        config {
            keyAlias '*****'
            keyPassword '*****'
            storeFile file(*****)
            storePassword '*****'
        }
    }
    compileSdkVersion 27
    buildToolsVersion '27.0.3'
    defaultConfig {

    minSdkVersion 16
    targetSdkVersion 27
    versionCode 1

    versionName "1.0"
    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

    externalNativeBuild {
        cmake {

            arguments "-DANDROID_ARM_NEON=TRUE", "-DANDROID_TOOLCHAIN=clang", "-DANDROID_STL=c++_shared", "-DCMAKE_BUILD_TYPE=Release", "-DANDROID_CPP_FEATURES=rtti exceptions"
            cppFlags "-D__STDC_FORMAT_MACROS", '-Ofast', '-fsigned-char', "-std=c++14", "-frtti", "-fexceptions", "-mtune=arm7", "-mfpu=vfpv3-d16", "-mfloat-abi=softfp", "-Wall",
                    "-DCOMPILE_EUROPE_ID_AND_FACE_OCR_MANAGER",
                    "-DCOMPILE_FRENCH_PASSPORT_SIGNATURE",
                    "-DCOMPILE_FRENCH_ID_BACK_OCR",
                    "-DCOMPILE_FRENCH_PASSPORT_SIGNATURE_MANAGER",
                    "-DCOMPILE_PASSPORT_AND_FACE_OCR_MANAGER",
                    "-DCOMPILE_MRZ_OCR",
                    "-DCOMPILE_FRENCH_ID_BACK_OCR_MANAGER"
        }

        ndk {
            abiFilters 'x86', 'armeabi-v7a'
        }
    }

    splits {
        abi {
            enable true
            reset()
            include 'x86', 'armeabi-v7a'
            universalApk true
        }
    }
}
    buildTypes {
       release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 
           'proguard-rules.pro'
            signingConfig signingConfigs.config
    }
}
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }

    libraryVariants.all { variant -> variant.outputs.all { output -> 
    outputFileName = "${"libScanovateImaging"}.aar" }
        }
    }

    allprojects {
            repositories {
            jcenter()
            maven {
                url "https://maven.google.com"
            }
        }    
    }
    dependencies {
        implementation 'com.google.android.gms:play-services-vision:15.0.0'
        implementation 'com.android.support:recyclerview-v7:27.1.1'
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        implementation 'com.android.support.constraint:constraint-layout:1.1.0-beta6'
        implementation 'com.android.support:appcompat-v7:27.1.1'
        implementation 'com.android.support:design:27.1.1'

}

提前致谢!

【问题讨论】:

  • 可能是您项目的Application.mk 或Android.mk 文件有问题。对 Android Studio 了解不够,无法确定。
  • 如果 Windows 上的这种错误行为只发生在 Android Studio 中,但命令行 ndk-build 或 cmake 可以正确进行部分重新编译,则可以运行终端窗口中的本地构建(确保使用与 AS 完全相同的路径和参数)。
  • 您的minifyEnabled true 文件中有minifyEnabled true 属性吗?
  • 这可能是因为GLOB 吗?我的意思是,如果您明确列出源文件,这可能会得到解决。而且我认为您不需要${CPP_SRC} 中的.h 和.hpp 文件
  • 您的build.gradle 文件中有错字(libraryVariants.all 的花括号过多)。我已经测试了两个ABIs 和ndkBuild 是否正确(请参阅更新的答案-> 结构)。 splits 没问题。正如link 所建议的那样,它必须是您的CMakeLists.txt。像我一样展示你的结构(它将在不同的地方)。

标签: android android-studio android-ndk java-native-interface


【解决方案1】:

终于找到问题的原因了。

在我的项目中,我使用过 symlink C++ 文件。 NDK 无法立即应用在这些文件中所做的更改,并且它们 除非您重建整个项目,否则不会在您的应用中表达。

解决方案是使用硬拷贝文件。

如果我能找到一些正确处理符号链接文件的方法,那就更好了 满足我的需要。在那之前,我至少可以编辑单个或多个文件,而无需重新编译整个项目。

这是一个相对深奥的情况,但可能有助于 将来的某个人。

【讨论】:

    【解决方案2】:

    简介

    我认为这在 Android Studio(更具体地说是 NDK 构建系统)中已经存在很长一段时间(从投诉来看)。现在,在最新版本中,它终于准备就绪并且可以工作了(希望如此)。

    注意:gradlew 构建速度明显快于使用 Android Studio IDE,并且可以使用批处理文件脚本 (.bat) 构建。

    CMake 可能的问题(P = 问题,C = 原因,S = 解决方案)

    (P1) Android Studio 如果支持多个 ABI,则每次都会重建所有内容,请参阅 this SO Q/A。
    (C1) 构建变体都具有相同的 .o 文件输出目录。
    (S1) 您需要将构建目录拆分为发布/调试和不同的 ABI。

    我的设置 (ndkBuild)

    Android Studio 3.1, NDK release 10, gradle 4.4版(插件3.1.0)

    我有 2 个库要构建(libhello_world.so 有 1 个 c++ 文件,libjni_photoeditor.so 有 24 个 c++ 文件)。

    我正在使用 externalNativeBuild -> ndkBuild 到 build 我的本机代码(您也可以使用 CMake,我还没有测试过)。

    应用级build.gradle:

    apply plugin: 'com.android.application'
            android {
                compileSdkVersion 25
    
                defaultConfig {
                    applicationId "xxxxxxxxxxxxxxxxxxxxx"
                    minSdkVersion 16
                    targetSdkVersion 16
                    versionCode 1
                    versionName "1.0"
                    ndk {
                             abiFilters 'armeabi-v7a' //,'x86'
                    }//ndk
                }//defaultConfig
    
                buildTypes {
                    release {
                        minifyEnabled true
                        proguardFiles.add(file('proguard-android-optimize.txt'))
                        proguardFiles.add(file('proguard-rules.pro'))
                    }//release
                    debug {
                        minifyEnabled false
                        jniDebuggable true
                        renderscriptDebuggable true
                    }//debug
                }//buildTypes
    
                externalNativeBuild {
                    // Encapsulates your CMake build configurations.
    //              cmake {
    //                // Provides a relative path to your CMake build script.
    //                path "src/main/cpp/CMakeLists.txt"
    //              }
                    ndkBuild {
                    //****this is the working build****
                        path 'src/main/cpp/Android.mk'
                    }//ndkBuild
                }//externalNativeBuild
            }//android
    
            dependencies {
            }//dependencies
    

    Application.mk:

    APP_ABI := armeabi-v7a
    APP_PLATFORM := android-19
    APP_STL := stlport_static
    

    Android.mk:

    #================================================
    LOCAL_PATH := $(call my-dir) #only call it ONCE !
    #================================================
    include $(CLEAR_VARS)
    LOCAL_MODULE      := hello_world
    LOCAL_MULTILIB := 32
    LOCAL_SRC_FILES :=  hello_world.cpp
    include $(BUILD_SHARED_LIBRARY)
    #================================================
    include $(CLEAR_VARS)
    LOCAL_MODULE      := libjni_photoeditor
    LOCAL_MODULE_TAGS := optional
    LOCAL_SHARED_LIBRARIES := libm liblog libjnigraphics
    LOCAL_LDLIBS := -lm -llog -ljnigraphics -lbcc
    LOCAL_LDLIBS := -lm -llog -ljnigraphics
    LOCAL_SRC_FILES := _jni.cpp utils.cpp quantize.cpp #etc.. 24 files
    LOCAL_CFLAGS := -Werror \
        -I$(OUT)/../../../../frameworks/compile/libbcc/include
    LOCAL_LDFLAGS := -L$(OUT)/system/lib
    include $(BUILD_SHARED_LIBRARY)
    

    测试1.Android Studio Build -> Build APK(s) build

    (A) 修改我的一个项目 24 个C++ 文件 (quantize.cpp) 并重建。

    (B) Build -> Build APK(s)

    (C) 仅 C:\Android\PhotoRend1\app\build\intermediates\ndkBuild\debug\obj\local\armeabi-v7a\objs-debug\jni_photoeditor\quantize.o 时间戳改变(和图书馆)。

    测试2.gradlew终端窗口(命令行)构建

    从项目根目录我使用terminal window 中的gradlew 到assemble 我的apk。

    (1) 一切都是最新的构建:

    C:\Android\PhotoRend1>gradlew assembleDebug

    Starting a Gradle Daemon, 1 busy and 1 incompatible and 1 stopped Daemons could not be reused, use --status for details
    > Configure project :app
    > Task :app:externalNativeBuildDebug
    Build hello_world armeabi-v7a
    make.exe: `C:/Android/PhotoRend1/app/build/intermediates/ndkBuild/debug/obj/local/armeabi-v7a/libhello_world.so' is up to date.
    Build jni_photoeditor armeabi-v7a
    make.exe: `C:/Android/PhotoRend1/app/build/intermediates/ndkBuild/debug/obj/local/armeabi-v7a/libjni_photoeditor.so' is up to date.
    BUILD SUCCESSFUL in 3m 46s
    

    (2) 修改我的项目之一 24 C++ 文件 (quantize.cpp) 并重新组装。

    (3) 一个文件更改是最新版本:

    C:\Android\PhotoRend1>gradlew assembleDebug

    > Configure project :app
    > Task :app:externalNativeBuildDebug
    Build hello_world armeabi-v7a
    make.exe: `C:/Android/PhotoRend1/app/build/intermediates/ndkBuild/debug/obj/local/armeabi-v7a/libhello_world.so' is up to date.
    Build jni_photoeditor armeabi-v7a
    [armeabi-v7a] Compile++ thumb: jni_photoeditor <= quantize.cpp
    [armeabi-v7a] SharedLibrary  : libjni_photoeditor.so
    BUILD SUCCESSFUL in 59s
    

    (4) 如您所见,它进行了增量构建。

    结构(带有abiFilters 'x86', 'armeabi-v7a'):

    C:\Android\PhotoRend1\app\build\intermediates\ndkBuild
    |
    V
    └───debug
        └───obj
            └───local
                ├───armeabi-v7a
                │   └───objs-debug
                │       ├───hello_world
                │       └───jni_photoeditor
                └───x86
                    └───objs-debug
                        ├───hello_world
                        └───jni_photoeditor
    

    一些链接: Manual NDK updates

    【讨论】:

    • 我已将我的 gradle 更新到 4.4。我正在使用 android 3.1.2 和 NDK 16。我必须使用 CMake 构建本机代码。我已经使用 gradlew assemblerelease 从 cmd 构建了项目,但问题仍然存在。可以使用 CMake 测试您的解决方案吗?
    • 我已经添加了我的 CMake 和 gradle 文件。我也会尝试调查您的最新答案
    猜你喜欢
    • 1970-01-01
    • 2011-09-16
    • 1970-01-01
    • 1970-01-01
    • 2014-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多