NDK on Android Studio keeps rebuilding all the time, takes forever - android

I have a big Android Studio project that has a separate module which contains native code.
The native build is defined with CMake and includes a bunch of source files of C++ code.
I noticed that since a very recent update (might be Android Studio 3.5), NDK rebuilds everything ALL THE TIME.
It can happen with a small change in Java code, switching flavor in an unrelated module in the project, incrementing version code, etc.
This is a major problem, since it can waste 10 minutes at a time for no reason.
I could not find a reasonable way to profile NDK builds in Android Studio and check what's causing the rebuild or what's taking so long.
Unfortunately the project's build files are too big to attach here. Any pointers for things to look after?

For the C/C++ code that you build with cmake, make sure you point cmake to a directory where it can keep its object files and binary outputs.
Let's say you have a dependency on Game in your top level CMakeLists.txt like so:
# dependency: Game
set ( game_src_DIR ../Game )
add_subdirectory( ${game_src_DIR} ${CMAKE_CURRENT_BINARY_DIR}/game )
Then the second parameter to add_subdirectory specified the place where AndroidStudio will keep the object files.
The debug and release object files will live in different subdirs, as will each dependency, so switching debug/release will not clash.

This appears to have been a regression in behavior from Android Studio 3.4 and has been fixed in Android Studio 4.1 Canary 4. Release notes are here.

Often, it helps to split the AS project such that the C++ part, possibly with its Java wrappers become a separate (library) module. This module will hopefully be more stable, not sensitive to increments of app version code.
Such module should not define many flavors, but have careful matching to the flavors of other modules. Sometimes, it makes sense even to disable "debug" variants for such library. There was an effort of the NDK team to better handle debug vs. release build switching, but this is still tricky.
But if after these improvements, insignificant changes to the project still cause massive rebuild, I would suggest to consider ccache.

Related

Same native code rebuilt for every build variant [duplicate]

I have a project with C++ code (JNI) and lots of build variants and combinations. These are used to implement different brandings / flavors of the app (i.e. colors, styles, icons, ...).
For example there could be build variants for n customers :
customerNDebug
customerNDebugproguard
customerNRelease.
Anyway, the C/C++ layer is the same for each product flavor.
Normally CMake in Android Studio compiles C code for every build variant. This makes sense if you have build variants like "debug" and "release" where the resulting code actually differs. However, for the build variants I have, the compiled output is always the same.
At the moment the compilation of C/C++ code is done using an external tool in our project and I want to compile using CMake in Android Studio only for proper IDE support of C/C++ code. So for me a single build would suffice.
Is it possible to tell Android Studio to build C/C++ code only once, no matter the build variants and flavors?
By default, Android Studio IDE together with CMake and Gradle will generate a series of native build tasks named with externalNative<BuildVariant>Build according to your build types and flavours. If you want to twist this behaviour, some workaround is as below:
Create an Android Studio module project which only builds your native code, e.g. shared-native.
Let the rest of your modules dependent on this project.
For this solution, you need to consider below points:
Put your .so files into a proper location that other projects can see and link with.
You can only include debug and release build types for this shared-native module project to avoid too many times of re-build. Or you can simply to let your other projects depends on the release type so that it will be built only ONCE.

ndk-build installs libraries even if no change. Can this be changed?

I'm using the Native Development Kit (NDK) in a project of mine, and I'm trying to automate the whole app build procedure with Python.
Whenever ndk-build is called, it copies the prebuilt shared libraries to libs/<abi>/, even if there's no changes in them or they already exist there. This causes problem when I call ant later on, as it detects changed files (the library timestamps are newer) and so rebuilds the apk without any need.
Is there a way to change the ndk-build behaviour so it checks for existing libraries in the libs/<abi>/ folder and if they need updating or some are missing, it will call ndk-build, otherwise, just proceed to the next build step?
I've tried using filecmp in Python, but as the timestamps are different between the prebuilt shared libraries and the installed ones, it doesn't work.
The OP probably doesn't need this any more, but I had the exact same problem, trying to set up a Makefile to build a project, so maybe this will be helpful to someone else in the future as well.
ndk-build is a wrapper around gnu make, that invokes a bunch of Makefiles in build/core directory of the ndk, so, while it's not universally applicable*, for your personal project you can modify those Makefiles to do whatever you want. I found a clean-installed-binaries target that a couple of build/install targets depended on, removing those dependencies fixed the issue with perpetual installs.
In whichever cases that clean target is necessary you can invoke it manually with:
ndk-build clean-installed-binaries.
*Given the time to come up with a clean opt-in solution you can submit a patch to ndk project, and if accepted it will eventually become universally applicable.

Debug Android Native located in dependent eclipse project

