【发布时间】:2018-10-25 10:07:41
【问题描述】:
我正在开发一个 Android 项目,该项目使用 Java 类,该类是 C++ 库的包装器。 C++库是公司内部库,我们可以访问它的源代码,但是在Android项目中它只是动态链接的,所以只能以头文件(.h)的形式使用,共享对象 (.so)。可以访问库源代码,是否可以向 Android Studio 指定源代码的路径,以便我可以使用调试器进入库?
调试器工作正常,我可以进入Java_clory_engine_sdk_CloryNative_nativeInit 函数,但我还想进一步调试与Clory::Engine 类对应的库,正如我所提到的,它是一个我们可以访问源代码的内部库.
例如,Clory::Engine::instance 是库的一部分,我想向 Android Studio 指定CloryEngine.cpp 文件的位置,这样我就可以使用调试器进入Clory::Engine::instance,从而调试这个静态成员函数。
我使用的是 Android Studio 3.1.4。
这可能吗?
编辑:
clory-sdk.gradle 文件指定了配置 C++ 层的CMakeLists.txt 文件。
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
所以我正在使用一个使用 Clory SDK 的内部应用程序。在我使用的app.gradle 文件中:
dependencies {
...
compile project(':clory-sdk-core')
compile project(':clory-sdk')
...
}
所以我认为我们不会将aars 用于app.gradle 项目。 aars 已发送到客户端,但在此之前我们正在使用 app.gradle 项目来测试我们的小 SDK 功能。 JNI 层位于 clory-sdk-core 项目内。
编辑 2:
这是处理 JNI 层的CMakeLists.txt:
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_AUTOMOC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_BUILD_TYPE Debug)
add_library(
clory-lib
SHARED
# JNI layer and other helper classes for transferring data from Java to Qt/C++
src/main/cpp/clory-lib.cpp
src/main/cpp/JObjectHandler.cpp
src/main/cpp/JObjectResolver.cpp
src/main/cpp/JObjectCreator.cpp
src/main/cpp/DataConverter.cpp
src/main/cpp/JObjectHelper.cpp
src/main/cpp/JEnvironmentManager.cpp
)
find_library(
log-lib
log
)
target_compile_options(clory-lib
PUBLIC
-std=c++11
)
# Hardcoded for now...will fix later...
set(_QT_ROOT_PATH /Users/jacob/Qt/5.8)
if(${ANDROID_ABI} MATCHES ^armeabi-v7.*$)
set(_QT_ARCH android_armv7)
elseif(${ANDROID_ABI} MATCHES ^x86$)
set(_QT_ARCH android_x86)
else()
message(FATAL_ERROR "Unsupported Android architecture!!!")
endif()
set(CMAKE_FIND_ROOT_PATH ${_QT_ROOT_PATH}/${_QT_ARCH})
find_package(Qt5 REQUIRED COMPONENTS
Core
CONFIG
)
target_include_directories(clory-lib
PUBLIC
${CMAKE_CURRENT_LIST_DIR}/src/main/cpp
)
set(_CLORYSDK_LIB_PATH ${CMAKE_CURRENT_LIST_DIR}/src/main/jniLibs/${ANDROID_ABI})
target_link_libraries(clory-lib
${log-lib}
-L${_CLORYSDK_LIB_PATH}
clorysdk
Qt5::Core
)
库clorysdk 实际上是我所说的我们内部的库,它包含例如Clory::Engine::instance 我想进入调试器。它是使用qmake 构建的,并且是在调试模式下构建的(CONFIG+=debug 已添加到有效的 qmake 调用中)。
编辑 3:
在遇到Java_clory_engine_sdk_CloryNative_nativeInit 断点后打开的LLDB 会话中,我得到以下信息:
(lldb) image lookup -vrn Clory::Engine::instance
2 matches found in /Users/jacob/.lldb/module_cache/remote-android/.cache/6EDE4F0A-0000-0000-0000-000000000000/libclorysdk.so:
Address: libclorysdk.so[0x0001bb32] (libclorysdk.so..text + 8250)
Summary: libclorysdk.so`Clory::Engine::instance(Clory::Engine::Purpose)
Module: file = "/Users/jacob/.lldb/module_cache/remote-android/.cache/6EDE4F0A-0000-0000-0000-000000000000/libclorysdk.so", arch = "arm"
Symbol: id = {0x0000005e}, range = [0xcb41eb32-0xcb41ebc0), name="Clory::Engine::instance(Clory::Engine::Purpose)", mangled="_ZN4Clory2Engine8instanceENS0_7PurposeE"
Address: libclorysdk.so[0x0001b82c] (libclorysdk.so..text + 7476)
Summary: libclorysdk.so`Clory::Engine::instance(Clory::RuntimeConfiguration const&, Clory::Engine::Purpose)
Module: file = "/Users/jacob/.lldb/module_cache/remote-android/.cache/6EDE4F0A-0000-0000-0000-000000000000/libclorysdk.so", arch = "arm"
Symbol: id = {0x000000bd}, range = [0xcb41e82c-0xcb41e970), name="Clory::Engine::instance(Clory::RuntimeConfiguration const&, Clory::Engine::Purpose)", mangled="_ZN4Clory2Engine8instanceERKNS_20RuntimeConfigurationENS0_7PurposeE"
(lldb) settings show target.source-map
target.source-map (path-map) =
首先,命令image lookup -vrn Clory::Engine::instance 的结果中没有CompileUnit 部分。如果libclorysdk.so 是在Debug 模式下构建的,这怎么可能没有定义source-map(第二个lldb 命令)?是否可以显式设置它以便调试器在那里搜索库的源文件?
编辑 4:
在搜索了更多之后,我发现创建 APK 的过程实际上从调试符号中去除了 *.so 库。 libclorysdk.so 内置调试模式大约有 10MB,而我在解压缩生成的 *.apk 文件后提取的 libclorysdk.so 文件只有 350KB。
如here 所述,在调试版本上运行greadelf --debug-dump=decodedline libclorysdk.so 会输出对源文件的引用,但如果在*.apk 提取的库上运行该命令,则不会输出任何内容。
有没有办法阻止 Android Studio 剥离 *.sos?我试过How to avoid stripping for native code symbols for android app但没有任何效果,*.apk文件大小和以前一样,调试本机库仍然不起作用。
我正在使用Gradle 3.1.4。
编辑 5:
stripping solution 有效,但在我的情况下,它需要一个 Clean & Build 才能到达库中的断点。部署未剥离的*.sos 允许您进行调试会话并进入本机库。
注意:
如果库是使用Qt for Android 工具链构建的,那么部署到$SHADOW_BUILD/android-build 的*.sos 也会被剥离(其中$SHADOW_BUILD 是构建目录,通常以build-* 开头)。因此,为了调试这些,您应该从生成每个*.so 的android-build 目录之外复制它们。
【问题讨论】:
-
您使用的是预构建共享库的调试版本吗?如果是这样,进入该库中的代码应该可以工作。
-
@Michael 我正在使用预构建共享库的调试版本。但是源代码不在使用共享库的项目中。所以它不知道在哪里搜索源代码(我假设),除非我告诉它在哪里搜索。我不知道该怎么做。我记得如果你想进入 Visual Studio 中的库,你会看到一个对话框,让你浏览与你正在进入的函数相对应的源文件,如下所示:i.imgur.com/doPgOs4.png 我期望某种功能给你类似的东西......
-
我自己做了一个小测试,从另一个项目进入预建共享库中的代码对我来说效果很好。但是,我只在同一台机器上构建两个项目的情况下对此进行了测试。与构建共享库的机器相比,您机器上的项目结构可能看起来不同?您可以尝试运行
readelf --string-dump=.debug_str mylib.so来查看源文件应该存在的位置。 -
@Michael 非常感谢您的回答。嗯...今晚我将构建一个小项目,我将尝试在较小的范围内重现我的场景,并让您知道我发现了什么。
-
您的项目有
ndk或cmake配置吗?还是您正在使用的 lib 打包为aar?
标签: android c++ android-studio java-native-interface android-studio-3.0