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中的目錄要根據自己的情況改一下):
成功了!!