I have two questions here.
- How to compile c++ source file into android?
- How to use an already generated c++ .so file
My Dev environment:
- Windows 10
- Android Studio 3.1.4
Q1
I have MyClass.h and MyClass.cpp that I want to use in Android. All of the example I have seen is to call the cpp function inside helloJni.cpp. How do i call other .cpp/.h files in helloJni.cpp??
These are what I have created.
app/src/main/cpp/MyClass.h
#ifndef MYCLASS_H_
#define MYCLASS_H_
class MyClass {
public:
MyClass();
virtual ~MyClass();
std::string hello();
};
#endif /* MYCLASS_H_ */
app/src/main/cpp/MyClass.cpp
#include <iostream>
#include "MyClass.h"
#include <string>
using namespace std;
MyClass::MyClass() {
// TODO Auto-generated constructor stub
}
MyClass::~MyClass() {
// TODO Auto-generated destructor stub
}
string MyClass::hello() {
string s = "hello from MyClass";
return s.c_str();
}
app/src/main/cpp/helloJni.cpp
#include <jni.h>
#include <string>
#include "MyClass.h"
extern "C"
JNIEXPORT jstring JNICALL Java_com_example_MainActivity_stringFromHello(
JNIEnv *env,
jobject /* this */) {
MyClass myClass;
return env->NewStringUTF(myClass.hello().c_str());
}
app/src/main/java/com/example/MainActivity.java
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("helloJni");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView jni2 = findViewById(R.id.jni_2);
jni2.setText(stringFromHello());
}
public native String stringFromHello();
}
app/CMakeLists.txt
# Sets the minimum version of CMake required to build your native library.
# This ensures that a certain set of CMake features is available to
# your build.
cmake_minimum_required(VERSION 3.4.1)
# Specifies a library name, specifies whether the library is STATIC or
# SHARED, and provides relative paths to the source code. You can
# define multiple libraries by adding multiple add_library() commands,
# and CMake builds them for you. When you build your app, Gradle
# automatically packages shared libraries with your APK.
add_library( # Specifies the name of the library.
helloJni
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/cpp/helloJni.cpp )
add_library( # Specifies the name of the library.
MyClass
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/cpp/MyClass.cpp )
# Specifies a path to native header files.
include_directories(src/main/cpp/)
Error when i built in Android Studio:
Build command failed.
Error while executing process C:\Android\Sdk\cmake\3.6.4111459\bin\cmake.exe with arguments {--build C:SomeDir\android\TestNdk\app\.externalNativeBuild\cmake\debug\x86_64 --target helloJni}
[1/2] Building CXX object CMakeFiles/helloJni.dir/src/main/cpp/helloJni.cpp.o
[2/2] Linking CXX shared library ..\..\..\..\build\intermediates\cmake\debug\obj\x86_64\libhelloJni.so
FAILED: cmd.exe /C "cd . && C:\Android\Sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++.exe --target=x86_64-none-linux-android --gcc-toolchain=C:/Android/Sdk/ndk-bundle/toolchains/x86_64-4.9/prebuilt/windows-x86_64 --sysroot=C:/Android/Sdk/ndk-bundle/sysroot -fPIC -isystem C:/Android/Sdk/ndk-bundle/sysroot/usr/include/x86_64-linux-android -D__ANDROID_API__=21 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wa,--noexecstack -Wformat -Werror=format-security -std=c++11 -O0 -fno-limit-debug-info -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libatomic.a -nostdlib++ --sysroot C:/Android/Sdk/ndk-bundle/platforms/android-21/arch-x86_64 -Wl,--build-id -Wl,--warn-shared-textrel -Wl,--fatal-warnings -LC:/Android/Sdk/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/x86_64 -Wl,--no-undefined -Wl,-z,noexecstack -Qunused-arguments -Wl,-z,relro -Wl,-z,now -shared -Wl,-soname,libhelloJni.so -o ..\..\..\..\build\intermediates\cmake\debug\obj\x86_64\libhelloJni.so CMakeFiles/helloJni.dir/src/main/cpp/helloJni.cpp.o -latomic -lm "C:/Android/Sdk/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/x86_64/libc++_static.a" "C:/Android/Sdk/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/x86_64/libc++abi.a" && cd ."
C:SomeDir\android\TestNdk\app\src\main\cpp/helloJni.cpp:18: error: undefined reference to 'MyClass::MyClass()'
C:SomeDir\android\TestNdk\app\src\main\cpp/helloJni.cpp:19: error: undefined reference to 'MyClass::hello()'
C:SomeDir\android\TestNdk\app\src\main\cpp/helloJni.cpp:22: error: undefined reference to 'MyClass::~MyClass()'
C:SomeDir\android\TestNdk\app\src\main\cpp/helloJni.cpp:22: error: undefined reference to 'MyClass::~MyClass()'
clang++.exe: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.
Q2
If I already have an .so file:
- Do i need to create a JNI cpp file? I followed here, but it didnt mentioned of any JNI file? is it because the .so file is compiled with JNI?
- Can I call .so file directly from Activity? If can, how?
- Is there a good article that points me in a right direction?
================================
UPDATE
I compiled a libCSharedLib.dll
library in eclipse with the following files:
Foobar.h
#ifndef FOOBAR_H_
#define FOOBAR_H_
class Foobar {
public:
Foobar();
virtual ~Foobar();
int wave();
};
#endif /* FOOBAR_H_ */
Foobar.cpp
#include "Foobar.h"
#include <iostream>
Foobar::Foobar() {
// TODO Auto-generated constructor stub
}
Foobar::~Foobar() {
// TODO Auto-generated destructor stub
}
int Foobar::wave() {
return 1;
}
Updated CMakeList.txt:
# Sets the minimum version of CMake required to build your native library.
# This ensures that a certain set of CMake features is available to
# your build.
cmake_minimum_required(VERSION 3.4.1)
# Specifies a library name, specifies whether the library is STATIC or
# SHARED, and provides relative paths to the source code. You can
# define multiple libraries by adding multiple add_library() commands,
# and CMake builds them for you. When you build your app, Gradle
# automatically packages shared libraries with your APK.
add_library( # Specifies the name of the library.
helloJni
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/cpp/helloJni.cpp )
add_library( # Specifies the name of the library.
MyClass
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/cpp/MyClass.cpp )
add_library( # Specifies the name of the library.
foobarJni
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/cpp/foobarJni.cpp )
add_library(libCSharedLib SHARED IMPORTED)
set_target_properties(libCSharedLib PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libCSharedLib.dll)
# Specifies a path to native header files.
include_directories(src/main/cpp/)
target_link_libraries(helloJni MyClass foobarJni libCSharedLib)
I placed Foobar.h into src/main/cpp
foobarJni.cpp (ignore that I didn't return the int value. just testing here)
#include <jni.h>
#include <string>
#include "Foobar.h"
extern "C"
JNIEXPORT jstring JNICALL Java_com_example_MainActivity_stringFoobar(
JNIEnv *env,
jobject /* this */) {
Foobar foobar;
int wave = foobar.wave();
std::string s = "abc";
return env->NewStringUTF(s.c_str());
}
In MainActivity:
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("helloJni");
System.loadLibrary("foobarJni");
}
....
}
But I'm still getting the error "undefined reference to Foobar..."
Build command failed.
Error while executing process C:\Android\Sdk\cmake\3.6.4111459\bin\cmake.exe with arguments {--build C:\somedir\TestNdk\app\.externalNativeBuild\cmake\debug\x86_64 --target helloJni}
[1/6] Building CXX object CMakeFiles/foobarJni.dir/src/main/cpp/foobarJni.cpp.o
[2/6] Building CXX object CMakeFiles/MyClass.dir/src/main/cpp/MyClass.cpp.o
[3/6] Linking CXX shared library ..\..\..\..\build\intermediates\cmake\debug\obj\x86_64\libfoobarJni.so
FAILED: cmd.exe /C "cd . && C:\Android\Sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++.exe --target=x86_64-none-linux-android --gcc-toolchain=C:/Android/Sdk/ndk-bundle/toolchains/x86_64-4.9/prebuilt/windows-x86_64 --sysroot=C:/Android/Sdk/ndk-bundle/sysroot -fPIC -isystem C:/Android/Sdk/ndk-bundle/sysroot/usr/include/x86_64-linux-android -D__ANDROID_API__=21 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wa,--noexecstack -Wformat -Werror=format-security -std=c++11 -O0 -fno-limit-debug-info -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libatomic.a -nostdlib++ --sysroot C:/Android/Sdk/ndk-bundle/platforms/android-21/arch-x86_64 -Wl,--build-id -Wl,--warn-shared-textrel -Wl,--fatal-warnings -LC:/Android/Sdk/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/x86_64 -Wl,--no-undefined -Wl,-z,noexecstack -Qunused-arguments -Wl,-z,relro -Wl,-z,now -shared -Wl,-soname,libfoobarJni.so -o ..\..\..\..\build\intermediates\cmake\debug\obj\x86_64\libfoobarJni.so CMakeFiles/foobarJni.dir/src/main/cpp/foobarJni.cpp.o -latomic -lm "C:/Android/Sdk/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/x86_64/libc++_static.a" "C:/Android/Sdk/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/x86_64/libc++abi.a" && cd ."
C:\somedir\TestNdk\app\src\main\cpp/foobarJni.cpp:19: error: undefined reference to 'Foobar::Foobar()'
C:\somedir\TestNdk\app\src\main\cpp/foobarJni.cpp:20: error: undefined reference to 'Foobar::wave()'
C:\somedir\TestNdk\app\src\main\cpp/foobarJni.cpp:24: error: undefined reference to 'Foobar::~Foobar()'
C:\somedir\TestNdk\app\src\main\cpp/foobarJni.cpp:24: error: undefined reference to 'Foobar::~Foobar()'
clang++.exe: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.
target_link_libraries(helloJni MyClass)
solve **Q1** – chrizonline Sep 13 '18 at 14:33