NDK - Android Java with native (JNI) C++ code build issue - android-ndk

I am using a mix of Java and native JNI C++ code for an android project, using NDK r8b, in Eclipse in OSX. I want to be able to use the regular C++ classes (map, string) in std namespace.
In the Android.mk file the following were added:
APP_STL := stlport_shared
Here I also tried static library. Refer to http://docs.huihoo.com/android/ndk/r5/CPLUSPLUS-SUPPORT.html
STLPORT_FORCE_REBUILD := true
Also tried removing the forced build.
In the C/C++ path and variables:
${NDKROOT}/sources/cxx-stl/stlport/stlport
"map" and "string" headers were included in the .cpp file. I am able to use std::string and std::map. The assistant picks up on them. When searching for the definition (F3 in eclipse) the header file is shown, i.e. resolved. Also, the outline shows the "string" and "map" header files and when double clicking them it also brings the headers to the forefront.
However, the build doesn't pick them up. I get the following:
> ndk-build
> Gdbserver : [arm-linux-androideabi-4.6] libs/armeabi/gdbserver
> Gdbsetup : libs/armeabi/gdb.setup
> Gdbserver : [arm-linux-androideabi-4.6] libs/armeabi-v7a/gdbserver
> Gdbsetup : libs/armeabi-v7a/gdb.setup
> Compile++ arm : ImageTargets <= ImageTargets.cpp
> xxx/Project/Code/MyImageTarget/jni/ImageTargets.cpp:20:18: fatal error: string: No such file > or directory
> compilation terminated.
> make: *** [xxx/Project/Code/MyImageTarget/obj/local/armeabi/objs-> debug/ImageTargets/ImageTargets.o] Error 1
Has anyone any idea what else is there to try.

Use V=1 parameter on ndk-build command line. This will echo all executed commands, including compilation and link, with all their parameters that NDK build assigns.
In your case, the answer can be found without detailed build log:
In the Android.mk file the following were added:
APP_STL := stlport_shared
This is your mistake. The document you cited explains that this setting should go into Application.mk. This file is usually considered optional. Yes it is. Instead of creating this file, you can specify APP_STL on the command line:
ndk-build V=1 APP_STL=stlport_static
I don't know why and how Eclipse resolves #include <string> or map.

Related

How do I fix "ld: error: unable to find library -lgcc" when cross-compiling rust to android?

I'm trying to get rust working on android. However, when I try to cross-compile to android I get the following linking error:
$ cargo build --target=arm-linux-androideabi
Compiling <project> v0.1.0 (<project>)
error: linking with `/opt/android-sdk/ndk/23.0.7599858/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi31-clang` failed: exit status: 1
(very long toolchain command from cargo)
ld: error: unable to find library -lgcc
clang-12: error: linker command failed with exit code 1 (use -v to see invocation)
I have installed the ndk and changed the linker in .cargo/config to the android clang linker. I also tried the standalone toolchains with the same result. The guide I used was the following: https://mozilla.github.io/firefox-browser-architecture/experiments/2017-09-21-rust-on-android.html
Cross-compilation does work when using crate-type = ["rlib"] instead of crate-type = ["cdylib"], but I need an .so file not an .rlib file.
In case it's relevant, i'm using Manjaro Linux.
UPDATE:
I found the following pull request: https://github.com/rust-lang/rust/pull/85806 After switching to ndk22 it worked. I havn't tried if the pull request fixes the issue (probably does).
Without switching to an older NDK version, I found using the workaround provided by ssrlive to work for me. Here's their comment:
Fixing build error for NDK 23 and above
find out all the 4 folders containing file libunwind.a, in my PC,
it's
C:\Users\Administrator\AppData\Local\Android\Sdk\ndk\23.1.7779620\toolchains\llvm\prebuilt\windows-x86_64\lib64\clang\12.0.8\lib\linux\x86_64\
and more. create 4 text files named libgcc.a in the same folders
with this contents
INPUT(-lunwind)
reference
link
In macOS, the paths are
~/Library/Android/sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/darwin-x86_64/lib64/clang/14.0.1/lib/linux/i386/libunwind.a
~/Library/Android/sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/darwin-x86_64/lib64/clang/14.0.1/lib/linux/arm/libunwind.a
~/Library/Android/sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/darwin-x86_64/lib64/clang/14.0.1/lib/linux/aarch64/libunwind.a
~/Library/Android/sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/darwin-x86_64/lib64/clang/14.0.1/lib/linux/x86_64/libunwind.a
In Linux, the paths are
~/Android/Sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang/14.0.1/lib/linux/i386/libunwind.a
~/Android/Sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang/14.0.1/lib/linux/aarch64/libunwind.a
~/Android/Sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang/14.0.1/lib/linux/x86_64/libunwind.a
~/Android/Sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang/14.0.1/lib/linux/arm/libunwind.a
In Windows, the paths are
~/AppData/Local/Android/Sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/windows-x86_64/lib64/clang/14.0.1/lib/linux/aarch64/libunwind.a
~/AppData/Local/Android/Sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/windows-x86_64/lib64/clang/14.0.1/lib/linux/arm/libunwind.a
~/AppData/Local/Android/Sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/windows-x86_64/lib64/clang/14.0.1/lib/linux/i386/libunwind.a
~/AppData/Local/Android/Sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/windows-x86_64/lib64/clang/14.0.1/lib/linux/x86_64/libunwind.a
create file command in Linux/macOS
cat << EOF > libgcc.a
INPUT(-lunwind)
EOF
This is of course extremely brittle and not the "right" solution, but the workaround works fine as of 2022-10-12 with ndk version 25.1.8937393.

NDK APP_CFLAGS can't handle <> characters?