(ADK 21, NDK r8d, Eclipse Juno)
[I've built several Android apps so decent experience using ADK/NDK etc]
Eclipse project setup:
- AppProject (android, java, no jni)
- LibProject (android, java, Yes jni)
Previously, all of it was in one project - builds fine, runs fine, and native debugging worked great.
Then I split off the "reusable" portion to make a library of common code to use with multiple "AppProject" application front ends. (Everything still builds, links, packs, and runs okay)
However, when I run "AppProject", I can no longer debug the native library.
What is the solution?
Possible option #1:
- Modify "LibProject" Android.mk to export a PreBuilt that is used by AppProject?
- (I would have all the debug symbols so I'm thinking that would work okay)
Would I need to cnature the AppProject as well? In other words, so it has an Android.mk to import the output .so from LibProject
Possible option #2
- http://stackoverflow.com/a/14344377/735533
- that workaround uses ndk-gdb
- I'm hoping for a solution where I can debug LibProject in Eclipse directly when running AppProject
Is there a better way to debug the native code located in the dependent project "LibProject" when running the main application "AppProject"?
Tia
For those curious ...
I tried prebuilts ...
And it definitely seems the be the way to go (test project setup worked)
But the structure of my codebase is a bit heavy on the native/non-native crosstalk and didn't want to take the time (yet) to do a proper reorganization at the moment.
However, restructuring as a prebuilt is on my "Important ToDo" list now
Anywhere, here is my solution.
On Linux (unix flavors) ... use links - the sources are linked into each AppProject from LibProject.
Basically the "LibProject" becomes a sort of "template" during development - it is not built or used as a library directly. Rather, each AppProject becomes self-sufficient, standalone, application with the contents of the library project embedded in its own code tree. Best part is native debugging works like a charm again.
Although it sort of defeats the point of making, there are benefits - one common codebase for the "library" portion ... which is really what I desire for the time being.
Also, conversion to use as a true Library dependency by the Application projects for, say, eventual release builds is an easy switch. Once debugged and ready, the Library can be built separately, packed normally with the application "front ends", and upgraded independently of the applications.

IntelliJ - Include module but exclude from build

I am trying the following:
Include an Android Module in my project.
Excluding it from actual build (if you e.g. press rebuild project).
Background: The Android module compilation takes 20 sec I don't want to wait, because I am only doing desktop tests at the moment. But I can't remove the Android Module completely from the project, would loose refactoring features (would not run later after e.g. I renamed classes in library project).
Any ideas how I can tell him to e.g. not DEX the Android (overwrite the build in Android ANT script with empty one is one way which comes to mind). Any tips are welcome...
Chris

Does slicing a large Android project into Android libraries improve build time?

I have a rather large Android project, and it takes considerable amounts of time for the sdk to do the resource-parsing / dexing / etc. I'd like to improve this somehow.
I've read that Android library projects can contain resources now too. So we can also put Activities, Fragments, etc. in them.
Does this mean, that if I export parts of my large project into library projects which I reference from the main project, then I don't have to rebuild the already built (and not modified) libraries again, when I rebuild the main project? So I only have to do the resource-parsing / dexing / etc. for the modified libraries and possibly the main project, decreasing the overall build time in most cases.
Does this mean, that if I export parts of my large project into library projects which I reference from the main project, then I don't have to rebuild the already built (and not modified) libraries again, when I rebuild the main project?
Partially no, Android Library Project is not built directly, it is always built along with the dependent Main Project, when SDK compile/build the Main Project, SDK tools compile the Library Project into a temporary JAR file and uses it in the main project. whenever you re-build your Main Project, the referenced Library Project is re-built as a part of main project build life cycle, even though nothing changed in Library Project. Check out timestamp of the temporary JAR generated under your app-lib/bin folder for evidence, it always get changed every time yo build Main Project.
Quoting from official dev guide:
However, a library project differs from an standard Android application project in that you cannot compile it directly to its own .apk and run it on an Android device. Similarly, you cannot export the library project to a self-contained JAR file, as you would do for a true library. Instead, you must compile the library indirectly, by referencing the library in the dependent application and building that application.
When you build an application that depends on a library project, the SDK tools compile the library into a temporary JAR file and uses it in the main project, then uses the result to generate the .apk. In cases where a resource ID is defined in both the application and the library, the tools ensure that the resource declared in the application gets priority and that the resource in the library project is not compiled into the application .apk. This gives your application the flexibility to either use or redefine any resource behaviors or values that are defined in any library.
Android Library Project is different from regular java library project. where you can compile and build everything into and jar library once, and start import/use the class from reference jar dependencies in main project. Currently Android Library Project is designed on source-based mechanism, not compiled-code based library mechanism, as mentioned in this Android blog, although self-contained jar distribution is promised in future release (unfortunately not in neither r15, r16, r17 nor r18 yet).
Yes... The build system rebuilds what needs to be built unless you build Clean.
I wouldn't expect huge time savings here.
In my experience, the slowest step of compilation is actually the dexing of the output files, which can not be performed incrementally, so moving your code into libraries will not speed things up. Similarly, incremental compilation (when it works — it often doesn't with the Android toolchain) will work equally well with unchanged files spread over a bunch of projects as will unchanged files in a single project.
Of course, the best way to find the answer for your actual use case is to experiment on your actual code base. And there may also be code maintainability benefits to splitting your project up into independent modules.

Categories

Resources