這一節我們就一起來看看如何用CMake來鏈接自己寫的lib庫,如何進行這些庫文件的管理。
一個團隊共同開發軟件時,一般都是分模塊進行作業的,每個人負責整個軟件中的一部分,然後再整合成一個完整的軟件系統。具體的做法一般是某個人開發的東西是以鏈接庫的形式供團隊中的其他人進行調用,或者供本人負責的程序的其他模塊進行調用。
比如,A童鞋開發了一種算法,能做數A與數B的加法運算,A童鞋把它編譯成lib庫的形式給B童鞋調用,提供給B童鞋的就只有該加法運算的頭文件(讓B童鞋知道這個函數的接口是怎麼樣的)以及相應的函數實現lib庫文件,B童鞋拿到了這兩個文件以後,就可以在自己的程序裏面直接調用A童鞋的加法運算。
當涉及到大型的軟件開發項目時,這種鏈接庫的形式普遍存在,文件少則幾十上百,多則成千上萬,這個時候就需要一個工具來對這些鏈接庫進行管理,個人覺得CMake就是一個最好的選擇。有用過VTK,ITK等開源工具包的童鞋應該都知道,VTK等編譯完了以後會產生好多lib文件,比如vtkCommon.lib, vtkFiltering.lib, vtkGenericFiltering.lib, vtkGraphics.lib, vtkHybrid.lib, vtkImaging.lib, vtkIO.lib……等,而且好多剛學VTK的童鞋在編譯鏈接VTK工程時會經常碰到類似“***無法解析的外部命令”,“***.h找不到”等等這樣的錯誤。如果你是用CMake來構建工程的話,相信這些問題都是小菜一碟而已,所以瞭解一點CMake的知識對你使用那些開源工具包是灰常有幫助的。
不扯那麼多了,進入主題吧。這一節我們就一起來看看如何用CMake來鏈接自己寫的lib庫,如何進行這些庫文件的管理。
跟《一起學習CMake - 02》一樣,在CMake-Study目錄下再建一個空的文件夾,就叫HelloCMake3吧(在我機子上完整路徑是:D:\CMake\CMake-Study\HelloCMake3),然後把HelloCMake2裏的文件都copy到這個新建文件夾裏去,等下我們就在這個基礎上進行更改。接着在HelloCMake3目錄下再建一個新的文件夾,等下里面會存放我們自己要實現lib的文件,簡單起見,我們就做一個加法運算可以了,文件夾就起名:AddFunction。接着在AddFunction裏新建兩個文件,分別是AddFunction.h和AddFunction.cpp,什麼作用應該不用再解釋了。
AddFunction.h的代碼如下://做整數的加法運算
int AddFunction(intx,inty);
AddFunction.cpp裏的代碼如下:
#include <iostream>
int AddFunction(intx,inty)
{
std::cout<<x<<" + "<<y<<" = "<<x+y<<std::endl;
return x + y;
}
然後在AddFunction文件夾裏再建立一個CMakeLists.txt文件,CMake原則上要求每個文件夾裏都要有一個名叫CMakeLists.txt的文件,因爲我們等下是要把AddFunction.h和AddFunction.cpp這兩個文件生成一個lib庫文件,所以我們必須告訴CMake這個事情,而CMake是隻認CMakeLists.txt文件的,所以這個目錄裏應該要有這個文件存在,裏面的內容如下:add_library(AddFunction AddFunction.cpp)
就這麼一行代碼。表示什麼意思?add_library命令與add_executable命令(在第01節裏有介紹)其實是差不多的,前者就是生成lib庫文件,後者就是生成exe文件;它們所帶的參數也都是一樣的,就是用這個參數列表裏的源文件來生成這些lib或exe文件。
這樣就完成了自己的lib庫文件創建的一些工程。接着回到AddFunction的外層目錄裏,裏面有HelloCMake.cpp; HelloCMakeConfig.h.in; CMakeLists.txt這三個文件,先打開CMakeLists.txt文件吧,把裏面的代碼改爲:
cmake_minimum_required(VERSION 2.6)
project(HelloCmake)
# 在CMake裏設置HelloCMake軟件的主版本號爲1,次版本號爲0。
set ( HelloCMake_VERSION_MAJOR 1 )
set ( HelloCMake_VERSION_MINOR 0 )
#是否要使用我們自己的lib庫裏的加法函數。默認是使用。
option(USE_AddFunction "Use our Add Function" ON)
configure_file(
"${PROJECT_SOURCE_DIR}/HelloCMakeConfig.h.in"
"${PROJECT_BINARY_DIR}/HelloCMakeConfig.h"
)
Include_directories ("${PROJECT_BINARY_DIR}")
#是否加載AddFunction庫文件?
if (USE_AddFunction)
include_directories ("${PROJECT_SOURCE_DIR}/AddFunction")
add_subdirectory (AddFunction)
set (EXTRA_LIBS ${EXTRA_LIBS} AddFunction)
endif (USE_AddFunction)
add_executable(HelloCMake hellocmake.cpp)
target_link_libraries (HelloCMake ${EXTRA_LIBS})
紅色字體標註的是新加的代碼,一起來看看這些代碼作用是什麼。首先是option一行代碼,option也是CMake裏的命令,它的作用就是在CMake GUI上增加一個選項(如圖(1)所示):
圖(1)
具體到這個例子就是增加選項”USE_AddFunction”;第二個參數”User our Add Function”是標註信息,也就是當你的鼠標停留在CMake GUI的”USE_AddFunction”選項上是會有提示信息出現;第三個參數就是這個選項的值,默認是ON,也就是使用我們自己的加法庫。如果更改了這些值,然後用CMake進行Configure, Generate時,這些選項的值會保存在你在”where to build the binaries”指定的編譯目錄裏的CMakeCache.txt文件裏。當你再次打開CMake時,CMake會自動去讀取CMakeCache.txt文件裏的各個選項的值。
再看看if/endif語句塊,它的作用就是根據用戶的選擇(即USE_AddFunction的值)來決定是否要包含子目錄AddFunction(include_directories/add_subdirectory兩行代碼)到頭文件的搜索路徑中去;以及設置變量EXTRA_LIBS的值爲AddFunction.lib(set一行代碼)。Set命令是CMake裏用於設置變量值的一個命令,使用頻率灰常高。還有,if/endif語句塊必須要成對出現,if和endif後面所帶的參數也必須一致。
target_link_libraries命令也是用得灰常多的一個命令,它的作用就是把${EXTRA_LIBS}這個變量裏的庫文件鏈接到HelloCMake這個工程裏去。${……}是取某個變量的值的意思。
最外層的CMakeLists.txt內容介紹完,接着看看HelloCMakeConfig.h.in裏要添加什麼東西?在該文件的最後加入如下代碼:
#cmakedefine USE_AddFunction
這行代碼是告訴CMake在生成HelloCMakeConfig.h文件時用”#define USE_AddFunction”或者”/*#undef USE_AddFunction*/”來代替” #cmakedefine USE_AddFunction”,到底是前者還是後者,取決於USE_AddFunction選項的值(ON還是OFF)。編譯完HelloCMake這個工程以後,打開HelloCMakeConfig.h看看就知道怎麼回事了。
接着來看看HelloCMake.cpp文件,完整代碼如下:
#include <iostream>
#include "HelloCMakeConfig.h"
#ifdef USE_AddFunction
#include "AddFunction.h"
#endif
int main(intargc,char *argv[])
{
std::cout<<"HelloCMake軟件的主版本號是:"
<< HelloCMake_VERSION_MAJOR <<std::endl;
std::cout<<"HelloCMake軟件的次版本號是:"
<< HelloCMake_VERSION_MINOR <<std::endl;
fprintf(stdout,"%s Version is: %d.%d\n",
argv[0],
HelloCMake_VERSION_MAJOR,
HelloCMake_VERSION_MINOR);
std::cout<<"Study CMake Together - HelloCMake2"<<std::endl;
int a, b;
std::cin>>a>>b;
#ifdef USE_AddFunction
int addResult = AddFunction(a,b);
#else
int addResult = a + b;
#endif
return 0;
}
增加的代碼都粗體字顯示,這些代碼都比較簡單,一看就能明白了,這裏就不多作介紹。有了這些文件以後,走一遍CMake(Configure, Generate),整個工程也就構建完成了。
我們來看看到底發生了哪些變量,有圖有真相,看圖吧:
圖(2)
圖(3)
圖(4)
知道了這些東西,以後你在使用VTK, ITK等工具包時,再碰到類似前文提到的錯誤時,也就知道怎麼回事了吧?下一節我們結合VTK等工具包來看看怎麼鏈接VTK裏的庫文件到自己的工程裏去。
轉自http://blog.163.com/jacky_ling0/blog/static/1373925712011090236524/