I'm developing a cross-platform static C++ library and am wondering if there are any build flags for reducing the size of the final MyLib.lib and libMyLib.a files on each platform (iOS, Android, Windows)?
I understand that every single dependency gets pulled into the build process and this is where my file size is coming from.
Why is my static library so huge?
But shouldn't there be some way to have the Linker/Librarian remove code from MyLib based on dependency calls actually made rather than theoretically possible?
The Linker does this when building the final .EXEcutable, but it seems the same rules could apply at the library linking level.
Overall this is a big problem for me because my cross-platform library is around 500MB for Windows and around 200MB on iOS. Oddly, Android is a reasonable 3.5MB.
Related
I've been making an Android app with a GoLang library containing my shared code (currently just code for handling an sqlite database) with the intention of making an IOS version in the future using the same library.
Just out of interest I generated an IOS version of my library using gomobile bind -target=ios -ldflags=-s myproject and was very surprised to see the resulting framework folder came out at 37mb which may be a deal breaker (this makes a fairly basic app become huge)
My android library generated with gomobile bind -target=android/arm64 -ldflags=-s myproject comes in at only 1.7mb (even generating an android library that contains binaries for all architectures comes out at only 7mb)
So my question is, is there some way to reduce the size of the IOS binary? Theres not much info in the gomobile help.
I have a C++ codebase that is currently set up in Visual Studio (to run on Windows), with multiple Projects with inter-dependencies. I'm trying to bring it over to Android Studio, to get it running on Android.
I'm familiar with Visual Studio and C++, but quite new to Android Studio's Gradle and CMake.
My (possibly wrong) expectation is to try and treat Android Studio Projects like Visual Studio Solutions, and Android Studio Modules like Visual Studio Projects. Given that my codebase uses multiple Projects in Visual Studio, I am trying to create multiple Modules in Android Studio -- each one with their own build.gradle and CMakeLists.txt files.
The issue is that I cannot get one section of code (AS Module) to link with the other. I am compiling these different sections as STATIC using add_library() (I plan to have one Module that creates a SHARED library, to load into Java).
I can easily get the includes to work via include_directories("../OtherModule/src/"). However, I cannot get it to link. I cannot find the .so (or similar) file to link to (via target_link_libraries() or equivalent). When I extract the .arr file from a given Module, I do not see any .so or anything.
I realize that I could simply put the entire codebase under one Module (using one build.gradle and one CMakeLists.txt -- or network of CMakeLists.txt's using add_subdirectory()). I don't know if this is fine, or if it would take more/less time to build.
I'm sure that there could be multiple ways to set this up, and it could just be a matter of preference. All research that I've done thus far has only found strictly adding native code to the same module with Java code -- doing basic JNI native bridge stuff. I haven't been able to find a single article about multiple native Modules linking together.
I'm hoping that someone with more experience with native development on Android could help me out. Thanks!
TL;DR: Simplified scenario: (Without being concerned with the JNI native bridge) I have two Modules in Android Studio, both with only native code. I would like to have each Module have its own build.gradle and CMakeLists.txt, creating its own STATIC libraries. One Module depends on the other and must set the correct include and link directories. How do?! Is this even correct (or should there ever be only one Module with native code)?
I asked a related question here. It seems to me that AS...
...does not actually link the final module-library unless it's SHARED (it does allow static 'sub-libraries' within the module); consider making the final library shared - you will have to System.loadLibrary() it specifically in Java though.
...does not allow you to install files to other places (e.g., from your native module to your Android app). I work around this by fetching the library through set_target_properties( jniwrapper PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../libnative/build/intermediates/cmake/${BUILD_TYPE}/obj/${ANDROID_ABI}/libnative.so ) and setting BUILD_TYPE in build.gradle. Not overly elegant though.
Overall, this does not seem to be an encouraged use-case in AS...
I have been cross-compiling some Linux tools (and some of my own C code) to Android and one of the challenges that I face is that Android's libc has some missing/stripped components and I end up patching my code to make it work with Android's libc (for e.g. a problem like this http://credentiality2.blogspot.com/2010/08/compile-ncurses-for-android.html)
Q1 : How do I go about statically linking against glibc (and other dependencies) while cross-compiling with the arm toolchain (or ndk-build)?
Q2 : Is it a good idea to statically link against glibc for binaries for Android? Should I expect anything to break if I start statically linking? Are there any performance/memory issues?
I understand most of the pros and cons of static vs dynamic linking from here -
C++ application - should I use static or dynamic linking for the libraries? and
Static linking vs dynamic linking
So I wish to know if I should be statically linking glibc for Android when cross-compiling binaries.
First a small note on the libc. The Android libc is the Bionic libc (https://github.com/android/platform_bionic/) rather than the GNU libc (glibc). Thus the libc contained in the NDK is Bionic, as is the libc available on android devices.
As far as glibc is concerned, it is possible to build it with the NDK. However, it's name will clash with the system libc when installed on android devices. Note that this is only if you go for building a dynamic library. If you build the GNU libc as a static library, then the whole issue above is sidestepped, as you never need to install a static library.
Now to answer your questions:
Q1: If you're building the glibc using the NDK, then the Android.mk uses the variable BUILD_STATIC_LIBRARY to build static libraries. However, if you dont use the NDK, then you'll probably need to get into the a lot of headache(dont know how much). I can't tell you more on this as I haven't tried a build of glibc, either static or dynamic. Also, it seems that static linking with glibc is highly discouraged, at-least for non-mobile platforms.
From a breakage viewpoint, there is no difference between static and dynamic linking. From a start-up viewpoint, a static executable start up faster as the dynamic libraries loading step is not needed. There is no memory or execution speed penalty in either static or dynamic linked executables. Disk storage requirement is larger for static executables.
As far as problems with the bionic libc missing functionality, you can use the method used by most GNU software, which is, provide your own implementation of a function in case it is missing from the system libraries. I've compiled file-5.11, GNU make 3.82, diffutils-2.8 for Android passing the NDK toolchains/includes/libs to autotools (./configure ...). It seems that these programs contain implementations of most of the non-core library function, in case the standard libraries dont provide them (in this case Bionic).
Note: I'll try and build a static glibc and update the answer as and when I succeed/fail.
If you are going to use glibc instead of bionic, it may be worth looking into using the toolchain of a (compatible kernel generation) arm-linux distro rather than the ndk. This would especially be true if you were generating a command line executable. (People have experimentally shoved chroot debian environments on android devices all the way back to the G1)
For a jni sub (which remains the only officially endorsed vehicle for native application code) it could get a bit "interesting" with either toolchain, as you will be running in a process that has already mapped and is making ongoing use of the bionic libc to support the Dalvik VM. Presumably if you statically link the library's own dependencies you won't run into name conflicts, but I expect whatever path you choose this will be a learning experience about the inner workings - not that that's necessarily a bad thing.
Do you have to have ncurses? I successfully built curses for android with the ndk once. Also consider if the program is seriously leveraging that (ie, are you actually doing substantial text formatting?), or just using it for some little thing because it was assumed to be available on target systems?
Too less memory in HW phones and tablets, but HAXM works fine?
My basic problem is that my app (most likely JNI dynamic library loaded by my Java app) is too large. The Java app crashes without calling the JNI instructions using HW phones and templates. However it works fine with the HAXM emulator that just enlarge the primary memory of itself.
I need to reduce the size of the JNI dynamic library, I assume.
I have a huge number of C-functions, most of them not used?
Covering an topic area of application programming, more than 64000 entries and 995 are used. Making a C-program in Win32 the linker filter the unused stuff away. Real smooth.
However in Android Studio I have as usual a Java app written using a dynamic JNI library, that is the Android JNI standard use. There is no linker determine what functions are used or not. However I have a front-end JNI file that calls the other bunch of C-functions. The Java system do not analyse what JNI functions are called and find the tree of calls being able to sort it out, I assume? (Nor would a DLL in WIn32 do because it don't know what will be called, I assume.)
The static lib approach might work, how do I do it?
One idea is to create a static lib of the huge number of C-functions and when the standard Android JNI uses it by calls from the front end JNI file, I assume that this will only use the functions of the static library needed and drop the rest, like when linking for the Win32 C-program. I might be wrong?
Well, I tried to find out how to do a static lib in the Android Studio, and also how to use a proprietary static lib to be linked into the JNI dynamic lib. However it is very hard to find out by googling or searching by stackoverflow. I assume this approach is rare.
Does anyone know how to make a static JNI lib in Android Studio
Does anyone know how to use a static JNI lib in Android Studio making a Android app with a
JNI front-end calling the static lib functions?
And is able to describe it?
It might not be possible in the JNI and then it is good to know it is
impossible. Is it possible to get this optimisation made this way?
You can use a static library in Android Studio, but you should build it with ndk-build using Android.mk as configuration.
In your build.gradle you can refer to this prebuilt library "c:\android\obj\libmystatic.a":
model {
android.ndk {
moduleName = "hello-jni"
abiFilters += armeabi-v7a
ldFlags += "-LC:/android/obj"
ldLibs += "mystatic"
}
}
The issue is how to disguard unused functions in a JNI file
Well I answer my own question with the help of #Michaels hint.
The basic problem is a too huge APK for the HW Samsung Tab3 so it crashes, while the HAXM works fine. Using a small JNI dummy I initially made works in the Tab3 but not the real JNI code. My assumption is it is too large, well is it?
The idea of making a static lib using it when making the dynamic automatic JNI lib is redundant if the optimisations are available in other ways. The horror is to manually sort out what is used among more than 64K entries. Thanks in anyway #Alex.
Yes there are optimisations possible by setting the following flags in the app gradle:
android.ndk {
moduleName = "XXXX"
cppFlags.add("-ffunction-sections")
cppFlags.add("-fdata-sections")
cppFlags.add("-fvisibility=hidden")
CFlags.add("-ffunction-sections")
CFlags.add("-fdata-sections")
CFlags.add("-fvisibility=hidden")
ldFlags.add("-Wl,--gc-sections")
/*
* Other ndk flags configurable here are
* cppFlags += "-fno-rtti"
* cppFlags += "-fno-exceptions"
* ldLibs = ["android", "log"]
* stl = "system"
*/
}
This reduces my APK from 11Mb to 7Mb (removing the unused functions in the JNI part). And some changes in the app, reducing the Win64 app from 0,9Mb to 0,6Mb, reducing the APK to 6Mb. Setting the Build variant to arm7 debug (Tab3) the APK is 2,7MB but still crashes (on the load jni library command in the Main java).
How do I know the release size? - Is it possible to test?
The issue is how large the APK will be in release mode (I have the assumption it is smaller than debug mode) but release versions must be signed etc and my intension is not releasing the app for market but testing the size of it, see if the planned app possibly can fit in a commercial Android HW unit. If not I have to make a general redesign of my planned app, however being much wiser. But redesigning is a huge work and I rather like to be certain the original plan was impossible? Seeing apps like MS Office copies I assumed it must be possible.
Being trying to fiddle with the Build/Edit flavours the Gradle just complains putting away the debugging capabilities, so that was a dead end.
So the present question is:
Is there any possibility to find out and try the app in release shape without commercially releasing it?
I have a .a static library file that i have created using Code Blocks. It contains the function definition of a function that adds two numbers. I want to use this library in Android using NDK. I want to know how this can be done in detail. I am beginner at this, and therefore step-by-step explanation would be very helpful.
You have to recompile your static library for Android using the NDK first. A static lib compiled for a Linux system will certainly not work (different C and system libraries).
Plus, Android runs on 7 different architectures as of now, so if you want to properly support all of them, you should end up with 7 different versions of your .a static library.
You can then reference your library from another NDK module (.so files) that you can load from an Android application. Please follow the NDK documentation to see how this works, and samples here: https://github.com/googlesamples/android-ndk