The following code will crash at vec2(vec.size()) if I build the code for Android x64 with ndk-build (x86 worked well).
hello.cpp
#include <vector>
#include <stdio.h>
using namespace std;
int main(int argc, char* argv[])
{
vector<int> vec;
vec.push_back(11);
vec.clear();
vector<int> vec2(vec.size());
return 0;
}
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello
LOCAL_SRC_FILES := hello.cpp
include $(BUILD_EXECUTABLE)
Application.mk
APP_ABI := x86_64
APP_STL := stlport_static
It is weird. The value of vec.size() equals to 0. If I change the code as follows:
vector<int> vec2(0);
the app will not crash. The issue seems to be caused by compiler optimization. CFLAG -O2 is used by default. If I add another CFLAG, such as -O0 after it, the app will not crash either.
Does anybody know why?
Thanks!
This happened to me too, seems there is a bug in stlport_static.
I put trace before push_back, and after, and in the copy constructor of what I push_back. It does not reach copy constructor if it crashed. If it happened to not crash, then every thing's fine.
I tried use std::map, using size of map as key, it does not crash, no copy constructor is called. Maybe std::map clone the item in different way.
Finally I use gnustl_static instead of stlport_static without change source code, everything works fine.
Related
I am attempting to compile an Android NDK library to use android-ndk-profiler for profiling.
In Audio.h, I have:
extern "C" {
void monstartup(char const*);
void moncleanup();
}
In Audio.cpp, I have:
#include "Audio.h"
com_example_native_init(JNIEnv *env, jobject thiz) {
// Start profiling
monstartup("libDMAudiolib.so");
...
}
I am compiling with
ndk-build NDK_MODULE_PATH=/cygdrive/c/ndk_modules
And the exact compilation error I am getting is
Path/to/Audio.cpp:136: error: undefined reference to 'monstartup'
Are there any android ndk gurus out there who can tell me what's going on?
Sounds like monstartup isn't getting linked in (that looks like a linker error, not a compiler error).
Make sure your Android.mk has the additions shown on the Usage page, particularly the LOCAL_STATIC_LIBRARIES directive.
ndk-build does not work well with cygwin. Please use C:/ndk-modules and similar notation in your scripts.
LOCAL_STATIC_LIBRARIES := android-ndk-profiler
is correct, but it requires that your Andorid.mk includes something like
include $(CLEAR_VARS)
LOCAL_PATH := c:/ndk-modules/android-ndk-profiler
LOCAL_MODULE := android-ndk-profiler
LOCAL_SRC_FILES := libandprof.a
include $(PREBUILT_STATIC_LIBRARY)
(see http://android-ndk-profiler.googlecode.com/svn-history/r11/wiki/Usage.wiki)
This happened to me and it was due to LOCAL_STATIC_LIBRARIES being in the wrong place in the Android.mk file. In particular, it had to be before the line "include $(BUILD_SHARED_LIBRARY)".
I've got a simple task to do. I need to merge set of pictures into a video using ffmpeg working in android environment.
After over a week fighting with different tutorials and examples explaining how to run compile ffmpeg I have, let's say, middle success. I've finally compiled ffmpeg for android.
I followed this example:
https://github.com/appunite/AndroidFFmpeg
which worked best for me.
As a result of building ffmpeg a have following directory structure:
[Project]/jni/ffmpeg-build/armeabi-v7a/libffmpeg.so
[Project]/jni/ffmpeg-build/armeabi/libffmpeg.so
[Project]/jni/ffmpeg-build/mips/libffmpeg.so
[Project]/jni/ffmpeg-build/x86/libffmpeg.so
I also followed the ndk examples so I have running c code from java:
#include <string.h>
#include <jni.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <android/log.h>
#include <stdlib.h>
#include <stdbool.h>
bool initted = false;
static JavaVM *sVm;
jstring Java_com_example_hellojni_HelloJni_stringFromJNI(JNIEnv* env, jobject thiz) {
char **argv;
char *cmd;
int argc;
// cmd = "ffmpeg -version";
// argv = parsedargs(cmd, &argc);
// ffmpeg(argc, argv);
return (*env)->NewStringUTF(env, "Hello from JNI !");
}
My question is how to run function from ffmpeg from my "hello-jni" c-file. I've read I need to write a wrapper over ffmpeg which my hello-jni is intended to be.
Here is my Android.mk which probably is importat part to achieve my goal, but honestly I don't understand some lines set in this file. Or simply I don't know how to make things work.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := ffmpeg-prebuilt
LOCAL_SRC_FILES := ffmpeg-build/$(TARGET_ARCH_ABI)/libffmpeg.so
LOCAL_EXPORT_C_INCLUDES := ffmpeg-build/$(TARGET_ARCH_ABI)/include
LOCAL_EXPORT_LDLIBS := ffmpeg-build/$(TARGET_ARCH_ABI)/libffmpeg.so
LOCAL_PRELINK_MODULE := true
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_ALLOW_UNDEFINED_SYMBOLS=true
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
LOCAL_C_INCLUDES := $(LOCAL_PATH)/ffmpeg-build/$(TARGET_ARCH_ABI)/include
LOCAL_SHARED_LIBRARY := ffmpeg-prebuilt
#LOCAL_CFLAGS += -g -Iffmpeg-prebuilt -Ihello-jni -Wno-deprecated-declarations
#LOCAL_LDLIBS += -llog -lz -landroid ffmpeg-build/$(TARGET_ARCH_ABI)/libffmpeg.so
include $(BUILD_SHARED_LIBRARY)
One more thing. I've found an example how to wrap ffmpeg's main function. It'd be the easiest way to use ffmpeg for me sinse I don't know ffmpeg's api and I hope it's possible to run ffmpeg this way:
Can FFmpeg be used as a library, instead of a standalone program?
To sum up, I think my problems are due to completely lack of c/c++ knowledge at all, especially how to use run any function from .so library.
I hope someone can help me :).
https://github.com/halfninja/android-ffmpeg-x264/blob/master/Project/jni/videokit/uk_co_halfninja_videokit_Videokit.c
Look at the 'JNI_Call...' in the link above. That is how to call the wrapper for 'ffmpeg.main()' from android.
https://github.com/halfninja/android-ffmpeg-x264/blob/master/Project/jni/videokit/ffmpeg.c
use link above and find 'main()' at the very end. This is example of very slightly altered version of ffmpeg.c (logger altered for java/android ndk).
If you study these samples , you should get feeling for how to wrapper ffmpeg.main() in one of the other projects if you want to use it. The logger issue is moot at this point so the more modern [android-ffmpeg] projects on git can just make ffmpeg.c out of the box and use it with JNI. The only thing u may still have to change is the 'exit()' at the very end of main().
So I'm attempting to use libopus on my native code for an Android application.
My Android.mk file looks like this:
PLATFORM_PREFIX := /opt/android-ext/
LOCAL_PATH := $(PLATFORM_PREFIX)/lib
include $(CLEAR_VARS)
LOCAL_MODULE := libopus
LOCAL_SRC_FILES := libopus.a
include $(PREBUILT_STATIC_LIBRARY)
# I have to redeclare LOCAL_PATH because the library is in /opt/android-ext/
# and my project is somewhere else. Not very elegant.
LOCAL_PATH := /home/sergio/workspace/Project/jni
include $(CLEAR_VARS)
LOCAL_MODULE := opusUtilsNative
LOCAL_SRC_FILES := opusUtilsNative.c
LOCAL_C_INCLUDES += $(PLATFORM_PREFIX)/include
LOCAL_STATIC_LIBRARIES := android_native_app_glue libopus
include $(BUILD_SHARED_LIBRARY)
And my code in opusUtilsNative.c looks like this:
#include "opusUtilsNative.h"
#include <opus/opus.h>
#include <opus/opus_types.h>
JNIEXPORT jbyteArray JNICALL Java_Project_OpusUtils_encode
(JNIEnv * je, jclass jc, jbyteArray data){
int rc;
opus_int16 * testOutBuffer;
unsigned char* opusBuffer;
OpusDecoder *dec;
dec = opus_decoder_create(48000, 2, &rc);
return data;
}
And when I try to build it, it works fine only if I remove the line that uses the "opus_decoder_create" function. Else I will get this:
error: undefined reference to 'opus_decoder_create'
I can see that opus_decoder_create is clearly defined on opus.h, which is clearly being included since if I exclude that line, I'll get an error regarding the opus_int16 and OpusDecoder declarations. How come some definitions are being included and some aren't?
Any help will be greatly appreciated.
This was tricky. After digging around for a bit, I realized I hadn't cross-compiled the opus library correctly, and I didn't have an ARM binary after all.
A good way to verify if your library was cross-compiled correctly:
cd /opt/android-ext/lib #Or wherever the .a file is
ar x libopus.a
file tables_LTP.o #Or any of the .o files generated by ar x
The output should look like this:
tables_LTP.o: ELF 32-bit LSB relocatable, ARM, version 1 (SYSV), not stripped
Otherwise, you might want to double-check your cross-compilation process.
It's error from linker, not from compiler. You forgot to add reference to correspondent libraries to your Android.mk file, do smth like this:
LOCAL_LDLIBS += -lopus
I forgot to integrate one key library
LOCAL_LDLIBS := -lGLESv2
This fixed my problem.
I've seen questions similar to this one, but the scenarios are not exactly the same, nor can I get an answer that works on my problem.
I have the source code for a C++ library. We need to use this library as part of an android application but it also needs to be available for third party to use as a C++ library.
I have a makefile that generates the .a file out of the library's source code, using ndk's compiler. That's the pure C++ part.
On the Java part, I have a simple demo project with a simple activity containing a button. When the button is pressed a call to native code is made.
Everything works fine as long as I don't try to call a function from the library from the JNI function.
Here are the sources for the library:
SimpleMath.h
int Add(int aNumber1, int aNumberB);
SimpleMath.cpp
#include "SimpleMath.h"
int Add(int aNumberA, int aNumberB)
{
return aNumberA + aNumberB;
}
The makefile
APP = simple_app
LIBRARY = simple_library.a
OBJECTS = SimpleMath.o
CFLAGS = -Wall -pedantic
NDK_PATH = /home/jug/perforce/jug_navui_personal_main/Env/Linux/Android/ndk/r7c
CXX = $(NDK_PATH)/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-g++
AR = $(NDK_PATH)/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-ar
SYSTEM_LIBS = -lstdc++ -lm
INCLUDE_PATH += ${NDK_PATH}/platforms/android-9/arch-arm/usr/include
all: $(LIBRARY)
$(LIBRARY):
$(CXX) -c SimpleMath.c
$(AR) rcs simple_library.a SimpleMath.o
clean:
rm *.o *.a
On the java side, these are the files:
hello-jni.c
#include <string.h>
#include <jni.h>
#include "../../../native/simple_library/SimpleMath.h"
jstring Java_com_amstapps_samples_draft08jni_MainActivity_helloJni(JNIEnv* env, jobject obj)
{
// Uncommenting the line below results in undefined-symbol compile error
//int d = Add(1, 2);
return (*env)->NewStringUTF(env, "Hello from JNI!");
}
Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := my_simple_library
LOCAL_ARM_MODE := arm
LOCAL_SRC_FILES := ../../../native/simple_library/simple_library.a
include $(PREBUILT_STATIC_LIBRARY)
#include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := eng
LOCAL_ARM_MODE := arm
#LOCAL_PRELINK_MODULE := false
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
LOCAL_C_INCLUDES := ../../../android/native/simple_library
LOCAL_STATIC_LIBRARIES := my_simple_library
#LOCAL_WHOLE_STATIC_LIBRARIES := my_simple_library
include $(BUILD_SHARED_LIBRARY)
Application.mk
APP_MODULES := my_simple_library hello-jni
As I said, the problem comes when I to actually make use of the functionality in the library from the jni native code in java application.
Now, I'm not longer sure whether my problem is in the static-library's makefile or on the Android.mk. I first thought it must have to do with the generation of the library itself, but at this point, after seeing there are so many options I didn't know about in Android.mk, I have to admit I have no clue.
What else..?
Oh, yes, I also noticed my pure C++ library is using cpp extension whereas the jni code in java project is using c extension. I tried to have the latter using cpp as well, but compiler complains. Could this be part of the problem?
The error code that I get when trying to compile the Android.mk file is "undefined symbol", so, is the list of functions in simple_library.a (there's actually 1 function) not visible to hello-jni.c because of it being C++ and not plain C?
Another thing you might notice is I'm trying to build the static library on its own makefile as opposed to generating it with Android.mk; there's a reason for that, but at this point I would also be happy if I had to have it in generated by Android.mk if that's what it takes.
I don't see any way to add an attachment in here so that to share a zip with the project.
Let me know if there's something I'm missing.. Otherwise the code is in a depot in bitbucket, so I can easily share it with anyone having an account there too.
Thanks for you answers.
You write a lot of correct things, but you're missing just one.
The function's name gets mangled in C++. And in the .so file you do not get "Add" symbol, but something like "Add#8i". To avoid mangling just use the
extern "C" int Add(int x, int y)
declaration in the .cpp file and in the .h.
Usually one also adds the
/// Some .h file
#ifdef __cplusplus
extern "C" {
#endif
/// Your usual C-like declarations go here
#ifdef __cplusplus
} // extern "C"
#endif
And the
extern "C"
for each of the exported functions in the .cpp file.
I can't seem to get the following trivial code to compile/link and the problem seems specific to std::wstring and the gnustl_static C++ library. Any help would be appreciated.
main.cpp file:
#include <string>
int main(void)
{
std::wstring wtest(L"Test");
return 0;
}
Application.mk file:
APP_CFLAGS += -fexceptions
APP_STL := gnustl_static
Android.mk file:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := TestWCharApp
LOCAL_CFLAGS := -D_GLIBCXX_USE_WCHAR_T
LOCAL_SRC_FILES := main.cpp
include $(BUILD_EXECUTABLE)
When attempting to link the above application using gnustl_static I get the following error message:
undefined reference to `std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >::basic_string(wchar_t const*, std::allocator<wchar_t> const&)'
If I change APP_STL to stlport_static and define _STLP_HAS_WCHAR_T everything seems to compile/link/run fine. I verify it works by uploading the exe to the emulator and running it via the shell.
I'm going to need to use the gnustl implementation for c++ exception support otherwise I'd go with stlport_shared. Any clues as to why the above sample works for stlport_static but not gnustl_static?
It's a problem with the file $NDK/sources/cxx-stl/gnu-libstdc++/Android.mk
Add the following line to that file:
LOCAL_MODULE_FILENAME := libstdc++
What's your target OS? According to this thread, gnustl_static doesn't support wchar_t prior to 2.3.
From the platforms\android-*\arch-arm\usr\include\wchar.h header file:
/* IMPORTANT: Any code that relies on wide character support is essentially
* non-portable and/or broken. the only reason this header exist
* is because I'm really a nice guy. However, I'm not nice enough
* to provide you with a real implementation. instead wchar_t == char
* and all wc functions are stubs to their "normal" equivalent...
*/
Funny though that running the following simple program in an android emulator show that wchar_t is 4 bytes.
#include <stdio.h>
int main(void)
{
printf("Size of wchar is %d\n", sizeof(wchar_t));
return 0;
}
Another thing to consider. The JNI bridge provides two useful ways to marshal string data. GetStringUTFChars (returns const char ) and GetStringChars (returns jchar). How many bytes do you think a jchar is defined as ... 2.
Make sure you run "ndk-build clean" and manually delete your libs/ and obj/
directories.
(Reference)