首页 > 其他分享 >CMake入门

CMake入门

时间:2023-05-29 19:44:27浏览次数:42  
标签:CMake 入门 -- demo PROJECT VERSION cmake include

CMake

cmake的定义是 -- 高级编译配置工具

当多人用不同的语言或者编译器开发一个项目,最终要输出一个可执行文件或者共享库(dll,so等等)这时候就需要用到 ------ CMake

所有操作都是通过编译 CMakeLists.txt 来完成的

官方网站是 www.cmake.org

学习CMake的目的,为将来处理大型的C/C++/JAVA项目做准备

CMake安装

  1. CMake:https://cmake.org/download/
  2. MinGW:https://sourceforge.net/projects/mingw-w64/files/mingw-w64/

构建和运行

  1. 创建一个文件夹,里面再创建一个 src 文件夹,src文件夹中包含:main.cpp,CMakeLists.txt

main.cpp:

#include<iostream>
using namespace std;

int main()
{
    cout<<"Hello World"<<endl;
    return 0;
}

CMakeLists.txt:

cmake_minimum_required(VERSION 3.10)

# set the project name
project(demo)

# add the executable
add_executable(demo main.cpp)
  1. 新建一个构建目录
mkdir build
  1. 进入该目录进行配置项目
cd build
cmake ../src

如果 cmake ../src 报错,则说明不是使用默认的Generator,应当添加 -G 选项:

cmake -G "MinGW Makefiles" ../src
  • 构建
cmake --build .
  • 运行,如果是上述例子(上面都是在cmd中运行)
demo.exe

说明

  • cmake命令不区分大小些写,但是参数、变量区分大小写
  • 参数使用空格或者分号隔开
  • 使用 ${VAR} 引用变量
  • 引号可加可不加,但如果字符串中有空格必须加

概念

  • 目标文件(target):可执行文件(add_executable)、库文件(add_library)
  • 命令(cmake-command):下面要讲的函数
  • 变量(cmake-variable):以 CMAKE_ 开头的变量名
  • 属性(cmake-properties):文件/文件夹都有各自的属性

命令

cmake_minimum_required

设置最低cmake版本

cmake_minimum_required(VERSION <min>)
cmake_minimum_required(VERSION 3.10)

project

设置项目名

project(<PROJECT-NAME> [<language-name>...])
project(<PROJECT-NAME>
        [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
        [DESCRIPTION <project-description-string>]
        [HOMEPAGE_URL <url-string>]
        [LANGUAGES <language-name>...])

# 项目名会被存储在变量 PROJECT_NAME 和 CMAKE_PROJECT_NAME 中
# PROJECT_SOURCE_DIR 等价于 <PROJECT-NAME>_SOURCE_DIR    项目的源目录的绝对路径。
# PROJECT_BINARY_DIR 等价于 <PROJECT-NAME>_BINARY_DIR    项目的二进制目录的绝对路径

# 如果定义了版本号
# 版本号被保存在 PROJECT_VERSION 和 <项目名称>_VERSION中
# 主版本号被保存在 PROJECT_VERSION_MAJOR 和 <项目名称>_VERSION_MAJOR
# 次版本号被保存在 PROJECT_VERSION_MINOR 和 <项目名称>_VERSION_MINOR
# 方式一: project(demo C CXX) 指定项目的语言为c和c++
# 方式二: project(demo VERSION 1.0 LANGUAGES CXX) 指定项目版本和语言
# set the project name
project(demo VERSION 1.0 LANGUAGES CXX)
# 打印项目名字  
message(${PROJECT_NAME})    # demo
# 打印项目源目录的绝对路径
message(${PROJECT_SOURCE_DIR})  # D:/Visual Studio/repos/CMakeDemo01/src
message(${demo_SOURCE_DIR})     # D:/Visual Studio/repos/CMakeDemo01/src
# 打印项目的二进制目录的绝对路径 
message(${PROJECT_BINARY_DIR})  # D:/Visual Studio/repos/CMakeDemo01/build
message(${demo_BINARY_DIR})     # D:/Visual Studio/repos/CMakeDemo01/build
# 打印版本号,主版本号,次版本号
message(${PROJECT_VERSION})         # 1.0
message(${PROJECT_VERSION_MAJOR})   # 1
message(${PROJECT_VERSION_MINOR})   # 0

add_executable

用指定的源文件为项目添加可执行文件

add_executable(<name> [WIN32] [MACOSX_BUNDLE]
               [EXCLUDE_FROM_ALL]
               [source1] [source2 ...])
       
# <name>即生成可执行文件的名字(与项目名没有关系),在一个项目中必须唯一
# 如windows系统会生成<name>.exe文件
add_executable(demo main.cpp)	# 系统会生成 demo.exe

message

打印信息

message([<mode>] "message text" ...)
# STATUS 前缀为--的信息
# SEND_ERROR 产生错误,跳过生成过程
# FATAL_ERROR 产生错误,终止运行
# 例如
message(STATUS "${PROJECT_VERSION_MAJOR}")  # -- 1

set

将变量设置为指定值

set(<variable> <value>)

# 例
set(A 1)
message(${A})	# 1

设置C++标准

# 使用c++11标准
set(CMAKE_CXX_STANDARD 11)

设置输出文件的位置

# 设置运行时目标文件(exe、dll)的输出位置,dll为动态库
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

# 设置存档目标文件(lib、a 静态库)的输出位置
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
# 在有静态库之后,就可以使用第二个设置了,就会这build生成一个lib文件夹,专门用来存放静态库文件
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)

