Cmake 教程

写在前面

  • 如果工程只有几个文件,直接编写Makefile更直接明了
  • 如果使用C、C++、之外的语言,请不要使用cmake
  • 如果使用的语言有非常完备的构建体系,不需要使用cmake

CGold: The Hitchhiker’s Guide to the CMake — CGold 0.1 documentation

step1,hello cmake

  1. # 项目名称
  2. PROJECT ("HelloCmake")
  3. # 设置变量
  4. SET (SRC_FILE main.c)
  5. MESSAGE (STATUS 你好啊)
  6. MESSAGE (STATUS "你好啊")
  7. # 附带产生两个变量
  8. MESSAGE (STATUS ${HelloCmake_SOURCE_DIR})
  9. MESSAGE (STATUS ${HelloCmake_BINARY_DIR})
  10. # 生成可执行文件
  11. ADD_EXECUTABLE (proc.exe ${SRC_FILE})
  1. # make VERBOSE=1
  2. make VERBOSE=1

step2,层次感

本小节的任务是让前面的 Hello World 更像一个工程,我们需要作的是:

  1. 为工程添加一个子目录 src,用来放置工程源代码;
  2. 添加一个子目录 doc,用来放置这个工程的文档 hello.txt
  3. 在工程目录添加文本文件 COPYRIGHT, README;
  4. 在工程目录添加一个 runhello.sh 脚本,用来调用 hello 二进制
  5. 将构建后的目标文件放入构建目录的 bin 子目录;
  6. 最终安装这些文件:
    1. 将 hello 二进制与 runhello.sh 安装至/usr/bin
    2. 将 doc 目录的内容以及 COPYRIGHT/README 安装到/usr/share/doc/cmake/t2,将

