JNI/NDK開發指進階(四) JNI/NDK 調試工具 LLDB, CMake

今天不是來講lldb ,因爲用的是android studio 3.0,只能用CMake 才能調試(3.0 以下可以配合 gradle-experimental,不過也要有改動,這裏不再細說),所以需要把原來的 Android.mk 轉成CMake,

前提,自己去下載 lldb,cmake,ndk,這個在sdk 管理中,見下圖:

這裏主要講一下,怎麼手機編寫CMakeList.txt

 

只要在Android中有使用過jni的應該都瞭解我們要編譯寫的c/c++文件都需要配置編譯用的配置文件,在eclipse中要寫mk文件;在Android Studio中要寫CMakeList.txt這個配置文件。
只有寫好了這個配置文件我們才正確編譯出我們想要的so動態庫,今天就講講Android Studio中的CMakeList.txt這個文件怎麼寫,eclispe的mk文件的寫法在這就不講了,如果不瞭解的可以到ndk安裝路徑中打中doc文檔中查看Android.mk的寫法,文檔中詳細的介紹


要了解CMakeList這個東西,那就應該要知道CMake幹嘛用的,CMake是一個跨平臺的安裝(編譯)工具,可以用簡單的語句來描述所有平臺的安裝(編譯過程)。他能夠輸出各種各樣的makefile或者project文件,能測試編譯器所支持的C++特性,類似UNIX下的automake。
太詳細的用法在此就不講了,下我會以ffmpeg的配置,來講解在Android Studio中CMakeList.txt的常用寫法。
在此附上CMake官方學習文檔:
英文文檔:https://cmake.org/documentation/
中文文檔:https://www.zybuluo.com/khan-lau/note/254724

在CMakeList.txt開頭時應該設置好我們的jni文件夾目錄,這樣才能讓gcc在編譯時找到對應的文件,具體的寫法如下:

set(distribution_DIR ${CMAKE_SOURCE_DIR}/src/main/jniLibs)

反斜線的後面是固定的格式,前面的你的jni文件夾所在的路徑;後面的寫法一般不建議修改。
寫好這個後,如裏我們有需要引入的第三方頭文件,在這時應該要配置頭文件的路徑,具體的寫法如下:

include_directories(src/main/jniLibs/include/ffmpeg)

如裏有多個, 也是一樣的依次往一加上就可以了,如裏有要引用第三方編譯好的.so庫,在這時應該要配置進來編譯;引入第三方的.so庫具體寫法如下:

add_library(
    avcodec-lib
    SHARED
    IMPORTED)
set_target_properties( avcodec-lib
                       PROPERTIES IMPORTED_LOCATION
                       ${distribution_DIR}/${ANDROID_ABI}/libavcodec-56.so)

首先要添加庫,也就是:add_library函數,裏面要傳入三個參數;第一個是要引入的庫別名,第二個是庫的類型,是靜態庫還是動態庫。在Android中是不能引用靜態庫的也就是.dll後綴的庫,所以第二個參數只要是引入第三方的.so庫都是寫“SHARED”,第三個是通過什麼樣方式引入進來,第三方的一般都是通過包含進來,所以第三個參數基本也是固定的都是寫“IMPORTED”。
add_library後,就要設置.so的詳細路徑了,通過set_target_properties()函數來設置;該函數也是要傳入三參數來指定.so庫的路徑。第一個參數和add_library的第一個參數一樣,不過這裏的庫別名要和add_library的庫別名要一致,要不然在編譯時會報找不到庫的錯誤。第二個參數是固定的,都是寫“ PROPERTIES IMPORTED_LOCATION”主要用來指定庫的引入方式。都是通過本地引入。第三個就是庫的具體路徑,這個不能寫錯,如果寫錯了,編譯時也同樣會找不到庫的。只要是引入第三方的庫使用add_library就要使用set_target_propeties這個組合,所以它們是成對出現的。
add_library還有一種寫法那就是CMakeList.txt中默認寫法

add_library( # Sets the name of the library.
             playController

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             src/main/cpp/playController.c)

這樣是就是編譯我們自己在項目中寫的c/c++文件。這裏就不用set_target_propeties()。
下面就到find_library()了;看到這個名字相信都會知道它是幹嘛用的,查找庫用的,用在哪裏呢,這個主要是查找系統庫用的,如果項目裏面有用到系統的.so庫就是要把庫名寫到這個函數裏面去找到相對應的爲。


