Android cmake 子目录依赖于 api 21
Android cmake subdirectory dependencies on api 21
Android 在 api < 23
上具有子目录 "dlopen failed: cannot locate symbol" 的 cmake 项目
相同的代码在 api >= 23
上工作正常
如果成功,此测试程序将打印日志
项目结构:
src/main/cpp
+foo
CMakeLists.txt
foo.cpp
+utils
CMakeLists.txt
log-utils.h
log-utils.cpp
CMakeLists.txt
CMakeLists.txt(foo)
project(foo)
add_library(foo SHARED foo.cpp)
target_link_libraries(foo PUBLIC utils)
foo.cpp
#include <jni.h>
#include <utils/log-utils.h>
#include <cstring>
jint JNI_OnLoad(JavaVM* vm, void * reserved) {
const char * test = "test message";
printByte("JNI_OnLoad", test, strlen(test));
JNIEnv *env;
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
return JNI_VERSION_1_6;
}
CMakeLists.txt(实用程序)
project(utils)
find_library(log-lib log)
add_library(utils SHARED log-utils.cpp)
target_link_libraries(utils ${log-lib})
log-utils.h
#ifndef LOG_UTILS_H
#define LOG_UTILS_H
void printByte(const char*tag, const char* content, unsigned int len);
#endif //LOG_UTILS_H
log-utils.cpp
#include "log-utils.h"
#include <cstring>
#include <cstdio>
#include <android/log.h>
static const char * TAG = "LOG_UTILS";
void printByte(const char*tag, const char* content, unsigned int len) {
char buff[len*2+1];
memset(buff, '[=17=]', len*2+1);
for (int i = 0; i<len; ++i) {
sprintf(buff+i*2, "%02x", content[i] & 0xff);
}
__android_log_print(ANDROID_LOG_DEBUG, TAG, "%-12s%04d: %s\n", tag, len, buff);
}
CMakeLists.txt(根)
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-omit-frame-pointer")
include_directories(./)
add_subdirectory(utils)
add_subdirectory(foo)
MainActivity.kt
class MainActivity : AppCompatActivity() {
companion object {
init {
System.loadLibrary("utils")
System.loadLibrary("foo")
}
}
// ...
}
两个库:libfoo.so、libutils.so、libfoo.so依赖于libutils.so。在 Android 4.4 和 5.0 上,它只是崩溃,系统日志:
09-10 17:36:33.388 10908-10908/? E/art: dlopen("/data/app/com.example.nativefoo-2/lib/x86/libfoo.so", RTLD_LAZY) failed: dlopen failed: cannot locate symbol "_Z9printBytePKcS0_j" referenced by "libfoo.so"...
09-10 17:36:33.388 10908-10908/? D/AndroidRuntime: Shutting down VM
09-10 17:36:33.389 10908-10908/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.nativefoo, PID: 10908
java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "_Z9printBytePKcS0_j" referenced by "libfoo.so"...
at java.lang.Runtime.loadLibrary(Runtime.java:371)
at java.lang.System.loadLibrary(System.java:989)
at com.example.nativefoo.MainActivity.<clinit>(MainActivity.kt:18)
at java.lang.reflect.Constructor.newInstance(Native Method)
at java.lang.Class.newInstance(Class.java:1572)
at android.app.Instrumentation.newActivity(Instrumentation.java:1065)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2199)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
at android.app.ActivityThread.access0(ActivityThread.java:144)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Update1 2019.09.11 07:23 UTC 时间
app/build.gradle
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.example.nativefoo"
minSdkVersion 18
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags ""
abiFilters "armeabi-v7a", "x86"
}
}
}
我认为 libutils.so 加载正确,请参阅 logcat
09-11 15:27:29.622 D/dalvikvm: Not late-enabling CheckJNI (already on)
09-11 15:27:29.672 D/dalvikvm: Trying to load lib /data/app-lib/com.example.nativefoo-1/libutils.so 0x9d061440
09-11 15:27:29.672 D/dalvikvm: Added shared lib /data/app-lib/com.example.nativefoo-1/libutils.so 0x9d061440
09-11 15:27:29.672 D/dalvikvm: No JNI_OnLoad found in /data/app-lib/com.example.nativefoo-1/libutils.so 0x9d061440, skipping init
09-11 15:27:29.672 D/dalvikvm: Trying to load lib /data/app-lib/com.example.nativefoo-1/libfoo.so 0x9d061440
09-11 15:27:29.672 E/dalvikvm: dlopen("/data/app-lib/com.example.nativefoo-1/libfoo.so") failed: dlopen failed: cannot locate symbol "_Z9printBytePKcS0_j" referenced by "libfoo.so"...
您可以在 github NativeFoo
查看整个项目
这是一个非常愚蠢的错误,我的库名称是 libutils.so,但是 Android 系统还有一个名为 libutils.so 的内部库。所以,当我尝试加载 libutils.so 时,它首先加载系统库, 不是我的 !因此,我的应用程序从未按预期运行。
Android 在 api < 23
上具有子目录 "dlopen failed: cannot locate symbol" 的 cmake 项目相同的代码在 api >= 23
上工作正常如果成功,此测试程序将打印日志
项目结构:
src/main/cpp
+foo
CMakeLists.txt
foo.cpp
+utils
CMakeLists.txt
log-utils.h
log-utils.cpp
CMakeLists.txt
CMakeLists.txt(foo)
project(foo)
add_library(foo SHARED foo.cpp)
target_link_libraries(foo PUBLIC utils)
foo.cpp
#include <jni.h>
#include <utils/log-utils.h>
#include <cstring>
jint JNI_OnLoad(JavaVM* vm, void * reserved) {
const char * test = "test message";
printByte("JNI_OnLoad", test, strlen(test));
JNIEnv *env;
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
return JNI_VERSION_1_6;
}
CMakeLists.txt(实用程序)
project(utils)
find_library(log-lib log)
add_library(utils SHARED log-utils.cpp)
target_link_libraries(utils ${log-lib})
log-utils.h
#ifndef LOG_UTILS_H
#define LOG_UTILS_H
void printByte(const char*tag, const char* content, unsigned int len);
#endif //LOG_UTILS_H
log-utils.cpp
#include "log-utils.h"
#include <cstring>
#include <cstdio>
#include <android/log.h>
static const char * TAG = "LOG_UTILS";
void printByte(const char*tag, const char* content, unsigned int len) {
char buff[len*2+1];
memset(buff, '[=17=]', len*2+1);
for (int i = 0; i<len; ++i) {
sprintf(buff+i*2, "%02x", content[i] & 0xff);
}
__android_log_print(ANDROID_LOG_DEBUG, TAG, "%-12s%04d: %s\n", tag, len, buff);
}
CMakeLists.txt(根)
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-omit-frame-pointer")
include_directories(./)
add_subdirectory(utils)
add_subdirectory(foo)
MainActivity.kt
class MainActivity : AppCompatActivity() {
companion object {
init {
System.loadLibrary("utils")
System.loadLibrary("foo")
}
}
// ...
}
两个库:libfoo.so、libutils.so、libfoo.so依赖于libutils.so。在 Android 4.4 和 5.0 上,它只是崩溃,系统日志:
09-10 17:36:33.388 10908-10908/? E/art: dlopen("/data/app/com.example.nativefoo-2/lib/x86/libfoo.so", RTLD_LAZY) failed: dlopen failed: cannot locate symbol "_Z9printBytePKcS0_j" referenced by "libfoo.so"...
09-10 17:36:33.388 10908-10908/? D/AndroidRuntime: Shutting down VM
09-10 17:36:33.389 10908-10908/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.nativefoo, PID: 10908
java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "_Z9printBytePKcS0_j" referenced by "libfoo.so"...
at java.lang.Runtime.loadLibrary(Runtime.java:371)
at java.lang.System.loadLibrary(System.java:989)
at com.example.nativefoo.MainActivity.<clinit>(MainActivity.kt:18)
at java.lang.reflect.Constructor.newInstance(Native Method)
at java.lang.Class.newInstance(Class.java:1572)
at android.app.Instrumentation.newActivity(Instrumentation.java:1065)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2199)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
at android.app.ActivityThread.access0(ActivityThread.java:144)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Update1 2019.09.11 07:23 UTC 时间
app/build.gradle
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.example.nativefoo"
minSdkVersion 18
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags ""
abiFilters "armeabi-v7a", "x86"
}
}
}
我认为 libutils.so 加载正确,请参阅 logcat
09-11 15:27:29.622 D/dalvikvm: Not late-enabling CheckJNI (already on)
09-11 15:27:29.672 D/dalvikvm: Trying to load lib /data/app-lib/com.example.nativefoo-1/libutils.so 0x9d061440
09-11 15:27:29.672 D/dalvikvm: Added shared lib /data/app-lib/com.example.nativefoo-1/libutils.so 0x9d061440
09-11 15:27:29.672 D/dalvikvm: No JNI_OnLoad found in /data/app-lib/com.example.nativefoo-1/libutils.so 0x9d061440, skipping init
09-11 15:27:29.672 D/dalvikvm: Trying to load lib /data/app-lib/com.example.nativefoo-1/libfoo.so 0x9d061440
09-11 15:27:29.672 E/dalvikvm: dlopen("/data/app-lib/com.example.nativefoo-1/libfoo.so") failed: dlopen failed: cannot locate symbol "_Z9printBytePKcS0_j" referenced by "libfoo.so"...
您可以在 github NativeFoo
查看整个项目这是一个非常愚蠢的错误,我的库名称是 libutils.so,但是 Android 系统还有一个名为 libutils.so 的内部库。所以,当我尝试加载 libutils.so 时,它首先加载系统库, 不是我的 !因此,我的应用程序从未按预期运行。