Android cmake使用外部動態(tài)共享庫

官方文檔分享:

CMake的基本用法參考Android官方文檔上的CMake教程:

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

他的內(nèi)容有:

  1. 創(chuàng)建CMake腳本
  2. 使用NDK中的靜態(tài)庫和動態(tài)共享庫
  3. 添加其他已經(jīng)編譯過得動態(tài)共享庫
  4. 如何進行多CMake project的開發(fā)

本篇文章

本篇文章主要是分析如何使用第三方的so庫進行c層的開發(fā)。

與官方文檔不同的是,官方文檔在連接第三方動態(tài)共享庫的時候,用法是:

# 添加共享庫imported-lib
add_library( imported-lib
             SHARED
             IMPORTED )
# 設置共享庫的路徑
set_target_properties( # Specifies the target library.
            imported-lib

            # Specifies the parameter you want to define.
            PROPERTIES IMPORTED_LOCATION

            # Provides the path to the library you want to import.
            imported-lib/src/${ANDROID_ABI}/libimported-lib.so )

# 設置頭文件的路徑
include_directories( imported-lib/include/ )

# 將第三方共享庫庫和你自己編譯出來的共享庫連接
target_link_libraries( native-lib imported-lib ${log-lib} )

而我這里用的是:

link_directories()

下面看下代碼:

1 項目目錄

? tree -L 5
.
├── build.gradle
├── consumer-rules.pro
├── ffmpegprebuild.iml
├── libs
│   └── armeabi-v7a
│       ├── libavcodec.so
│       ├── libavfilter.so
│       ├── libavformat.so
│       ├── libavutil.so
│       ├── libswresample.so
│       └── libswscale.so
└── src
    ├── main
    │   ├── AndroidManifest.xml
    │   ├── cpp
    │   │   ├── CMakeLists.txt
    │   │   ├── ff.c
    │   │   └── include
    │   │       ├── libavcodec
    │   │       ├── libavfilter
    │   │       ├── libavformat
    │   │       ├── libavutil
    │   │       ├── libswresample
    │   │       └── libswscale
    │   ├── java
    │   │   └── com
    │   │       └── hwilliamgo
    │   └── res
    │       ├── drawable
    │       └── values
    │           └── strings.xml

我這里是使用我提前編譯好的armveabi-v7a架構(gòu)下的ffmpeg的動態(tài)共享庫。并將頭文件放在了/cpp/include目錄下。

cpp/ff.c作為源文件。

我的目標是:在ff.c中使用ffmpeg提供的api,提供到java層去調(diào)用。

ff.c ==>

#include <stdio.h>
#include <jni.h>
#include <malloc.h>
#include <android/log.h>
#include "libavformat/avformat.h"


JNIEXPORT jint JNICALL
Java_com_hwilliamgo_ffmpegprebuild_FFMpegUtils_getVersion(JNIEnv *env, jclass clazz) {
    return avformat_version();
}

2 如何編寫CMakeLists.txt

cmake_minimum_required(VERSION 3.4.1)

# 查找目錄下的所有源文件
# 并將名稱保存到 DIR_SRCS 變量
aux_source_directory(. DIR_SRCS)

# 找到NDK提供的共享庫log,并保存在變量log-lib中
find_library(
        log-lib
        log)

# 指定頭文件的目錄
include_directories(./include)
# 指定第三方動態(tài)共享庫的目錄
link_directories(../../.././libs/${ANDROID_ABI}/)
# 指定將${DIR_SRCS}目錄下的源碼文件編譯成共享庫,名字為:ff
add_library( 
        ff
        SHARED
        ${DIR_SRCS})
# 指定將將第三方共享庫庫和你自己編譯出來的共享庫連接
target_link_libraries(
        ff

        ${log-lib}
        avformat
        )

3 遇到的問題

這里要確保一件事情:

link_directories()指令要放在add_library指令之前。也就是設置第三方庫的路徑要放在前面。

否則會遇到找不到共享庫的問題:

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':ffmpegprebuild:externalNativeBuildDebug'.
> Build command failed.
  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}
  ninja: Entering directory `/Users/HWilliam/AllProject/AndroidStudioProjects/windowsProject/JNILearnCMake/ffmpegprebuild/.cxx/cmake/debug/armeabi-v7a'
  [1/2] Building C object CMakeFiles/ff.dir/ff.c.o
  [2/2] Linking C shared library /Users/HWilliam/AllProject/AndroidStudioProjects/windowsProject/JNILearnCMake/ffmpegprebuild/build/intermediates/cmake/debug/obj/armeabi-v7a/libff.so
  FAILED: /Users/HWilliam/AllProject/AndroidStudioProjects/windowsProject/JNILearnCMake/ffmpegprebuild/build/intermediates/cmake/debug/obj/armeabi-v7a/libff.so 
  : && /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 && :
  /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
  /Users/HWilliam/AllProject/AndroidStudioProjects/windowsProject/JNILearnCMake/ffmpegprebuild/src/main/cpp/ff.c:10: error: undefined reference to 'avformat_version'
  clang: error: linker command failed with exit code 1 (use -v to see invocation)
  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.

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()命令。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容