find_library( # Sets the name of the path variable.
              log-lib

              # Specifies the name of the NDK library that
              # you want CMake to locate.
              log )

比如上面用了日誌庫,那就要把日誌庫加進來。
最後一個函數target_link_libraries()這個是函數是幹嘛用的呢,講到這個函數就要講到c/c++的編譯原理了,在linux中c/c++的編譯一般都是用gcc來編譯的,c/c++編譯時會產生.o文件要通過make工具來把這些.o文件鏈接起來,這樣才能得一個可執行程序。所以.so在編譯時要把所有庫鏈接起來才能編譯。target_link_libraries()就是幹這個事的。

target_link_libraries( # Specifies the target library.
                       playController
                       avcodec-lib
                       avdevice-lib
                       avfilter-lib
                       avformat-lib
                       avutil-lib
                       postproc-lib
                       swresample-lib
                       swscale-lib
                       yuv-lib
                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

把要鏈接的庫別名都寫到這裏就可以了,如果是系統的庫要用這個格式${庫的名字}。
好了,CMakeList.txt的基本寫法就講到這裏,如裏有發現寫錯了,小夥伴可以留言給我,及時改正大家一起進步。
最後附上ffmpeg的CMakeList.txt全部寫法

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

set(distribution_DIR ${CMAKE_SOURCE_DIR}/src/main/jniLibs)

add_library(
    avcodec-lib
    SHARED
    IMPORTED)
set_target_properties( avcodec-lib
                       PROPERTIES IMPORTED_LOCATION
                       ${distribution_DIR}/${ANDROID_ABI}/libavcodec-56.so)

add_library( avdevice-lib
             SHARED
             IMPORTED)

set_target_properties( avdevice-lib
                       PROPERTIES IMPORTED_LOCATION
                       ${distribution_DIR}/${ANDROID_ABI}/libavdevice-56.so)

add_library(
            avfilter-lib
            SHARED
            IMPORTED)
set_target_properties( avfilter-lib
                      PROPERTIES IMPORTED_LOCATION
                      ${distribution_DIR}/${ANDROID_ABI}/libavfilter-5.so)

add_library(
            avformat-lib
            SHARED
            IMPORTED)

set_target_properties( avformat-lib
                       PROPERTIES IMPORTED_LOCATION
                       ${distribution_DIR}/${ANDROID_ABI}/libavformat-56.so)
add_library(
            avutil-lib
            SHARED
            IMPORTED)
set_target_properties(
                      avutil-lib
                      PROPERTIES IMPORTED_LOCATION
                      ${distribution_DIR}/${ANDROID_ABI}/libavutil-54.so)
add_library(
             postproc-lib
             SHARED
             IMPORTED)
set_target_properties(
                      postproc-lib
                      PROPERTIES IMPORTED_LOCATION
                      ${distribution_DIR}/${ANDROID_ABI}/libpostproc-53.so)
add_library(
            swresample-lib
            SHARED
            IMPORTED)
set_target_properties(
                      swresample-lib
                      PROPERTIES IMPORTED_LOCATION
                      ${distribution_DIR}/${ANDROID_ABI}/libswresample-1.so)
add_library(
            swscale-lib
            SHARED
            IMPORTED)

set_target_properties(
            swscale-lib
            PROPERTIES IMPORTED_LOCATION
            ${distribution_DIR}/${ANDROID_ABI}/libswcale-3.so)


add_library(
            yuv-lib
            SHARED
            IMPORTED)
set_target_properties(
             yuv-lib
             PROPERTIES IMPORTED_LOCATION
             ${distribution_DIR}/${ANDROID_ABI}/libyvu.so)
#支持-std=gnu++11
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")

#判斷編譯器類型,如果是gcc編譯器,則在編譯選項中加入c++11支持
if(CMAKE_COMPILER_IS_GNUCXX)
    set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
    message(STATUS "optional:-std=c++11")
endif(CMAKE_COMPILER_IS_GNUCXX)







# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
             playController

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             src/main/cpp/playController.c)

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
              log-lib

              # Specifies the name of the NDK library that
              # you want CMake to locate.
              log )

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
include_directories(src/main/jniLibs/include/ffmpeg)
include_directories(src/main/jniLibs/include/libyuv)
target_link_libraries( # Specifies the target library.
                       playController
                       avcodec-lib
                       avdevice-lib
                       avfilter-lib
                       avformat-lib
                       avutil-lib
                       postproc-lib
                       swresample-lib
                       swscale-lib
                       yuv-lib
                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章