• 9.复杂的例子:模块的使用和自定义模块


    本章我们将着重介绍系统预定义的 Find 模块的使用以及自己编写 Find 模块,系统中提供了其他各种模块,一般情况需要使用 INCLUDE 指令显式的调用,FIND_PACKAGE 指令是一个特例,可以直接调用预定义的模块。

    其实使用纯粹依靠 cmake 本身提供的基本指令来管理工程是一件非常复杂的事情,所以,cmake 设计成了可扩展的架构,可以通过编写一些通用的模块来扩展 cmake.

    在本章,我们准备首先介绍一下 cmake 提供的 FindCURL 模块的使用。然后,基于我们前面的 libhello 共享库,编写一个 FindHello.cmake 模块。

    一,使用 FindCURL 模块

    建立 src 目录,并建立 src/main.c,内容如下

    #include 
    #include 
    #include 
    #include 
    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 = "/tmp/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.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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    建立 src/CMakeLists.txt

    cmake_minimum_required(VERSION 3.0.0)
    PROJECT(CURLTEST)
    ADD_SUBDIRECTORY(src)
    
    • 1
    • 2
    • 3

    建立 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(curltest curl)
    然后建立 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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    对于系统预定义的 Find.cmake 模块,使用方法一般如上例所示:
    每一个模块都会定义以下几个变量

    二,编写属于自己的 FindHello 模块。

    我们在此前的 t3 实例中,演示了构建动态库、静态库的过程并进行了安装。

    接下来, 我们演示如何自定义 FindHELLO 模块并使用这个模块构建工程
    建立 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_FOUND TRUE)
    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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    针对上面的模块让我们再来回顾一下 FIND_PACKAGE 指令

    FIND_PACKAGE( [major.minor] [QUIET] [NO_MODULE]
                [[REQUIRED|COMPONENTS] [componets...]])
    
    • 1
    • 2

    前面的 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 指令中使用。

    OK,下面建立 src/main.c,内容为

    #include 
    int main()
    {
    HelloFunc();
    return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    建立 src/CMakeLists.txt 文件,内容如下

    FIND_PACKAGE(HELLO)
    IF(HELLO_FOUND)
        ADD_EXECUTABLE(hello main.c)
        INCLUDE_DIRECTORIES(${HELLO_INCLUDE_DIR})
        TARGET_LINK_LIBRARIES(hello ${HELLO_LIBRARY})
    ENDIF(HELLO_FOUND)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    为了能够让工程找到 FindHELLO.cmake 模块(存放在工程中的 cmake 目录)
    我们在主工程文件 CMakeLists.txt 中加入

    SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
    
    • 1

    三,使用自定义的 FindHELLO 模块构建工程

    仍然采用外部编译的方式,建立 build 目录,进入目录运行:

    cmake ..
    
    • 1

    我们可以从输出中看到:
    Found Hello: /usr/lib/libhello.so
    如果我们把上面的 FIND_PACKAGE(HELLO)修改为 FIND_PACKAGE(HELLO QUIET),则不会看到上面的输出。
    接下来就可以使用 make 命令构建工程,运行:
    ./src/hello 可以得到输出

    Hello World。
    
    • 1

    说明工程成功构建

    构建和输出全过程如下:

    root@BIH-L-55661:/mnt/d/study/lwstudy/cmake/t8/build# cmake ..
    -- The C compiler identification is GNU 9.4.0
    -- The CXX compiler identification is GNU 9.4.0
    -- Check for working C compiler: /usr/bin/cc
    -- Check for working C compiler: /usr/bin/cc -- works
    -- Detecting C compiler ABI info
    -- Detecting C compiler ABI info - done
    -- Detecting C compile features
    -- Detecting C compile features - done
    -- Check for working CXX compiler: /usr/bin/c++
    -- Check for working CXX compiler: /usr/bin/c++ -- works
    -- Detecting CXX compiler ABI info
    -- Detecting CXX compiler ABI info - done
    -- Detecting CXX compile features
    -- Detecting CXX compile features - done
    -- Found Hello: /usr/lib/libhello.so
    -- Configuring done
    -- Generating done
    -- Build files have been written to: /mnt/d/study/lwstudy/cmake/t8/build
    root@BIH-L-55661:/mnt/d/study/lwstudy/cmake/t8/build# make
    Scanning dependencies of target hello
    [ 50%] Building C object src/CMakeFiles/hello.dir/main.c.o
    [100%] Linking C executable hello
    [100%] Built target hello
    root@BIH-L-55661:/mnt/d/study/lwstudy/cmake/t8/build# cd src/
    root@BIH-L-55661:/mnt/d/study/lwstudy/cmake/t8/build/src# ls
    CMakeFiles  Makefile  cmake_install.cmake  hello
    root@BIH-L-55661:/mnt/d/study/lwstudy/cmake/t8/build/src# ./hello
    Hello World
    root@BIH-L-55661:/mnt/d/study/lwstudy/cmake/t8/build/src#
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    四,如果没有找到 hello library 呢?

    我们可以尝试将/usr/lib/libhello.x 移动到/tmp 目录,这样,按照 FindHELLO 模块
    的定义,就找不到 hello library 了,我们再来看一下构建结果:

    cmake ..
    
    • 1

    仍然可以成功进行构建,但是这时候是没有办法编译的。
    修改 FIND_PACKAGE(HELLO)为 FIND_PACKAGE(HELLO REQUIRED),将 hello
    library 定义为工程必须的共享库。
    这时候再次运行 cmake …
    我们得到如下输出:

    CMake Error: Could not find hello library.
    
    • 1

    因为找不到 libhello.x,所以,整个 Makefile 生成过程被出错中止。

  • 相关阅读:
    字节跳动笔试题——算法岗
    微波雷达感应模块技术,实时智能检测人体存在,静止微小动静感知
    C++初阶 入门
    【思悟】一定要给自己留出空间
    这些 channel 用法你都用起来了吗?
    6、docker下mysql修改配置文件
    小咖批量剪辑助手款视频批量自动剪辑软件
    prometheus监控mysql主从
    MySQL Explain关键字:`EXPLAIN ANALYZE` 的使用
    SpringBoot校园二手书管理系统
  • 原文地址:https://blog.csdn.net/qq_29407397/article/details/127685542