使用Android Studio调试C ++库

非淡泊无以明志,非宁静无以致远。这篇文章主要讲述使用Android Studio调试C ++库相关的知识,希望能为你提供帮助。
我正在开发一个android项目,该项目使用java类,它是C++库的包装器。 C ++库是一个公司内部库,我们可以访问它的源代码,但在Android项目中它只是动态链接的,所以它只能以头文件(.h)和共享对象(.so)的形式使用。有权访问库源代码,是否可以向Android Studio指定源代码的路径,以便我可以使用调试器进入库内部?
调试器工作,我可以进入Java_clory_engine_sdk_CloryNative_nativeInit函数,但我还想进一步调试对应于Clory::Engine类的库,正如我所提到的,它是一个我们有源代码访问的内部库。

使用Android Studio调试C ++库

文章图片

例如,Clory::Engine::instance是库的一部分,我想向Android Studio指定CloryEngine.cpp文件的位置,以便我可以使用调试器进入Clory::Engine::instance,从而调试此静态成员函数。
【使用Android Studio调试C ++库】我使用的是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构建的,并且是在调试模式下构建的(在有效的qmake调用中添加了CONFIG+=debug)。
编辑3:
在点击LLDB断点后打开的Java_clory_engine_sdk_CloryNative_nativeInit会话中,我得到以下内容:
(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) =

首先,命令CompileUnit的结果中没有image lookup -vrn Clory::Engine::instance部分。如果libclorysdk.so是在Debug模式下构建的,那怎么可能没有定义源映射(第二个lldb命令)?是否可以显式设置它以便调试器在那里搜索库的源文件?
编辑4:
经过更多搜索,我发现创建APK的过程实际上从调试符号中删除了*.so库。在调试模式下构建的libclorysdk.so大约有10MB,而在解压缩生成的libclorysdk.so文件后我提取的*.apk文件只有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有效,但在我的情况下,它需要一个清洁和构建才能到达库中的断点。部署未剥离的*.sos允许您在本机库中进行调试会话和步骤。
注意:
如果库是使用Qt for Android工具链构建的,则部署到*.so$SHADOW_BUILD/android-builds也会被剥离(其中$SHADOW_BUILD是通常以build-*开头的构建目录)。因此,为了调试它们,您应该从生成每个android-build*.so目录之外复制它们。
答案调试信息记录源文件构建时的位置。
(lldb) image lookup -vrn Clory::Engine::instance

CompileUnit行显示源文件。假设它说:
"/BuildDirectory/Sources/Clory/CloryEngine.cpp"

我们假设您的机器上有源:
"Users/me/Sources/Clory"

所以你可以告诉lldb:在Users / me / Sources / Clory中找到以/ BuildDirectory / Sources / Clory为根的源文件。
(lldb) settings set target.source-map /BuildDirectory/Sources/Clory Users/me/Sources/Clory

您可以在Android Studio的lldb控制台中使用这些命令,也可以将其放入.lldbinit文件中以供一般使用。
另一答案如果没有可用的调试符号,则可能必须在调试模式下构建引用的库。
要么与-DCMAKE_BUILD_TYPE=DEBUG
defaultConfig { externalNativeBuild { cmake { arguments "-DANDROID_TOOLCHAIN=gcc", "-DCMAKE_BUILD_TYPE=DEBUG" cppFlags "-std=c++14 -fexceptions -frtti" } } }externalNativeBuild { cmake { path file('src/main/cpp/CMakeLists.txt') } }

或者将其添加到库的CMakeLists.txt
set(CMAKE_BUILD_TYPE Debug)

请参阅CMake文档和Symbolicating with LLDB。
elsewhere它解释(lldb) settings set target.source-map /buildbot/path /my/path
重新映射调试会话的源文件路径名。如果您的源文件不再位于与构建程序时相同的位置 - 可能程序是在不同的计算机上构建的 - 您需要告诉调试器如何在其本地文件路径中查找源代码构建系统的文件路径。
还有(lldb) settings show target.source-map,看看映射的是什么。 (lldb) set append target.source-map /buildbot/path /my/path似乎相当合适,以免覆盖现有的映射。

    推荐阅读