CMake基础入门-2

简介: CMake基础入门

二、一个目录下有多个源文件

2.1 基础的实例

2.1.1 项目结构和实例


9dbde3097fa6b450fbb4ed3ad9073d33_4977226a20a84104b1f4ad714f65fde6.png

main.c编写


#include <stdio.h>
#include "testFunc.h"
int main(void)
{
  func(100);
  return 0;
}

testFunc.h编写

void func(int data);

testFunc.c编写

#include <stdio.h>
#include "testFunc.h"
void func(int data)
{
  printf("data is %d\n", data);
}

CMakeLists.txt编写(不加打印信息了)

cmake_minimum_required (VERSION 2.8)
project (zxm)
add_executable(hello main.c testFunc.c)

2.1.2 编译运行

进入build,运行查看


cd build/
cmake ..
make
./hello

7ad90ac66bd07f40920a383161960ebd_73f5f8c8c944482b938eed19d6d2acfe.png


2.2 进阶优化

如果源文件很多呢,几十个,一个个加入到add_executable就很麻烦。这时候可以使用aux_source_directory,用于自动将指定目录下的源文件列表添加到变量中。

并且,这么多源文件,最好放到单独的文件夹里面。


2.2.1 项目结构和实例

创建子目录src,存放源文件。在2.1例子的基础上,增加testFun1.c,testFun1.h文件,修改main.c文件。

7aeec17109ac9aca69d85ab8199994d0_ad610adc6fd04cb884e2c09be46836b0.png

testFun1.c编写


#include <stdio.h>
#include "testFunc1.h"
void func1(int data)
{
  printf("data is %d\n", data);
}

testFun1.h编写


void func1(int data);

main.c编写

#include <stdio.h>
#include "testFunc.h"
#include "testFunc1.h"
int main(void)
{
  func(100);
  func1(200);
  return 0;
}

src目录下的CMakeLists.txt编写


cmake_minimum_required (VERSION 2.8)
project (zxm)
# 把当前目录下的源文件添加到变量SRC_LIST中
aux_source_directory(. SRC_LIST)
add_executable(hello ${SRC_LIST})

主目录下的CMakeLists.txt编写


cmake_minimum_required (VERSION 2.8)
project (zxm)
add_subdirectory(src bin)

2.2.2 编译运行

cd build/
cmake ..
make
cd bin/
./hello

6b1d63cd6a36afecbcdbd5495dba9988_22b2269af4e243d18d58d96c94df978c.png


2.2.3 aux_source_directory

用于自动查找指定目录 dir 下的所有源文件,并将它们的完整路径(包括文件名)存储在变量 variable 中。

aux_source_directory(dir variable)

其中:


  • dir 是要进行源文件搜索的目录路径。
  • variable 是用于存储找到的源文件列表的变量名。

例如

假设有一个名为 src 的目录,其中包含以下源文件:main.cpp、helper.cpp 和 utils.cpp。你可以使用 aux_source_directory 命令来自动获取这些源文件:


# 搜索 src 目录下的所有源文件,并将它们的完整路径存储在变量 SOURCES 中。
aux_source_directory(src SOURCES)

然后,你可以使用 SOURCES 变量来指定要编译的源文件列表

add_executable(my_app ${SOURCES})

三、多个目录有多个源文件

3.1 基础的实例

3.1.1 项目结构和实例

.
├── build
├── CMakeLists.txt
└── src
    ├── CMakeLists.txt
    ├── main.c
    ├── test_func
    │   ├── testFunc.c
    │   └── testFunc.h
    └── test_func1
        ├── testFun1.c
        └── testFunc1.h

把testFunc.c和testFunc.h放在test_func目录下,把testFunc1.c和testFunc1.h放在test_func1目录下。


修改src目录下的CMakeLists.txt为

重点是include_directories,向工程添加多个特定的头文件搜索路径;相当于指定g++编译器的-I参数值。


