My Android application (game) uses native C++ code for certain operations. That is, I use the Android NDK. The native C++ code is compiled for armeabi only (to the default, armeabi-v5).
The last time I built my c++ code into nativestuff.so was a few months ago, in another computer (Windows 7 + cygwin, because cygwin is recommended for compiling with Android NDK).
I just installed the NDK on my current PC (Windows 7), along with the newest cygwin, and rebuilt the c++ code for my app.
To my surprise, it generates an .so file of 14KB, while the previous .so file was 37KB. Note that the c++ source files are exactly the same (they haven't changed for a year), my project is under version control, so I'm 100% sure.
I tested the c++ functionality in the game, and it works exactly as before, without any bugs.
My C++ files use only cstring.h and jni.h as includes. My Android.mk is as follows:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := nativestuff
LOCAL_SRC_FILES := nativestuff.cpp
include $(BUILD_SHARED_LIBRARY)
Any idea why the drastic change in .so filesize?
(I added the linux tag as well to this question, because maybe it's a general thing so I want to make sure that linux gurus also check it.)
Run objdump -x file.so on both versions. This will list all the sections and their sizes. That should give you a clue as to where the problem lies. (i.e. is there a new .debug section that's 23KB long? Maybe debug mode got enabled.)
If your code sections are radically different, compare the output of objdump -d file.so. Maybe your compiler automatically inlined more code, which saved a lot of space.
If another section is new/different, post the output in another SO question.
Maybe the previous .so was generated with debugging information.
(compiled with gcc -g option)
You may try one thing: use the command size executable-name. That will give you size of the different areas of your executable code. If the previous build is available do the same to that. You may get an idea where the change is.
Related
I like to have a high level understanding of how the android build system work. That is when does it complement the GNU make and the Linux build system and when and how does it differ? What I mean by this is how come sometimes we use make files to add functionality to the final image, and sometimes we use Andoroid.mk? Then again sometimes we use both. Does anyone have a good grasp of how these components work together?
For example, I used just a make file to add a simple program as a module. On the other hand, looking at the /external directory some of the modules have Android.mk file and some have a make file also. Then there is the bionic directory. Can anyone elaborate please?
# arkascha- I appreciate this but I think there is a little more to it. It seems to me that GNU make has control over the Linux kernel directories and Android.mk over the Android folders; this sounds intuitive doesn't it? I was looking for a comment that would take this further and elaborate on which files need to be updated in order to add functionality. ie. looking at my build environment I have:
0628Samsung build.sh Documentation include Makefile packages sound
abi config-backup drivers init Makefile.bak pdk system
AndroidKernel.mk COPYING drivres ipc Makefile-original Platform.tar.gz tools
arch CREDITS dtbTool Kbuild mkbootimg prebuilts usr
art crypto external Kconfig mm README vendor
bin cts files kernel modules.order REPORTING-BUGS virt
bionic dalvik firmware Kernel.tar.gz ndk samples
block developers frameworks lib net scripts
bootable development fs libcore note3 sdk
build device github-repo libnativehelper out security
build_msm8974pro_kernel.sh docs hardware MAINTAINERS output
I ask this question since there does not seem to be clear understanding of the AOSP environment. For instance, this link has a section called steps for adding a new program to the Android source tree. In it they advise updating the core/main.mk file. But my environment does not really have the lines they mention. Also sometimes one does not really have a choice of using one, make file vs. android.mk, or the other. At least that has been my experience. Maybe I missed something, but what I did was to add a sample program to the external directory. I was able to compile it with the same toolchain I used to create an image and flash my phone. But the executable did not run on my phone, which led me to believe that perhaps I needed to issue other switches and set various environment variables. So I kept trying to build the image with the program included, but the build environment did not go in that directory. After looking through other directories, I realized that most of them had an Android.mk file so I added one in, and it is chugging along right now. I'll let you know how it turns out. That is why I am asking this question. Maybe I am not looking at the right place, there is no clear stable content about how to add functionality to the final image and what are the differences between what resides in each folder. There is a high level description but no discussion on here is how you add a module to this /external, /bionic, ...and here is what the end result would be.
#Dan Albert- Thanks. I am trying to map what is in the /external directory with what is on my device in an effort to get my code into the image. I am not having much luck. I followed a set of procedures to get a simple kernel module in. But I just used a simple make file as follows:
lib_src := src
lib_headers := headers
.PHONY: all $(lib_src) $(lib_headers)
$(lib_src) :
$(MAKE) --directory=$#
$(lib_*): $(MAKE) --directory=$#
obj-$(CONFIG_TOS) += examples.o
So when you say Android just uses Android.mk, I wonder. The reason being, here I just used a make file and I was able to see the resulting code in my image. Further, I'll share another example with you. Within the Android Studio projects, in order to get some native project in, you have to create a make file as well as an Android.mk. So....? There has to be more; no? Each file does have some unique functionality within the build system; don't you agree?
Please note, I am just making this argument in an effort to get my code into the finale image.
I believe I heard what is in /external directory just goes into the /system folder of the final image. But I can not validate that. Here is what is in my external directory:
aac droiddriver hyphenation libpng nist-sip sonivox
android-clat dropbear icu4c libppp noto-fonts speex
android-mock e2fsprogs iproute2 libselinux oauth sqlite
ant-glob easymock ipsec-tools libsepol objenesis srec
antlr ebtables iptables libusb okhttp srtp
apache-harmony eclipse-basebuilder iputils libusb-compat opencv stlport
apache-http eclipse-windowbuilder jack libvorbis openfst strace
apache-qp eigen javasqlite libvpx openssh stressapptest
apache-xml elfutils javassist libxml2 openssl svox
arduino embunit jdiff libxslt open-vcdiff tagsoup
bison emma jhead libyuv oprofile tcpdump
blktrace esd jmdns linux-tools-perf pixman temp
bluetooth expat jmonkeyengine littlemock ppp timezonepicker-support
bouncycastle eyes-free jpeg llvm proguard tinyalsa
brctl fdlibm jsilver lzma protobuf tinycompress
bsdiff flac jsr305 marisa-trie qemu tinyxml
bzip2 freetype junit markdown qemu-pc-bios tinyxml2
ceres-solver fsck_msdos kernel-headers mdnsresponder regex-re2 tremolo
checkpolicy ganymed-ssh2 libcap-ng mesa3d replicaisland v8
chromium gcc-demangle libffi mksh robolectric valgrind
chromium-libpac genext2fs libgsm mockito safe-iop webkit
chromium_org giflib liblzf mockwebserver scrypt webp
chromium-trace google-diff-match-patch libmtp mp4parser sepolicy webrtc
clang grub libnfc-nci mtpd sfntly wpa_supplicant_8
compiler-rt gtest libnfc-nxp naver-fonts shahin xmlwriter
dexmaker guava libnl-headers netcat sil-fonts xmp_toolkit
dhcpcd hamcrest libogg netperf skia yaffs2
dnsmasq harfbuzz libpcap neven smack zlib
doclava harfbuzz_ng libphonenumber nist-pkits smali zxing
This is basically what I have in the external/shahin directory:
sansari#ubuntu:~/WORKING_DIRECTORY/external/shahin$ more Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= hello_world.S
LOCAL_MODULE := shahin
include $(BUILD_EXECUTABLE)
sansari#ubuntu:~/WORKING_DIRECTORY/external/shahin$ more hello_world.S
.syntax unified
.global main
main:
push {ip, lr}
ldr r0, =message
bl printf
mov r0, #0 # Return 0.
pop {ip, pc}
message:
.asciz "Hello, world.\n"
A simple assembly code and an Android.mk file. But when I issue make from the root of the project I am not sure if this is added to the final image. I don't see any object file created afterwards in this directory. Am I mistaken perhaps? My question is how do I get this into the final image?
Only Android.mk is used by the Android platform build system. There are normal makefiles in the external/ directory because those projects use make when built outside Android, and we just mirror their source. Still, we only use the Android.mk to build it for Android.
Bionic is no different than the other projects in Android, it just has somewhat more complicated Android.mk structure to deal with the complexity of CPU specific sources and various issues that come along with building low level system libraries.
Android.mk is still just make. Each include $(BUILD_*) gets handled in build/core to eventually be rewritten as a normal make rule.
I am building an Android native application that uses OpenAL Soft for Android. Everything builds nicely, resulting in two shared libraries in my libs folder: libdig.so (mine) and libopenal.so (the OpenAL library).
When I try to load libdig.so on the device (using System.loadLibrary( "dig" );), however, the link fails with the message:
java.lang.UnsatisfiedLinkError: dlopen failed: could not load library "libopenal.so.1" needed by "libdig.so"; caused by library "libopenal.so.1" not found
Now in some sense the problem is obvious. dlopen is looking for a dependency named libopenal.so.1, but the file actually on the system (copied there by ant install) is libopenal.so: with no .1.
In other words, the libopenal.so library is called just that everywhere, except that somehow, internally, libdig.so references it as libopenal.so.1.
Also relevant: When building libopenal, the actual shared library name is libopenal.so.1.13.0, with two symlinks: libopenal.so.1 and libopenal.so. But nowhere is the .1 version referenced: not in Application.mk, or Android.mk, not in the output libs/, or anywhere else.
Android.mk links the libraries thus:
include $(CLEAR_VARS)
LOCAL_MODULE := openal
LOCAL_SRC_FILES := ../../../Fresh/lib/openal-soft-android-master/libs/$(TARGET_ARCH_ABI)/libopenal.so
LOCAL_EXPORT_C_INCLUDES := $(BASE_PATH)/Fresh/lib/openal-soft-android-master/include
include $(PREBUILT_SHARED_LIBRARY)
...
LOCAL_SHARED_LIBRARIES += openal
Now, what is interesting is that if I literally delete the libopenal.so.1 symlink from my system, ndk-build will fail, complaining:
No rule to make target `openal-soft-android-master/libs/armeabi-v7a/libopenal.so', needed by `obj/local/armeabi-v7a/libopenal.so'.
This implies that internally, ndk-build is trying to reference the .1 symlink, even though it's never named and the output file will be libopenal.so.
I am not familiar enough with UNIX or Android development to really understand the purpose of the .1 symlink, so I don't know why there would be this secret reference to that file.
Has anyone encountered this problem? Or do you understand something deeper down about the compilation or management of shared libraries that would explain why libdig.so is referencing a (slightly) wrongly-named library, or how to change it?
I know this question is a couple of years old, but I recently ran into the exact same problem while re-porting my game to Android. This problem frustrated me, and I even tried Alex's link above, only to find I had the same problem. After spending days researching this problem, I came to the following conclusion based on a similar problem someone else had in a forum. The .1 at the end is generally a sign of either using a library that was not built for your target platform (in this case, Android, obviously) or an incorrectly built library altogether.
If you want a quick fix to get around this (without statically compiling OpenAL-Soft into your app while forcing your entire project to be subject to the LGPL), you can simply download some prebuilt libraries from SFML's github page here... that's what I did anyway. You don't have to replace the .a files if you don't need to. Builds for arm, armv7, x86 and mips are in their respective folders.
Hope this helps either the OP or someone else in the future.
The easiest way out would be to use the static library for OpenAL. You can find the prebuilt static libraries in the same ZIP file as the shared libraries.
using openal-soft distrib or git
edit openal-soft/build/CMakeFiles/openal.dir/link.txt
remove '-Wl,-soname,libopenal.so.1'
and rebuild the lib
I am trying to build a native daemon on Android. The purpose to to control some specific hardware, and Java applications will be able to communicate to this daemon using sockets.
I have been using cmake meanwhile to compile my libraries, demos and the real daemon (which works fine BTW). I am now trying to do 2 different things:
Build the same apps using ndk-build.
Port the C++ daemon to an Android service, by making JNI calls very similar to the way the c++ daemon works.
As far as I understand, ndk-build cannot make native applications, but only native libraries, which in turn can be loaded by the Java GUI... am I correct? For step1 I don't really need java (and I have proven it already), but I have yet found a way for ndk-build to spit an elf application.
For reference - I am using cmake, as described here: http://opekar.blogspot.com/2011/06/android-cmake-is-much-easier-in-ndk-r5b.html
This way I can have builds for "normal" linux, and also android using out of source builds. Quite nice hack if you ask me.
An alternative is to use the script make-standalone-toolchain.sh bundled with the NDK to create a stand-alone toolchain, then use it to compile your project. The shell code below illustrates how to use it:
# Assumed path to the NDK, change it to suit your environment.
NDK_HOME=$HOME/bin/android-ndk-r8e
# Desired API and NDK versions and destination folder of
# the stand-alone toolchain, change them to suit your needs.
api=14
ver=4.7
folder=$HOME/bin/android-$api-ndk-$ver
# Create folder if it doesn't already exist.
mkdir -p $folder
$NDK_HOME/build/tools/make-standalone-toolchain.sh \
--toolchain=arm-linux-androideabi-$ver \
--platform=android-$api --install-dir=$folder
Running the lines above will generate a new stand-alone toolchain at $HOME/bin/android-14-ndk-4.7, which you can then use as any regular C/C++ cross-compilation toolchain.
The advantage of working with a stand-alone toolchain is that it makes cross-compiling Linux projects to Android a breeze; see for example my port of Valgrind to Android ARMv7.
As mentioned by #Mārtiņš Možeik in one of the comments, this pice of Android.mk will work:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := my_daemon
LOCAL_C_INCLUDES := src
LOCAL_SRC_FILES := src/daemon.c
include $(BUILD_EXECUTABLE)
One thing I do notice is that the binary produced by this "makefile" is 130k, while the binary produced by cmake was ~40 kb. This is because I used -s as a C_FLAG and then gcc will strip the produced object on the fly. This can be done later on by calling $NDK/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-strip or the corresponding strip for your arch.
As I have not found documentation of this feature on the internet, some more words:
This works quite good, no problem here :)
This must be saved in a file called jni/Android.mk.
The code must be saved inside the JNI directory
If your code is outside of the jni directory this get ugly, but not impossible. You just need to prefix the code with the corresponding prefixes, don't forget to modify also the include path. This is left to the reader as an exercise.
Still unsure why the code generated from Android build system is larger then the code generated by cmake. I previously said that strip is not called - but it is called before the *.so are copied to the lib directory.
Still don't know how to package that binary into an android package, and not even how to run it (for example when the system is up) without modifying the Android code. I assume I can write a Java service that starts on boot and then execvps the daemon.
Your option 2 is the only way to do it AFAIK.
I am trying to write a simple Android application using the NDK and C++. Specifically, I'd like to use the gnustdc++ included with the newest version of the NDK (r7). The JNI library has compiled and worked perfectly fine as C, but now that I'm trying to introduce C++, I've run into some issues.
I have added ${NDK_ROOT}/sources/cxx-stl/gnu-libstdc++/include/ to my project's include paths, and the #includes inline are resolved. However, attempting to actually use any STL class (such as vector) results in Symbol 'vector' could not be resolved.
All of the standard C symbols imported from <stdlib.h> and such work as well, until I try to replace the #include with <cstdlib>. Then it fails with Function 'malloc' could not be resolved and so forth.
Oddly enough, adding the stlport headers (in ${NDK_ROOT}/sources/cxx-stl/stlport/stlport) fixes all of my issues. However I am linking in GNU C++, not STLPort, so this is an inconvenient and improper "solution" at best. It seems odd that these headers would work but the others would not. Is Eclipse failing to index or resolve the GNU C++ headers?
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libfoobar-jni
LOCAL_SRC_FILES := foobar.cpp
LOCAL_LDLIBS := -llog -lGLESv2
LOCAL_C_INCLUDES := sources/cxx-stl/gnu-libstdc++/include/
LOCAL_CFLAGS := -g -std=c99
include $(BUILD_SHARED_LIBRARY)
Application.mk
APP_STL := gnustl_shared
Edit: I set up my project based on:
http://mhandroid.wordpress.com/2011/01/23/using-eclipse-for-android-cc-development/
Read this, it has the solution:
http://comments.gmane.org/gmane.comp.handhelds.android.ndk/14371
The summary, in case the link dies some day is this:
It's a bug in the gnustl_shared module declaration. Sorry about that, it will be fixed in the next release.
In the meantime, you can manually change $NDK/sources/cxx-stl/gnu-libstdc++/Android.mk and replace the line that says:
LOCAL_EXPORT_LDLIBS := $(LOCAL_PATH)/libs/$(TARGET_ARCH_ABI)/libsupc++.a
with:
LOCAL_EXPORT_LDLIBS := $(call host-path,$(LOCAL_PATH)/libs/$(TARGET_ARCH_ABI)/libsupc++.a)
I know it's not a perfect solution, but at least it'll let you click "run" or "debug" through Eclipse:
Right click on your Android C++ project and select Properties.
Under C/C++ General, click "Code Analysis"
Switch to "Use project settings"
Switch any errors you're receiving due to using the vector class to be "warnings".
For me, the errors I've needed to switch so far are:
"Symbol is not resolved"
"Member declaration not found"
"Invalid template argument"
"Invalid arguments"
"Method cannot be resolved"
Like I said, it's not perfect and you might miss real errors due to this, but you still get the ability to usually select "Go To Declaration" and some syntax checking abilities, as well as the ability to launch your program. The ndk-build step will catch any real errors anyway, so it's really not a huge loss.
Honestly, I'm not sure of the source of this issue. It's likely got to be an Eclipse bug.
Off topic but relevant: you can also use the ndk-gdb through eclipse. The tutorial is on the blog linked to the OP, but here's a direct link anyway.
Best of luck!
Edit (followup):
I've since figured out a way to get around this problem, at least on my box. The OP said that including the STLPORT headers worked for him. It didn't for me, at first. I had to destroy my Eclipse project and start fresh (for some reason, it wouldn't let me remove some include definitions). Adding STLPORT fixed some issues, but in ndk r7b, I was still getting weird errors (e.g. NULL was not defined even after including stddef). I ended up having to include the x86 headers too. These should largely overlap with the arm ones, however, it's useful to have the arm ones 'on top' in the include order.
So, if you've been running into the same issue as I was, add
$NDK_DIR/platforms/android-14/arch-x86/usr/include
to your list of eclipse includes as well.
I had this issue come up on windows due to the different path formats in cygwin, my prefered windows shell, and which uses pseudo unix style paths rather than windows. If you are having this problem, and you have cygwin floating around in your path, eclipse could be using it. Change the paths in Properties>C General>Paths and Symbols to be cygwin style rather than windows style (/cygwin/c/Android.... rather than C:\Android...) ... anyway, this worked for me.
I'm working on a large game engine that must be ported to Android. All the code is C/C++, so we are porting via the NDK. I've got everything building, but after lots of scouring, I'm still uncertain what the best method is for building Debug vs. Release versions of our .so file. Changing things by hand every time is getting old.
Do you have different Application.mk files for each target? Or is there some way to include multiple targets in a single Android.mk file under the jni/ directory? Or perhaps a third option might be to write a standard makefile that sets environment variables that the Android.mk file uses to inform the build process?
Finally, one last question regarding the android:debuggable flag that must be set in the AndroidManifest.xml file. What this actually have any effect on the generated native code that's copied to the device?
Best and thanks,
Kevin
Do you have different Application.mk files for each target?
No. Separate subdirectories, all with their own Android.mk (shared and static libs) but only one Application.mk for me.
My Application.mk is just:
APP_STL := gnustl_static
APP_OPTIM := debug
I'm still uncertain what the best method is for building Debug vs. Release versions of our .so file. Changing things by hand every time is getting old.
It's a bit spread out, for me at least, using the jni/Android.mk + Application.mk layout.
Application.mk has APP_OPTIM := debug
Then in the application element of AndroidManifest.xml I have android:debuggable="true"
When you build with ndk-build, it uses this manifest flag to determine optimization (which is useful to turn off or on, off for profiling, etc.)
(A Little Off topic) I recently ran across
https://code.google.com/p/android-ndk-profiler/
Which, when combined with http://code.google.com/p/jrfonseca/wiki/Gprof2Dot
Generates some pretty images to help my little mind grasp how things are running over on the phone itself.
You're not required to use the Android.mk system to build your .so's. Personally, I use my own Makefile's with the targets I need and this allows for very standardized debug vs. release build specification.
I use a single file to build a library for diferent targets. In the Application.mk add this "APP_ABI := armeabi armeabi-v7a" it works for me.