I am including a procedurally generated file into code used by several libraries, using something like
#include MY_CONFIG_FILE_H
Then I am attempting to set this value in my Application.mk using the following directive
APP_CFLAGS += -DMY_CONFIG_FILE_H=<Config/MyFile.h>
however, this results in ndk-build not finding the path. It fails right away on the first file it tries to compile
"Compile++ thumb : MyLibraryName <= MyFirstFile.cpp
The system cannot find the path specified.
make: *** [obj/local/armeabi-v7a/objs/MyLibraryName/MyFirstFile.o] Error 1
Indeed, the file is not there, but it did manage to create the file path. There must be some strange/inconsistent string manipulation going on.
Any ideas? Work arounds? Is this a known issue in ndk-build.cmd? For the record I'm on Windows x64 and NDK R9.
Also notice that if I only include > and no <, I get a different error
The filename, directory name, or volume label syntax is incorrect.
Changing the line to
APP_CFLAGS += -DMY_CONFIG_FILE_H="<Config/MyFile.h>"
worked. Hope this helps anyone else!

CMake finds the correct library, but VC++ attempts to link with something else

I have a CMake module to locate FreeGLUT:
FIND_PATH(FREEGLUT_INCLUDE_DIR NAMES GL/freeglut.h)
FIND_LIBRARY(FREEGLUT_LIBRARY NAMES freeglut freeglut_static)
SET(FREEGLUT_LIBRARIES ${FREEGLUT_LIBRARY})
SET(FREEGLUT_INCLUDE_DIRS ${FREEGLUT_INCLUDE_DIR})
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(FreeGLUT DEFAULT_MSG FREEGLUT_LIBRARY FREEGLUT_INCLUDE_DIR)
MARK_AS_ADVANCED(FREEGLUT_INCLUDE_DIR FREEGLUT_LIBRARY)
It works fine and locates freeglut_static.lib when I generate NMake Makefiles on Windows. I'm attempting to statically link FreeGLUT into my DLL:
FIND_PACKAGE(FreeGLUT REQUIRED)
ADD_LIBRARY(vti SHARED ${VTI_SOURCES})
ADD_DEFINITIONS("-DBUILD_VTI=1 -DFREEGLUT_STATIC=1")
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${FREEGLUT_INCLUDE_DIRS})
TARGET_LINK_LIBRARIES(vti ${FREEGLUT_LIBRARIES})
My source code builds correctly, but when it gets to the linking stage, VC++ fails with:
LINK : fatal error LNK1104: cannot open file 'freeglut.lib'
Which is strange since freeglut.lib isn't mentioned anywhere that I can see in the generated NMake makefiles. It should be trying to link with freeglut_static.lib, which CMake locates and sets in FREEGLUT_LIBRARIES.
What might be causing this?
This is caused with pragma directives in FreeGLUT code (see freeglut_std.h). Using FREEGLUT_STATIC should really fix that for you, but I think you should pass it to CMake without quotes: ADD_DEFINITIONS(-DBUILD_VTI -DFREEGLUT_STATIC)

Problem in Cross-Compiling libSDL for MIPS Platform

I was trying to compile libSDL-1.2.14 for my mips platform.
But it was not successful.
These were the steps that I tried out :
export PATH=/opt/mips-4.3/bin:$PATH
Went inside the libSDL-1.2.14 source folder.
Gave a "./configure --prefix=/usr/local/SDL_Lib --host=mips-linux-gnu"
Executed the "make" command
This was the error received :
cc1: warning: include location
"/usr/include" is unsafe for
cross-compilation
./src/audio/dma/SDL_dmaaudio.c: In
function 'DMA_WaitAudio':
./src/audio/dma/SDL_dmaaudio.c:167:
error: can't find a register in class
'COP3_REGS' while reloading 'asm'
./src/audio/dma/SDL_dmaaudio.c:167:
error: 'asm' operand has impossible
constraints make: *
[build/SDL_dmaaudio.lo] Error 1
But then i reconfigured the make file by giving the following commands :
make clean
./configure --prefix=/usr/local/SDL_Lib --host=mips-linux-gnu CPPFLAGS=-I/opt/mips-4.3/mips-linux-gnu/libc/usr/include/
make
NOTE : /opt/mips-4.3/mips-linux-gnu/libc/usr/include/ - This is the path where you can locate the select.h file for the mips Platform.
It contains the definitions of the macros FD_ZERO and FD_SET.
Still I am getting the same error.
cc1: warning: include location
"/usr/include" is unsafe for
cross-compilation
./src/audio/dma/SDL_dmaaudio.c: In
function 'DMA_WaitAudio':
./src/audio/dma/SDL_dmaaudio.c:167:
error: can't find a register in class
'COP3_REGS' while reloading 'asm'
./src/audio/dma/SDL_dmaaudio.c:167:
error: 'asm' operand has impossible
constraints make: *
[build/SDL_dmaaudio.lo] Error 1
Please help me with some valuable pointers.
Thanks,
Sen
First, don't set the path to the cross-compiler as the first part of your PATH, set it as last:
export PATH=$PATH:<path to cross-compiler>
It's safer this way. Second, run ./configure --help to get all the options. What that error message would say if it was smarter is the following:
You're trying to cross-compile since you're setting the --host flag
But you're not changing any of the other options for where to find includes and libs for the target environment
I'm going to use /usr/include by default
But that's for the host system which will not work when cross-compiling
Check what other configure options you need to set to tell the configure script where to find the .h files (includes) and the libraries for your target. These usually come with the cross-compiler that you download. Also, you should probably set the CROSS_COMPILE environment variable to the cross-compiler prefix before running configure. The prefix is the part before gcc in a cross-compiler, assuming you're using GCC as your cross-compiler.

How to resolve the java.lang.UnsatisfiedLinkError in NDK in Android?

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.

Resources