cmake_minimum_required (VERSION 2.8)
project (zxm)
# 向工程添加多个指定头文件的搜索路径
include_directories(test_func test_func1)
# 把当前目录下的源文件添加到变量SRC_LIST中
aux_source_directory(test_func SRC_LIST)
aux_source_directory(test_func1 SRC_LIST1)
add_executable(hello main.c ${SRC_LIST} ${SRC_LIST1})

当然,也可以在main.c里包含具体的头文件路径,这就不需要include_directories


#include "test_func/testFunc.h"
#include "test_func1/testFunc1.h"

3.1.2 编译运行

cd build/
cmake ..
make
cd bin/
./hello

372e0eb74d48eca81109e9235f026ea5_b31be187de6946fe86a31f39f0861659.png


3.1.3 include_directories

用于向 CMake 构建系统添加一个或多个包含目录,告诉 CMake 在编译源代码时搜索头文件所在的目录。

include_directories(dir1 [dir2 ...])

其中,dir1、dir2 等是要添加的包含目录的路径。


例如,假设你的项目中有一个名为 include 的目录,里面包含了一些头文件。你可以使用 include_directories 命令将该目录添加到项目中:

include_directories(include)

3.2 进阶优化

综合上面介绍的,工程项目中,一般会把源文件放在src目录,头文件放在include目录,cmake生成的对象文件放在build目录,最终输出可执行文件放在build目录下的bin目录


3.2.1 项目结构和实例

.

.
├── build
├── CMakeLists.txt
├── include
│   ├── testFunc1.h
│   └── testFunc.h
└── src
    ├── CMakeLists.txt
    ├── main.c
    ├── testFunc1.c
    └── testFunc.c

修改src目录下的CMakeLists.txt


cmake_minimum_required (VERSION 2.8)
project (zxm)
# 向工程添加多个指定头文件的搜索路径
include_directories(../include)
# 把当前目录下的源文件添加到变量SRC_LIST中
aux_source_directory(. SRC_LIST)
add_executable(hello ${SRC_LIST})

3.2.2 编译运行

cd build/
cmake ..
make
cd bin/
./hello

d9e0442b5bbaf44bd41fe6739128c538_2e63e3d3821c41c2bec9972386202933.png

3.3 进阶优化2

3.3.1 项目结构和实例

进一步,如果想修改可执行文件的生成路径,比如在src目录下的bin目录

04d6c06ac655e73a7daea799439226da_9f100f5ab8ba4d6eb7b5f280687d8eb8.png

修改src目录下的CMakeLists.txt

cmake_minimum_required (VERSION 2.8)
project (zxm)
# 向工程添加多个指定头文件的搜索路径
include_directories(../include)
# 把当前目录下的源文件添加到变量SRC_LIST中
aux_source_directory(. SRC_LIST)
add_executable(hello ${SRC_LIST})
# EXECUTABLE_OUTPUT_PATH 可执行文件输出的存放路径
# 包PROJECT_SOURCE_DIR 含项目名的最近一个 CMakeLists.txt 文件所在的目录的路径
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

修改主目录下的CMakeLists.txt

cmake_minimum_required (VERSION 2.8)
project (zxm)
add_subdirectory(src)

3.2.2 编译运行

cd build/
cmake ..
make
cd ../src/bin/
./hello

四、生成库(待更新)

在软件开发中,动态库(Dynamic Library)和静态库(Static Library)是两种常见的库文件类型。


1) 动态库:


  • 动态库是一种在运行时加载的库文件。它以共享的方式被多个程序使用,可以在不同的应用程序之间共享代码和数据。
  • 动态库具有独立编译和链接的优势,因此可以以相对较小的体积提供功能模块。
  • 当一个程序调用动态库时,操作系统会在内存中加载该库,并将其映射到运行进程的地址空间。这种共享的方式可以节省系统资源和内存使用,并允许库的更新和升级。
  • 动态库的扩展名通常为 .so(在Linux/Unix)或 .dll(在Windows)。

