I'm trying to create an native executable for android and it keeps crashing. testing the file with readelf and objdump revivals that the file is considered to be an shared object file.
I'm using the r8e and compiling with ndk-build
test.c:
int main(){
return 0;
}
Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC FILES := test.c
LOCAL_MODULE := test
include(BUILD_EXECUTABLE)
--
Setting the app_platform to android-9 results in the creation of an executable file ( and no crashes).
Have you tried specifying arguments int args and char *argv[] for your main() method? Also, where are you trying to run it?
I confirm this bug... I had a project that compiled perfectly with ndk-r8, but when I switched to ndk-8e my executable did not build properly anymore.
I reported it here: https://code.google.com/p/android/issues/detail?id=55769
Here is the answer I got from google:
This is normal.
By default, when targetting API level 17 or higher, "Position Independent Executables" (a.k.a. PIE) are generated by the BUILD_EXECUTABLE rule.
These are executable binaries, but they are only supported on Android 4.1 or higher. See [1] for more details.
If you really don't want these (e.g. because you want your program to run on previous releases of the platform), you have two choices:
Target a lower API level.
Use 'APP_PIE := false' in your Application.mk
Related
I'm a long time programmer but new to Android Studio. I have inherited some existing JNI library code intended to be run with ndk-build that already has its Android.mk file. It would be nice to reuse that. When I opened a new project with Android Studio and set the C++ support flag, it set itself up to use CMake instead of ndk-build. The documentation for Android Studio says both are available so I decided to try a simple test to see if I had found all the places that needed to change. It was a complete fail with error messages that seem to lead nowhere.
To recreate, create a new project ProjTest2 with Android Studio and check the Include C++ Support box. Accept the default Phone and Tablet form factor with a Minimum SDK of API 16: Android 4.1. Choose the Empty Activity. Accept the default Activity and Layout names. Accept the default Toolchain and do not check the boxes for Exceptions Support or Runtime. Run program, select device Android Emulator Nexus_5_API_24:5554. All is well; get message Hello from C++ on emulator screen.
Attempt to change to ndk-build. Open build.grade file for Module:app. Replace lines:
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
with:
externalNativeBuild {
ndkBuild {
path "jni/Android.mk"
}
}
Create a new folder jni in the directory ProjTest2/app. Create the file Android.mk in that folder with the following content:
# A simple test for the minimal standard C++ library
#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := native-lib
LOCAL_SRC_FILES := $(LOCAL_PATH)/../src/main/cpp/native-lib.cpp
LOCAL_LDLIBS := -llog -landroid
include $(BUILD_SHARED_LIBRARY)
The build now fails claiming that it cannot find the target of #include <string> and that it cannot resolve the container 'std'. I find that I can clear the IDE error flags by adding LOCAL_C_INCLUDES += C:\Users\JWC\AppData\Local\Android\sdk\ndk-bundle\sources\cxx-stl\gnu-libstdc++\4.9\include to the Android.mk file but the resulting make still fails when it cannot find some of the sub-includes from <string>.
Did I miss something simple, or is this just not as easy as it seems it should be?
Edit:
Also needs file:
# Application.mk
APP_ABI := armeabi-v7a armeabi
APP_PLATFORM := android-21
APP_OPTIM := release
APP_STL := gnustl_static
CMake defaults to using the gnustl_static STL, whereas ndk-build defaults to using none.
Add the following to your project:
jni/Application.mk:
APP_STL := gnustl_static
There are a handful of these available. gnustl_static will match the cmake use, but you can see other choices in the official docs.
I am trying to build a shared library of FFTW by means of the following script:
INSTALL_DIR="`pwd`/jni/fftw3"
SRC_DIR="`pwd`/../fftw-3.3.4"
cd $SRC_DIR
NDK_ROOT=/path_to_android/Sdk/ndk-bundle
export PATH="$NDK_ROOT/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/:$PATH"
export SYS_ROOT="$NDK_ROOT/platforms/android-21/arch-arm/"
export CC="arm-linux-androideabi-gcc --sysroot=$SYS_ROOT"
export LD="arm-linux-androideabi-ld"
export AR="arm-linux-androideabi-ar"
export RANLIB="arm-linux-androideabi-ranlib"
export STRIP="arm-linux-androideabi-strip"
mkdir -p $INSTALL_DIR
./configure --enable-shared --host=arm-eabi --build=i386-linux --prefix=$INSTALL_DIR LIBS="-lc -lgcc" --enable-float
make
make install
exit 0
However, after executing the script I always only receive a static FFTW library even though I am using the enable-shared parameter. Is there any other way to generate the shared library file?
I really need a shared library since Android Studio demands a shared library to compile additional JNI sources.
Update:
Based on #bullsy's answer, I could build the shared library by chaning the host parameter to --host=arm-linux-androideabi. The resulting problem is that FFTW generates a versioned shared library with library files libfftw.so.3 and libfftw.so.3.4.4. I found a tutorial that shows how to convert these files into .so files. While working on libfftw3.so or libfftw3.so.3, I always received the error that file is not a (regular) file so I tried everything on libfftw3.so.3.4.4:
rpl -R -e libfftw3.so.3 libfftw3_3.so libfftw3.so.3.4.4
mv libfftw3.so.3.4.4 libfftw3_344.so
ln -sfn libfftw3_344.so libfftw3.so.3
mv libfftw3.so.3 libfftw3_3.so
I had to add the ln command manually. Without changing the symlink, Gradle could not find libfftw3_3.so during the building process of the apk.
So my application is running now with the shared libs but it is also possible to generate shared FFTW libs with single precision (-enable-float)?
Another approach was to take the static library file and to build a shared library file by means of an Android.mk and ndk-build:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := fftw3
LOCAL_SRC_FILES := fftw3/lib/libfftw3.a
include $(PREBUILT_STATIC_LIBRARY)
LOCAL_MODULE := fftw_wrapper
LOCAL_C_INCLUDES := /path_to_fftw_headers/include
LOCAL_C_INCLUDES += /pat_to_wrapper/fftw_wrapper.h
LOCAL_SRC_FILES := fftw_wrapper.cpp
LOCAL_SHARED_LIBRARIES := fftw3f
include $(BUILD_SHARED_LIBRARY)
But this approach always returns undefined reference errors, e.g. undefined reference to 'fftw_malloc'. I have also tried it without the --build parameter as it is explained in this question: Using FFTW on Android undefined references
Whenever I use the static library, my application runs fine, even when I statically link the fftw_wrapper in the Android.mk. However, since my C/C++ imports are all defined in the app Gradle file of Android Studio, I do not want to change back to Android.mk files. Is there any other solution?
Try using
--host=arm-linux-androideabi
instead. This tells configure 'Hey, I'm building for a linux variant', which makes shared libraries the default choice.
I have read many posts on how to share prebuilt libraries using the Android.mk system. The solutions boil down to two steps:
A directory with the already-built library uses *include $(PREBUILT_SHARED_LIBRARY)*
The project consuming the library uses *LOCAL_SHARED_LIBRARIES*
(you can substitute "STATIC" for "SHARED" to build and use a .a instead of a .so)
What I am trying to do is add a step 0: build the library from sources. If I change a source file that contributes to the library I want the Android.mk system to execute steps 0, 1, and 2 in order.
I have two projects in Eclipse/ADT:
MyApp - uses MyLibrary
MyLibrary - contains the source files for the library
The question I'm asking here focuses on MyLibrary project. Here is the Android.mk for MyLibrary:
LOCAL_PATH := $(call my-dir)
# step 0: build my library
include $(CLEAR_VARS)
LOCAL_MODULE := mylibrary
LOCAL_LDLIBS := -llog
LOCAL_SRC_FILES := libsrc1.c libsrc2.c
include $(BUILD_SHARED_LIBRARY)
# step 1: export my library (PREBUILT_SHARED_LIBRARY):
include $(CLEAR_VARS)
LOCAL_MODULE := mylibrary-prebuilt
LOCAL_SRC_FILES := ../libs/$(TARGET_ARCH_ABI)/libmylibrary.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
include $(PREBUILT_SHARED_LIBRARY)
If I do a project->clean... and then a project->build project in this project I get the error:
ERROR:jni/Android.mk:mylibrary-prebuilt: LOCAL_SRC_FILES points to a missing file.
The clean removes the .so and I'm guessing PREBUILT_SHARED_LIBRARY detects the missing .so before BUILD_SHARED_LIBRARY rebuilds the library and copies it (even though the steps are in the correct order).
If I comment out step 1 and build, libmylibrary.so is correctly built and copied to libs/armeabi/libmylibrary.so. If I then uncomment step 2 and do a project->build project, that is without doing a clean first, I get these warnings and error:
warning: overriding commands for target `obj/local/armeabi/libmylibrary.so'
warning: ignoring old commands for target `obj/local/armeabi/libmylibrary.so'
warning: overriding commands for target `libs/armeabi/libmylibrary.so'
warning: ignoring old commands for target `libs/armeabi/libmylibrary.so'
make: *** No rule to make target `jni/../libs/armeabi/libmylibrary.so', needed by `obj/local/armeabi/libmylibrary.so'. Stop.
I think I understand these errors, but I do not see a way to accomplish what I want.
What am I missing?
You can simply avoid step 1 entirely and just rebuild the library from sources. I'm not sure I understand the benefits of having the three steps your describe. Feel free to clarify.
In all cases, your analysis of ndk-build's behaviour is spot on, and all of this is completely intentional.
The NDK itself provides several prebuilt libraries and allows you to rebuild them from sources if you want. For example, if you look at sources/cxx-stl/stlport/Android.mk, you will see that a variable (STLPORT_FORCE_REBUILD) is used to control whether to use the prebuilt binaries, or rebuild them from sources.
Maybe using a similar method for your project would work.
I am working with Android NDK r6b under cygwin (the system is updated correctly). I am modifying the hello-jni sample in order to learn working with NDK. Since i have a library written in C++ that i wish to use in the hello-jni (actually, i have created a prj called helloworld with a single .cpp file called ndkfoo.cpp) sample, i created a new Android project in Eclipse (updated for Android), added a jni directory, added a Android.mk and Application.mk files, edited them in order to compile the .cpp. At the end of the compilation, i obtain a .so file.
Now, in the helloworld Android.mk, i need to make some edits in order to tell the linker to include that library. Suppose the library file is libmylib.so, i have the following android.mk script:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := ndkfoo
LOCAL_SRC_FILES := ndkfoo.cpp
LOCAL_C_INCLUDES += $(LOCAL_PATH)/mylib
LOCAL_LDLIBS += -L$(LOCAL_PATH)/../../mylib/libs/armeabi/ -lmylib
include $(BUILD_SHARED_LIBRARY)
My directories are organized in the following way:
d:/android/android-ndk-r6b => android ndk root
d:/android/workspace/helloworld => helloworld project
d:/android/workspace/mylib => mylib project library
(therefore, the path to libmylib.so is: d:/android/workspace/mylib/libs/armeabi).
Unfortunately, this doesn't seems to work. If i remove every reference to mylib from ndkfoo.cpp, it compiles and run even on my phone. If i do not remove references to mylib, it compiles but doens't link: i obtain the following result:
D:/android/android-ndk-r6b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windo
ws/bin/../lib/gcc/arm-linux-androideabi/4.4.3/../../../../arm-linux-androideabi/
bin/ld.exe: cannot find -lmylib
Ps.
I forgot to mention that i run ndk-buld under the jni directory of the helloworld project.
Pss.
I have found a lot of similar questions over the internet. I have always worked with Visual C/C++ IDE, so i am really new to GCC, makefiles and so on...
The message
D:/android/android-ndk-r6b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windo ws/bin/../lib/gcc/arm-linux-androideabi/4.4.3/../../../../arm-linux-androideabi/ bin/ld.exe: cannot find -lmylib
is indicating you that the linker is not finding your library, this should come from a problem in the LD_LIBS' path.
I think that my-dir macro does not include devices' unit identifier so, your LOCAL_PATH variable should miss the D: and, I think, won't work with cygwin. I'm a Linux user and I'm not 100% sure but, if you replace
LOCAL_PATH := $(call my-dir)
by
LOCAL_PATH := D:$(call my-dir)
it should work. On the other hand you can always set the relative path by setting:
LOCAL_LDLIBS += -L$../../mylib/libs/armeabi/ -lmylib
I am new in ndk development in android.I have gone through the file system of ndk android.
Here, explaining what i have done.
1) i have created a folder named "jni" then create 2 file named Android.mk and ndkfoo.c.
In Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Here we give our module name and source file(s)
LOCAL_MODULE := ndkfoo
LOCAL_SRC_FILES := ndkfoo.c
include $(BUILD_SHARED_LIBRARY)
and in ndkfoo.c
#include <string.h>
#include <jni.h>
jstring Java_com_mindtherobot_samples_ndkfoo_NdkFooActivity_invokeNativeFunction(JNIEnv* env, jobject javaThis) {
return (*env)->NewStringUTF(env, "Hello from native code!");
}
then i have created NdkFooActivity class, in which i have written
// load the library - name matches jni/Android.mk
static {
System.loadLibrary("ndkfoo");
}
But now when i build from cygwin in xp it creates .so file successfully then i run as android application. It gives me java.lang.UnsatisfiedLinkError in LOGCAT.
So, Please let me know where i am wrong.
Thanks in Advance,
I think you forgot to change the package name.
Java_com_mindtherobot_samples_ndkfoo
It should be your package what you have specified creating project.
Also(just ran into this issue), please note that System.loadLibrary() will always throw an exception if you are testing on the Intel Atom x86 emulator. It works just fine on regular Android emulators and debugging on a physical device.
Although this has not been the OP's problem, I had the same java.lang.UnsatisfiedLinkError because of missing
static {
System.loadLibrary("mylibraryname");
}
There's a good chance the signature is wrong, as others have mentioned.
If you run the javah utility, you can find the exact signature. From the bin folder in your project, where the .apk is and the root of the Java class hierarchy is generated, run:
javah -o jni_sig.h com.mindtherobot.whatever.your.package.is.NdkFooActivity
...and, if you got the package name and class name correct, it will write out a header (called jni_sig.h) with the correct function signature(s) for any native functions. Copy that to your header and .c file, adding parameters as needed, and it should work correctly.
Maybe not relevant anymore but as far as I know you also need to add the "lib" prefix to your native library name. In your case you need to change the Android.mk to
"LOCAL_MODULE := libndkfoo" and keep "System.loadLibrary("ndkfoo");" as it is. Check the ndk sample code.
I'm pretty sure that should be:
JNIEXPORT jstring JNICALL Java_com_mindtherobot_samples_ndkfoo_NdkFooActivity_invokeNativeFunction(JNIEnv* env, jobject javaThis) {
return (*env)->NewStringUTF(env, "Hello from native code!");
}
Which SDK are you targeting and which version of the NDK do you have? Does the error you're getting say that it couldn't load the library at all or that there was an unimplemented method? Either way make sure you don't have android:hasCode="false" set on the application tag in your manifest.
You can also open up the APK file after a build using winrar or something similar to make sure that the libndkfoo.so file is actually being included with the package.
Either way if you aren't declaring the native function in NdkFooActivity you will get that error, i.e.
public static native String invokeNativeFunction();
JNIEXPORT jstring JNICALL Java_com_mindtherobot_samples_ndkfoo_NdkFooActivity_invokeNativeFunction(JNIEnv* env, jobject javaThis) {
return (*env)->NewStringUTF(env, "Hello from native code!");
}
the problem is that you compile for a target processor and execute in other. if you compile in ARM(armeabi) then execute in armeabi based emulator.
create a file called application.mk in same folder as Android.mk and put inside it one of this:
APP_ABI := x86
APP_ABI := armeabi
APP_ABI := mips
APP_ABI := armeabi x86 mips //to compile in all target and you will get 3 *.so files
then compile->run.
it should work.
Create a file Application.mk in jni folder.Copy following line and paste it to Application.mk and save.Now build the project with your cgywin and run again
APP_ABI := armeabi armeabi-v7a
The method name Java_com_mindtherobot_samples_ndkfoo_NdkFooActivity_invokeNativeFunction
may be not same as that of your package name or class name.
To make this naming of method exactly same you must use javah.
This will make a header file which will be having the same method name that is required.To make this header file go to the classes folder in the bin of your project(make sure you have created the java file with static method and build it properly) by this command in your terminal
~/workspace/Android_Example2/bin/classes$
In this directory write the following command
sudo javah -jni com.NDK.android_example2.MainActivity
Change the package name and class name according to your project.This will create a com_NDK_android_example2_MainActivity.h in your classes folder.
Simply move this file into your jni folder. In this file, there will be static methods that you have created in the MainActivity.java file but they are just declared not implemented that you will implement in your C file.
NOTE: While Coping the method check that the method parameters are need to be declared, so make them declare in your C file.
Hope this help.
Replace this
Java_com_mindtherobot_samples_ndkfoo_NdkFooActivity_invokeNativeFunction
With
Java_your_packege_name_your_Activity_Name_invokeNativeFunction
Example if your package is com.pack and Activity Name name is MainActivity then
Java_com_pack1_MainActivity_invokeNativeFunction
Don't forget to add reference in Activity.
// load the library - name matches jni/Android.mk
static {
System.loadLibrary("ndkfoo");
}
public native String invokeNativeFunction();
Repeat all these step it should work :)
I also had a java.lang.UnsatisfiedLinkError error. I verified everything mention in above answers but was still getting the error. I eventually discovered that the JNI method names cannot have underscores.
Example:
Java_com_example_app_NativeLib_print_out_stuff <- generates java.lang.UnsatisfiedLinkError: print_out_stuff
Rename the print_out_stuff function to something without underscores:
Java_com_example_app_NativeLib_printOutStuff <- works
here's a tutorial how to use native code: here
make sure you dont have any spaces in your project path.
also you cant use an underscore in your package or project name.