官方文档分享:

CMake的基本用法参考Android官方文档上的CMake教程:

https://developer.android.com/studio/projects/configure-cmake

他的内容有:

  1. 创建CMake脚本
  2. 使用NDK中的静态库和动态共享库
  3. 添加其他已经编译过得动态共享库
  4. 如何进行多CMake project的开发

本篇文章

本篇文章主要是分析如何使用第三方的so库进行c层的开发。

与官方文档不同的是,官方文档在连接第三方动态共享库的时候,用法是:

  1. # 添加共享库imported-lib
  2. add_library( imported-lib
  3. SHARED
  4. IMPORTED )
  5. # 设置共享库的路径
  6. set_target_properties( # Specifies the target library.
  7. imported-lib
  8. # Specifies the parameter you want to define.
  9. PROPERTIES IMPORTED_LOCATION
  10. # Provides the path to the library you want to import.
  11. imported-lib/src/${ANDROID_ABI}/libimported-lib.so )
  12. # 设置头文件的路径
  13. include_directories( imported-lib/include/ )
  14. # 将第三方共享库库和你自己编译出来的共享库连接
  15. target_link_libraries( native-lib imported-lib ${log-lib} )

而我这里用的是:

  1. link_directories()

下面看下代码:

1 项目目录

  1. tree -L 5
  2. .
  3. ├── build.gradle
  4. ├── consumer-rules.pro
  5. ├── ffmpegprebuild.iml
  6. ├── libs
  7. └── armeabi-v7a
  8. ├── libavcodec.so
  9. ├── libavfilter.so
  10. ├── libavformat.so
  11. ├── libavutil.so
  12. ├── libswresample.so
  13. └── libswscale.so
  14. └── src
  15. ├── main
  16. ├── AndroidManifest.xml
  17. ├── cpp
  18. ├── CMakeLists.txt
  19. ├── ff.c
  20. └── include
  21. ├── libavcodec
  22. ├── libavfilter
  23. ├── libavformat
  24. ├── libavutil
  25. ├── libswresample
  26. └── libswscale
  27. ├── java
  28. └── com
  29. └── hwilliamgo
  30. └── res
  31. ├── drawable
  32. └── values
  33. └── strings.xml

我这里是使用我提前编译好的armveabi-v7a架构下的ffmpeg的动态共享库。并将头文件放在了/cpp/include目录下。

cpp/ff.c作为源文件。

我的目标是:在ff.c中使用ffmpeg提供的api,提供到java层去调用。

ff.c ==>

  1. #include <stdio.h>
  2. #include <jni.h>
  3. #include <malloc.h>
  4. #include <android/log.h>
  5. #include "libavformat/avformat.h"
  6. JNIEXPORT jint JNICALL
  7. Java_com_hwilliamgo_ffmpegprebuild_FFMpegUtils_getVersion(JNIEnv *env, jclass clazz) {
  8. return avformat_version();
  9. }

2 如何编写CMakeLists.txt

  1. cmake_minimum_required(VERSION 3.4.1)
  2. # 查找目录下的所有源文件
  3. # 并将名称保存到 DIR_SRCS 变量
  4. aux_source_directory(. DIR_SRCS)
  5. # 找到NDK提供的共享库log,并保存在变量log-lib中
  6. find_library(
  7. log-lib
  8. log)
  9. # 指定头文件的目录
  10. include_directories(./include)
  11. # 指定第三方动态共享库的目录
  12. link_directories(../../.././libs/${ANDROID_ABI}/)
  13. # 指定将${DIR_SRCS}目录下的源码文件编译成共享库,名字为:ff
  14. add_library(
  15. ff
  16. SHARED
  17. ${DIR_SRCS})
  18. # 指定将将第三方共享库库和你自己编译出来的共享库连接
  19. target_link_libraries(
  20. ff
  21. ${log-lib}
  22. avformat
  23. )

3 遇到的问题

这里要确保一件事情:

