Problems exporting class for shared library on Android - android

I have a core project which I'm building as a shared library. In one of the headers, I've defined a simple class shown below:
typedef pthread_mutex_t Mutex;
class CORE_API AutoLock
{
public:
AutoLock(Mutex& m);
~AutoLock();
private:
AutoLock();
AutoLock(const AutoLock&);
AutoLock& operator=(const AutoLock&);
Mutex m_Mutex;
};
where CORE_API is defined as:
#ifdef CORE_DLL
#define CORE_API __attribute__ ((dllexport))
#else
#define CORE_API __attribute__ ((dllimport))
#endif
In the Android.mk for core, I've defined CORE_DLL under LOCAL_CFLAGS. However, when building, I get the warning:
warning: 'dllimporot' attribute directive ignored
When ndk-build gets to the other project where I want to use the AutoLock class, I get the error:
error: 'AutoLock::AutoLock()' is private
error: within this context
Why would the compiler ignore the dllexport attribute? I would hope that once that's fixed, my other project should build and be able to use the AutoLock class without any problems.

Shared libraries are created differently on Android (Linux) than with Windows.
In Windows you have the special dllimport and dllexport directives but not on Android (Linux).
When using your shared library, you should just compile with -lYourLibraryName
This might help you: http://www.adp-gmbh.ch/cpp/gcc/create_lib.html

Have a look at the sample code available in the android-ndk, specially the Android.mk file this might solve your problem.

Related

How to properly use a c++ static library (.lib) in a Android shared library (.so) project in Visual Studio?

I need to create a .so Android shared library for a project, and I need to use functions from a C++ static library (.lib). The .so library is meant to be used just as a bridge, so I can use functions from my static library in Android apps and games. I've created a C++ cross-platform Android project in Visual Studio 2017 (also testing it in VS2019), included the header file for the static library and the library itself, and everything is theoretically configured and linked.
The current library I'm using is a simple static library for tests that has just a single function:
namespace StaticLibrary
{
extern "C" void Func()
{
// something
}
}
The file for the Android looks something like this:
#include "StaticLibraryHeader.h"
extern "C"
{
// ...
void StaticLibFunc()
{
StaticLibrary::Func();
}
}
When I try to compile the project, the compiler says:
C:\\Microsoft\AndroidNDK64\android-ndk-r16b\toolchains\x86_64-4.9\prebuilt\windows-x86_64/lib/gcc/x86_64-linux-android/4.9.x/../../../../x86_64-linux-android/bin\ld: error: F:\Android_IOS_libs\MobileLibraries2019\Build\x64\Debug\libStaticLibTest_x64_Debug.lib: bad extended name index at 778
and:
undefined reference to 'Func'
I can get rid of this second error by using the --whole-archive option of the linker but then this new error shows up, along with the first one:
C:\\Microsoft\AndroidNDK64\android-ndk-r16b\toolchains\x86_64-4.9\prebuilt\windows-x86_64/lib/gcc/x86_64-linux-android/4.9.x/../../../../x86_64-linux-android/bin\ld: fatal error: F:\Android_IOS_libs\MobileLibraries2019\Build\x64\Debug\libStaticLibTest_x64_Debug.lib: attempt to map 60 bytes at offset 6324 exceeds size of file; the file may be corrupt
I've also used Google Lib2A ( https://code.google.com/archive/p/lib2a/ ) to create a .a file, but then the following error happens:
C:\\Microsoft\AndroidNDK64\android-ndk-r16b\toolchains\x86_64-4.9\prebuilt\windows-x86_64/lib/gcc/x86_64-linux-android/4.9.x/../../../../x86_64-linux-android/bin\ld: error: F:\Android_IOS_libs\MobileLibraries2019\Krilloud_Android\lib\x64\libStaticLibTestDLL_x64_Debug.a: member at 192 is not an ELF object
C:\\Microsoft\AndroidNDK64\android-ndk-r16b\toolchains\x86_64-4.9\prebuilt\windows-x86_64/lib/gcc/x86_64-linux-android/4.9.x/../../../../x86_64-linux-android/bin\ld: error: F:\Android_IOS_libs\MobileLibraries2019\Krilloud_Android\lib\x64\libStaticLibTestDLL_x64_Debug.a: member at 870 is not an ELF object
C:\\Microsoft\AndroidNDK64\android-ndk-r16b\toolchains\x86_64-4.9\prebuilt\windows-x86_64/lib/gcc/x86_64-linux-android/4.9.x/../../../../x86_64-linux-android/bin\ld: error: F:\Android_IOS_libs\MobileLibraries2019\Krilloud_Android\lib\x64\libStaticLibTestDLL_x64_Debug.a: member at 1656 is not an ELF object
I'm not an Android/Java developer, so I'm lost here. How do I properly link and use my static library in a .so project? Can it be done using Visual Studio or do I really need to install Android Studio for this? I will also need to create the same thing for iOS, so I was hoping to have both projects in a Visual Studio solution.

