• 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 "
    ")
    
    # 调用宏
    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 "
    ")
    _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 "
    ")
    _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 "
    ")
    _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 "
    ")
    _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 功能。
  • 相关阅读:
    自动化测试如何解析excel文件?
    Unittest加载执行用例的方法总结
    pytest进阶之配置文件
    [编程题] 把二叉树打印成多行
    [编程题]求1+2+3+....n
    [编程题]-[位运算技巧系列]不用加减乘除做加法
    [编程题]数值的整数次方
    [编程题]构建乘积数组
    [编程题]变态跳台阶
    [编程题][剑指 Offer 10- II. 青蛙跳台阶问题]
  • 原文地址:https://www.cnblogs.com/zhoug2020/p/13659952.html
Copyright © 2020-2023  润新知