今天不是來講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} )