2)静态库:


  • 静态库是一种在编译时链接到程序中的库文件。它会将库的代码和数据复制到最终生成的可执行文件中。
  • 静态库使得可执行文件完全自包含,不依赖于外部的库文件。这可以提供更好的可移植性和独立性,因为所有需要的代码都包含在一个文件中。
  • 静态库通常比动态库更容易部署和分发,因为不需要处理共享库的加载和依赖关系。
  • 静态库的扩展名通常为 .a(在Linux/Unix)或 .lib(在Windows)。

在实际开发中,可以根据项目需求和约束来选择使用动态库还是静态库。动态库适合用于提供公共功能的共享库,而静态库则适合用于构建独立、可移植的可执行文件。


DCMAKE_INSTALL_PREFIX

指定 camke install 时的相对路径前缀

cmake -DCMAKE_INSTALL_PREFIX=/usr ..

install

参考cmake的install指令

用于指定在安装时运行的规则。它可以用来安装很多内容,可以包括目标二进制、动态库、静态库以及文件、目录、脚本等。

install(TARGETS <target>... [...])
install({FILES | PROGRAMS} <file>... [...])
install(DIRECTORY <dir>... [...])
install(SCRIPT <file> [...])
install(CODE <code> [...])
install(EXPORT <export-name> [...])

目标文件的安装

install(TARGETS targets... [EXPORT <export-name>]
        [[ARCHIVE|LIBRARY|RUNTIME|OBJECTS|FRAMEWORK|BUNDLE|
          PRIVATE_HEADER|PUBLIC_HEADER|RESOURCE]
         [DESTINATION <dir>]
         [PERMISSIONS permissions...]
         [CONFIGURATIONS [Debug|Release|...]]
         [COMPONENT <component>]
         [NAMELINK_COMPONENT <component>]
         [OPTIONAL] [EXCLUDE_FROM_ALL]
         [NAMELINK_ONLY|NAMELINK_SKIP]
        ] [...]
        [INCLUDES DESTINATION [<dir> ...]]
        )

参数中的TARGET可以是很多种目标文件,最常见的是通过ADD_EXECUTABLE或者ADD_LIBRARY定义的目标文件,即可执行二进制、动态库、静态库。


为了符合一般的默认安装路径,如果设置了DESTINATION参数,推荐配置在安装目录变量下的文件夹。

例如:


INSTALL(TARGETS myrun mylib mystaticlib
     # 可执行二进制myrun安装到${CMAKE_INSTALL_BINDIR}目录
       RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
       # 可执行二进制myrun安装到${CMAKE_INSTALL_BINDIR}目录
       LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
       # 可执行二进制myrun安装到${CMAKE_INSTALL_BINDIR}目录
       ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)

普通文件的安装


install(<FILES|PROGRAMS> files...
        TYPE <type> | DESTINATION <dir>
        [PERMISSIONS permissions...]
        [CONFIGURATIONS [Debug|Release|...]]
        [COMPONENT <component>]
        [RENAME <name>] [OPTIONAL] [EXCLUDE_FROM_ALL])

FILES|PROGRAMS若为相对路径给出的文件名,将相对于当前源目录进行解释。其中,FILES为普通的文本文件,PROGRAMS指的是非目标文件的可执行程序(如脚本文件)。


# 将文本文件 myfile.txt 安装到目标路径的 share/myproject 目录下
install(FILES myfile.txt DESTINATION share/myproject)

目录的安装


install(DIRECTORY dirs...
        TYPE <type> | DESTINATION <dir>
        [FILE_PERMISSIONS permissions...]
        [DIRECTORY_PERMISSIONS permissions...]
        [USE_SOURCE_PERMISSIONS] [OPTIONAL] [MESSAGE_NEVER]
        [CONFIGURATIONS [Debug|Release|...]]
        [COMPONENT <component>] [EXCLUDE_FROM_ALL]
        [FILES_MATCHING]
        [[PATTERN <pattern> | REGEX <regex>]
         [EXCLUDE] [PERMISSIONS permissions...]] [...])

