Reputation: 340
I'm using the Android Studio with NDK and JNI in a project with a large amount of C++ files. When I make changes in a single C++ file it won't apply in the code unless I rebuild the whole project and refresh the entire C++ files so they have to recompile.
The compilation process takes more than 3 minutes for every small change. Make it 20 times a day and you have lost an hour.
According to today, after I make a change to a file I go to menu Build → Refresh Linked C++ Projects and then run the project, resulting in a full, redundant compilation of all files.
I'm looking for way for the compiler to refresh only the changed file, and as a result shorten the build process.
Note: This problem only occurs in Windows. When I run Android Studio on a Mac, the compiler recompiles only the relevant files.
This is my CMakeLists.txt file:
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)
And my build.gradle file:
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'
}
Upvotes: 11
Views: 3595
Reputation: 9153
I think this has been a problem for a long time (judging by the complaints) in Android Studio (more specifically the NDK
build system). Now, in the latest version, it is finally ready and working (hopefully).
Note: gradlew
builds are significantly faster than using the Android Studio IDE
, and can be built using a batch file script (.bat
).
(P1) Android Studio
rebuilds everything every time if multiple ABIs are supported See this SO Q/A.
(C1) Build variants all had the same output directory for the .o files.
(S1) You need to split out the build directory into release/debug and into the different ABIs.
Android Studio 3.1
, NDK release 10
, gradle
version 4.4 (plugin 3.1.0)
I have 2 libraies to build (libhello_world.so
with 1 c++ file, and libjni_photoeditor.so
with 24 c++ files).
I am using externalNativeBuild
-> ndkBuild
to build my native code (you could use CMake
also, I have not tested that).
app level build.gradle
:
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
defaultConfig {
applicationId "xxxxxxxxxxxxxxxxxxxxx"
minSdkVersion 16
targetSdkVersion 16
versionCode 1
versionName "1.0"
ndk {
}//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)
Build -> Build APK(s)
build(A) Modify one of my projects 24 C++
files (quantize.cpp
) and rebuild.
(B) Build -> Build APK(s)
(C) Only the C:\Android\PhotoRend1\app\build\intermediates\ndkBuild\debug\obj\local\armeabi-v7a\objs-debug\jni_photoeditor\quantize.o timestamp changed (and the library).
gradlew
terminal window (command line) buildFrom the project root I use gradlew
in a terminal window
to assemble
my apk
.
(1) Every thing is up-to-date build:
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) Modify one of my projects 24 C++
files (quantize.cpp) and re-assemble.
(3) One file changes is up-to-date build:
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) As you can see it did an incremental build.
Some links:
Manual NDK
updates
Upvotes: 3
Reputation: 340
Finally I have found the cause to the problem.
In my project I have worked with symlink C++ files. The NDK cannot immediately apply the changes made in these files and they won't be expressed in your app unless you rebuild the whole project.
The solution is to work with hard copy files.
If I find some way to work correctly with symlink files it would be better for my needs. Until then I can at least edit single or multiple files without recompiling the whole project.
This is a relatively esoteric situation but might be helpful for someone in the future.
Upvotes: 0