# 在src的CMakeLists.txt中加入这个命令之后,在配置和构建,就能在build文件下得到一个lib文件夹
|--build
	|--lib
		|--***
|--src
	***

option

定义一个开关

option(<variable> "<help_text>" [value])
# value的值为 ON 或 OFF ,默认为 OFF
# 命令行 -D<variable>=ON/OFF
# 例如:定义是否输出版本号	option(VERSION_ENABLE "output version" ON)

configure_file

将输入文件进行替换并生成输出文件

1.
configure_file(<input> <output>)
# 输入文件中形如 @VAR 或 ${VAR} 的字符串会被替换为这些变量的当前值,如果未定义则被替换为空字符串
# 其规则见下
例1:

在src目录下创建一个config.h.in文件

# config.h.in文件
#define PROJECT_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
#define PROJECT_VERSION_MINOR @PROJECT_VERSION_MINOR@

# 由上面可知,PROJECT_VERSION_MAJOR = 1,PROJECT_VERSION_MINOR = 0

在CMakeLists.txt中版本号下面添加

# 将config.h.in中的 @...@ 里面的值换成当前变量的值
configure_file(config.h.in config.h)

然后再cmd中配置和构建以后,会再build下生成一个config.h文件

cmake -G "MinGW Makefiles" ..\src
cmake --build .
# config.h文件中的内容
#define PROJECT_VERSION_MAJOR 1
#define PROJECT_VERSION_MINOR 0

现在我们就能够调用config.h中的内容了

在main.cpp中加入

#include<iostream>
#include"../build/config.h"		//加入的内容
using namespace std;

int main()
{
    cout<<"Hello World"<<endl;
    //加入的内容
    cout<<"version: "<< PROJECT_VERSION_MAJOR << "." << PROJECT_VERSION_MINOR <<endl;
    return 0;
}

在CMakeLists.txt中加入

target_include_directories(demo PUBLIC "${PROJECT_BINARY_DIR}")

再重新配置和构建,运行可看到运行结果

cmake -G "MinGW Makefiles" ..\src
cmake --build .
bin\demo.exe
    
//结果显示:Hello World
//		  version :1.0
2.
#cmakedefine VAR ...
// 会被替换为以下两行之一,取决于VAR是否被设置
#define VAR ...
/* #undef VAR */
例2:

在CMakeLists.txt中写入

# 设置开关是否打开,ON 表示打开
option(DATE_ENABLE "output date" ON)
# 如果开关打开,则打印时间
if(DATE_ENABLE)
    set(DATE "2022.12.6")
endif()

在config.h.in中加入

#cmakedefine DATE "2022.12.6"