Why the same C++ library has much smaller size in static build than shared build, and static is not working while shared works?

I have problem when I try to use C++ library in Android studio project.
I am using statically built Qt 5.14.2 for Android.
I have Qt library project which has only 1 class with this 2 functions:
testclass.h
#include <QDebug>
#include <jni.h>
extern "C"
{
JNIEXPORT void JNICALL Java_com_example_MyTestAndroidApp_LibraryClass_log();
void logNormal();
}
testclass.cpp
JNIEXPORT void JNICALL Java_com_example_MyTestAndroidApp_LibraryClass_log()
{
qDebug() << "---> log from Qt library";
}
void logNormal()
{
qDebug() << "---> log from Qt library";
}
An in the .pro file I am using shared or staticlib to switch from shared(.so) and static(.a) library.
TEMPLATE = lib
CONFIG += shared
#CONFIG += staticlib
CONFIG += c++11
After successfully building the lib (shared and static) I got this files(for ABI x86 but others ABIS have similar sizes too):
libTestLibrary.so ---> 3,359 KB
libTestLibrary.a ---> 7 KB
For the shared (.so) library I was able to successfully call the function from android app.
In Android Studio I am creating new Native C++ project. I have Java JNI LibraryClas which is used to load the library and call the log() function from the library. I placed the library in jniLibs folder.
But for the static(.a) library there are a lot of problems. I tried to call the logNormal() function from the C++ part of the android app(from native-lib.cpp). I am not using JNI like in the shared library case. Here is what I tried:
Create new Native C++ project
Created libs(for the static library) and include(for testclass.h) folders inside app\src\main\cpp
Inside CMakeList.txt I have added this:
add_library(TestLibrary STATIC IMPORTED)
set_target_properties(TestLibrary PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/libTestLibrary.a)
target_link_libraries( native-lib TestLibrary ${log-lib} )
And I called logNormal(); from native-lib.cpp.
First I got Error about missing Qt5Core library. After adding it the same way like my library I got errors for others missing libraries and files.
I have this questions:
Why static library is so much smaller then the shared library? (7KB vs 3,359KB) I found this which is opposite from my case:
Can I somehow build my static lib with all libraries and files that it need, so I don't get errors for missing libraries?
Can I use JNI to call C++ functions from static lib? Or when calling C++ functions from static lib it must be done from the C++ part of the android project?
Sorry for the long post and more then 1 question. Any hint or help is welcome. Thank you so much in advance.

Class 'stat64' doesn't have constructor stat64(const char *,stat64*)

I am trying to build my android application with support for OpenSceneGraph. I am trying to render a simple box from my project's raw folder. However, when I build the project I am getting this compile error in the FileUtils class of the OpenSceneGraph library:
Class 'stat64' doesn't have constructor stat64(const char *,stat64*)
Any ideas what is causing the problem?
I'm also faced with such problem when I have tried to compile OpenSceneGraph to Android. The problem is that NDK's <sys/stat.h> header for Android API less that 21 doesn't contain stat64 function definition so compiler thinks that stat64 is a struct. Problem can be solved by adding
#if defined(ANDROID) || defined(__ANDROID__)
#if __ANDROID_API__ < 21
#define stat64 stat
#endif
#endif
after src/osgDB/FileUtils.cpp:92.

rand() function Bionic vs glibc

I found that rand() function from bionic does't work without including stdlib.h
extern int rand(void);
static void foo()
{
int a = rand();
}
int main()
{
foo()
return 0;
}
Results for glibc:
Compilation successful
Results for bionic:
Compilation unsuccessful
error: undefined reference to 'rand'
In bionic sources we have following implementation:
static __inline__ int rand(void) {
return (int)lrand48();
}
Why it works for glibc but not for bionic
glibc's rand() is a "normal" function located in a library. I suspect you're getting a warning about the symbol not being defined from the compiler (which cannot find it), but since the function exists in a library, the link stage can still find and link to it.
bionic's rand() is a static inline in your header file, that means it's not even defined unless the header file is included. Since the compiler cannot find it without the include and it does not exist in any library that the linker can resolve it from, compilation will fail at the linking stage.
You will get the answer if you just compare bionic and glibc sources of rand function: https://github.com/android/platform_bionic/blob/master/libc/include/stdlib.h and
http://sourceware.org/git/?p=glibc.git;a=blob;f=stdlib/rand.c;hb=glibc-2.15#l26
You can see that in bionic library it inlined in header file so without .h file you can't use it.And in glibc it is separated like most of the functions. The reason is obvious I think - bionic library was developed specially for use in embedded and mobile devices with memory and speed limits, so less code and inline optimizations is useful.

