cmake函數、宏和模塊


cmake函數function和宏定義macro在某種程度上來說是一樣的,都是創建一段有名字的代碼稍后可以調用,還可以傳參數。
他們的定義如下:

macro定義:

macro(<name> [arg1 [arg2 [arg3 ...]]])
...
endmacro([name])

function定義:

function(<name> [arg1 [arg2 [arg3 ...]]])
...
endfunction([name])

函數和宏的默認內部變量

變量 說明
ARGV# ARGV0為第一個參數,ARGV1為第二個參數,依次類推
ARGV 定義宏(函數)時參數為2個,實際傳了4個,則ARGV代表實際傳入的兩個
ARGN 定義宏(函數)時參數為2個,實際傳了4個,則ARGN代表剩下的兩個
ARGC 實際傳入的參數的個數

從定義上看他們貌似一模一樣,宏和函數確實差不多,宏跟C語言中的宏概念不一樣,不過還是有一點區別

相同點

調用方式一模一樣,都是name(arg1....)形式調用,都是要先聲明在調用,實際傳入參數個數可以大於定義的參數個數

使用示例:
在sample9創建macro_function.cmake,內容如下:

# 定義函數 Function(myfunction ag1 ag2 ag3) message(STATUS "function ag is " ${ag1}) message(STATUS "function ag is " ${ag2}) message(STATUS "function ag is " ${ag3}) endfunction(myfunction) # 定義宏 macro(mymacro ag1 ag2 ag3) message(STATUS "macro ag is " ${ag1}) message(STATUS "macro ag is " ${ag2}) message(STATUS "macro ag is " ${ag3}) endmacro(mymacro) # 調用函數 myfunction(1 2 3 4 5) message(STATUS "\n") # 調用宏 mymacro(1 2 3 4 5) 

輸出如下:
-- function ag is 1
-- function ag is 2
-- function ag is 3
--

-- macro ag is 1
-- macro ag is 2
-- macro ag is 3

不同點

宏的ARGN、ARGV等內部變量不能直接在if語句和foreach(..IN LISTS..)語句中使用。其它一樣

示例如下:


macro(_bar) message(STATUS "this is in macro bar " ${ARGN}) set(aa ${ARGV0}) if(ARGV0) message(STATUS "this is in a 1") endif() if(aa) message(STATUS "this is in a 2 " ${aa}) endif() set(list_var ${ARGN}) foreach(arg IN LISTS ARGN) message(STATUS "this is in macro 2 ${arg}") endforeach() foreach(arg ${ARGN}) message(STATUS "this is in macro 3 ${arg}") endforeach() foreach(arg IN LISTS list_var) message(STATUS "this is in macro 4 ${arg}") endforeach() endmacro(_bar) message(STATUS "\n") _bar(a b c) function(_func) message(STATUS "this is in func __func " ${ARGN}) set(aa ${ARGV0}) if(ARGV0) message(STATUS "this is in a 1 " ${ARGV0}) endif() if(aa) message(STATUS "this is in a 2 " ${aa}) endif() set(list_var ${ARGN}) foreach(arg IN LISTS ARGN) message(STATUS "this is in __func 2 ${arg}") endforeach() foreach(arg IN LISTS list_var) message(STATUS "this is in __func 3 ${arg}") endforeach() endfunction(_func) message(STATUS "\n") _func(d e f) 
示例如下:

macro(_bar) message(STATUS "this is in macro bar " ${ARGN}) set(aa ${ARGV0}) if(ARGV0) message(STATUS "this is in a 1") endif() if(aa) message(STATUS "this is in a 2 " ${aa}) endif() set(list_var ${ARGN}) foreach(arg IN LISTS ARGN) message(STATUS "this is in macro 2 ${arg}") endforeach() foreach(arg ${ARGN}) message(STATUS "this is in macro 3 ${arg}") endforeach() foreach(arg IN LISTS list_var) message(STATUS "this is in macro 4 ${arg}") endforeach() endmacro(_bar) message(STATUS "\n") _bar(a b c) function(_func) message(STATUS "this is in func __func " ${ARGN}) set(aa ${ARGV0}) if(ARGV0) message(STATUS "this is in a 1 " ${ARGV0}) endif() if(aa) message(STATUS "this is in a 2 " ${aa}) endif() set(list_var ${ARGN}) foreach(arg IN LISTS ARGN) message(STATUS "this is in __func 2 ${arg}") endforeach() foreach(arg IN LISTS list_var) message(STATUS "this is in __func 3 ${arg}") endforeach() endfunction(_func) message(STATUS "\n") _func(d e f)

輸出:

