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)
Related
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.
I'm having problems with the android ndk r10. I get the following: std::string has not been declared. I watched other forum threads like this, but nope of them helped me. My Application.mk looks like this:
APP_PLATFORM := android-14
APP_ABI := armeabi-v7a # build for the ARM version of MCPE
APP_CFLAGS := -O2 -std=gnu99 # optimization level 2, use C99 (for decleations in for loops, etc)
APP_CPPFLAGS := -std=c++11
LOCAL_CFLAGS := -std=c++11
APP_STL := stlport_static
Please help me!
The class std::string has not been declared because it's not there. Unfortunately, there is no std::string in NDK. Some ports of std::string exist, I remember I found one or two, but finally I decided just not to use std::string. Why? Because we already have Java strings and C strings, Java strings come from JNI calls, C strings come from files, and if you introduce one more string type, it will be more conversion than usage.
EDIT: but read the comment below.
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)".
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.