Android NDK C++ JNI (no implementation found for native...)

I'm trying to use the NDK with C++ and can't seem to get the method naming convention correct. my native method is as follows:
extern "C" {
JNIEXPORT void JNICALL Java_com_test_jnitest_SurfaceRenderer_drawFromJni
(JNIEnv* env, jclass c)
{
//
}
}
with a header wrapped in extern "C" {} aslo.
Everything compiles fine, creates a .so file and copies to the libs folder under my project, but when I debug and run in Eclipse I keep getting a log cat message that of "no implementation found for native...". Is there something i'm missing as all the NDK examples are in C?
Thanks.
There are a couple of things that can lead to "no implementation found". One is getting the function prototype name wrong, another is failing to load the .so at all. Are you sure that System.loadLibrary() is being called before the method is used?
If you don't have a JNI_OnLoad function defined, you may want to create one and have it spit out a log message just to verify that the lib is getting pulled in successfully.
You already dodged the most common problem -- forgetting to use extern "C" -- so it's either the above or some slight misspelling. What does the Java declaration look like?
An additional cause for this error: your undecorated native method name must not contain an underscore!
For example, I wanted to export a C function named AudioCapture_Ping(). Here is my export declaration in C:
JNI_EXPORT int Java_com_obsidian_mobilehashhost_MainActivity_AudioCapture_Ping(JNIEnv *pJniEnv, jobject object); //Notice the underscore before Ping
Here was my Java class importing the function:
package com.obsidian.mobileaudiohashhost;
...
public class MainActivity extends Activity {
private native int AudioCapture_Ping(); // FAILS
...
I could not get Android to dynamically link to my native method until I removed the underscore:
JNI_EXPORT int Java_com_obsidian_mobilehashhost_MainActivity_AudioCapturePing(JNIEnv *pJniEnv, jobject object);
package com.obsidian.mobileaudiohashhost;
...
public class MainActivity extends Activity {
private native int AudioCapturePing(); // THIS WORKS!
...
I had the same problem, but to me the error was in the file Android.mk. I had it:
LOCAL_SRC_FILES := A.cpp
LOCAL_SRC_FILES := B.cpp
but should have this:
LOCAL_SRC_FILES := A.cpp
LOCAL_SRC_FILES += B.cpp
note the detail += instead :=
I hope that helps.
Called extern "C" as provided in the automatically-generated Studio example, but forgot to wrap the entire rest of the file, including following functions, in {} brackets. Only the first function worked.
An additional reason: Use LOCAL_WHOLE_STATIC_LIBRARIES instead of LOCAL_STATIC_LIBRARIES in android.mk. This stops the library from optimizing out unused API calls because the NDK cannot detect the use of the native bindings from java code.
There is a cpp example under apps in ndk:
https://github.com/android/ndk-samples/blob/master/hello-gl2/app/src/main/cpp/gl_code.cpp
Use javah (part of Java SDK). Its the tool exactly for this (generates .h header from .class file).
If your package name includes _ character, you should write 1(one) after _ character as shown below:
MainActivity.java
package com.example.testcpp_2;
native-lib.cpp
JNICALL
Java_com_example_testcpp_12_MainActivity_stringFromJNI(
I try all above solutions, but no one can solved my build error(jni java.lang.UnsatisfiedLinkError: No implementation found for...),
at last I found that I forget to add my verify.cpp source file to CMakeList.txt add_library segement(verify.cpp is auto generate by Ctrl + Enter short key, maybe other file name), hope my response can help some one.
my build environment: Gradle + CMake
I Faced the same problem, and in my case the reason was that I had underscore in package name "RFID_Test"
I renamed the Package and it worked.
Thanks user1222021
I faced the same problem twice. It happened, that the phone I tried to start the app from Android Studio used an API level that I haven't downloaded yet in Android Studio.
Upgrade Android Studio to the latest version
Download the necessary API from within Android Studio

Categories

Resources