-- this is in macro bar abc -- this is in a 2 a -- this is in macro 3 a -- this is in macro 3 b -- this is in macro 3 c -- this is in macro 4 a -- this is in macro 4 b -- this is in macro 4 c -- -- this is in func __func def -- this is in a 1 d -- this is in a 2 d -- this is in __func 2 d -- this is in __func 2 e -- this is in __func 2 f -- this is in __func 3 d -- this is in __func 3 e -- this is in __func 3 f 

模塊

cmake能夠識別CMakeLists.txt文件和xxx.cmake結尾的文件,模塊就是以xxx.cmake結尾的文件,可以理解為,將一些通用的函數功能封裝到到一個指定的文件中,然后通過include(xxx.cmake)方式引用,這樣可以達到代碼復用的目的。模塊既可以被CMakeLists.txt引用,也可以被其它模塊引用

cmake系統本身內置了一些預定義的模塊可以供我們使用,比如FindCURL模塊,它的使用方式是通過FIND_PACKAGE指令來完成的,請看如下例子:

創建sample10,建立src/main.cpp文件,內容如下:

#include <curl/curl.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> FILE *fp; int write_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 = "curl-test"; const char * mode = "w"; fp = fopen(path,mode); curl_global_init(CURL_GLOBAL_ALL); CURLcode res; CURL *curl = curl_easy_init(); curl_easy_setopt(curl, CURLOPT_URL, "http://www.baidu.com"); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); res = curl_easy_perform(curl); curl_easy_cleanup(curl); return 0; } 

這段代碼的作用是通過curl [取回www.baidu.com]的首頁並寫入當前目錄下的curl-test 文件中。

創建工程根目錄的CMakeLists.txt文件,內容如下:

# CMake 最低版本號要求 cmake_minimum_required (VERSION 2.8) if(POLICY CMP0042) cmake_policy(SET CMP0042 NEW) # CMake 3.0+ (2.8.12): MacOS "@rpath" in target's install name endif() # 項目工程名 project (sample10) message(STATUS "root This is BINARY dir " ${PROJECT_BINARY_DIR}) message(STATUS "root This is SOURCE dir " ${PROJECT_SOURCE_DIR}) # 添加子目錄 ADD_SUBDIRECTORY(src) 

創建src/CMakeLists.txt,內容如下:

# 打印信息
message(STATUS "src This is BINARY dir " ${PROJECT_BINARY_DIR})
message(STATUS "src This is SOURCE dir " ${PROJECT_SOURCE_DIR})

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

# 定義工程根目錄; CMAKE_SOURCE_DIR為內建變量,表示工程根目錄的CMakeLists.txt文件路徑
SET(ROOT_DIR ${CMAKE_SOURCE_DIR})

# 構建可執行程序
ADD_EXECUTABLE(sample10 main.cpp)

# 查找指定的庫
FIND_PACKAGE(CURL)

IF(CURL_FOUND)

MESSAGE(STATUS ”CURL library ${CURL_INCLUDE_DIR}”) 
MESSAGE(STATUS ”CURL library ${CURL_LIBRARY}”) 

INCLUDE_DIRECTORIES(${CURL_INCLUDE_DIR})
TARGET_LINK_LIBRARIES(sample10 ${CURL_LIBRARY})

ELSE(CURL_FOUND)
 
MESSAGE(FATAL_ERROR ”CURL library not found”) 

ENDIF(CURL_FOUND)


在build文件夾內構建工程 cmake .. 然后執行 make,執行bin/sample10,就模擬了一次curl操作,將百度的首頁內容寫入到curl-text文件中了

cmake中關於內置Find.cmake模塊的使用語法:

對於系統預定義的Find.cmake 模塊,使用方法一般如上例所示:每一個模塊都會定義以下幾個變量

  • _FOUND
  • _INCLUDE_DIR or _INCLUDES
  • _LIBRARY or _LIBRARIES

比如上面是要查找CURL庫的頭文件以及庫文件路徑,對應的變量就是CURL_FOUND、CURL_INCLUDE_DIR、CURL_INCLUDE_DIR

通過_FOUND 來判斷模塊是否找到,如果_FOUND 為真,則將_INCLUDE_DIR 加入INCLUDE_DIRECTORIES,將_LIBRARY 加入TARGET_LINK_LIBRARIES 中。

看如下一段代碼,通過_FOUND 來控制工程特性:

SET(mySources viewer.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)

ADD_EXECUTABLE(viewer ${mySources} ${optionalSources} )
TARGET_LINK_LIBRARIES(viewer ${optionalLibs} 


通過判斷系統是否提供了JPEG 庫來決定程序是否支持JPEG 功能。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM