1. 程式人生 > >cmake 從放棄到入門

cmake 從放棄到入門

簡介

cmake的亮點在於編譯複雜專案上的應用 —— cmake是一個跨平臺的Makefile 生成工具!
一言以蔽之——cmake 為專案自動生成Makefile, 雖然cmake功能遠不止步於此,但是本文聚焦於此。

原始碼

這篇文章是cmake的helloworld, 所用例項非常短小,我按照原文在ubuntu上測試了,全部通過,所以程式碼可以放心使用。
本文程式碼位於github:

git clone https://github.com/derekmolloy/exploringBB.git

例1:Hello World

第一個例子的原始碼位於extras/cmake/helloworld ,原始碼只有一個檔案HelloWorld.cpp:

#include<iostream>

int main(int argc, char *argv[]){
   std::cout << "Hello World!" << std::endl;
   return 0;
}

CMakeLists.txt也只有三行而已(使用cmake管理專案的過程,也就是編寫CMakeLists.txt的過程)

cmake_minimum_required(VERSION 2.8.9)
project (hello)
add_executable(hello helloworld.cpp)

第一行用於指定cmake最低版本
第二行指定專案名稱(這個名稱是任意的)
第三行指定編譯一個可執行檔案,hello是第一個引數,表示生成可執行檔案的檔名(這個檔名也是任意的),第二個引數helloworld.cpp則用於指定原始檔。

如果您電腦上已經安裝了cmake,那麼我們就已經完事具備了。
第一步,用cmake生成Makefile檔案

cmake命令後邊跟的就是CMakelist.txt所在的目錄,這個目錄不必是當前目錄,你也可以新建一個build目錄或者其他名字的目錄來生成build檔案,實際專案中也都是這麼做的,這樣程式碼會很乾淨也便於git管理:

這裡寫圖片描述
第二步,make編譯程式,編譯成功

通過上一步我們發現,當前目錄下已經多出了幾個檔案,特別是Makefile檔案
這裡寫圖片描述

第三步,測試程式
到此,第一個用cmake管理的程式,成功了!

這裡寫圖片描述

例2: 包含目錄結構的專案

在例1中完全體現不出cmake的任何優勢,用g++一行可以解決的問題我們繞了一大圈。可是cmake本來的優勢就是管理龐大的專案的。

這個例子用最小的程式來體現一個帶目錄結構的專案。其中有原始檔目錄,標頭檔案目錄。額。。。這就夠了,例項程式碼位於/extras/cmake/student

例項的目錄結構如下圖:
這裡寫圖片描述


cmake_minimum_required(VERSION 2.8.9)
project(directory_test)

#Bring the headers, such as Student.h into the project
include_directories(include)

#Can manually add the sources using the set command as follows:
#set(SOURCES src/mainapp.cpp src/Student.cpp)

#However, the file(GLOB...) allows for wildcard additions:
file(GLOB SOURCES "src/*.cpp")

add_executable(testStudent ${SOURCES})

和第一個例子比起來,CMakelist.txt有如下改變:
1. 使用include_directories() 包含標頭檔案目錄
2. 使用set(SOURCES … ) 或GLOB (or GLOB_RECURSE) 設定原始檔SOURCES
3. add_executable 使用變數SOURCES ,而不是具體的檔名
接下來的步驟就和例子1一樣了,不同之處是我們新建了一個build目錄來儲存編譯中間檔案,如下圖:
這裡寫圖片描述
下一步make,然後執行結果如下:
這裡寫圖片描述

例3:動態庫編譯(.so)

有了前兩個例子的基礎,接下來的例子我們只需要看一下目錄結構和CMakelist.txt.本例程式碼位於/exploringBB/extras/cmake/studentlib_shared
這裡寫圖片描述
CMakelist.txt如下:

project(directory_test)
set(CMAKE_BUILD_TYPE Release)

#Bring the headers, such as Student.h into the project
include_directories(include)

#However, the file(GLOB...) allows for wildcard additions:
file(GLOB SOURCES "src/*.cpp")

#Generate the shared library from the sources
add_library(testStudent SHARED ${SOURCES})

#Set the location for library installation -- i.e., /usr/lib in this case
# not really necessary in this example. Use "sudo make install" to apply
install(TARGETS testStudent DESTINATION /usr/lib)

兩個重要變化:
1. 我們不再使用add_executable() 而是使用add_library()
2. install 指定安裝目錄,執行sudo make install時動態庫將被安裝在/usr/lib目錄
如前兩個例子,我們依次執行,cmake make編譯結果如下:
這裡寫圖片描述

例4:靜態庫編譯 (.a)

基於例3,我們編譯一個靜態庫,程式碼位置
exploringBB/extras/cmake/studentlib_static/
這裡寫圖片描述
將CMakeList.txt修改為如下所示:

cmake_minimum_required(VERSION 2.8.9)
project(directory_test)
set(CMAKE_BUILD_TYPE Release)

#Bring the headers, such as Student.h into the project
include_directories(include)

#However, the file(GLOB...) allows for wildcard additions:
file(GLOB SOURCES "src/*.cpp")

#Generate the static library from the sources
add_library(testStudent STATIC ${SOURCES})

#Set the location for library installation -- i.e., /usr/lib in this case
# not really necessary in this example. Use "sudo make install" to apply
install(TARGETS testStudent DESTINATION /usr/li

可以看出,只需將add_library中的shared改為static即可。
編譯結果如下:
這裡寫圖片描述

例5:使用靜態庫或動態庫

下邊我們來測試一下我們例3的結果,程式碼和CMakeList.txt如下:

#include"Student.h"

int main(int argc, char *argv[]){
   Student s("Joe");
   s.display();
   return 0;
}
cmake_minimum_required(VERSION 2.8.9)
project (TestLibrary)

#For the shared library:
set ( PROJECT_LINK_LIBS libtestStudent.so )
link_directories( ~/exploringBB/extras/cmake/studentlib_shared/build )

#For the static library:
#set ( PROJECT_LINK_LIBS libtestStudent.a )
#link_directories( ~/exploringBB/extras/cmake/studentlib_static/build )

include_directories(~/exploringBB/extras/cmake/studentlib_shared/include)

add_executable(libtest libtest.cpp)
target_link_libraries(libtest ${PROJECT_LINK_LIBS} )

結果如下(CMakeList.txt中的目錄要根據自己的情況改一下):
這裡寫圖片描述
成功了!!