link_directories()指令要放在add_library指令之前。也就是设置第三方库的路径要放在前面。

否则会遇到找不到共享库的问题:

  1. FAILURE: Build failed with an exception.
  2. * What went wrong:
  3. Execution failed for task ':ffmpegprebuild:externalNativeBuildDebug'.
  4. > Build command failed.
  5. Error while executing process /Users/HWilliam/Library/Android/sdk/cmake/3.10.2.4988404/bin/ninja with arguments {-C /Users/HWilliam/AllProject/AndroidStudioProjects/windowsProject/JNILearnCMake/ffmpegprebuild/.cxx/cmake/debug/armeabi-v7a ff}
  6. ninja: Entering directory `/Users/HWilliam/AllProject/AndroidStudioProjects/windowsProject/JNILearnCMake/ffmpegprebuild/.cxx/cmake/debug/armeabi-v7a'
  7. [1/2] Building C object CMakeFiles/ff.dir/ff.c.o
  8. [2/2] Linking C shared library /Users/HWilliam/AllProject/AndroidStudioProjects/windowsProject/JNILearnCMake/ffmpegprebuild/build/intermediates/cmake/debug/obj/armeabi-v7a/libff.so
  9. FAILED: /Users/HWilliam/AllProject/AndroidStudioProjects/windowsProject/JNILearnCMake/ffmpegprebuild/build/intermediates/cmake/debug/obj/armeabi-v7a/libff.so
  10. : && /Users/HWilliam/ndk/android-ndk-r20/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang --target=armv7-none-linux-androideabi16 --gcc-toolchain=/Users/HWilliam/ndk/android-ndk-r20/toolchains/llvm/prebuilt/darwin-x86_64 --sysroot=/Users/HWilliam/ndk/android-ndk-r20/toolchains/llvm/prebuilt/darwin-x86_64/sysroot -fPIC -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -fno-addrsig -march=armv7-a -mthumb -Wa,--noexecstack -Wformat -Werror=format-security -O0 -fno-limit-debug-info -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libatomic.a -static-libstdc++ -Wl,--build-id -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,--exclude-libs,libunwind.a -Wl,--no-undefined -Qunused-arguments -Wl,-z,noexecstack -shared -Wl,-soname,libff.so -o /Users/HWilliam/AllProject/AndroidStudioProjects/windowsProject/JNILearnCMake/ffmpegprebuild/build/intermediates/cmake/debug/obj/armeabi-v7a/libff.so CMakeFiles/ff.dir/ff.c.o -llog -lavformat -latomic -lm && :
  11. /Users/HWilliam/ndk/android-ndk-r20/toolchains/llvm/prebuilt/darwin-x86_64/lib/gcc/arm-linux-androideabi/4.9.x/../../../../arm-linux-androideabi/bin/ld: error: cannot find -lavformat
  12. /Users/HWilliam/AllProject/AndroidStudioProjects/windowsProject/JNILearnCMake/ffmpegprebuild/src/main/cpp/ff.c:10: error: undefined reference to 'avformat_version'
  13. clang: error: linker command failed with exit code 1 (use -v to see invocation)
  14. ninja: build stopped: subcommand failed.

浓缩一下:error: cannot find -lavformat

还有就是,cmake官方不建议我们使用link_directories()命令:

https://cmake.org/cmake/help/v3.4/command/link_directories.html

该命令的文档:

link_directories

Specify directories in which the linker will look for libraries.

  1. link_directories(directory1 directory2 ...)

Specify the paths in which the linker should search for libraries. The command will apply only to targets created after it is called. Relative paths given to this command are interpreted as relative to the current source directory, see CMP0015.

Note that this command is rarely necessary. Library locations returned by find_package() and find_library() are absolute paths. Pass these absolute library file paths directly to the target_link_libraries() command. CMake will ensure the linker finds them.

并且android官方也是使用的find_library()命令的。所以最好还是用find_library()命令。