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++?
Related
I have seen the similar questions undefined reference to std::ios_base::Init::Init() and undefined reference to `std::ios_base::Init::Init()' but I'm not sure whether I have the same situation.
I'm configuring opencv for android 3.4.7 on Android Studio 3.5. I imported libs of opencv by editing CMakeList.txt and build.gradle:
set(opencv_version OpenCV3-android-sdk)
set(OpenCV_STATIC ON)
set(OpenCV_DIR /home/lynx/Android/Proj/${opencv_version}/sdk/native/jni)
find_package(OpenCV REQUIRED)
if (OpenCV_FOUND)
message(WARNING "opencv libs: ${OpenCV_LIBS}")
else (OpenCV_FOUND)
message(WARNING "opencv not found!")
endif(OpenCV_FOUND)
target_link_libraries(
${OpenCV_LIBS})
sourceSets {
main {
jniLibs.srcDirs = ['/home/lynx/Android/Proj/OpenCV3-android-sdk/sdk/native/libs']
}
}
and my native-lib.cpp is
#include <jni.h>
#include <string>
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_stitch_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from OpenCV " + (std::string)CV_VERSION;
return env->NewStringUTF(hello.c_str());
}
When building the project it shows many undefined reference errors from the file of opencv. It seems not the problem of linking cpp files with c linker: it called clang++ to do the task and when not using opencv, the project can be build successful.
So is it because that I didn't correctly configured opencv?
This is usually a case of using a library built against a different STL than you're using. I can't tell with the information you've given, but there are a lot of other questions on SO where people build their app with libc++ but build opencv with libstdc++. These are not compatible. See NDK - problems after GNUSTL has been removed from the NDK (revision r18).
I'm compiling a library in gradle like this:
externalNativeBuild {
// Encapsulates your CMake build configurations.
cmake {
// Provides a relative path to your CMake build script.
path "../../JRTPLIB/CMakeLists.txt"
}
}
I need to compile another source, probably using cmake or any other tool, also inside gradle, that will link to the compiled object from the lib above (JRTPLIB).
The obvious way would be to include the source of the library above in the lib I want to use and just link, but I need to do it separatedly.
The other way would be to rely on the generated library object at android/app/build/intermediates/cmake/... but first, it's supposed to have a debug binary and a release one in this folder, making it more coplicated to link, and secondly, it's not an elegant solution.
So how to do it?
Here's a simple example that accomplishes something like what I think you're trying to do.
Two libraries are being built and packaged into the app, where the second library depends on the first one. I chose to have lib1 and lib2 as part of the current project, but they could really be located anywhere.
app/CMakeLists.txt
cmake_minimum_required(VERSION 3.4.1)
add_subdirectory(src/main/cpp/lib1)
add_subdirectory(src/main/cpp/lib2)
app/src/main/cpp/lib1/CMakeLists.txt
cmake_minimum_required(VERSION 3.4.1)
add_library( # Sets the name of the library.
native-lib1
SHARED
native-lib1.cpp )
target_include_directories(native-lib1 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
app/src/main/cpp/lib2/CMakeLists.txt
cmake_minimum_required(VERSION 3.4.1)
add_library( # Sets the name of the library.
native-lib2
SHARED
native-lib2.cpp )
find_library(log-lib log)
# native-lib2 depends on log and native-lib1
target_link_libraries(native-lib2 ${log-lib} native-lib1)
app/src/main/cpp/lib1/native-lib1.h
#pragma once
int foo();
app/src/main/cpp/lib1/native-lib1.cpp
#include "native-lib1.h"
int foo()
{
return 42;
}
app/src/main/cpp/lib2/native-lib2.cpp
#include <jni.h>
#include <android/log.h>
#include <string>
#include "native-lib1.h"
extern "C" JNIEXPORT jstring JNICALL Java_com_example_cmaketwolibs_MainActivity_stringFromJNI(
JNIEnv *env, jobject thiz) {
// Call function from native-lib1
__android_log_print(ANDROID_LOG_WARN,
"native-lib2", "Calling native-lib1\'s foo(): %d",
foo());
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
Working on an Android NDK project. The project is using CMake to build the C++ libraries.
The library has the following structue -
Main Library
main.cpp
CMakeLists.txt
hello (sub library)/
CMakeLists.txt
include/
hello.h
src/
hello.c
world (sub library)/
CMakeLists.txt
include/
world.h
src/
world.c
The contents are the following:
main.cpp
#include <jni.h>
#include <string>
#include <hello.h>
#include <world.h>
extern "C"
JNIEXPORT jstring
JNICALL
Java_com_test_myapplication_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string str = hello() + world();
return env->NewStringUTF(str.c_str());
}
CMakeLists.txt for main.cpp
cmake_minimum_required(VERSION 3.4.1)
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/cpp/native-lib.cpp )
add_subdirectory(src/main/cpp/hello)
include_directories(src/main/cpp/hello)
add_subdirectory(src/main/cpp/world)
include_directories(src/main/cpp/world)
target_link_libraries( # Specifies the target library.
native-lib
hello
world)
world.h
#include <string>
std::string world();
world.c
#include "world.h"
std::string world() {
return std::string("world");
}
CMakeLists.txt
cmake_minimum_required (VERSION 2.8)
project (world)
add_definitions(/DVERSION="0.4.0")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Os")
include_directories(include/)
set(SOURCES
src/world.c
include/world.h
)
add_library(world STATIC IMPORTED
${SOURCES}
)
target_include_directories(world PUBLIC ./)
The content is the same for the "hello" library as the only difference is the output returned from hello's function.
Now, my experience with CMake is close to non-existent and I can't get this to work. I'm constantly getting errors upon building it. Latest error is the following -
CMake Error at src/main/cpp/hello/CMakeLists.txt:19
(target_include_directories): Cannot specify include directories for
imported target "hello". CMake Error at
src/main/cpp/world/CMakeLists.txt:19 (target_include_directories):
Cannot specify include directories for imported target "world".
I just can't find a way to compile all of it into a simple library that will be used in the app. Sometimes I get " not found", sometimes it can't find the header files and etc.
I'd appericiate if someone will be able to post a simple structure and CMake of the correct way of doing so as I'm lost.
In the actual project I try to use libmicrohttpd, but again, can't make it work. I've tried using CentOS's libraries but Android Studio seems to use the system's libraries which causes things to get messed up. This is the reason for which I download the library and try to compile it via Android Studio.
So, again, if anyone will be able to find a way to compile all of the 3 libraries together into a single library (main) which connected the other 2 (hello, world), I'd greatly appericiate it.
Much appericiated.
I'm trying to use the NDK, and I've been working with official samples to get started. I've managed to get the "Hello JNI" sample working :
https://github.com/googlesamples/android-ndk/tree/master/hello-jni
(I work with Android Studio)
But I don't know how to add source files to the project. So, for example, the JNI function provided is (I removed macros that aren't useful for this) :
jstring Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
return (*env)->NewStringUTF(env, "Hello from JNI !");
}
Let's say I want to get the string from a C function "getString()", defined as below:
const char* getString()
{
return "Hello from getString()";
}
//Then, JNI function becomes
jstring Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
return (*env)->NewStringUTF(env, getString());
}
If I create a getString.h where I declare the function, and put the implementation in my current and only one source file, everything works like a charm. So, headers do work.
However, If I create a GetString.c file where I put the implementation, my code stops compiling. I do understand it's because GetString.o doesn't get linked (or even compiled ? I don't know), but I have no idea about how to tell Android Studio to compile both hello-jni.c (sample's source fil) and GetString.c
Should I get my hands dirty and modify gradle files ?
I also heard about a file called Android.mk which acts like a makefile, but I haven't found it in the project. If it's mandatory, should I create it, and what to put in it ? If it's not, how does the IDE knows he must build hello-jni.c ? (AKA "how did the project get configured before I modified it")
If you need any information about java-side things or gradle scripts, just have a look on the github link :)
Well, a bit of testing was enough to confirm what I thought. I just had to create Android.mk :
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := hello-jni.c, GetString.cpp
LOCAL_MODULE := hello-jni
include $(BUILD_SHARED_LIBRARY)
I have namespace error building with ndk-build for native code in my Android app. The error sample is
C:/adt-bundle-windows-x86/ndk/sources/cxx-stl/gnu-libstdc++/4.6/include/bits
/allocator.h:54:1: error: unknown type name 'namespace'
C:/adt-bundle-windows-x86/ndk/sources/cxx-stl/gnu-libstdc++/4.6/include/bits
/allocator.h:55:1: error: expected ',' or ';' before '{' token
For OpenCV settings, my Application.mk file is
APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := armeabi
APP_PLATFORM := android-10
That means I am using gnu-libstdc++ in compiling the native code.
My jni.c has c extension. That is I receive from my third party and they prefer in .c extension as if they have to change to .cpp extension, they have to change a lot in their other libraries.
So far is OK, I did all project settings for OpenCV for native development and if I do ndk-build, I can make .so libraries.
The problem of those namespace error happened when I include OpenCV's header file #include <opencv2/contrib/detection_based_tracker.hpp> into jni.c and I got a lot of name space error. If I include that #include <opencv2/contrib/detection_based_tracker.hpp> into cpp file, no error.
My questions are
(1)Is the error is because of using .hpp file in .c file?
(2)If I have no choice and have to use that .c file, is there way around to remove that error?
Thanks
My assumption would be that the file is compiled as a "C" file instead of a "C++" file because of the extension ".c". That means you cannot use any "C++" Code in your jni.c, wike classes or namespaces. These are obviously used however in your file "detection_based_tracker.hpp" that you are using.
So the problem is not that you include a file named ".hpp", but that this file contains "C++" code wich the "C" compiler cannot handle.
One solution to this problem is to only use the "C" functions in opencv (for example "opencv2/imgproc/imgproc_c.h" instead of "opencv2/imgproc/imgproc.hpp"). However, your function "detection_based_tracker.hpp" might not have a "C" version, as far as I can see.
The other option is to add a second file "function.cpp" with the "C++" functions that use opencv. The functions from "function.cpp" can be declared in a file "functions.h" and included in your "jni.c", so you can still use opencv c++ functions. Be careful to only use C style functions then, though (no classes, namespaces, ...) in your "function.h" file, otherwise you will have the same problems as before.