会在bulid目录中复现src的文件结构

  1. # 在build文件生成一个src文件夹
  2. ADD_SUBDIRCTOPYT(src)
  3. # 在build文件中生成一个bin文件夹存放二进制文件
  4. ADD_SUBDIRCTOPYT(src bin)
  5. # 指定,最终目标二进制文件/库文件存放位置。不包括编译生成的中间文件
  6. # 在哪里 ADD_EXECUTABLE 或 ADD_LIBRARY,如果需要改变目标存放路径,就在哪里加入上述的定义
  7. SET (EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
  8. SET (LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
  9. # bash 中输入
  10. cmake -D CMAKE_INSTALL_PREFIX=/usr
  11. SET (CMAKE_INSTALL_PREFIX /usr1/code/code/)
  12. #CMAKE_INSTALL_PREFIX 的默认值
  13. # /usr/local 直接安装到系统
  14. # 目标文件安装
  15. # 安装 可执行二进制RUNTIME、静态库ARCHIVE、动态库LIBRARY
  16. INSTALL(TARGETS myrun mylib mystaticlib
  17. RUNTIME DESTINATION bin
  18. LIBRARY DESTINATION lib
  19. ARCHIVE DESTINATION libstatic
  20. )
  21. #DESTINATION 定义了安装的路径,如果路径以/开头,那么指的是绝对路径,这时候
  22. #CMAKE_INSTALL_PREFIX 其实就无效了。如果你希望使用 CMAKE_INSTALL_PREFIX 来
  23. #定义安装路径,就要写成相对路径,即不要以/开头
  24. # 二进制 myrun 安装到${CMAKE_INSTALL_PREFIX}/bin
  25. # ...
  26. # 普通文件安装,并指定访问权限,,默认权限644
  27. INSTALL(FILES )

step3,生成动态库、静态库

  1. ADD_LIBRARY (hello SHARED hello.c) # 生成动态库libhello.so
  2. SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 12.87.2 SOVERSION 8848)
  3. # VERSION 指代动态库版本,SOVERSION 指代 API 版本。
  4. ADD_LIBRARY (hello_static STATIC hello.c)
  5. SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello")
  6. GET_TARGET_PROPERTIES(OUTPUT_VALUE hello_static OUTPUT_NAME)
  7. MESSAGE(STATUS This is the hello_static OUTPUT_NAME:”${OUTPUT_VALUE})
  8. #如果没有这个属性定义,则返回 NOTFOUND.
  9. # cmake 在构建一个新的 target 时,会尝试清理掉其他使用这个名字的库,因为,在构建 libhello.a 时,就会清理掉 libhello.so.
  10. # 使用 SET_TARGET_PROPERTIES 定义CLEAN_DIRECT_OUTPUT 属性。
  11. SET_TARGET_PROPERTIES(hello PROPERTIES CLEAN_DIRECT_OUTPUT 1)
  12. SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
  13. SET (LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/so)
  14. SET (CMAKE_INSTALL_PREFIX /home/orange/code/cmake/usr)
  15. INSTALL (TARGETS hello hello_static
  16. LIBRARY DESTINATION lib
  17. ARCHIVE DESTINATION lib)
  18. INSTALL (FILES hello.h DESTINATION include) # <prefix>/include

step4,使用库、外部头文件

  1. # 添加头文件搜索路径
  2. INCLUDE_DIRECTORIES ( AFTER /home/orange/code/cmake/usr/include 路径2 路径3)
  3. # AFTER 加在当前搜索路径之后,BEFORE 加在当前搜索路径之前
  4. # 添加共享搜索路径
  5. LINK_DIRECTORIES ( /home/orange/code/cmake/usr/lib 路径2 路径3 )
  6. # 使用相对路径报错???
  7. ADD_EXECUTABLE (main main.c)
  8. # 添加链接描述 为库或可执行二进制加入库链接
  9. #TARGET_LINK_LIBRARIES ( main hello )
  10. TARGET_LINK_LIBRARIES ( main libhello.so )
  11. #TARGET_LINK_LIBRARIES ( main hello.a )

特殊环境变量

CMAKE_INCLUDE_PATHCMAKE_LIBRARY_PATH

  1. export CMAKE_INCLUDE_PATH=/usr/include/hello

然后在头文件中将 INCLUDE_DIRECTORIES(/usr/include/hello) 替换为:

  1. FIND_PATH(myHeader hello.h)
  2. IF(myHeader)
  3. INCLUDE_DIRECTORIES(${myHeader})
  4. ENDIF(myHeader)
  5. # CMAKE_LIBRARY_PATH 可以用在 FIND_LIBRARY 中

连接标准位置的库

  1. # 一些约定俗成的变量
  2. # <name>_FOUND 判断模块是否被找到
  3. # <name>_INCLUDE_DIR or <name>_INCLUDES 头文件位置
  4. # <name>_LIBRARY or <name>_LIBRARIES 库位置。
  5. # 因为是在标准位置所以不需要 LINK_DIRECTORIES ( <name>_LIBRARY )
  6. FIND_PACKAGE(CURL)
  7. IF(CURL_FOUND)
  8. INCLUDE_DIRECTORIES(${CURL_INCLUDE_DIR})
  9. TARGET_LINK_LIBRARIES(curltest ${CURL_LIBRARY})
  10. ELSE(CURL_FOUND)
  11. MESSAGE(FATAL_ERROR CURL library not found”)
  12. ENDIF(CURL_FOUND)
  13. # 如果<name>_FOUND 为真,则将<name>_INCLUDE_DIR 加入 INCLUDE_DIRECTORIES,
  14. # 将<name>_LIBRARY 加入 TARGET_LINK_LIBRARIES 中。

编写自己的模块

FIND_PACAGE指令

  1. FIND_PACKAGE(<name> [major.minor] [QUIET] [NO_MODULE]
  2. [[REQUIRED|COMPONENTS] [componets...]])
  3. # QUIET 参数对应 Find<name>.cmake 中的 <name>_FIND_QUIETLY
  4. # REQUIRED 参数对应 Find<name>.cmake 中的 <name>_FIND_REQUIERED
  5. #REQUIRED 参数,其含义是指这个共享库是否是工程必须的,如果使用了这个参数,说明这
  6. #个链接库是必备库,如果找不到这个链接库,则工程不能编译。

工程目录/CMakeLists.txt

  1. CMAKE_MINIMUM_REQUIRED (VERSION 3.20)
  2. PROJECT (HELLO)
  3. set (CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
  4. ADD_SUBDIRECTORY ( src )

工程目录/src/CMakeLists.txt

  1. # HELLO_FOUND、HELLO_INCLUDE_DIR、HELLO_LIBRARY 变量在 “工程目录/cmake/FindHELLO.cmake”中定义
  2. find_package (HELLO)
  3. if (HELLO_FOUND)
  4. add_executable (proc main.c)
  5. include_directories (${HELLO_INCLUDE_DIR})
  6. target_link_libraries (proc ${HELLO_LIBRARY})
  7. endif (HELLO_FOUND)

工程目录/cmake/FindHELLO.cmake

  1. find_path ( HELLO_INCLUDE_DIR func.h /usr1/code/code/step5/include 路径2 路径3)
  2. # 如果找到 HELLO_INCLUDE_DIR 返回找到func.h 所在的文件夹
  3. # 如果没找到 值为 HELLO_INCLUDE_DIR-NOTFOUND
  4. find_library (HELLO_LIBRARY func /usr1/code/code/step3/lib)
  5. # 如果找到返回库路径,不是库所在的文件夹
  6. # 如果没找到 值为 HELLO_LIBRARY-NOTFOUND
  7. if (HELLO_INCLUDE_DIR AND HELLO_LIBRARY)
  8. #如果头文件和库文件都找到了
  9. set (HELLO_FOUND TRUE)
  10. endif (HELLO_INCLUDE_DIR AND HELLO_LIBRARY)
  11. if (HELLO_FOUND)
  12. # 如果都找到了
  13. if (NOT HELLO_FIND_QUIETLY)
  14. message (STATUS "因为FIND_PACKAGE 指令中没有指定QUIET参数")
  15. endif (NOT HELLO_FIND_QUIETLY)
  16. else (HELLO_FOUND)
  17. if (NOT HELLO_FOUND_REQUIRED)
  18. message (FATAL_ERROR "因为在FIND_PACKAGE 指令中没有指定了 REQUIRED 参数")
  19. endif (HELLO_FOUND_REQUIRED)
  20. endif (HELLO_FOUND)

杂记

源代码外构建 方便生成多套不同的配置

  1. cmake -H. -B_builds/Debug -DCMAKE_BUILD_TYPE=Debug
  2. cmake -H. -B_builds/Release -DCMAKE_BUILD_TYPE=Release
  3. cmake -H. -B_builds/feature-on -DFOO_FEATURE=ON
  4. cmake -H. -B_builds/feature-off -DFOO_FEATURE=OFF
  5. cmake -H. -B_builds/xcode -G Xcode
  6. cmake -H. -B_builds/make -G "Unix Makefiles"

CMake也会为其他工具运行测试,因此请 尽量避免在项目声明之前检查任何内容 ,并在项目声明后进行所有检查。

  1. cmake_minimum_required(VERSION 2.8)
  2. message("Before 'project':")
  3. message(" C: '${CMAKE_C_COMPILER}'")
  4. message(" C++: '${CMAKE_CXX_COMPILER}'")
  5. project(Foo)
  6. message("After 'project':")
  7. message(" C: '${CMAKE_C_COMPILER}'")
  8. message(" C++: '${CMAKE_CXX_COMPILER}'")

变量作用域

  • 每个变量都链接到定义它的作用域。add_subdirectory函数引入了它们自己的作用域。类似C语言中的代码块。

  • 创建新作用域时,将使用父作用域的变量对其进行初始化。命令 unset(abc) 可以从当前作用域中删除变量。如果在当前作用域中找不到变量,它将被取消引用为空字符串

  • include并且不要引入新的作用域,因此像 和 这样的命令会影响当前作用域:macrosetunset

    1. # 宏
    2. macro(modify_xyz)
    3. set(xyz "789")
    4. endmacro()
    5. # 调用宏
    6. modify_xyz()
  • set("${varname}" 16 PARENT_SCOPE)

CMakeLists.txt文件遍历顺序

  • 深度优先遍历

添加模块路径

设置此路径的正确方法是将其追加到现有值,例如,当用户出于任何原因想要使用自己的模块而不是标准模块时

  1. list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/modules")

执行命令行

  1. execute_process(
  2. COMMAND rm -rf "${dir_to_remove}"
  3. RESULT_VARIABLE result
  4. )
  5. if(NOT result EQUAL 0)
  6. # Error
  7. endif()

CMake 教程(待完善)的更多相关文章

  1. CMake 教程

    CMake是一个跨平台的程序构建工具,比如起自己编写Makefile方便很多. 介绍:http://baike.baidu.com/view/1126160.htm 本文件不介绍CMake的基本语法, ...

  2. cmake教程

    1 教程 cmake界的hello world[2] 进阶的入门教程参考[3] 2 引用 [1] cmake官网 [2] 在 linux 下使用 CMake 构建应用程序 [3] Valgrind官网

  3. CMAKE 教程前两章节学习

    原文 https://cmake.org/cmake-tutorial/ 以下是一个循序渐进的教程,它覆盖了CMAKE帮助改进的通常的构建系统的话题.许多话题在<掌握CMAKE>(< ...

  4. CMake教程——Leeds_Garden

    本系列适合 乐于学习新知识的人 想要深入学习C++的人 赞美作者的人 系列目录 初步入门 基本操作 (更新中) 创作不易,欢迎分享,把知识分享给更多有需要的人.

  5. 微软有完善的WP开发教程

    微软的Windows Phone 开发者中心 地址:http://dev.windowsphone.com/zh-cn/develop由于这里的教程非常完善,大家直要把开发者中心的内容看完就可以了,所 ...

  6. Python学习入门教程,字符串函数扩充详解

    因有用户反映,在基础文章对字符串函数的讲解太过少,故写一篇文章详细讲解一下常用字符串函数.本文章是对:程序员带你十天快速入门Python,玩转电脑软件开发(三)中字符串函数的详解与扩充. 如果您想学习 ...

  7. Docker最全教程之使用TeamCity来完成内部CI、CD流程(十六)

    本篇教程主要讲解基于容器服务搭建TeamCity服务,并且完成内部项目的CI流程配置.教程中也分享了一个简单的CI.CD流程,仅作探讨.不过由于篇幅有限,完整的DevOps,我们后续独立探讨. 为了降 ...

  8. Netty4.x中文教程系列(六) 从头开始Bootstrap

    Netty4.x中文教程系列(六) 从头开始Bootstrap 其实自从中文教程系列(五)一直不知道自己到底想些什么.加上忙着工作上出现了一些问题.本来想就这么放弃维护了.没想到有朋友和我说百度搜索推 ...

  9. Docker最全教程——从理论到实战(十四)

    本篇教程主要讲解基于容器服务搭建TeamCity服务,并且完成内部项目的CI流程配置.教程中也分享了一个简单的CI.CD流程,仅作探讨.不过由于篇幅有限,完整的DevOps,我们后续独立探讨. 为了降 ...

  10. 《虚拟伙伴》AR增强现实应用开发总结

    一.概述 1.1选题背景 随着时代的发展,人们的生活节奏越来越快,生活质量也越来越高,但却在繁忙之中忽略或者忘记了关心自己成长时代最重要或者最正确的事情和道理.虽然现在有很多社交平台,如微博,微信,f ...

随机推荐

  1. APP探索之iAPP

    APP探索之iAPP 1.基本作用 iAPP是一个手机上的应用,可以用于快速设计手机应用,基本免费.使用的语言好像是自创的脚本语言.无聊时可以用iAPP做一些简单的训练,可以练习文件和数据的操作.对于 ...

  2. Spring Cloud 服务的注册与发现之eureka客户端注册

    1.在客户端maven项目中添加eureka客户端依赖 <dependency> <groupId>org.springframework.cloud</groupId& ...

  3. Rust 实现日志记录功能

    目录 log 日志库标准 简单示例 使用方法 库的开发者 应用开发者 日志库开发者 使用 log4rs 添加依赖 配置文件 运行项目 参考文章 log 日志库标准 log 是 Rust 的日志门面库, ...

  4. Go~开发笔记~目录

    Go(又称为Golang)是一门由Google开发的开源编程语言,于2009年首次公开发布.Go语言被设计用来提高软件开发的效率和可靠性,在处理大规模系统时表现出色.以下是Go语言的一些特点和优势: ...

  5. #虚树,树形dp#洛谷 3233 [HNOI2014]世界树

    题目 分析 考虑建一棵虚树,倍增找到虚树上相邻两个点的中间点统计答案 记录每个虚树点最近的距离以及编号最小的点,主要是细节问题 代码 #include <cstdio> #include ...

  6. RabbitMQ 06 工作队列模式

    工作队列模式结构图: 这种模式非常适合多个工人等待任务到来的场景.任务有多个,一个一个丢进消息队列,工人也有很多个,就可以将这些任务分配个各个工人,让他们各自负责一些任务,并且做的快的工人还可以多完成 ...

  7. Windows系统编译libhv带SSL,开启WITH_OPENSSL

    需要开发一个https的服务,使用libhv来做,需要重新编译libhv,需要开启 WITH_OPENSSL,前面编译一直很顺利,但是打开VS生成动态库的时候,报错,找不到ssl相关的文件,看了官方的 ...

  8. JackSon反序列化通杀

    前言 Springboot一般都会自带JackSon这个依赖包,JackSon跟Fastjson有相同的功效 简单复现 package com.example.jakeson.demo; import ...

  9. 整理k8s————k8s概念[一]

    前言 简单整理一下k8s. 正文 k8s 是基于容器的一套解决方案,那么解决了什么问题呢? 解决了分布式部署问题. k8s 特点: 轻量 开源 弹性伸缩:IPVS 知识图谱: 更多的看官网就好. 结 ...

  10. redis 简单整理——java 客户端jedis[十六]

    前言 简单介绍一下java客户端jedis. 正文 Java有很多优秀的Redis客户端(详见:http://redis.io/clients#java),这 里介绍使用较为广泛的客户端Jedis,本 ...