I am trying to create an Android Studio wrapper around C code and am running into a problem with the NDK. Because the C code is from a 3rd party project, I am trying to not move the code location and have the project in a subdirectory of the repository and as such have to not use the build in call to the NDK and its autogenerated make file. The NDK call works correctly, but I get the following error:
make.exe: *** No rule to make target `C:/some_relative_path/jni/../../../../core.c', needed by `C:/some_relative_path/obj/local/armeabi/objs/my_module/C_/some_relative_path/jni/__/__/__/__/core.o'. Stop.
As you can see, the object path has been mangled such that : and .. have been turned into underscores.
I had to add a jni folder to my project and place the Android.mk and Application.mk files in it to satisfy the path appending of the NDK Gradle plugin. As a result the jni folder had no source files in it. Since I found several links on google talking about needing more than one source file, I added two dummy source files to the jni directory.
Among other things, my Android.mk file contains the following:
LOCAL_SRC_FILES := \
$(LOCAL_PATH)/NDKBug1.c \
$(LOCAL_PATH)/NDKBug2.c \
$(LOCAL_PATH)/../../../../core.c \
I'm looking to see if anyone can help me with either this path issue directly, or perhaps suggest an alternative way of setting things up.
The file names in LOCAL_SRC_FILES are supposed to be relative to the local directory, so you need to remove the $(LOCAL_PATH)/ prefix - then it should work.
I haven't heard about a bug requiring to have source files in the local dir though, so I think you can get rid of them.
Related
I'm trying to add libogg to my android NDK project.
I'm using project template that comes with SDL library.
I'm on Windows, so all following scripts were executed under MSYS, a linux terminal emulator.
First, I generated a standalone toolchain.
android-ndk/build/tools/make-standalone-toolchain.sh --platform=android-12 --system=windows-x86_64 --toolchain=arm-linux-androideabi-4.9 --install-dir=Y:/gcc_android_androideabi-4.9_api12/
Then I built the library.
make clean
configure CC="/y/gcc_android_androideabi-4.9_api12/bin/arm-linux-androideabi-gcc" LIBS="-lgnustl_shared" CFLAGS="-mthumb" --host=arm-linux-androideabi
make
Then I copied resulting libogg.so to my project folder and added following to my jni/src/Android.mk:
...
include $(CLEAR_VARS)
LOCAL_MODULE := ogg-prebuilt
LOCAL_SRC_FILES := ../../prebuilt-libs/$(TARGET_ARCH_ABI)/libogg.so
include $(PREBUILT_SHARED_LIBRARY)
...
LOCAL_SHARED_LIBRARIES := ... ogg-prebuilt ...
...
Similar code works fine for another libraries that I use.
ndk-build successfully finds my libraries and adds them to the .apk.
The problem arises when I call System.loadLibrary("ogg"); at runtime. Dynamic linker gives me error message saying something like
Can't find library "libogg.so.0".
I'm sure that my library loading code is ok because it works for other libraries that I have.
Error from the dynamic linker is interesting because make not just generated single libogg.so. It generated 3 completely same files with different names: libogg.so, libogg.so.0 and libogg.so.0.8.2.
I tried to replace libogg.so with libogg.so.0 and adjusted Android.mk properly, but NDK build script yelled at me, saying that prebuilt shared libraries must have .so extension. I tried to just copy libogg.so.0 to libs/ folder, but NDK build script ignored it when building .apk.
Then I opened libogg.so in a hex editor and searched for libogg. I found only one occurence: libogg.so.0[NUL]. I replaced .0 with 2 [NUL]s, so it became libogg.so[NUL][NUL][NUL] and now library loads perfectly.
I can reproduce this error with all toolchains I use: arm-linux-androideabi-gcc-4.9, i686-linux-android-gcc-4.9 and mipsel-linux-android-gcc-4.9. They all are generated using similar scripts.
The error persists if I rename libogg.so.0 or libogg.so.0.8.2 to libogg.so and use it instead of original one. As I said, all three files have same content.
While I can make a sed script to automatically fix library name in .so files when necessary, I wonder if there is a better solution to this problem.
Maybe I have to add some flags to configure?
My slightly less hacky fix for this is to remove the version information from the build system of libogg.
In the directory where you have the libogg source code, open the file src/Makefile.am and change this line:
libogg_la_LDFLAGS = -no-undefined -version-info #LIB_CURRENT#:#LIB_REVISION#:#LIB_AGE#
to
libogg_la_LDFLAGS = -avoid-version
If you don't have automake installed then you can change the generated Makefile after running ./configure. Find the libogg_la_LDFLAGS and make a similar change to the one detailed above. On Linux a sed one-liner like this does the job:
sed -i 's/^libogg_la_LDFLAGS.*/libogg_la_LDFLAGS = -avoid-version/g' src/Makefile
I have an Android Eclipse library project "Lib" that contains both Java and C code built with the NDK. I have another project "App", which is dependant on Lib. App also contains both Java and C. My goal is to have multiple Eclipse App-like projects which each use the Lib project.
A Java routine in App calls a Java routine in Lib which calls C code in Lib. This compiles, links, and runs perfectly on the device.
Now I want to add a call from the C code in App to the C code in Lib. My First problem is header files. I need to include a header file, jni/lib-jni,h, from the Lib project:
#include "lib-jni.h"
in a .c file in App. For this #include to work I believe I need to add Lib's jni/ directory to LOCAL_C_INCLUDES in App's jni/Android.mk. I do not want to hard-code this path, I would like to get it from Eclipse if possible. After all, I've told Eclipse that the App project depends on the Lib project and Eclipse knows how to connect Java calls between the two.
I temporarily kludged around the first problem by copying lib-jni.h from Lib's jni/ directory to App's jni/ directory. Now App's C code compiles, but it won't link; it gets an undefined. In App's Android.mk I need to tell the C linker to link against libLib.so. I tried putting -lLib on LOCAL_LDLIBS, but that didn't work. libLib.so is in the Lib project in Lib/libs/armeabi/libLib.so. Eclipse knows to incorporate this .so into the .apk file it builds for App.
Is there a way to cleanly solve these two problems?
Add Lib's jni/ directory to App's LOCAL_C_INCLUDES
Add a reference to libLIb.so to App's LOCAL_LDLIBS
I phrased these problems in terms of possible solutions. I'm open to any solution. For example, if using LOCAL_LDLIBS the wrong way to go, what is the right way?
Note: Because App and Lib are two separate Eclipse projects built at separate times I am pretty sure I can not use LOCAL_EXPORT_C_INCLUDES in Lib's Android.mk to make Lib's jni/ directory available to App's Anroid.mk - I tried it didn't work. But I'm prepared to be educated.
I always set the LOCAL_C_INCLUDES to the original lib, so I think that is not that bad idea. An other solution is to include the external library as a static library in your libs folder, but I'm not sure if it will work.
I'm completely new to Java and Android dev but I'm trying to port a C/C++ project to an android phone just to do some testing. Here are some details. The project depends on the Openssl, GMP, and NTL libraries. I downloaded copies and put everything inside a the jni/ folder. So now the folder structure looks like this:
jni/
Android.mk
gmp/
Android.mk
...
ntl/
Android.mk
...
openssl/
Android.mk
...
myproject/
Android.mk
...
Every one of the subfolders that has .cpp, c. files has an Android.mk file. Now, my question is: very broadly, how should I go about structuring the contents of the Android.mk files? I was able to follow instructions online and compile Openssl (I produced all the .so files inside of it). How will the top-level Android.mk use these? Or does it now?
When we run ndk-build in the top directory of your project (the parent of the jni directory in your picture), we essentially run gnu make and include jni/Android.mk.
In your case, this top jni/Android.mk should only include all child .mk files:
include $(call all-subdir-makefiles)
The main file is jni/myproject/Android.mk, which refers to the binaries produced by others, like
LOCAL_SHARED_LIBRARIES += openssl
and so on. Note that the names are not the names of library files, but of the LOCAL_MODULE's that build them.
Often, it is easier to use static libraries. For example, you need to load all shared libraries from Java yourself, in the correct dependencies order.
main is an informal word here. I just want to say that this is the make file that causes its siblings to do their work, and do it in expected order. It does that because it refers to the binaries produced by the other make files, by specifying LOCAL_SHARD_LIBRARIES and LOCAL_STATIC_LIBRARIES.
It is important to understand that it is not enough to include all the make files in jni/Android.mk to cause them all do their work, and do it in expected order. I want to emphasize that the jni/Android.mk file is a service file, not the main, even though it sits on top of the directory hierarchy.
I am writing a make file for compiling jni code in Android.
I would like to be able to compile all cpp files that reside under specific folder, recursively.
How can i do that?
I tried playing with the wildcard command, but did not get to the result i need.
The Android make system has a gmake macro for handling this. Please see the documentation doc\ANDROID-MK.html in the NDK. Here is an extract:
all-subdir-makefiles
Returns a list of Android.mk located in all sub-directories of
the current 'my-dir' path. For example, consider the following
hierarchy:
sources/foo/Android.mk
sources/foo/lib1/Android.mk
sources/foo/lib2/Android.mk
If sources/foo/Android.mk contains the single line:
include $(call all-subdir-makefiles)
Then it will include automatically sources/foo/lib1/Android.mk and
sources/foo/lib2/Android.mk
This function can be used to provide deep-nested source directory
hierarchies to the build system. Note that by default, the NDK
will only look for files in sources/*/Android.mk
The Android.mk for my NDK project contains several hundred CPP files from which I build about a dozen static libs and finally a single shared lib. Most of my developing experience so far is on Windows, so I'm not very familiar with Linux, GNU Make, and the like.
When I add a new CPP file to Android.mk (i.e. to LOCAL_SRC_FILES), issuing ndk-build rebuilds all of my files, apparently because Android.mk changed, and it refers to all of the CPP files. Is there a way to avoid this? Let's assume I make a separate file for each static lib, and each such file would add that lib's CPP files to LOCAL_SRC_FILES and be included by Android.mk. Should that result in rebuilding only the lib whose included file is modified? This was actually my first attempt, but I went seriously wrong somewhere, and had to start over as the build would no longer succeed (which is why I'm asking before trying again).
Assuming the above approach is reasonable, how does including a file relate to the scope/lifetime of variables set in the including/included files?
Still hoping someone can answer this...
Firstly try to split your project into multiple android.mk files, instead of just one. It would limit the recompilation step each time you change one of them.
Then try this ndk-build -o <your_android.mk>. For instance:
ndk-build -o jni/Android.mk
Ref: How to prevent Android native project full rebuild after changing Android.mk?