该命令将一个或多个目录的内容安装到给定的目的地,目录结构被逐个复制到目标位置。

# 将目录 mydir/ 及其内容安装到目标路径的 include/myproject 目录下
install(DIRECTORY mydir/ DESTINATION include/myproject)
目录
相关文章
|
弹性计算 网络协议 存储
10分钟幻兽帕鲁服务器搭建保姆级教程
幻兽帕鲁最近非常火。有些小伙伴可能不喜欢跟陌生人一起玩,那么你可以搭建一个专有服务器和朋友一起联机游戏。自己搭建服务器不仅更私密,还能自定义游戏里的一些选项,比如调整工作速度倍率、经验获取倍率等。 这篇教程将引导你在10分钟左右快速完成幻兽帕鲁服务器的搭建。
4150 5
|
8月前
|
网络安全
一个简单的网站建设需要多少费用?
网站建设费用因类型、功能和需求的不同而差异较大,包括基础型网站、设计和定制网站、功能型与电商网站、域名费用、服务器费用、HTTPS认证费用、网站维护费用等,其中独立站建设费用相对较高。
398 2
|
11月前
|
数据采集 数据可视化 前端开发
怎么通过API获取电竞赛事实时数据
选择合适的电竞数据API是开发电竞应用的关键。主流API包括OP.GG、Liquipedia、Stratz、Riot Games和熊猫比分,涵盖LOL、DOTA2等游戏的实时数据。注册并获取API密钥后,需仔细阅读文档,了解资源、请求方法、必需参数及响应格式。编写代码调用API时,注意优化请求频率,避免封禁。最后,通过Web界面或可视化工具展示数据,如React/D3.js、Tableau等。示例代码展示了如何使用熊猫比分API获取即将开始的比赛信息。
|
9月前
|
数据采集 存储 数据可视化
Pandas高级数据处理:数据报告生成
Pandas 是数据分析领域不可或缺的工具,支持多种文件格式的数据读取与写入、数据清洗、筛选与过滤。本文从基础到高级,介绍如何使用 Pandas 进行数据处理,并解决常见问题和报错,如数据类型不一致、时间格式解析错误、内存不足等。最后,通过数据汇总、可视化和报告导出,生成专业的数据报告,帮助你在实际工作中更加高效地处理数据。
254 8
|
10月前
|
机器学习/深度学习 人工智能 自然语言处理
通义千问Qwen征文活动获奖公布
Qwen征文获奖公布啦!
752 3
|
机器学习/深度学习 自然语言处理 算法
AIGC技术的核心算法与发展趋势
【7月更文第27天】随着人工智能技术的迅速发展,AIGC技术已经逐渐成为内容创造领域的一个重要组成部分。这些技术不仅能够帮助人们提高工作效率,还能创造出以往难以想象的新颖内容。本文将重点介绍几种核心算法,并通过一个简单的代码示例来展示如何使用这些算法。
438 7
|
Java Linux 数据安全/隐私保护
libreOffice word 转 pdf
在Windows环境下,使用documents4j进行DOCX到PDF的转换大约需要20秒,而Linux环境下通过Docker配置LibreOffice进行转换,时间仅为1.4秒。documents4j仅适用于Windows且需Microsoft Office支持,libreOfficeCommand则依赖于Linux环境。Spire.Doc.Free有前4页免费但有水印,不推荐。
953 0
|
移动开发 前端开发
ruoyi-nbcio-plus基于vue3的flowable多租户机制
ruoyi-nbcio-plus基于vue3的flowable多租户机制
546 0
|
存储 安全 物联网
为什么需要等保测试,等保测评是为了什么
为什么需要等保测试,等保测评是为了什么