У меня здесь два вопроса.
- Как скомпилировать исходный файл c ++ в Android?
- Как использовать уже созданный файл C ++ .so
Моя среда разработки:
- Windows 10
- Android Studio 3.1.4
Q1
У меня есть MyClass.h и MyClass.cpp, которые я хочу использовать в Android. Весь пример, который я видел, - это вызов функции cpp внутри helloJni.cpp. Как мне вызвать другие .cpp / .h файлы в helloJni.cpp ??
Это то, что я создал.
приложение / SRC / главная / CPP / MyClass.h
#ifndef MYCLASS_H_
#define MYCLASS_H_
class MyClass {
public:
MyClass();
virtual ~MyClass();
std::string hello();
};
#endif /* MYCLASS_H_ */
приложение / SRC / главная / 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();
}
приложение / SRC / главная / 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());
}
приложение / SRC / главная / Java / COM / пример / 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();
}
Приложение / 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/)
Ошибка при сборке в 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
Если у меня уже есть файл .so:
- Нужно ли мне создавать cpp файл JNI? Я следовал здесь , но там не упоминалось ни о каком файле JNI? потому что .so файл скомпилирован с JNI?
- Можно ли вызвать .so файл напрямую из Activity? Если можно, то как?
- Есть ли хорошая статья, которая указывает мне правильное направление?
================================
UPDATE
Я собрал библиотеку libCSharedLib.dll
в Eclipse со следующими файлами:
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;
}
Обновлен 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)
Я поместил Foobar.h в src/main/cpp
foobarJni.cpp (игнорируйте, что я не возвращал значение int. Просто тестирую здесь)
#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());
}
В MainActivity:
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("helloJni");
System.loadLibrary("foobarJni");
}
....
}
Но я все еще получаю ошибку "неопределенная ссылка на 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.