本文以在Android App工程中依赖xhook为例,记录如何在CMakeLists.txt中依赖外部第三方so库。
编译xhook
1 下载xhook源码
git clone https://github.com/iqiyi/xHook.git
2 修改支持的abi
cd xHook
xHook 支持armeabi, 需要使用android-ndk 16, 因为android-ndk 17以上已经不支持armeabi了。如果不需要armeabi,并且使用高版本的android-ndk,可以去掉xHook对armeabi的支持。
打开 ./libxhook/jni/Application.mk
删除armeabi:
3 编译xhook
执行以下命令,编译xHook:
./build_libs.sh
该脚本会调用ndk-build命令,需要先将ndk的目录配置在~/.bashrc中:
export PATH=/home/zhangjg/tools/android-ndk-r21:$PATH
./build_libs.sh
执行完成之后,会输出armeabi-v7a, arm64-v8a,x86,x86_64的so:
将xhook加到项目中
1 将libxhook/libs目录拷贝到项目中
拷贝到CMakeLists.txt文件所在的目录, 一般为app/src/main/cpp中:
2 将xhook.h拷贝到项目中
为了方便配置,直接将xhook.h拷贝到app/src/main/cpp中,和CMakeLists.txt在同级目录:
3 依赖xhook.h写hook的逻辑
#include "xhook.h"
static void fake_abort() {
LOGI("fake abort");
}
static void do_hook() {
xhook_register("ibchrome.so", "abort", (void *)fake_abort, nullptr);
xhook_refresh(0);
}
编译以上代码,发现链接错误:
[2/2] Linking CXX shared library /home/zhangjg/AndroidStudioProjects/BLEDemo/app/build/intermediates/cmake/debug/obj/arm64-v8a/libble_compat.so
FAILED: /home/zhangjg/AndroidStudioProjects/BLEDemo/app/build/intermediates/cmake/debug/obj/arm64-v8a/libble_compat.so
: && /home/zhangjg/tools/android-ndk-r21/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++ --target=aarch64-none-linux-android26 --gcc-toolchain=/home/zhangjg/tools/android-ndk-r21/toolchains/llvm/prebuilt/linux-x86_64 --sysroot=/home/zhangjg/tools/android-ndk-r21/toolchains/llvm/prebuilt/linux-x86_64/sysroot -fPIC -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security -std=c++11 -O0 -fno-limit-debug-info -Wl,--exclude-libs,libgcc_real.a -Wl,--exclude-libs,libatomic.a -static-libstdc++ -Wl,--build-id -Wl,--fatal-warnings -Wl,--no-undefined -Qunused-arguments -shared -Wl,-soname,libble_compat.so -o /home/zhangjg/AndroidStudioProjects/BLEDemo/app/build/intermediates/cmake/debug/obj/arm64-v8a/libble_compat.so CMakeFiles/ble_compat.dir/ble_compat.cpp.o /home/zhangjg/tools/android-ndk-r21/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/26/liblog.so /home/zhangjg/.gradle/caches/transforms-2/files-2.1/bba815dfd2e33446c27bb2585a849af4/jetified-xdl-1.0.4/prefab/modules/xdl/libs/android.arm64-v8a/libxdl.so -latomic -lm && :
CMakeFiles/ble_compat.dir/ble_compat.cpp.o: In function `do_hook()':
/home/zhangjg/AndroidStudioProjects/BLEDemo/app/src/main/cpp/ble_compat.cpp:133: undefined reference to `xhook_register'
/home/zhangjg/AndroidStudioProjects/BLEDemo/app/src/main/cpp/ble_compat.cpp:134: undefined reference to `xhook_refresh'
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.
我们都知道,c/c++代码的构建分为编译和链接两个部分,编译期间依赖的头文件xhook.h是没有问题的。但是链接的时候,即使我们自己的so是动态链接到libxhook.so,连接器ld也是要找到libxhook.so,去检查libxhook.so中的符号,以确保我们自己的so中的符号,需要做静态链接还是动态链接。
以上错误就是因为链接器不知道去哪里找libxhook.so。
需要在CMakeLists.txt中加入相关的配置:
add_library(xhook SHARED IMPORTED)
set_target_properties(xhook PROPERTIES IMPORTED_LOCATION
${PROJECT_SOURCE_DIR}/libs/${CMAKE_ANDROID_ARCH_ABI}/libxhook.so)
target_link_libraries(ble_compat xhook)
add_library(xhook SHARED IMPORTED)
这句话的意思是,定义一个库,这个库需要有一个名字xhook
,这个名字可以被其他库依赖。
set_target_properties
这句话是对xhook这个库进行配置,主要是配置它的so的路径。${PROJECT_SOURCE_DIR}
就是当前CMakeLists.txt文件所在的路径app/src/main/cpp
。${CMAKE_ANDROID_ARCH_ABI}
就是当前编译任务对应的abi(armeabi-v7a, arm64-v8a, x86, x86_64)。
上面的两句代码定义了xhook这个库,并且指定了这个库的so的位置。
target_link_libraries(ble_compat xhook)
这句话说明当前的模块ble_compat
需要链接到xhook这个库。
加上上面的代码后,就可以编译通过了。
并且在打包apk的时候,会自动把libxhook.so打进去。
我之前不会配置如何链接外部第三方so,就在网上搜了很多资料,很多都是使用link_directories()
配置的,都不生效。