配置,构建,之后再config.h中会出现

cmake -G "MinGW Makefiles" ..\src
cmake --build .

#define DATE "2022.12.6"	

如果 CMakeLists.txt 中的 option 是 OFF

# 设置开关是否打开,OFF 表示打开
option(DATE_ENABLE "output date" ON)

在进行同样的操作(再进行同样操作之前,要将缓存清理掉,就是删除build中的文件,重新配置和构建),这 config.h 中则会出现

/* #undef DATE */

include_directories

指定所有目标的头文件路径

include_directories(dir1 [dir2 ...])
# 目录会被添加到当前文件的 INCLUDE_SIRECTORIES 属性中
# 当前文件的每一个目标文件的 INCLUDE_DIRECTORIES 属性也会添加该目录
# CMakeLists.txt
# 指定所有目标的头文件路径,如果不加这个,那么再构建的时候 main.cpp 中的 #include"config.h" 会报错
include_directories(${PROJECT_BINARY_DIR})

target_include_directories

指定(一个)目标的头文件路径

target_include_directories(<target> [SYSTEM] [AFTER|BEFORE]
  <INTERFACE|PUBLIC|PRIVATE> [items1...]
  [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
  
# 目标文件有 INCLUDE_DIRECTORIES 和 INTERFACE_INCLUDE_DIRECTORIES 两个属性
# INCLUDE_DIRECTORIES	对内头文件目录
# INTERFACE_INCLUDE_DIRECTORIES	对外头文件目录
INCLUDE_DIRECTORIES INTERFACE_INCLUDE_DIRECTORIES
PRIVATE(自己使用)
INTERFACE(给别人使用)
PUBLIC(都能使用)
# 指定(一个)目标的头文件路径,这样写 main.cpp 中的 #include"config.h" 也不会报错
target_include_directories(demo PUBLIC ${PROJECT_BINARY_DIR})

add_subdirectory

添加源文件目录

add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
# binary_dir 指定编译结果存放的位置
# 在 src 的 CMakeLists.txt 中加入
# 添加一个子目录,执行该命令时,则会进入到calc中,运行calc中的CMakeLists.txt
add_subdirectory(clac)

add_library

用指定的源文件生成库

add_library(<name> [STATIC | SHARED | MODULE]
            [EXCLUDE_FROM_ALL]
            [<source>...])
           
# STATIC 静态库
# SHARED 动态库
# 生成的库文件名为 lib<name>.xxx
# 在 calc 中的 CMakeLists.txt 中写
add_library(addition STATIC addition.cpp)	# 创建静态库
add_library(subtract SHARED subtract.cpp)   # 创建动态库

为目标链接库

target_link_libraries(<target>
                      <PRIVATE|PUBLIC|INTERFACE> <item>...
                     [<PRIVATE|PUBLIC|INTERFACE> <item>...]...)
                    
# item 可以是 target名、绝对路径(必须保证文件存在)
# 将 calc 中生成的库,链接到demo
# 在 src 下的 CMakeLists.txt 写
# 为目标链接库,给demo链接一个addition 静态库
target_link_libraries(demo PUBLIC addition)
# 为目标链接库,给demo链接一个subtract 动态库
target_link_libraries(demo PUBLIC subtract)

# 指定目标的头文件路径
target_include_directories(demo PUBLIC ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/calc)
# 为了使 main.cpp 中的 #include"addition.h" 不报错,需要给他添加一个 头文件搜索目录,即加入${PROJECT_SOURCE_DIR}/calc 
// 之后就能在main.cpp中调用add函数了
#include<iostream>
#include"config.h"
#include"addition.h"	// 新加的
#include"subtract.h"	// 新加的
using namespace std;

int main()
{
    cout<<"Hello World"<<endl;
    cout<<"version: "<< PROJECT_VERSION_MAJOR << "." << PROJECT_VERSION_MINOR <<endl;
    #ifdef DATE
    cout << "date " << DATE << endl;
    #endif

    cout<< "1 + 2 = " << add(1,2) << endl;	//新加的
    cout<< "3 - 1 = " << sub(3,1) << endl;	//新加的
    
    return 0;
}

进行配置和构建,构建完之后,由上面 set 设置的文件输出路径可知:

  • 动态库生成在 build/bin 下面的 .dll 文件
  • 静态库生成在 build/lib 下面的 .a文件

链接外部其他的库

先创建一个文件夹,将要 链接的库和所需的头文件 放入其中,如other_lib

|--build
    |--bin
    	***
    	|--libdivision.dll	// 如果链接的是外部动态库,还需要将外部动态库放到 build/bin 目录下
    	***
|--other_lib
	|--libmultiply.a	//外部静态库
	|--multiply.h		//头文件
	|--libdivision.dll	//外部动态库
	|--division.h		//头文件
|--src

在 src 的 CMakeLists.txt 添加

# 为目标链接库,给demo链接一个 外部的静态库 multiply
target_link_libraries(demo PUBLIC "D:/Visual Studio/repos/CMakeDemo01/other_lib/libmultiply.a")
# 为目标链接库,给demo链接一个 外部的动态库 division
target_link_libraries(demo PUBLIC "D:/Visual Studio/repos/CMakeDemo01/other_lib/libdivision.dll")

# 指定(一个)目标的头文件路径,并添加文件路径 ${PROJECT_SOURCE_DIR}/../other_lib
target_include_directories(demo PUBLIC ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/calc ${PROJECT_SOURCE_DIR}/../other_lib)

之后就能够在 main.cpp 中调用了

#include<iostream>
#include"config.h"
#include"addition.h"
#include"subtract.h"
#include"multiply.h"	// 新加的
#include"division.h"	// 新加的
using namespace std;

int main()
{
    cout<<"Hello World"<<endl;
    cout<<"version: "<< PROJECT_VERSION_MAJOR << "." << PROJECT_VERSION_MINOR <<endl;
    #ifdef DATE
    cout << "date " << DATE << endl;
    #endif

    cout<< "1 + 2 = " << add(1,2) << endl;
    cout<< "3 - 1 = " << sub(3,1) << endl;
    cout<< "2 * 3 = " << mult(2,3) << endl;	// 新加的
    cout<< "6 / 2 = " << divi(6,2) << endl;	// 新加的

    return 0;
}

区分

# 头文件目录
include_directories()
target_include_directories()

# 链接时库目录,不推荐使用
link_directories()
target_link_directories()

# 链接库
link_libraries()
target_link_libraries()

# 都推荐使用以 target_ 开头的函数

安装

cmake代码

在对应目录的CMakeLists.txt中使用

install(TARGETS <target> DESTINATION <dir>)
install(FILES <file> DESTINATION <dir>)
install(PROGRAMS <非目标文件的可执行程序> DESTINATION <dir>)	# 如脚本
install(DIRECTORY <dir> DESTINATION <dir>)	# 安装目录

在 src 的 CMakeLists.txt 中添加

# 安装目标文件,将demo可执行文件安装到bin目录下
install(TARGETS demo DESTINATION bin)
# 将外部的静态库文件安装到lib目录下
install(FILES "D:/Visual Studio/repos/CMakeDemo01/other_lib/libmultiply.a" DESTINATION lib)
# 将外部的动态库文件安装到bin目录下
install(FILES "D:/Visual Studio/repos/CMakeDemo01/other_lib/libdivision.dll" DESTINATION bin)
# 安装config的头文件
install(FILES "${PROJECT_BINARY_DIR}/config.h" DESTINATION include)
# 安装外部multiply的头文件
install(FILES "D:/Visual Studio/repos/CMakeDemo01/other_lib/multiply.h" DESTINATION include)
# 安装外部division的头文件
install(FILES "D:/Visual Studio/repos/CMakeDemo01/other_lib/division.h" DESTINATION include)

在 calc 的 CMakeLists.txt 中添加

add_library(addition STATIC addition.cpp)   # 创建静态库

# 新添加的部分 start
# 将addition安装到lib目录下,因为addition为静态库
install(TARGETS addition DESTINATION lib)
# 安装addition的头文件
install(FILES addition.h DESTINATION include)
# end

add_library(subtract SHARED subtract.cpp)   # 创建动态库

# 新添加的部分 start
# 将subtract安装到bin目录下,因为subtract为动态库
install(TARGETS subtract DESTINATION bin)
# 安装subtract的头文件
install(FILES subtract.h DESTINATION include)
# end

命令行

cmake --install .	# 安装到默认目录
CMAKE_INSTALL_PREFIX
cmake --install . --prefix <dir>	# 安装到指定目录

标签:CMake,入门,--,demo,PROJECT,VERSION,cmake,include
From: https://www.cnblogs.com/sususuH/p/17441471.html

相关文章

  • Kubernetes 入门实战
    Kubernetes入门实战DockerDocker的安装安装docker.io为了方便,你还可以使用-y参数来避免确认,实现自动化操作:sudoaptinstall-ydocker.io#安装DockerEngineDockerEngine不像DockerDesktop那样可以安装后就直接使用,必须要做一些手工调整才能用起来,所以你还要......
  • Apache Flume教程_编程入门自学教程_菜鸟教程-免费教程分享
    教程简介Flume是Apache下面的一个分布式组件,它提供高效,可靠的收集,整合,传输日志数据的服务。Flume可以理解成一个管道,它连接数据的生产者和消费者,它从数据的生产者(Source)获取数据,保存在自己的缓存(Channel)中,然后通过Sink发送到消费者。它不对数据做保存和复杂的处理(可以做简单......
  • Java学习 - 入门
    Java三大版本JavaSE:标准版JavaME:嵌入式开发JavaEE:E企业级开发JDK、JRE、JVMJDK:Java开发者工具JRE:Java运行时环境JVM:Java虚拟机Java开发环境卸载JDKJava安装目录:环境变量-JAVA_HOME删除java安装目录删除JAVA_HOME删除path下关于java目录运行cmdjava-version......
  • Javase入门|史上最好用的截图工具Snipaste
    在学习Java的时候,有时候老师操作的比较快,通过截图的方式将老师的操作保存下来,以便后期的操作。另外截图之后的图片也可以用于笔记的记录,在笔记当中最好采用图文并茂的方式,这样更加利于知识的回顾。这篇文章详细介绍下snipaste截图工具的下载安装及使用,配合视频效果更佳动力节点老杜......
  • pytest从入门到精通笔记
    一、pytest简介pytest是一个非常成熟的全功能的Python测试框架,比unittest更灵活,容易上手。主要有以下几个特点:1.简单灵活,容易上手2.支持参数化3.能够支持简单的单元测试和复杂的功能测试,还可以用来做selenium/appnium等自动化测试、接口自动化测试(pytest+requests)4.pytest具......
  • 功能测试面试没人要了!软件自动化测试如何入门?
    对于我来说,我做的是web端的测试,做测试也有好几个年头了,每次都是使用手工测试的话,一直是做重复性的工作,既枯燥又繁琐,所以我在两年前自己使用java语言写了一系列的自动化测试脚本,利用的框架是java+testng+reportng+selenium,这个框架在项目中基本可用了。不过最近由于公司项目发生变......
  • 软件架构入门
    软件架构(softwarearchitecture)就是软件的基本结构。合适的架构是软件成功的最重要因素之一。大型软件公司通常有专门的架构师职位(architect),只有资深程序员才可以担任。O'Reilly出版过一本免费的小册子《SoftwareArchitecturePatterns》(PDF),介绍了五种最常见的软件架构,是非常好......
  • Maven学习总结(一)——Maven入门
    一、Maven的基本概念Maven(翻译为"专家","内行")是跨平台的项目管理工具。主要服务于基于Java平台的项目构建,依赖管理和项目信息管理。1.1、项目构建项目构建过程包括【清理项目】→【编译项目】→【测试项目】→【生成测试报告】→【打包项目】→【部署项目】这几个步骤,这六个......
  • Spark入门看这篇就够了(万字长文)
    本文已收录至Github,推荐阅读......
  • Isito 入门:为什么学 Istio、Istio 是什么
    1,Istio概述......