Friday, November 4, 2016

Optimizing C++ android code for minimum size

Any more or less serious Android  C++ code (NDK) will immediately bring a huge piece of C++ stdlib into your native library, something like 150kb+ surplus per ABI (cpu arhitecture).
Even such as this:
char *data = new char[1000];
More funny example is having a huge complex C++ class defined (several kloc including several subclases), which is producing like 30kb binary when stack-instantiated ("MyClass obj;"), and like 200kb binary when created using "new" operator ("MyClass *obj = new MyClass()").

Long story short this all happens due to a huge amount of exception handling code (which invokes iostream and other bullshit)  linked to your code due to just a single "new" operator (to handle bad_alloc exceptions), and yes, -fno-exceptions won't help you at all.

Solution is to link against minimal system STL (the only one built with no exceptions code for new/delete), by modifying your application.mk (if you are using plain NDK build) with the following line (there are a lot examples on the net):
APP_STL := system
I wasn't able to find ready solution for the modern Gradle (Android Studio) + CMake case, so had to spend a bit of time studying this fairly bad documented stuff. Finally, here we go, a piece of config you came here for (place it into your module gradle file) undo "android.defaultConfig.externalNativeBuild.cmake" element:
arguments "-DANDROID_STL=system", "-DCMAKE_CXX_STANDARD_LIBRARIES=-Lm"
Technically a ADROID_STL parameter definition should be enough, but I was still getting a rogue
"cxx-stl\gnu-libstdc++\4.9\libs\...\libsupc++.a" library sneaking into my linking command, so standard libraries override came to fix.

While we are here:
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
set(CMAKE_C_VISIBILITY_PRESET hidden)
set_property(TARGET native-lib PROPERTY INTERPROCEDURAL_OPTIMIZATION True)
 Adding these lines to your CMakeLists.txt should hide your exports not marked with JNIEXPORT, and MAY BE enable link-time-compilation/optimization for some ABIs (third line, notice library name argument). Might save you a few KBs as well (hiding non marked exports is a good thing anyway).