CMake 語法 - 詳解 CMakeLists.txt

關於 《Android 開發者需要知道的 Linux 知識》與 《從 Linux 內核的角度來看 Binder 驅動》兩篇文章被鎖定,官方申訴也未給予回覆,大家可以看這裏:
https://blog.csdn.net/z240336124/article/details/89451641
https://blog.csdn.net/z240336124/article/details/90137352

CMake 是一個跨平臺的安裝(編譯)工具,可以用簡單的語句來描述所有平臺的安裝(編譯過程)。他能夠輸出各種各樣的 Makefile 或者 project 文件,CMake 並不直接建構出最終的軟件,而是產生標準的建構檔(如 Makefile 或 projects)。

以前做 NDK 開發都是基於 Android.mk、Application.mk 來構建項目的,但從 AS 2.2 之後便開始採用 CMake 的這種方式來構建,採用 CMake 相比與之前的 Android.mk、Application.mk 方便簡單了許多。但公司有一些古老的項目還是採用 Android.mk 和 Application.mk 來構建的,因此大家還是需要花些時間去了解這種構建方式。但重心得放在 CMake 的構建方式上,因此本文主要來說說 CMake 的構建語法基礎。

語法和關鍵字要大家全部記住是不太可能的,個人也不建議大家去死記硬背。我們只需要知道目前有哪些內容,需要生成哪些內容即可,有不太瞭解甚至不知道的可以查筆記或資料。我們來詳細看下以下四個事例,相信對於以後的 CMake 構建基本就可以不怕了。

1. 初試 cmake 的 helloworld

現在新建一個 hello.cpp 源碼文件,代碼如下:

#include <stdio.h>
int main(int argc, char* argv[]){
  printf("Hello CMake!\n");
}

之前都是採用 gcc hello.cpp -o hello 命令來生成可執行文件,但現在我們用 CMake 這種方式來生成,新建一個 CMakeLists.txt 文件名大小寫都按照這個來:

# 指定工程名
PROJECT (HELLO)
# 現階段,你只需要瞭解 SET 指令可以用來顯式的定義變量即可
# 將 hello.cpp 賦值給 SRC_LIST 變量,也可以指定多個源文件,用空格隔開
# SET(SRC_LIST hello.cpp add.cpp sub.cpp)
SET(SRC_LIST hello.cpp)
# 輸出打印構建目錄
MESSAGE(STATUS "This is HELLO_BINARY_DIR " ${HELLO_BINARY_DIR})
# 輸出打印資源目錄
MESSAGE(STATUS "This is HELLO_SOURCE_DIR " ${HELLO_SOURCE_DIR})
# 輸出打印資源目錄,與HELLO_SOURCE_DIR 一樣 
MESSAGE(STATUS "This is PROJECT_SOURCE_DIR " ${PROJECT_SOURCE_DIR})
# 輸出打印 CMake 資源目錄,與 PROJECT_SOURCE_DIR 一樣 
MESSAGE(STATUS "This is CMAKE_SOURCE_DIR " ${CMAKE_SOURCE_DIR})
# 生成可執行文件 hello ,${SRC_LIST}是引用變量,也就是源文件 hello.cpp
ADD_EXECUTABLE(hello ${SRC_LIST})

新建 build 目錄,cd 到 build 目錄下,敲 cmake .. 命令,ls 一下會發現 CMake 幫我們生成了 Makefile 等等一些文件。敲 make 命令生成 hello 可執行文件,ls 文件列表如下:

ubuntu@VM-0-9-ubuntu:~/NDK_Day88/t1/build$ ls
CMakeCache.txt  CMakeFiles  cmake_install.cmake  hello  Makefile

2. 構建生成 .so 動態庫

上面的例子看不出有啥優勢,甚至說還不如用 gcc hello.cpp -o hello 來得快,但像 FFmpeg 、OpenCV 等等,類似這樣複雜的項目,我們敲命令去構建項目是很麻煩的。下面我們來講一個稍微複雜一點的例子:

mkdir 新建 3 個目錄分別爲 src、libs、include 。src 用來存放源文件 add.ccp、sub.cpp、div.cpp。include 用來存放頭文件 add.h、div.h、sub.h 。源碼如下:

#include "add.h"
int add(int num1, int num2){
        return num1 + num2;
}

#include "sub.h"                         
int sub(int num1, int num2){         
        return num1 - num2;         
}

#include "div.h"                                              
int div(int num1, int num2){                    
        return num1 / num2;                  
}

基於這些準備工作,我們想用 CMake 來構建一個 libmath.so 動態庫,並且將其生成在 libs 目錄文件夾下。

# 指定 cmake 最低編譯版本
CMAKE_MINIMUM_REQUIRED(VERSION 3.14)
PROJECT (MATH)
# 把當前工程目錄下的 src 目錄的下的所有 .cpp 和 .c 文件賦值給 SRC_LIST
# AUX_SOURCE_DIRECTORY(${PROJECT_SOURCE_DIR}/src SRC_LIST)
FILE(GLOB SRC_LIST "${PROJECT_SOURCE_DIR}/src/*.cpp")
# 打印 SRC_LIST 文件列表
# MESSAGE(STATUS ${SRC_LIST})
# 指定頭文件目錄
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include)
# 指定輸出 .so 動態庫的目錄位置
SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
# 指定生成動態庫
ADD_LIBRARY(math SHARED ${SRC_LIST})
# 指定生成版本號,VERSION指代動態庫版本,SOVERSION指代API版本
# SET_TARGET_PROPERTIES(math PROPERTIES VERSION 1.2 SOVERSION 1)

3. 鏈接外部動態庫和頭文件

將 libs 目錄和 include 目錄 copy 到 hello.cpp 同級目錄下,修改 hello.cpp 源碼如下:

#include <stdio.h>
#include "add.h"
#include "sub.h"
#include "div.h"

int main(int argc, char* argv[]){
        int a = 20;
        int b = 10;
        printf("%d+%d=%d\n",a,b,add(a,b));
        printf("%d-%d=%d\n",a,b,sub(a,b));
        printf("%d/%d=%d\n",a,b,div(a,b));
        return 0;
}

現在我引用了 include 目錄下的頭文件,同時需要鏈接 libs 目錄下的 libmath.so ,我們再次創建一個 CMakeLists.txt 來生成可執行文件 hello。

# 指定cmake最低編譯版本
CMAKE_MINIMUM_REQUIRED(VERSION 3.14)
# 指定工程的名稱
PROJECT(HELLO)
#指定頭文件目錄位置
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include)
#添加共享庫搜索路徑
LINK_DIRECTORIES(${PROJECT_SOURCE_DIR}/lib)
#生成可執行文件
ADD_EXECUTABLE(hello hello.cpp)
#爲hello添加共享庫鏈接
TARGET_LINK_LIBRARIES(hello math)

4. 基於 FFmpeg 開發的 CMakeLists.txt

音視頻的播放,在線直播,音視頻通話開發,後面可能都得基於 FFmpeg 來寫。那麼首先我們需要編譯 .so 動態庫,然後把動態庫和頭文件 copy 到 AS 來開發,這裏我已經編譯好了一個 3.3.9 的版本,至於怎麼寫 shell 編譯腳本,會在下篇文章中介紹。目前大夥先直接拿過來用就行了。我把編譯好的 .so 動態庫和 include 目錄拷貝到 AS 工程的 jniLibs 目錄下

# 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)

# 需要引入我們頭文件,以這個配置的目錄爲基準
include_directories(src/main/jniLibs/include)
include_directories(src/main/jniLibs/other)

# 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.

#添加共享庫搜索路徑
LINK_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi)

# 指定源文件目錄
AUX_SOURCE_DIRECTORY(${CMAKE_SOURCE_DIR}/src/main/cpp SRC_LIST)

add_library( 
        # Sets the name of the library.
        native-lib
        # Sets the library as a shared library.
        SHARED
        # Provides a relative path to your source file(s).
        # src/main/cpp/native-lib.cpp
        ${SRC_LIST}
        )


# 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.

target_link_libraries( 
        # Specifies the target library.
        # 鏈接額外的 ffmpeg 的編譯
        native-lib
        # 編解碼(最重要的庫)
        avcodec-57
        # 設備信息
        avdevice-57
        # 濾鏡特效處理庫
        avfilter-6
        # 封裝格式處理庫
        avformat-57
        # 工具庫(大部分庫都需要這個庫的支持)
        avutil-55
        # 後期處理
        postproc-54
        # 音頻採樣數據格式轉換庫
        swresample-2
        # 視頻像素數據格式轉換
        swscale-4

        -landroid

        # Links the target library to the log library
        # included in the NDK.
        ${log-lib})
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章