Cmake Practice 总结 复杂例子
2021/7/20 6:05:46
本文主要是介绍Cmake Practice 总结 复杂例子,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
本章我们将着重介绍系统预定义的 find 模块的使用以及自己编写 find 模块,系统中提供了其他各种模块,一般情况需要使用 include 指令显式的调用,find_package 指令是一个特例,可以直接调用预定义的模块。
其实使用纯粹依靠 cmake 本身提供的基本指令来管理工程是一件非常复杂的事情,所以,cmake 设计成了可扩展的架构,可以通过编写一些通用的模块来扩展 cmake.
在本章,我们准备首先介绍一下 cmake 提供的 FindCURL 模块的使用。然后,基于我们前面的 libhello 共享库,编写一个 FindHello.cmake 模块。
使用 FindCURL 模块
在 /home/xiao/cmake_practice 目录建立 t5 目录,用于存放我们的 CURL 的例子。
建立 src 目录,并建立 src/main.c,内容如下:
#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 = “/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.google.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); }
这段代码的作用是通过 curl 取回 www.google.com 的首页并写入/tmp/curl-test文件中。
建立主工程文件 CMakeLists.txt
project(CURLTEST) add_subdirectory(src)
建立 src/CMakeLists.txt
add_executable(curltest main.c)
现在自然是没办法编译的,我们需要添加 curl 的头文件路径和库文件。
方法 1:
直接通过 include_directories 和 target_link_libraries 指令添加:
我们可以直接在 src/CMakeLists.txt 中添加:
include_directories(/usr/include) target_link_libraries(curltest curl)
然后建立 build 目录进行外部构建即可。
方法 2: 使用 FindCURL 模块。
向 src/CMakeLists.txt 中添加:
find_package(CURL) if(CURL_FOUND) include_directories(${CURL_INCLUDE_DIR}) target_link_libraries(curltest ${CURL_LIBRARY}) else() message(FATAL_ERROR ”CURL library not found”) endif()
对于系统预定义的 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(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) find_package(PNG) 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 或 PNG 库 来决定程序是否支持 JPEG 或 PNG 功能。
编写属于自己的 FindHello 模块。
我们在此前的 t3 实例中,演示了构建动态库、静态库的过程并进行了安装。
接下来,我们在 t6 示例中演示如何自定义 FindHELLO 模块并使用这个模块构建工程:
在/home/xiao/cmake_practice/中建立 t6 目录,并在其中建立 cmake 目录用于存放我们自己定义的 FindHELLO.cmake 模块,同时建立 src 目录,用于存放我们的源文件。
定义 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 () if (HELLO_FOUND) if (NOT HELLO_FIND_QUIETLY) message(STATUS "Found Hello: ${HELLO_LIBRARY}") endif () ELSE () if (HELLO_FIND_REQUIRED) message(FATAL_ERROR "Could not find hello library") endif () ENDIF ()
针对上面的模块让我们再来回顾一下 find_package 指令:
find_package(<name> [major.minor] [QUIET] [NO_MODULE] [[REQUIRED|COMPONENTS] [componets...]])
前面的 CURL 例子中我们使用了最简单的 find_package 指令,其实他可以使用多种参数.
QUIET 参数,对应与我们编写的 FindHELLO 中的 HELLO_FIND_QUIETLY,如果不指定这个参数,就会执行:
message(STATUS "Found Hello: ${HELLO_LIBRARY}")
REQUIRED 参数,其含义是指这个共享库是否是工程必须的,如果使用了这个参数,说明这个链接库是必备库,如果找不到这个链接库,则工程不能编译。对应于FindHELLO.cmake 模块中的 HELLO_FIND_REQUIRED 变量。
同样,我们在上面的模块中定义了 HELLO_FOUND, HELLO_INCLUDE_DIR, HELLO_LIBRARY 变量供开发者在 find_package 指令中使用。
OK,下面建立 src/main.c,内容为:
#include <hello.h> int main() { HelloFunc(); return 0; }
建立 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()
为了能够让工程找到 FindHELLO.cmake 模块(存放在工程中的 cmake 目录)
我们在主工程文件 CMakeLists.txt 中加入:
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
使用自定义的 FindHELLO 模块构建工程
仍然采用外部编译的方式,建立 build 目录,进入目录运行:
cmake ..
我们可以从输出中看到:
Found Hello: /usr/lib/libhello.so
如果我们把上面的 find_package(HELLO)修改为 find_package(HELLO QUIET),则不会看到上面的输出。
接下来就可以使用 make 命令构建工程,然后运行:
./src/hello
可以得到输出
Hello World
说明工程成功构建。
如果没有找到 hello library 呢?
我们可以尝试将/usr/lib/libhello.x 移动到/tmp 目录,这样,按照 FindHELLO 模块的定义,就找不到 hello library 了,我们再来看一下构建结果:
cmake ..
仍然可以成功进行构建,但是这时候是没有办法编译的。
修改 find_package(HELLO)为 find_package(HELLO REQUIRED),将 hello library 定义为工程必须的共享库。
这时候再次运行 cmake ..
我们得到如下输出:
CMake Error: Could not find hello library.
因为找不到 libhello.x,所以,整个 Makefile 生成过程被中止。
这篇关于Cmake Practice 总结 复杂例子的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-20获取apk的md5值有哪些方法?-icode9专业技术文章分享
- 2024-11-20xml报文没有传 IdentCode ,为什么正常解析没报错呢?-icode9专业技术文章分享
- 2024-11-20如何知道代码有没有进行 Schema 验证?-icode9专业技术文章分享
- 2024-11-20Mycat教程:新手快速入门指南
- 2024-11-20WebSocket入门:轻松掌握WebSocket基础
- 2024-11-19WebSocket入门指南:轻松搭建实时通信应用
- 2024-11-19Nacos安装资料详解:新手入门教程
- 2024-11-19Nacos安装资料:新手入门教程
- 2024-11-19升级 Gerrit 时有哪些注意事项?-icode9专业技术文章分享
- 2024-11-19pnpm是什么?-icode9专业技术文章分享