I've been building an Android app off and on. It uses NDK to delivery audio mixing and synthesis capabilities. There is functionality I would like to add which exists in third party libraries such as Boost and
libsodium. There are a bunch of pieces necessary to make it all work: tooling, directory locations, options, ...
To start, Boost has quite a number of symbols, and even with improvements in Android Studio, which as I write this, is at v3.1.2, Android Studio will consume much CPU for many minutes while it builds symbol tables.
To help make this go a bit faster, it would probably be good to have the project installed on fast drives like SSD or NVME drives. In addition, if you have memory to spare, providing memory to Android Studio benefits the process. These are changes I made to my bin/studio.vmoptions file:
-Xms1024m
-Xmx4096m
-XX:ReservedCodeCacheSize=1024m
Some say the above doesn't work. An alternate location is in "Help" -> "Edit custom VM options" , which will create studio64.vmoptions, and put something similar in place:
-Xms1024m
-Xmx4096m
-XX:MaxPermSize=700m
-XX:ReservedCodeCacheSize=480m
-XX:+UseCompressedOops
Another suggested setting from Speed Up Gradle Build In Android Studio is "File" -> "Settings" -> "Gradle", and select "Offline Work".
Running 'invalidate caches' from the main File menu helped trial some changes in configuration. With three sets of boost include files (a set of files per each of the three architectures, it took about 12minutes for the Symbol Build to happen. I think for Boost, I will just use a single Include directory and list accordingly in the CMakeLists.txt file, rather than one for each architecture.
Changing anything in build.gradle, causes a total resync of everything, including rebuilding the Symbols. Uggh.
Reading in Reduce the APK size , I wonder if these Symbol Build issues have to with classes.dex file, as mentioned under the heading "Avoid enumerations". [in looking, it seems to be about MB in size, so that may not be the issue]
I'm not sure if it is really required, but
Android Studio: Background task running indefinitely suggested putting the following into /etc/sysctl.conf file and restarting with 'sudo sysctl -p':
# Increase the limit for Android Studio
fs.inotify.max_user_watches = 500000
For the really desperate, more suggestions are found at
Speed up your slow Android Studio.
When I had just one architecture, x86, the initial symbol build took a number of minutes. When I bumped it up to three architectures, 'x86', 'arm64-v8a', 'armeabi-v7a', building symbols seemed to take for ever. I had to add additional changes. In gradle.properties (in Gradle Scripts via Project window), I added:
org.gradle.daemon=true
I've scripted much of what I've learned, with the latest version available in
github -
rburkholder/android-ndk-build-libraries. Since the script is designed to run from within the libsodium directory and from within the boost directory, you will need to change into the directory of the library you wish to build, then run an absolute or relative path to run the script. BASE and PROJECT will need to be defined. You will probably want to read through the script first to understand the implied directory locations for the library, the build tools, the target android project, and the options available for the command line. Only some of the Boost libraries are built in this script. Additional ones can be easily added.
No matter what settings I applied to the boost shared library build, I was unable to remove the boost version codes at the end of the filename. There must be an option, but I havn't spotted it yet. So I build that library as a static library and link it it. Even changing 'version_type=linux' to 'version_type=none' in libtool.m4 in section 'linux*)' did not work. Even the patch suggested at NDK: Support for prebuild libs with full sonames didn't seem to work. But then I got to thinking, that it would be better to run with statically linked libraries. Since multiple architectures are packaged together, multiple architectures of the libraries will tend to bloat the package, where static libraries are reduced down to only the parts required. But having said that, for reference sake, there may be a solution to the Boost issue via an article at
Build boost without version number suffixes where they suggest commenting out some or all of the following in boostcpp.jam:
if $(type) = SHARED_LIB &&
! [ $(property-set).get ] in windows cygwin darwin aix &&
! [ $(property-set).get ] in pgi
{
result = $(result).$(BOOST_VERSION) ;
}
One of the next libraries to build will be ffmpeg, with a good write up at
How to integrate pre-built libraries in case of the FFmpeg.
Via a suggestion at How to build Boost 1.64.0 libraries (static, shared) for ARM, MIPS, x86, +64-bit variants (using clang), it is possible to view the file type of the built libraries:
$ ar -t libboost_thread.a
thread.o
once.o
future.o
$ ar -x libboost_thread.a
$ ls -alt
total 1352
drwxr-sr-x 1 rpb rpb 498 May 29 16:34 .
-rw-r--r-- 1 rpb rpb 12080 May 29 16:34 future.o
-rw-r--r-- 1 rpb rpb 4184 May 29 16:34 once.o
-rw-r--r-- 1 rpb rpb 308220 May 29 16:34 thread.o
-rw-r--r-- 1 rpb rpb 359568 May 29 16:32 libboost_thread.a
$ file future.o
future.o: ELF 32-bit LSB relocatable, ARM, EABI5 version 1 (SYSV), not stripped
A possible optimization for the boost libraries is to run 'ranlib' on them prior to copying over to the final project. This code would need to be modified to work with the directory structures and destinations in the script, but is recorded here for posterity. From the man page, ranlib "enerates an index to the contents of an archive and stores it in the archive".
echo "Running ranlib on libraries..."
libs=$(find "bin.v2/libs/" -name '*.a')
for lib in $libs; do
"$toolchain/bin/arm-linux-androideabi-ranlib" "$lib"
done
Some miscellaneous references for working with CMake and NDK: