CMake 簡介和 CMake 模板

weixin_33782386發表於2016-07-13

轉載自我的部落格:CMake 簡介和 CMake 模板


如果你用 Linux 作業系統,使用 cmake 會簡單很多,可以參考一個很好的教程:CMake 入門實戰 | HaHack。如果你用 Linux 作業系統,而且只是執行一些小程式,可以看看我的另一篇部落格:你就編譯一個 cpp,用 CMake 還不如用 pkg-config 呢

但如果你用 Windows,很大的可能你會使用圖形介面的 CMake(cmake-gui.exe)和 Visual Studio。本文先簡單介紹使用 CMake + Visual Studio 的使用流程,然後以幾個例子介紹 CMake 相關知識。

CMake 使用流程

如果你還沒安裝 cmake,下載 https://cmake.org/files/v3.6/cmake-3.6.0-win64-x64.msi(15 MB)安裝它。如果你還沒裝 VS,推薦使用 VS2015 社群版本,到 這裡 下載,選擇那個 3.7 GB 的。因為一次下載好,安裝起來很省心。如果你已經有了 VS2010 或者 VS2013,也可以不安裝 VS2015。

下載第一份原始碼 cpp.zip(1.16 KB)。解壓進入資料夾,開啟 cmake-gui,把原始碼和 cmake-gui 介面對半放。如下圖:

29284-aac2232398b7dcc3.png

然後,

  1. 把原始碼根目錄的 CMakeLists.txt 拖動到 cmake-gui 介面上
  2. 修改輸出目錄(我通常都是新增 /build
  3. 點選 configure(配置),選擇【Visual Studio 14 VS2015 Win64】,點選確定^[“Win64”是指的是編譯 VS2015 x64 工程,沒有“Win64”則為 x86 工程)。]
  4. 點選 generate(生成)

最後,到輸出目錄,用 VS2015 開啟 CPP.sln 工程。在 Solution Explorer 中右鍵單擊 CPP,然後【Set as StartUp Project】,然後 <kbd>Ctrl</kbd>+<kbd>F5</kbd> 執行。

相信你已經看到了程式執行結果,大概如下:

0^2 --->    0
0^2 --->    0
2^2 --->    4
3^2 --->    9
4^2 --->    16

使用 CMake 的好處是,它可以生成 VS 工程,也可以生成 Linux 系統下常用的 Makefile工程,甚至還可以用 Qt creator 開啟 CMakeLists.txt 檔案,然後生成 qt 工程。^[參考我的教程:HOWTO: Use Qt creator to Open CMakeLists.txt directly (will generate proper project files) · Issue #5 · district10/cmake-templates,裡面包含一個 Linux 上的例子,一個 Windows 上的例子。]這份程式碼,在 Linux 上也可以迅速跑起來,這是我虛擬機器中執行的截圖:

29284-e07edf9e83232434.png

CMake 基礎

簡單的四行 CMakeLists.txt

本小節原始碼:cmake-templates/cpp at master · district10/cmake-templates

我們從根目錄的 CMakeLists.txt 看起,它簡潔到只有 4 行!如下:

project( CPP )
cmake_minimum_required( VERSION 2.6 )
file( GLOB SRCS *.c *.cpp *.cc *.h *.hpp )
add_executable( ${PROJECT_NAME} ${SRCS} )

我們一行一行看,

  • 第一行,設定了工程名稱,叫“CPP”(所以後來生成的 VS 工程名為 CPP.sln);
  • 第二行,設定了 CMake 最低版本號,通常在根目錄的 CMakeLists.txt 新增這個指定;
  • 第三行,把當前資料夾下的原始碼列表(檔案字尾匹配的那些檔案)存到變數 SRCS 中;
  • 第四行,把原始碼編譯成一個二進位制這裡的 ${PROJECT_NAME} 就是 CPP,是在第一行設定的。

這就是一個基本的用 CMake 組織的 C++ 程式。只要四行配置,利用 CMake,我們就生成了 Windows 下的 VS 工程,還生成了 Linux 下的 Makefile 工程。只要四行!

當然還可以生成多個二進位制,如果你有多份原始碼,比如

add_executable( foo foo.cpp )
add_executable( bar bar.cpp )

如果上面沒問題,還是這兩個程式碼,我們在 CMakeLists.txt 裡去掉上面兩行,改成 add_executable( foobar foo.cpp bar.cpp ){.cmake},會不會有什麼問題?

生成靜態、動態庫

本小節原始碼:cmake-templates/modules at master · district10/cmake-templates

還可以用 CMake 生成連結庫,可以是靜態庫(.lib),也可以是動態庫(.dll),語法如下:

add_library(    動態連結庫名稱      SHARED      原始碼列表    )
add_library(    靜態連結庫名稱      STATIC      原始碼列表    )

如果不指定 SHARED 或是 STATIC,預設生成的是 STATIC,這個例子裡,src 資料夾下生成了 3 個連結庫,LibCubic 是“指定”生成的靜態庫,LibExtras 是“指定”生成的動態庫,LibSquare 是“預設”生成的靜態庫。

生成庫檔案就是為了讓人用,所以我們要把它連結給某個二進位制,語法如下:

add_executable(             二進位制名    原始碼列表        )
target_link_libraries(      二進位制名    動靜態庫名      )

生成庫的原始碼有什麼最基本的要求嗎?如果 add_executable( baz baz.cpp b.cpp a.cpp z.cpp ){.cmake} 可以正確地生成二進位制檔案 baz(windows 上就是 baz.exe),那這行 CMake 配置可以修改為 add_library( baz baz.cpp b.cpp a.cpp z.cpp ){.cmake} 嗎?為什麼。

連結系統配置了的庫

本小節原始碼:cmake-templates/opencv3 at master · district10/cmake-templates

CMake 的一個方便之處,便是新增第三方庫。在我的 CMake 安裝目錄(C:\Program Files\CMake\share\cmake-3.6\Modules)下,有多達 145 個 FindX.cmake 檔案,比如FindQt4.cmake。當你在自己原始碼中使用 find_package( Qt4 ) 時,CMake 就會嘗試去引入 FindQt4.cmake,這個檔案引入後,特定的變數裡就儲存了標頭檔案地址(include_directories)、連結庫地址(link_directories)、連結庫的名稱以及一些開關配置(options)。

本節用 OpenCV 來說明如何連結使用第三方庫,這裡用的是 opencv3。OpenCV3 官網提供的只有 VS2013 (vc12) 和 VS2015 (vc14) 的 prebuild,如果你使用 VS2012,你只能使用 OpenCV2(或者你要自己編譯 OpenCV3?)。OpenCV 的配置可以參考我寫得教程:HOWTO: OpenCV 2 & OpenCV 3 · Issue #4 · district10/cmake-templates

本節原始碼的 CMakeLists.txt 裡,我沒有使用 find_package( OpenCV REQUIRED ),而是使用了include( $ENV{OpenCV3_DIR}/OpenCVConfig.cmake ),因為我覺得這是一種更好的解決方案,如此一來,你只要設定環境變數(%OpenCV3_DIR%),新增相應目錄到 %PATH%,便可以同時使用 OpenCV2 和 OpenCV3(當然是在不同的專案中)。上面的原始碼連結中對此也有簡要說明。

看看我們的 CMakeLists.txt:

project( OPENCV3 )
cmake_minimum_required( VERSION 2.8 )

# find_package( OpenCV REQUIRED )                       # 不使用 find_package
include( $ENV{OpenCV3_DIR}/OpenCVConfig.cmake )         # 直接引入 cmake 檔案

message( STATUS "OpenCV library status:" )              # 輸出一下得到的變數
message( STATUS "    version: ${OpenCV_VERSION}" )
message( STATUS "    libraries: ${OpenCV_LIBS}" )
message( STATUS "    include path: ${OpenCV_INCLUDE_DIRS}" )

include_directories( ${OpenCV_INCLUDE_DIRS} )           # 引入 OpenCV 標頭檔案目錄

add_executable( ${PROJECT_NAME} example.cpp )
target_link_libraries( ${PROJECT_NAME} ${OpenCV_LIBS} ) # exe 連結 OpenCV

在我的系統下,輸出如下(我調整了換行):

OpenCV ARCH: x64
OpenCV RUNTIME: vc14
OpenCV STATIC: ON
Found OpenCV 3.1.0 in C:/OpenCV/opencv3/build/x64/vc14/lib
You might need to add C:\OpenCV\opencv3\build\x64\vc14\bin to your PATH to be able to run your applications.
OpenCV library status:
    version: 3.1.0
    libraries:  opencv_world;opencv_videostab;opencv_videoio;opencv_video;
                opencv_superres;opencv_stitching;opencv_shape;opencv_photo;
                opencv_objdetect;opencv_ml;opencv_imgproc;opencv_imgcodecs;
                opencv_highgui;opencv_flann;opencv_features2d;opencv_core;opencv_calib3d
    include path: C:/OpenCV/opencv3/build/include;C:/OpenCV/opencv3/build/include/opencv
Configuring done

很容易地,程式也執行起來了。

更多的瞭解

只要掌握上面那基本的幾點(通俗地說,就是生成 exe、lib、dll,連結 lib、dll,引入第三方庫),然後積攢一些別人的 CMakeLists.txt 片段,CMake 便不難了。

如果你還覺得 CMake 很麻煩,那一定是我部落格寫得不好。如果你覺得 CMake 不好用,那不是我的錯,那是 CMake 的官方教程太垃圾導致的,我反正從來沒見過如此晦澀,一個例子都不給的教程。當時寫 https://github.com/district10/cmake-templates/blob/master/qt4-project/CMakeLists.txt 的時候,我可是深受其苦。

寫起來雖難,但用起來方便,所以……我大讚 CMake。

想對 CMake 有更多的瞭解,可以參考我的 district10/cmake-templates: Some CMake Templates. Qt, Boost, OpenCV, C++11, etc.,裡面有簡單的 C 工程,C++ 工程,C++11 工程,Boost 庫的配置,OpenCV2、OpenCV3 的配置,Qt4、Qt5 的配置,等等。程式碼在大多在 Windows + VS2010/VS2015 和 Linux + GCC4.8 測試通過。

我還寫了一些庫的配置,不同平臺不同 IDE、編譯器上有關 CMake 使用的教程:Issues · district10/cmake-templates

相關文章