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 定义宏(函数)时参数为3个,实际传了4个,则ARGN代表多出来的一个参数
ARGC 实际传入的参数的个数

从定义上看他们貌似一模一样,宏和函数确实差不多,宏跟C语言中的宏概念不一样,不过还是有一点区别

相同点

调用方式一模一样,都是name(arg1....)形式调用,都是要先声明在调用,实际传入参数个数可以大于定义的参数个数

使用示例:
在sample9创建macro_function.cmake,内容如下:

# CMake 最低版本号要求
cmake_minimum_required(VERSION 3.24)

# 定义函数
Function(myfunction ag1 ag2 ag3)
message(STATUS "function ag is ${ag1} ${ag2} ${ag3} ${ARGV} ${ARGN} ${ARGC} ")
endfunction(myfunction)

# 定义宏
macro(mymacro ag1 ag2 ag3)
message(STATUS "macro ag is ${ag1} ${ag2} ${ag3} ${ARGV} ${ARGN} ${ARGC} ")
endmacro(mymacro)

# 调用函数
myfunction(a b c d e f)
message(STATUS "\n")
# 调用宏
mymacro(a b c d e f)

函数和宏可以单独放入一个文件中,并以.cmake命名,用以复用。调用时用include()指令进行加载

例如:在CMakeLists.txt中添加如下,

include(macro_function.cmake)

执行

cmake ..

输出如下:
-- function ag is a b c a;b;c;d;e;f d;e;f 6

-- macro ag is a b c a;b;c;d;e;f d;e;f 6

不同点

宏的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)

输出:

-- 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 功能。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,271评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,725评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,252评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,634评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,549评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,985评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,471评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,128评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,257评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,233评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,235评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,940评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,528评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,623评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,858评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,245评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,790评论 2 339

推荐阅读更多精彩内容