I built FAT APK from hello-gl2 example from NDK examples.
It has 2 folders armeabi and armeabi-v7a
I added following method to it
JNIEXPORT jstring JNICALL Java_com_android_gl2jni_GL2JNILib_status(JNIEnv * env, jobject obj)
{
const char * result = "Hop";
#ifdef __ARM__
result = "__ARM__";
#endif
#ifdef __ARM_ARCH_5TE__
result = "__ARM_ARCH_5TE__";
#endif
#ifdef __ARM_ARCH_7A__
result = "__ARM_ARCH_7A__";
#endif
return env->NewStringUTF(result);
}
When app runs it calls that method and shows returned value in popup dialog.
When I run app on device with ARMv7 CPU I get __ARM_ARCH_5TE__ message instead of __ARM_ARCH_7A__
Then I delete armeabi folder in APK and re-install APK. I see __ARM_ARCH_7A__ message
If I compile armeabi-v7a only APK then I see __ARM_ARCH_7A__ and it does not work on ARMv6 device.
I wish to compile FAT APK that will run armeabi-v7a lib on ARMv7 CPU and armeabi on ARMv6 CPU.
What I am doing wrong or missing to do?
I'm guessing you are getting this Android ICS bug:
http://www.moodstocks.com/2012/03/20/ice-cream-sandwich-why-native-code-support-sucks/
https://groups.google.com/forum/#!msg/android-ndk/N8FLjvM81pg/2rYeClQZcckJ
Related
I am working on Android native project using C++ code built using CMake. Currently my app is running fine and native lib(.so) is successfully loaded using System.loadLibrary().
But I want to test JUnit tests on my mac in Android Studio. When running tests on mac, It throws error
myapp.dylib not found.
Here is my CMakeLists.txt :
cmake_minimum_required(VERSION 3.18.1)
# Declares and names the project.
project("myapplication")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin)
add_library( # Sets the name of the library.
myapplication
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
native-lib.cpp
native2.cpp)
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log)
Here is my cpp file:
#include <jni.h>
#include <string>
#include "header.h"
#include<android/log.h>
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_myapplication_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
return env->NewStringUTF(hello.c_str());
}
To build .dylib when running cmake from command line, I get other errors like jni not found and liblog(android log library) not found.
Is there a way that I can build .dylib for mac OS in such a way that it can resolve android specific dependencies like jni and log library?
I am building a C++ library for android. I have X.so shared library which ends up in the android app and it's accessed through JNI. I also have a Y.a static library which has few generic functions that is used by X.so. Y.a also has some JNI interface functions as well that should be accessible by the android app.
Currently the problem I'm having is that, after building Y.a, I can see all the symbols I need to be exported. But after linking that to X.so, linker discards all the JNI interface functions because they are not used internally. I tried the following 2 options without any luck,
1.
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT void JNICALL myImportantFunction(JNIEnv*, jclass);
.
.
.
void* volatile tmp = (void*)&myImportantFunction;
#ifdef __cplusplus
}
#endif
2.
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT void __attribute__((used)) JNICALL myImportantFunction(JNIEnv*, jclass);
.
.
.
#ifdef __cplusplus
}
#endif
If there are any clang attributes or hacks which can force the linker not to discard specific functions I need (when I'm building Y.a) it would be ideal. Thank you all for any help in this regards.
If you want to keep the entire Y.a, then -Wl,--whole-archive -lY -Wl,--no-whole-archive is indeed the way to go.
If you want to keep only specific symbols from Y.a, but let the linker discard other (unused) object files from it, then you need to tell the linker that these functions are used, like so:
g++ -u myImportantFunction x1.o x2.o ... -lY -shared -o X.so
I am using pjsip library through android ndk. I used Android NDK 16 to compile pjsip. One user (HTC One, Android 5.0.2) faced a lot of crashes while trying to start our project. This is the error:
Fatal Exception: java.lang.UnsatisfiedLinkError
dlopen failed: cannot locate symbol "stdin" referenced by "libpjsua2.so"...
... .PjSipApp.<clinit>
In the project we have .so-files for 4 abis, as stated in google android ndk official docs: arm64-v8a, armeabi-v7a, x86, x86_64.
Here is how I load libraries in code:
public class PjSipApp {
private static final String TAG = "Pjsua-PjSipApp";
static {
try {
System.loadLibrary("openh264");
System.loadLibrary("yuv");
} catch (UnsatisfiedLinkError ignore) {
}
System.loadLibrary("pjsua2");
Log.v(TAG, "LibraryLoaded");
}...
So System.loadLibrary("pjsua2"); throws this UnsatisfiedLinkError.
Maybe anyone knows, what is the reason for this?
You probably compiled binaries with a higher API Level.
This is how they are defined in stdio.h
#if __ANDROID_API__ >= 23
extern FILE* stdin __INTRODUCED_IN(23);
extern FILE* stdout __INTRODUCED_IN(23);
extern FILE* stderr __INTRODUCED_IN(23);
/* C99 and earlier plus current C++ standards say these must be macros. */
#define stdin stdin
#define stdout stdout
#define stderr stderr
#else
/* Before M the actual symbols for stdin and friends had different names. */
extern FILE __sF[] __REMOVED_IN(23);
#define stdin (&__sF[0])
#define stdout (&__sF[1])
#define stderr (&__sF[2])
#endif
So, if you built for API level >= 23, the symbol will resolve to File* stdin which doesn't exist in API < 23. I'd suggest to reduce the API level.
I am just initializing ffmpeg by calling av_register_all in Android jni code
JNIEXPORT jstring JNICALL Java_com_testplayer_MainActivity_ffmpegOpen( JNIEnv* env, jobject thiz, jstring path)
{
const char *input_filename = "mtbiketribe-small.mp4";
av_register_all();
return env->NewStringUTF("Success in av_register_all");
}
I am including libavcodec, libavformat, libavutil in extern "C" in the file.
In makefile I am including prebuilt ffmpeg.so.
My code is building fine but on running the code I am getting error in av_register_all.
segmentation fault :fatal signal 11 at 0xa660001d.
Please point why I am getting this error.
I'm afraid it is unlikely anyone would be able to help you with the limited information you provided. Most likely the FFmpeg build you're using is not compatible with your device/CPU. Are you running it on an emulator?
If you want to debug it, what you need to do is to compile a standalone C application which would only have an av_register_all call, and run it under gdb so you can trace the crash.
I am playing with android ndk. I am using Window Vista with cygwin (latest version). I compiled and launched the hello world jni sample on my phone. It is working. The code is (is a .cpp file):
#include <string.h>
#include <jni.h>
extern "C" {
JNIEXPORT jstring JNICALL Java_org_android_helloworld_HelloworldActivity_invokeNativeFunction(JNIEnv* env, jobject javaThis);
};
jstring Java_org_android_helloworld_HelloworldActivity_invokeNativeFunction(JNIEnv* env, jobject javaThis)
{
return env->NewStringUTF("Hello from native code!");
}
I wanted to add some modifications, just to play with it a bit:
#include <algorithm>
and then, in the function above, i added:
int a;
a=std::min<int>(10, 5);
but the compiler says that it cannot find the file 'algorithm' and that min() is not part of std.
After a bit of searching, i have found that the android ndk has a gnu-libstdc++ directory with all the std files needed. Reading the NDK docs, i have learned that usint std::* should work without any modification to the code (if one include the proper header files). But it seems that gcc on cygwin is not able to find the needed files.
What are the steps to do in order to be able to use std and stl within a .cpp file in an android ndk app?
From NDK r5's docs/CPLUSPLUS-SUPPORT.html:
By default, the headers and libraries for the minimal C++ runtime system
library (/system/lib/libstdc++.so) are used when building C++ sources.
You can however select a different implementation by setting the variable
APP_STL to something else in your Application.mk, for example:
APP_STL := stlport_static
To select the static STLport implementation provided with this NDK.
Value APP_STL values are the following:
system -> Use the default minimal C++ runtime library.
stlport_static -> Use STLport built as a static library.
stlport_shared -> Use STLport built as a shared library.
gnustl_static -> Use GNU libstdc++ as a static library.
Which NDK are you using? Have you tried compiling one of the sample applications that utilize the STL such as test-libstdc++?