C语言工具makefile

第一篇:最详尽,最初心的的CMake技术文档

2019-08-24  本文已影响3人  铁甲万能狗

CMake简述

CMake旨在成为一个跨平台的构建流程管理器,因此它定义了它自己的脚本语言,具有一定的语法和内置功能。 CMake本身是一个软件程序,因此应该使用脚本文件调用它来解释和生成实际的构建文件。
开发人员可以使用CMake语言为项目编写简单或复杂的构建脚本。

使用CMake语言构建逻辑和定义可以在CMakeLists.txt中编写,也可以使用<project_name> .cmake编写。 但作为最佳实践,主脚本命名为CMakeLists.txt而不是cmake。

编写Makefile可能比编写CMake脚本更难。 通过语法和逻辑的CMake脚本与高级语言具有相似性,因此开发人员可以更轻松地创建他们的cmake脚本,而不会在Makefile中迷失。

常用的命令:

下文的示例会尽量用到这些命令

还有一些命令可以让开发人员编写条件语句,循环,迭代列表,分配:

缩写不是强制性的,但在编写CMake脚本时建议使用。 CMake不使用';'来理解陈述的结尾。所有条件语句都应该以相应的结束命令结束(endif,endwhile,endforeach)CMake的所有这些属性可帮助开发人员编写复杂的构建过程,包括多个模块,库和平台。

CMake环境变量

环境变量用于配置编译器标志,链接器标志,常规构建过程的测试配置。 必须引导编译器搜索库的给定目录。
从以下URL可以看到环境变量的详细列表,可以参见一下链接:
https://cmake.org/cmake/help/latest/manual/cmake-env-variables.7.html

某些环境变量被预定义的CMake变量覆盖。 例如 定义CMAKE_CXX_FLAGS时,CXXFLAGS将被覆盖。

下面是一个示例用例,当您想在编译过程中启用所有警告时,您可以编写-Wall to build命令。 如果使用CMake构建代码,可以使用set命令添加-Wall标志。

set(CMAKE_CXX_FLAGS,"-Wall")
defined flags
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")

CMake变量

CMake包括预定义变量,这些变量默认设置为源树和系统组件的位置。
变量区分大小写,而不是命令。 在变量的定义中,您只能使用字母数字字符和下划线,短划线(_, - )。
您可以在以下URL中找到有关CMake变量的更多详细信息
https://cmake.org/cmake/help/v3.5/manual/cmake-language.7.html#variables

一些变量是根据根文件夹预定义的:

可以使用$ {<variable_name>}访问变量值

message("CXX Standard: ${CMAKE_CXX_STANDARD}")
set(CMAKE_CXX_STANDARD 14)

就像上面的变量一样,您可以定义自己的变量。 您可以调用set命令将值设置为新变量或更改现有变量的值,如下所示:

set("APP_VERSION","1.0.1")
message("${APP_VERSION}")

CMake 列表

CMake中的所有值都存储为字符串,但在某些上下文中可以将字符串视为列表。

通过连接由半列';'分隔的元素表示为字符串的元素列表

set(files a.txt b.txt c.txt)
# sets files to "a.txt;b.txt;c.txt"

要访问值列表,您可以使用CMake的foreach命令,如下所示:

foreach(file ${files})
    message("Filename: ${file}")
endforeach()

完整的表达式列表可以看这里
https://cmake.org/cmake/help/v3.8/manual/cmake-generator-expressions.7.html

使用CMake构建C ++项目

在前面的部分中,我们介绍了编写CMake脚本的核心原则。 现在,我们可以构建一个基本的链表为示例。

如图所示:


vs-code示例

很明显,对于这样一个小项目来说,使用CMake是多余的,但是当事情变得复杂时,它会有很大帮助。

为了构建main.cpp,在项目的根目录下创建一个CMakeLists.txt,并且写入如下代,然后执行cmake命令

/**/
cmake_minimum_required(VERSION 3.9.1)
/*设定项目的名称*/
project(cmake_tor)
/*我们编译的目标文件*/
add_executable(cmake_tor main.cpp)

然后在vscode终端中使用运行cmake命令,CMake会生成如下文件和目录

问题导入

我们的目的是生成一个二进制文件,但我们这里首先看一下刚才配置有哪些不足之处?

  • 首先,我们希望cmake生成的文件放到一个指定的目录里面,这样我们的项目不至于杂乱无章。
  • 其次,我希望能够使用自己指定的C/C++编译器,而不是cmake预定义的操作系统默认的编译器。
  • 最后,希望执行make命令的时候,编译后的可执行程序和库文件存放到一个有别于其他cmake文件夹的特殊目录。

下面先看看我们之后改进的项目目录结构,如下图,这是更符合我们实际开发工作中的一个目录结构。


屏幕快照 2019-08-24 上午11.53.59.png

那么,我们带着这三个问题定制自己的CMake配置方案吧!

首先,我们在项目的根目录先手动创建一个build的文件夹,在VSCode的终端重定向到build目录之下.

$ mkdir build
$ cd build

然后,在CMakeLists.txt使用以下cmake脚本,每个脚本的语句,代码中有注解

cmake_minimum_required(VERSION 3.1.0)
#设定c编译器和c++编译器,必须放在整个脚本的开头
set(CMAKE_C_COMPILER /usr/local/bin/gcc)
set(CMAKE_CXX_COMPILER /usr/local/bin/g++)

#工程项目的名称
project(cmake_tor)

#包含headers和source目录
include_directories(
    "${PROJECT_SOURCE_DIR}/headers"
    "${PROJECT_SOURCE_DIR}/source"
)

# 修正在macOS下CMAKE_CXX_STANDARD判断C++编译器标准的
#出错的bug,如果你用到是Windows/Linux系统,可以忽略这条语句
if (POLICY CMP0025)
  cmake_policy(SET CMP0025 NEW)
endif ()

#让CMake自动检测gcc的支持的c++标准,
#根据CMake的版本号判断它所支持c++标准
if(CMAKE_VERSION VERSION_LESS "3.8")
    set(CMAKE_CXX_STANDARD 14)
    message("The compile ${CMAKE_CXX_COMPILER} use C++14 standard!!")
elseif(CMAKE_VERSION VERSION_LESS "3.11")
    set(CMAKE_CXX_STANDARD 17)
    message("The compile ${CMAKE_CXX_COMPILER} use C++17 standard!!")
else()
    set(CMAKE_CXX_STANDARD 20)
    message("The compile ${CMAKE_CXX_COMPILER} use C++20 standard!!")
endif()
set(CMAKE_CXX_EXTENSIONS OFF)

#构建自己的软件系统
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/app)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/libs)

add_executable(main "${PROJECT_SOURCE_DIR}/source/main.cpp")
add_library(shape SHARED "${PROJECT_SOURCE_DIR}/source/shape.c")

最后执行cmake和make,我们会发现如下图,正如我们所愿在指定的目录下生成了一个可执行文件和共享对象文件

$ cmake
$ make

结束语:
第一次接触CMake的同学,可能觉得无从入手,单独花上一段时间去完全掌握它得不偿失,本文是对以前遇到的一些典型问题做成一个易懂的教程。

带着问题去stackflow寻找一些相关问题的答案是很好的学习方法之一,至少你在碰壁的时候,不会为了某个方面迷失了自我,然后自己去根据前人提供的建议去实践并归纳到一个文件里,这样就变成你自己已经掌握的技能了。

技术文~~分享至此,希望你喜欢。

上一篇 下一篇

猜你喜欢

热点阅读