自定義變量
主要有隱式定義和顯式定義兩種。
隱式定義的一個例子是PROJECT指令,它會隱式的定義< projectname >_BINARY_DIR和< projectname >_SOURCE_DIR兩個變量;顯式定義使用SET指令構建自定義變量,比如:SET(HELLO_SRCmain.c)就可以通過${HELLO_SRC}來引用這個自定義變量了。
變量引用方式
使用${}進行變量的引用;在IF等語句中,是直接使用變量名而不通過${}取值。
常用變量
CMAKE_BINARY_DIR
PROJECT_BINARY_DIR
< projectname >_BINARY_DIR
這三個變量指代的內容是一致的,如果是in-source編譯,指得就是工程頂層目錄;如果是out-of-source編譯,指的是工程編譯發生的目錄。PROJECT_BINARY_DIR跟其它指令稍有區別,目前可以認為它們是一致的。
CMAKE_SOURCE_DIR
PROJECT_SOURCE_DIR
< projectname >_SOURCE_DIR
這三個變量指代的內容是一致的,不論采用何種編譯方式,都是工程頂層目錄。也就是在in-source編譯時,他跟CMAKE_BINARY_DIR等變量一致。PROJECT_SOURCE_DIR跟其它指令稍有區別,目前可以認為它們是一致的。
(out-of-source build與in-source build相對,指是否在CMakeLists.txt所在目錄進行編譯。)
CMAKE_CURRENT_SOURCE_DIR
當前處理的CMakeLists.txt所在的路徑,比如上面我們提到的src子目錄。
CMAKE_CURRRENT_BINARY_DIR
如果是in-source編譯,它跟CMAKE_CURRENT_SOURCE_DIR一致;如果是out-of-source編譯,指的是target編譯目錄。使用ADD_SUBDIRECTORY(src bin)可以更改這個變量的值。使用SET(EXECUTABLE_OUTPUT_PATH <新路徑>)並不會對這個變量造成影響,它僅僅修改了最終目標文件存放的路徑。
CMAKE_CURRENT_LIST_FILE
輸出調用這個變量的CMakeLists.txt的完整路徑
CMAKE_CURRENT_LIST_LINE
輸出這個變量所在的行
CMAKE_MODULE_PATH
這個變量用來定義自己的cmake模塊所在的路徑。如果工程比較復雜,有可能會自己編寫一些cmake模塊,這些cmake模塊是隨工程發布的,為了讓cmake在處理CMakeLists.txt時找到這些模塊,你需要通過SET指令將cmake模塊路徑設置一下。比如SET(CMAKE_MODULE_PATH,${PROJECT_SOURCE_DIR}/cmake)
這時候就可以通過INCLUDE指令來調用自己的模塊了。
EXECUTABLE_OUTPUT_PATH
新定義最終結果的存放目錄
LIBRARY_OUTPUT_PATH
新定義最終結果的存放目錄
PROJECT_NAME
返回通過PROJECT指令定義的項目名稱。
cmake調用環境變量的方式
使用$ENV{NAME}指令就可以調用系統的環境變量了。比如MESSAGE(STATUS "HOME dir: $ENV{HOME}")設置環境變量的方式是SET(ENV{變量名} 值)。
CMAKE_INCLUDE_CURRENT_DIR
自動添加CMAKE_CURRENT_BINARY_DIR和CMAKE_CURRENT_SOURCE_DIR到當前處理的CMakeLists.txt,相當於在每個CMakeLists.txt加入:INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE
將工程提供的頭文件目錄始終置於系統頭文件目錄的前面,當定義的頭文件確實跟系統發生沖突時可以提供一些幫助。
CMAKE_INCLUDE_PATH和CMAKE_LIBRARY_PATH
系統信息
CMAKE_MAJOR_VERSION,CMAKE主版本號,比如2.4.6中的2
CMAKE_MINOR_VERSION,CMAKE次版本號,比如2.4.6中的4
CMAKE_PATCH_VERSION,CMAKE補丁等級,比如2.4.6中的6
CMAKE_SYSTEM,系統名稱,比如Linux-2.6.22
CMAKE_SYSTEM_NAME,不包含版本的系統名,比如Linux
CMAKE_SYSTEM_VERSION,系統版本,比如2.6.22
CMAKE_SYSTEM_PROCESSOR,處理器名稱,比如i686
UNIX,在所有的類Unix平台為TRUE,包括OSX和cygwin
WIN32,在所有的Win32平台為TRUE,包括cygwin
主要的開關選項
CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS
用來控制IF ELSE語句的書寫方式。
BUILD_SHARED_LIBS
這個開關用來控制默認的庫編譯方式。如果不進行設置,使用ADD_LIBRARY並沒有指定庫類型的情況下,默認編譯生成的庫都是靜態庫;如果SET(BUILD_SHARED_LIBSON)后,默認生成的為動態庫。
CMAKE_C_FLAGS
設置C編譯選項,也可以通過指令ADD_DEFINITIONS()添加。
MAKE_CXX_FLAGS
設置C++編譯選項,也可以通過指令ADD_DEFINITIONS()添加。
cMake常用指令
這里引入更多的cmake指令,為了編寫的方便,將按照cmakeman page 的順序介紹各種指令,不再推薦使用的指令將不再介紹。
基本指令
PROJECT(HELLO)
指定項目名稱,生成的VC項目的名稱,使用${HELLO_SOURCE_DIR}表示項目根目錄。
INCLUDE_DIRECTORIES
指定頭文件的搜索路徑,相當於指定gcc的-I參數
INCLUDE_DIRECTORIES(${HELLO_SOURCE_DIR}/Hello) #增加Hello為include目錄
TARGET_LINK_LIBRARIES
添加鏈接庫,相同於指定-l參數
TARGET_LINK_LIBRARIES(demoHello) #將可執行文件與Hello連接成最終文件demo
LINK_DIRECTORIES
動態鏈接庫或靜態鏈接庫的搜索路徑,相當於gcc的-L參數
LINK_DIRECTORIES(${HELLO_BINARY_DIR}/Hello)#增加Hello為link目錄
ADD_DEFINITIONS
向C/C++編譯器添加-D定義,比如:
ADD_DEFINITIONS(-DENABLE_DEBUG-DABC)
參數之間用空格分割。如果代碼中定義了:
#ifdef ENABLE_DEBUG
#endif
這個代碼塊就會生效。如果要添加其他的編譯器開關,可以通過CMAKE_C_FLAGS變量和CMAKE_CXX_FLAGS變量設置。
ADD_DEPENDENCIES*
定義target依賴的其它target,確保在編譯本target之前,其它的target已經被構建。ADD_DEPENDENCIES(target-name depend-target1 depend-target2 ...)
ADD_EXECUTABLE
ADD_EXECUTABLE(helloDemo demo.cxx demo_b.cxx)
指定編譯,好像也可以添加.o文件,將cxx編譯成可執行文件
ADD_LIBRARY
ADD_LIBRARY(Hellohello.cxx) #將hello.cxx編譯成靜態庫如libHello.a
ADD_SUBDIRECTORY
ADD_SUBDIRECTORY(Hello) #包含子目錄
ADD_TEST
ENABLE_TESTING
ENABLE_TESTING指令用來控制Makefile是否構建test目標,涉及工程所有目錄。語法很簡單,沒有任何參數,ENABLE_TESTING()一般放在工程的主CMakeLists.txt中。
ADD_TEST指令的語法是:ADD_TEST(testnameExename arg1 arg2 …)
testname是自定義的test名稱,Exename可以是構建的目標文件也可以是外部腳本等等,后面連接傳遞給可執行文件的參數。
如果沒有在同一個CMakeLists.txt中打開ENABLE_TESTING()指令,任何ADD_TEST都是無效的。比如前面的Helloworld例子,可以在工程主CMakeLists.txt中添加
ADD_TEST(mytest ${PROJECT_BINARY_DIR}/bin/main)
ENABLE_TESTING
生成Makefile后,就可以運行make test來執行測試了。
AUX_SOURCE_DIRECTORY
基本語法是:AUX_SOURCE_DIRECTORY(dir VARIABLE),作用是發現一個目錄下所有的源代碼文件並將列表存儲在一個變量中,這個指令臨時被用來自動構建源文件列表,因為目前cmake還不能自動發現新添加的源文件。比如:
AUX_SOURCE_DIRECTORY(. SRC_LIST)
ADD_EXECUTABLE(main ${SRC_LIST})
可以通過后面提到的FOR EACH指令來處理這個LIST。
CMAKE_MINIMUM_REQUIRED
語法為CMAKE_MINIMUM_REQUIRED(VERSION versionNumber [FATAL_ERROR]),
比如:CMAKE_MINIMUM_REQUIRED(VERSION 2.5 FATAL_ERROR)
如果cmake版本小與2.5,則出現嚴重錯誤,整個過程中止。
EXEC_PROGRAM
在CMakeLists.txt處理過程中執行命令,並不會在生成的Makefile中執行。具體語法為:
EXEC_PROGRAM(Executable [directory in which to run] [ARGS <arguments to executable>] [OUTPUT_VARIABLE <var>] [RETURN_VALUE <var>])
用於在指定的目錄運行某個程序,通過ARGS添加參數,如果要獲取輸出和返回值,可通過OUTPUT_VARIABLE和RETURN_VALUE分別定義兩個變量。
這個指令可以幫助在CMakeLists.txt處理過程中支持任何命令,比如根據系統情況去修改代碼文件等等。舉個簡單的例子,我們要在src目錄執行ls命令,並把結果和返回值存下來,可以直接在src/CMakeLists.txt中添加:
EXEC_PROGRAM(ls ARGS "*.c" OUTPUT_VARIABLE LS_OUTPUT RETURN_VALUE LS_RVALUE)
IF(not LS_RVALUE)
MESSAGE(STATUS "ls result: " ${LS_OUTPUT})
ENDIF(not LS_RVALUE)
在cmake生成Makefile過程中,就會執行ls命令,如果返回0,則說明成功執行,那么就輸出ls *.c的結果。關於IF語句,后面的控制指令會提到。
FILE指令
文件操作指令,基本語法為:
FILE(WRITEfilename "message to write"... )
FILE(APPENDfilename "message to write"... )
FILE(READfilename variable)
FILE(GLOBvariable [RELATIVE path] [globbing expression_r_rs]...)
FILE(GLOB_RECURSEvariable [RELATIVE path] [globbing expression_r_rs]...)
FILE(REMOVE[directory]...)
FILE(REMOVE_RECURSE[directory]...)
FILE(MAKE_DIRECTORY[directory]...)
FILE(RELATIVE_PATHvariable directory file)
FILE(TO_CMAKE_PATHpath result)
FILE(TO_NATIVE_PATHpath result)
INCLUDE指令
用來載入CMakeLists.txt文件,也用於載入預定義的cmake模塊。
INCLUDE(file1[OPTIONAL])
INCLUDE(module[OPTIONAL])
OPTIONAL參數的作用是文件不存在也不會產生錯誤,可以指定載入一個文件,如果定義的是一個模塊,那么將在CMAKE_MODULE_PATH中搜索這個模塊並載入,載入的內容將在處理到INCLUDE語句是直接執行。
INSTALL指令
FIND_指令
FIND_系列指令主要包含一下指令:
FIND_FILE(<VAR>name1 path1 path2 …) VAR變量代表找到的文件全路徑,包含文件名
FIND_LIBRARY(<VAR>name1 path1 path2 …) VAR變量表示找到的庫全路徑,包含庫文件名
FIND_PATH(<VAR>name1 path1 path2 …) VAR變量代表包含這個文件的路徑
FIND_PROGRAM(<VAR>name1 path1 path2 …) VAR變量代表包含這個程序的全路徑
FIND_PACKAGE(<name>[major.minor] [QUIET] [NO_MODULE] [[REQUIRED|COMPONENTS][componets...]]) 用來調用預定義在CMAKE_MODULE_PATH下的Find<name>.cmake模塊,也可以自己定義Find<name>模塊,通過SET(CMAKE_MODULE_PATH dir)將其放入工程的某個目錄中供工程使用,后面會詳細介紹FIND_PACKAGE的使用方法和Find模塊的編寫。
FIND_LIBRARY示例:
FIND_LIBRARY(libXX11 /usr/lib)
IF(NOT libX)
MESSAGE(FATAL_ERROR "libX not found")
ENDIF(NOT libX)
控制指令
IF指令,基本語法為:
IF(expression_r_r)
#THEN section.
COMMAND1(ARGS…)
COMMAND2(ARGS…)
…
ELSE(expression_r_r)
#ELSE section.
COMMAND1(ARGS…)
COMMAND2(ARGS…)
…
ENDIF(expression_r_r)
另外一個指令是ELSEIF,總體把握一個原則,凡是出現IF的地方一定要有對應的ENDIF,出現ELSEIF的地方,ENDIF是可選的。表達式的使用方法如下:
IF(var) 如果變量不是:空, 0, N, NO, OFF, FALSE, NOTFOUND 或 <var>_NOTFOUND時,表達式為真。
IF(NOT var), 與上述條件相反。
IF(var1AND var2), 當兩個變量都為真是為真。
IF(var1OR var2), 當兩個變量其中一個為真時為真。
IF(COMMANDcmd), 當給定的cmd確實是命令並可以調用是為真。
IF(EXISTS dir) or IF(EXISTS file), 當目錄名或者文件名存在時為真。
IF(file1IS_NEWER_THAN file2), 當file1比file2新,或者file1/file2其中有一個不存在時為真文件名請使用完整路徑。
IF(IS_DIRECTORY dirname), 當dirname是目錄時為真。
IF(variableMATCHES regex)
IF(string MATCHES regex) 當給定的變量或者字符串能夠匹配正則表達式regex時為真。比如:
IF("hello" MATCHES "hello")
MESSAGE("true")
ENDIF("hello" MATCHES "hello")
IF(variable LESS number)
IF(string LESS number)
IF(variable GREATER number)
IF(string GREATER number)
IF(variable EQUAL number)
IF(string EQUAL number)
數字比較表達式
IF(variable STRLESS string)
IF(string STRLESS string)
IF(variable STRGREATER string)
IF(string STRGREATER string)
IF(variable STREQUAL string)
IF(string STREQUAL string)
按照字母序的排列進行比較。
IF(DEFINED variable),如果變量被定義,為真。
一個小例子,用來判斷平台差異:
IF(WIN32)
MESSAGE(STATUS“This is windows.”) #作一些Windows相關的操作
ELSE(WIN32)
MESSAGE(STATUS“This is not windows”) #作一些非Windows相關的操作
ENDIF(WIN32)
上述代碼用來控制在不同的平台進行不同的控制,但是閱讀起來卻並不是那么舒服, ELSE(WIN32)之類的語句很容易引起歧義。
這就用到了我們在 常用變量 一節提到的CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS開關。可以SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTSON),這時候就可以寫成:
IF(WIN32)
ELSE()
ENDIF()
如果配合ELSEIF使用,可能的寫法是這樣:
IF(WIN32)
#dosomething related to WIN32
ELSEIF(UNIX)
#dosomething related to UNIX
ELSEIF(APPLE)
#dosomething related to APPLE
ENDIF(WIN32)
WHILE指令
WHILE指令的語法是:
WHILE(condition)
COMMAND1(ARGS…)
COMMAND2(ARGS…)
…
ENDWHILE(condition)
其真假判斷條件可以參考IF指令。
FOREACH指令
FOREACH指令的使用方法有三種形式:
(1)列表
FOREACH(loop_vararg1 arg2 …)
COMMAND1(ARGS…)
COMMAND2(ARGS…)
…
ENDFOREACH(loop_var)
像我們前面使用的AUX_SOURCE_DIRECTORY的例子
AUX_SOURCE_DIRECTORY(.SRC_LIST)
FOREACH(F ${SRC_LIST})
MESSAGE(${F})
ENDFOREACH(F)
(2)范圍
FOREACH(loop_var RANGE total)
ENDFOREACH(loop_var)
從0到total以1為步進,舉例如下:
FOREACH(VARRANGE 10)
MESSAGE(${VAR})
ENDFOREACH(VAR)
最終得到的輸出是:
0
1
2
3
4
5
6
7
8
9
10
(3)范圍和步進
FOREACH(loop_var RANGE start stop [step])
ENDFOREACH(loop_var)
從start開始到stop結束,以step為步進。舉例如下:
FOREACH(A RANGE 5 15 3)
MESSAGE(${A})
最終得到的結果是:
5
8
11
14
1
2
3
4
這個指令需要注意的是,直到遇到ENDFOREACH指令,整個語句塊才會得到真正的執行。
復雜的例子:模塊的使用和自定義模塊
這里將着重介紹系統預定義的Find模塊的使用以及自己編寫Find模塊,系統中提供了其他各種模塊,一般情況需要使用INCLUDE指令顯式的調用,FIND_PACKAGE指令是一個特例,可以直接調用預定義的模塊。
其實純粹依靠cmake本身提供的基本指令來管理工程是一件非常復雜的事情,所以cmake設計成了可擴展的架構,可以通過編寫一些通用的模塊來擴展cmake。
首先介紹一下cmake提供的FindCURL模塊的使用,然后基於前面的libhello共享庫,編寫一個FindHello.cmake模塊。
(一)使用FindCURL模塊
在/backup/cmake目錄建立t5目錄,用於存放CURL的例子。
建立src目錄,並建立src/main.c,內容如下:
#include<curl/curl.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
FILE*fp;
intwrite_data(void *ptr, size_t size, size_t nmemb, void *stream)
{
int written = fwrite(ptr, size, nmemb, (FILE *)fp);
return written;
}
int main()
{
const char *path = “/tmp/curl-test”;
const char *mode = “w”;
fp = fopen(path,mode);
curl_global_init(CURL_GLOBAL_ALL);
CURL coderes;
CURL *curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, “http://www.linux-ren.org”);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
這段代碼的作用是通過curl取回www.linux-ren.org的首頁並寫入/tmp/curl-test文件中
建立主工程文件CmakeLists.txt,如下:
PROJECT(CURLTEST)
ADD_SUBDIRECTORY(src)
建立src/CmakeLists.txt
ADD_EXECUTABLE(curltest main.c)
1
現在自然是沒辦法編譯的,我們需要添加curl的頭文件路徑和庫文件。
方法1:
直接通過INCLUDE_DIRECTORIES和TARGET_LINK_LIBRARIES指令添加:
我們可以直接在src/CMakeLists.txt中添加:
INCLUDE_DIRECTORIES(/usr/include)
TARGET_LINK_LIBRARIES(curltestcurl)
然后建立build目錄進行外部構建即可。
現在要探討的是使用cmake提供的FindCURL模塊。
方法2:
使用FindCURL模塊。向src/CMakeLists.txt中添加:
FIND_PACKAGE(CURL)
IF(CURL_FOUND)
INCLUDE_DIRECTORIES(${CURL_INCLUDE_DIR})
TARGET_LINK_LIBRARIES(curltest${CURL_LIBRARY})
ELSE(CURL_FOUND)
MESSAGE(FATAL_ERROR”CURL library not found”)
ENDIF(CURL_FOUND)
對於系統預定義的Find<name>.cmake模塊,使用方法一般如上例所示,每一個模塊都會定義以下幾個變量:
<name>_FOUND
<name>_INCLUDE_DIR or <name>_INCLUDES
<name>_LIBRARY or <name>_LIBRARIES
可以通過<name>_FOUND來判斷模塊是否被找到,如果沒有找到,按照工程的需要關閉某些特性、給出提醒或者中止編譯,上面的例子就是報出致命錯誤並終止構建。
如果<name>_FOUND為真,則將<name>_INCLUDE_DIR加入INCLUDE_DIRECTORIES,將<name>_LIBRARY加入TARGET_LINK_LIBRARIES中。
我們再來看一個復雜的例子,通過<name>_FOUND來控制工程特性:
SET(mySourcesviewer.c)
SET(optionalSources)
SET(optionalLibs)
FIND_PACKAGE(JPEG)
IF(JPEG_FOUND)
SET(optionalSources${optionalSources} jpegview.c)
INCLUDE_DIRECTORIES(${JPEG_INCLUDE_DIR} )
SET(optionalLibs${optionalLibs} ${JPEG_LIBRARIES} )
ADD_DEFINITIONS(-DENABLE_JPEG_SUPPORT)
ENDIF(JPEG_FOUND)
IF(PNG_FOUND)
SET(optionalSources${optionalSources} pngview.c)
INCLUDE_DIRECTORIES(${PNG_INCLUDE_DIR} )
SET(optionalLibs${optionalLibs} ${PNG_LIBRARIES} )
ADD_DEFINITIONS(-DENABLE_PNG_SUPPORT)
ENDIF(PNG_FOUND)
ADD_EXECUTABLE(viewer${mySources} ${optionalSources}
TARGET_LINK_LIBRARIES(viewer${optionalLibs}
通過判斷系統是否提供了JPEG庫來決定程序是否支持JPEG功能。
(二)編寫屬於自己的FindHello模塊
接下來在t6示例中演示如何自定義FindHELLO模塊並使用這個模塊構建工程。在/backup/cmake/中建立t6目錄,並在其中建立cmake目錄用於存放我們自己定義的FindHELLO.cmake模塊,同時建立src目錄,用於存放我們的源文件。
1.定義cmake/FindHELLO.cmake模塊
FIND_PATH(HELLO_INCLUDE_DIR hello.h /usr/include/hello /usr/local/include/hello)
FIND_LIBRARY(HELLO_LIBRARY NAMES hello PATH /usr/lib /usr/local/lib)
IF(HELLO_INCLUDE_DIR AND HELLO_LIBRARY)
SET(HELLO_FOUNDTRUE)
ENDIF(HELLO_INCLUDE_DIR AND HELLO_LIBRARY)
IF(HELLO_FOUND)
IF(NOT HELLO_FIND_QUIETLY)
MESSAGE(STATUS"Found Hello: ${HELLO_LIBRARY}")
ENDIF(NOT HELLO_FIND_QUIETLY)
ELSE(HELLO_FOUND)
IF(HELLO_FIND_REQUIRED)
MESSAGE(FATAL_ERROR"Could not find hello library")
ENDIF(HELLO_FIND_REQUIRED)
ENDIF(HELLO_FOUND)
針對上面的模塊讓我們再來回顧一下FIND_PACKAGE指令:
FIND_PACKAGE(<name>[major.minor] [QUIET] [NO_MODULE] [[REQUIRED|COMPONENTS][componets...]])
1
前面的CURL例子中我們使用了最簡單的FIND_PACKAGE指令,其實它可以使用多種參數:
QUIET參數,對應與我們編寫的FindHELLO中的HELLO_FIND_QUIETLY,如果不指定這個參數,就會執行:
MESSAGE(STATUS"Found Hello: ${HELLO_LIBRARY}")
1
REQUIRED參數,其含義是指這個共享庫是否是工程必須的,如果使用了這個參數,說明這個鏈接庫是必備庫,如果找不到這個鏈接庫,則工程不能編譯。對應於FindHELLO.cmake模塊中的HELLO_FIND_REQUIRED變量。
同樣,我們在上面的模塊中定義了HELLO_FOUND,HELLO_INCLUDE_DIR, HELLO_LIBRARY變量供開發者在FIND_PACKAGE指令中使用。
下面建立src/main.c,內容為:
#include<hello.h>
int main()
{
HelloFunc();
return 0;
}
建立src/CMakeLists.txt文件,內容如下:
FIND_PACKAGE(HELLO)
IF(HELLO_FOUND)
ADD_EXECUTABLE(hellomain.c)
INCLUDE_DIRECTORIES(${HELLO_INCLUDE_DIR})
TARGET_LINK_LIBRARIES(hello${HELLO_LIBRARY})
ENDIF(HELLO_FOUND)
為了能夠讓工程找到 FindHELLO.cmake 模塊(存放在工程中的cmake目錄)我們在主工程文件 CMakeLists.txt 中加入:
SET(CMAKE_MODULE_PATH${PROJECT_SOURCE_DIR}/cmake)
1
(三)使用自定義的FindHELLO模塊構建工程
仍然采用外部編譯的方式,建立build目錄,進入目錄運行:
cmake ..
1
我們可以從輸出中看到:
FoundHello: /usr/lib/libhello.so
1
如果我們把上面的FIND_PACKAGE(HELLO)修改為FIND_PACKAGE(HELLO QUIET),
不會看到上面的輸出。接下來就可以使用make命令構建工程,運行:
./src/hello
1
可以得到輸出
HelloWorld
1
說明工程成功構建。
(四)如果沒有找到hellolibrary呢?
我們可以嘗試將/usr/lib/libhello.x移動到/tmp目錄,這樣按照FindHELLO模塊的定義,找不到hellolibrary了,我們再來看一下構建結果:
cmake ..
1
仍然可以成功進行構建,但是這時候是沒有辦法編譯的。
修改FIND_PACKAGE(HELLO)為FIND_PACKAGE(HELLO REQUIRED),將hellolibrary定義為工程必須的共享庫。
這時候再次運行
cmake ..
1
我們得到如下輸出:
CMakeError: Could not find hello library.
1
因為找不到libhello.x,所以,整個Makefile生成過程被出錯中止。
一些問題
1.怎樣區分debug、release版本
建立debug/release兩目錄,分別在其中執行cmake -D CMAKE_BUILD_TYPE=Debug(或Release),需要編譯不同版本時進入不同目錄執行make即可:
Debug版會使用參數-g;
Release版使用-O3–DNDEBUG
另一種設置方法——例如DEBUG版設置編譯參數DDEBUG
IF(DEBUG_mode)
add_definitions(-DDEBUG)
ENDIF()
在執行cmake時增加參數即可,例如cmake -D DEBUG_mode=ON
2.怎樣設置條件編譯
例如debug版設置編譯選項DEBUG,並且更改不應改變CMakelist.txt
使用option command,eg:
option(DEBUG_mode"ON for debug or OFF for release" ON)
IF(DEBUG_mode)
add_definitions(-DDEBUG)
ENDIF()
使其生效的方法:首先cmake生成makefile,然后make edit_cache編輯編譯選項;Linux下會打開一個文本框,可以更改,改完后再make生成目標文件——emacs不支持make edit_cache;
局限:這種方法不能直接設置生成的makefile,而是必須使用命令在make前設置參數;對於debug、release版本,相當於需要兩個目錄,分別先cmake一次,然后分別makeedit_cache一次;
期望的效果:在執行cmake時直接通過參數指定一個開關項,生成相應的makefile。