Linux 系统下 CMake 示 例

这篇具有很好参考价值的文章主要介绍了Linux 系统下 CMake 示 例。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

linux cmake,# C/C++,linux,运维,服务器,原力计划


CMake 是一个开源的跨平台工具,可以构建、测试和打包软件。
它具有如下特性:

  • 自动搜索可能需要的程序、库和头文件的能力;
  • 独立的构建目录(如build),可以安全清理;
  • 支持复杂的自定义命令(下载、生成各种文件);
  • 自定义配置可选组件;
  • 从简单的文本文件(CMakeLists.txt)自动生成工作区和项目的能力;
  • 在主流平台上自动生成文件依赖项并支持并行构建;
  • 几乎支持所有的 IDE

1. 安装CMake

sudo apt install cmake -y

安装完成后用查看版本指令cmake -version检查CMake是否安装成功。

linux cmake,# C/C++,linux,运维,服务器,原力计划
出现以上提示代表安装成功。


2. 第一个CMake例子

我们首先新建两个文件,main.cppCMakeLists.txt

linux cmake,# C/C++,linux,运维,服务器,原力计划

touch main.cpp CMakeLists.txt

main.cpp 中编写如下代码

#include <iostream>
using namespace std;

int main(){
    cout << "第一个CMake程序" << endl;
    return 0;
}

CMakeLists.txt 中编写如下代码

# CMake 最低版本号要求
cmake_minimum_required (VERSION 3.1)

# demo 代表项目名称
project (demo)

# 添加一个可执行程序,demo是可执行程序名称,main.cpp是源文件
add_executable(main main.cpp)

这里我们用到 add_executable,其中第一个参数是最终生成的可执行文件名以及在CMake 中定义的 Target 名。我们可以在 CMake 中继续使用 Target 的名字为 Target 的编译设置新的属性和行为。命令中第一个参数后面的参数都是编译目标所使用到的源文件。

在准备好后我们依次执行下列指令:

# 第一步:配置,-S 指定源码目录,-B 指定构建目录
cmake -S . -B build 
# 第二步:生成,--build 指定构建目录
cmake --build build
# 运行
./build/main
  1. 第一步,我们输入cmake -S . -B build

linux cmake,# C/C++,linux,运维,服务器,原力计划

linux cmake,# C/C++,linux,运维,服务器,原力计划

  1. 第二步,我们输入 cmake --build build

linux cmake,# C/C++,linux,运维,服务器,原力计划

此时会产生一个可执行文件 main

linux cmake,# C/C++,linux,运维,服务器,原力计划

  1. 第三步,我们输入 ./build/main 运行可执行文件 main

linux cmake,# C/C++,linux,运维,服务器,原力计划


3. 同一个目录下编译多个文件

接下来我们尝试在同一个目录下编译多个文件,我们首先在文件夹下新建如下 4 4 4 个文件,我们首先演示同时编译带有头文件和 cpp 文件的案例。

linux cmake,# C/C++,linux,运维,服务器,原力计划

touch main.cpp Account.cpp Account.h CMakeLists.txt

mian.cpp 的内容如下:

# include "Account.h"
# include <iostream>

int main()
{
    Account Q;
}

Account.cpp 的内容如下:

#include "Account.h"
#include <iostream>

Account::Account(/* args */)
{
    std::cout << "构造函数Account::Account()" << std::endl;
}
Account::~Account()
{
    std::cout << "析构函数Account::~Account()" << std::endl;
}

Account.h 的内容如下:

#ifndef Account_H
#define Account_H

class Account
{
private:
    /* data */
public:
    Account(/* args */);
    ~Account();
};


#endif // Account_H

CMakeLitsts.txt 的内容如下:

#account_dir/CMakeLists.txt

# 最低版本要求
cmake_minimum_required(VERSION 3.10)

# 项目信息
project(Account)

# main 是可执行文件名称,后面是源文件
add_executable(main Account.cpp main.cpp Account.h)

接下来我们开始编译,依次输入以下指令:

cmake -S . -B build
cmake --build build

linux cmake,# C/C++,linux,运维,服务器,原力计划

编译成功后文件结构如下所示

linux cmake,# C/C++,linux,运维,服务器,原力计划


这个案例是想说明,如果在同一目录下有多个源文件,那么只要在 add_executable 里把所有源文件都添加进去就可以了,但是当我们源文件过多的时候就不太方便了,这时候我们用到了 cmake 的另一个命令 aux_source_directory(dir var)
第一个参数 dir是指定目录,第二个参数 var是用于存放源文件列表的变量。

所以我们可以改写一下 CMakeLists.txt

# 最低版本要求
cmake_minimum_required(VERSION 3.10)

# 项目信息
project(Account)

aux_source_directory(. SRC_LIST)

add_executable(main ${SRC_LIST})

这段代码使用 aux_source_directory 把当前目录下的源文件存列表存放到变量 SRC_LIST 里,然后在 add_executable 里调用 SRC_LIST

再次执行 cmake 后最终的得到的结果是完全一样的。

linux cmake,# C/C++,linux,运维,服务器,原力计划

值得注意的是,aux_source_directory() 也存在弊端,它会把指定目录下的所有源文件都加进来,可能会加入一些我们不需要的文件,此时我们可以使用 set 命令去新建变量来存放需要的源文件,如下:

cmake_minimum_required (VERSION 3.10)

project (Account)

set( SRC_LIST
	 ./main.cpp
	 ./Account.cpp
     ./Account.h)

add_executable(main ${SRC_LIST})

set 命令是用于定义变量的,set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
EXECUTABLE_OUT_PATHPROJECT_SOURCE_DIRCMake 自带的预定义变量,其意义如下,

  • EXECUTABLE_OUTPUT_PATH :目标二进制可执行文件的存放位置
  • PROJECT_SOURCE_DIR:工程的根目录

4. 不同目录下编译多个文件

接着上面的内容,我们来演示不同目录下编译多个文件的案例,我们将上面的文件按照如下的结构重构,内容不需要改变。

一般来说, 源文件都放到 src 目录下,把头文件放入到 include 文件下,生成的对象文件放入到 build 目录下,最终输出的 elf 文件会放到 bin 目录下

linux cmake,# C/C++,linux,运维,服务器,原力计划

随后在最外层目录下新建 main.cppCMakeLists.txt

linux cmake,# C/C++,linux,运维,服务器,原力计划

main.cpp代码如下:

#include <iostream>
#include "Account.h"

int main()
{
    Account alice_account;
    std::cout << "test Account 的main函数" << std::endl;
    return 0;
}

CMakeLists.txt 代码如下:

cmake_minimum_required (VERSION 3.10)

project (Account)

include_directories (include src)

aux_source_directory (include SRC_LIST)
aux_source_directory (src SRC_LIST1)

add_executable (main main.cpp ${SRC_LIST} ${SRC_LIST1})

这里出现了一个新的命令:include_directories 。该命令是用来向工程添加多个指定头文件的搜索路径,路径之间用空格分隔。
因为 main.cppincludeAccount.h,如果没有这个命令来指定头文件所在位置,就会无法编译。当然,也可以在main.cpp 里使用 include 来指定路径,如下

#include "include/Account.h""

完成后开始编译:

cmake -S . -B build
cmake --build build
./build/main

linux cmake,# C/C++,linux,运维,服务器,原力计划

linux cmake,# C/C++,linux,运维,服务器,原力计划


5. 静态库和动态库

5.1 什么是库文件?

库文件(Library files)是预先编译好的可重用代码和资源的集合,它们被用于简化软件开发过程并提供常见功能的封装。库文件包含一组函数、类、数据结构、变量、常量或其他可执行代码的实现。

库文件的主要目的是为了促进代码的重用和模块化开发,以提高开发效率、减少代码冗余,并使代码更易于维护。通过使用库文件,开发人员可以在自己的应用程序中调用库中提供的函数、方法和类,从而实现特定功能而无需从头开始编写代码。

库文件可以分为两种主要类型:

  1. 静态库(Static Library):静态库的代码在编译时被复制到可执行文件中,可执行文件独立于库文件运行。静态库提供了一种静态链接的方式,使得可执行文件可以在没有外部依赖的情况下运行。静态库通常以.lib (Dynamic-Link Libraries)(Windows)或.a(Unix/Linux)等文件扩展名表示。
  2. 动态库(Dynamic Library):动态库的代码在运行时由操作系统动态加载到内存中,并与可执行文件共享。动态库可以被多个应用程序共享使用,减少了内存占用和重复加载的开销。动态库通常以.dll(Windows)或.so (Shared Object)(Unix/Linux)等文件扩展名表示。

库文件可以提供各种功能,例如数学计算、文件操作、网络通信、图形界面、数据库访问、加密解密等。通过使用库文件,开发人员可以利用已经实现和测试过的功能,加速开发过程,减少错误和重复劳动。

5.2 静态库和动态库的区别?

  1. 链接方式:

    • 静态库:在编译时,静态库的代码会被完整地复制到可执行文件中。链接时,编译器将库的代码与应用程序代码合并成一个独立的可执行文件。这意味着可执行文件在运行时不依赖于外部的库文件。
    • 动态库:在编译时,动态库的代码不会被复制到可执行文件中。相反,可执行文件在运行时加载动态库,并在内存中共享库的代码和数据。这意味着可执行文件依赖于外部的库文件,并且可以与多个应用程序共享。
  2. 文件大小和内存占用:

    • 静态库:静态库将代码复制到可执行文件中,因此可执行文件的大小会增加。每个使用该静态库的可执行文件都包含该库的完整副本,因此占用的内存空间也会较大。

    • 动态库:动态库的代码不复制到可执行文件中,因此可执行文件的大小较小。多个应用程序可以共享同一个动态库的实例,因此内存占用可以被多个应用程序共享,减少了重复加载的开销。

  3. 更新和维护:

    • 静态库:静态库一旦被编译到可执行文件中,更新库的代码需要重新编译可执行文件。这意味着每个使用该静态库的应用程序都需要重新构建以包含最新版本的库。
    • 动态库:动态库可以被独立地更新,而不需要重新编译可执行文件。只需替换动态库文件即可,所有使用该库的应用程序都可以享受到更新的功能和修复的 bug。
  4. 可移植性:

    • 静态库:静态库是平台相关的,需要为每个目标平台编译不同的库文件。可执行文件与特定平台上的静态库文件紧密耦合,不易在不同平台上移植。
    • 动态库:动态库是平台独立的,可以在多个平台上共享使用。可执行文件只需要加载适应当前平台的动态库即可实现跨平台的移植性。

5.3 生成库文件

下面使用代码来演示一下生成静态库的过程,依然新建三个文件,Account.cppAccount.h CMakeLists.txt

linux cmake,# C/C++,linux,运维,服务器,原力计划
Account.cpp 内容如下:

#include "Account.h"
#include <iostream>

Account::Account(/* args */)
{
    std::cout << "构造函数Account::Account()" << std::endl;
}
Account::~Account()
{
    std::cout << "析构函数Account::~Account()" << std::endl;
}

Account.h 内容如下:

#ifndef Account_H
#define Account_H

class Account
{
private:
    /* data */
public:
    Account(/* args */);
    ~Account();
};


#endif // Account_H

CMakeLists.txt 内容如下:

#account_dir/CMakeLists.txt

# 最低版本要求
cmake_minimum_required(VERSION 3.10)

# 项目信息
project(Account)

# 添加静态库,Linux下会生成libAccount.a
# Account是库名,STATIC表示静态库,SHARED表示动态库,后面是源文件
add_library(Account STATIC Account.cpp Account.h)

add_library 生成动态库或静态库 (第 1 1 1 个参数指定库的名字;第 2 2 2 个参数决定是动态还是静态 (默认静态);第 3 3 3 个参数指定生成库的源文件)

准备完成后我们使用如下指定编译:

cmake -S . -B build
cmake --build build

linux cmake,# C/C++,linux,运维,服务器,原力计划

成功编译后我们就可以在 build 文件夹下看到我们以 .a 结尾的库文件了

linux cmake,# C/C++,linux,运维,服务器,原力计划


下面来演示更加复杂的例子,我们首先将上一步编译好的部分文件移除,下图高亮部分,也就是在build 目录下只留下 libAccount.a 文件:

linux cmake,# C/C++,linux,运维,服务器,原力计划

随后在 test_account 文件夹下新建如下两个文件:

mian.cpp 内容如下:

#include <iostream>
#include "Account.h"

int main()
{
    Account alice_account;
    std::cout << "main函数被调用" << std::endl;
    return 0;
}

CMakeLists.txt 内容如下:

# test_account/CMakeLists.txt

# 最低版本要求
cmake_minimum_required(VERSION 3.10)

# 项目名称
project(test_account)

# 添加执行文件
add_executable(test_account main.cpp)

# 指定目标包含的头文件目录
target_include_directories(test_account PUBLIC "../account_dir")
# 添加库文件目录,如果不添加,找不到库文件
target_link_directories(test_account PUBLIC "../account_dir/build")
# 指定目标链接的库
target_link_libraries(test_account PRIVATE Account)

通过 target_include_directories ,我们给 test_account 添加了头文件引用路径 "../account_dir"。上面的关键词 PUBLIC , PRIVATE 用于说明目标属性的作用范围。
通过 target_link_libraries ,将前面生成的静态库 libAccount.a 链接给对象 test_account ,但此时还没指定库文件的目录,CMake 无法定位库文件
再通过 target_link_directories ,添加库文件的目录即可。

准备完成后结构如下:

linux cmake,# C/C++,linux,运维,服务器,原力计划
进入 test_account 目录开始编译:

linux cmake,# C/C++,linux,运维,服务器,原力计划
编译后结构如下所示:
linux cmake,# C/C++,linux,运维,服务器,原力计划


6. CMake OpenCV 例子

安装 OpenCV 库:

sudo apt install libopencv-dev

main.cpp 代码如下:

#include <iostream>
#include <opencv2/opencv.hpp>


# 输入一张图像返回这张图象缩放后的灰度图
int main(int argc, char **argv)
{
    if (argc != 2)
    {
        std::cout << "请输入图片路径" << std::endl;
        return -1;
    }
    else
    {
        std::cout << "图片路径为:" << argv[1] << std::endl;

        cv::Mat image = cv::imread(argv[1]);
        cv::Mat image_resized;
        cv::resize(image, image_resized, cv::Size(400, 400));
        cv::cvtColor(image_resized, image_resized, cv::COLOR_BGR2GRAY);
        cv::imwrite("resized.png", image_resized);

        std::cout << "图片已处理完毕,并保存为resized.png" << std::endl;
    }

    return 0;
}

CMakeLists.txt 代码如下

cmake_minimum_required(VERSION 3.10)

project(demo_opencv)

find_package(OpenCV REQUIRED)

if (OpenCV_FOUND)
    message(STATUS "OpenCV library status:")
    message(STATUS "    libraries: ${OpenCV_LIBS}")
    message(STATUS "    include path: ${OpenCV_INCLUDE_DIRS}")
else ()
    message(FATAL_ERROR "Could not find OpenCV")
endif ()


add_executable(demo_opencv main.cpp)
target_include_directories(demo_opencv PRIVATE ${OpenCV_INCLUDE_DIRS})
target_link_libraries(demo_opencv ${OpenCV_LIBS})

linux cmake,# C/C++,linux,运维,服务器,原力计划
左侧为原图,右侧为缩放后的图


知识点整理较为混乱
TODO:后面应该多做几个真实案例


参考文献

Linux下CMake简明教程文章来源地址https://www.toymoban.com/news/detail-700224.html

到了这里,关于Linux 系统下 CMake 示 例的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【运维】Linux 跨服务器复制文件文件夹

    如果是云服务 建议用内网ip scp是secure copy的简写,用于在Linux下进行远程拷贝文件的命令,和它类似的命令有cp,不过cp只是在本机进行拷贝不能跨服务器,而且scp传输是加密的。可能会稍微影响一下速度。当你服务器硬盘变为只读 read only system时,用scp可以帮你把文件移出来

    2024年02月08日
    浏览(74)
  • 【Linux 服务器运维】定时任务 crontab 详解 | 文末送书

    本文思维导图概述的主要内容: 1.1 什么是 crontab Crontab 是一个在 Unix 和 Linux 操作系统上 用于定时执行任务 的工具。它允许用户创建和管理计划任务,以便在特定的时间间隔或时间点自动运行命令或脚本。Crontab 是 cron table 的缩写, cron 指的是 Unix 系统中的一个后台进程,它

    2024年02月08日
    浏览(92)
  • Linux 系统下 CMake 示 例

    CMake 是一个开源的跨平台工具,可以构建、测试和打包软件。 它具有如下特性: 自动搜索可能需要的程序、库和头文件的能力; 独立的构建目录(如 build ),可以安全清理; 支持复杂的自定义命令(下载、生成各种文件); 自定义配置可选组件; 从简单的文本文件( C

    2024年02月09日
    浏览(28)
  • 【Linux运维】shell脚本检查服务器内存和CPU利用率

    在管理服务器时候写了一个 shell脚本,在服务上实现每天凌晨3点查系统的指定文件夹下的容量大小,如果超过10G就要删除3天前的内容,还要时刻查询内存和cpu利用率,如果超过80%就要提示用户出现过载 将以上代码保存为一个.sh文件,然后通过crontab在每天凌晨3点运行即可:

    2024年02月09日
    浏览(67)
  • Linux服务器常见运维性能测试(1)综合跑分unixbench、superbench

    最近需要测试一批服务器的相关硬件性能,以及在常规环境下的硬件运行稳定情况,需要持续拷机测试稳定性。所以找了一些测试用例。本次测试包括在服务器的高低温下性能记录及压力测试,高低电压下性能记录及压力测试,常规环境下CPU满载稳定运行的功率记录。 这个系

    2024年02月04日
    浏览(82)
  • Linux本地部署1Panel服务器运维管理面板并实现公网访问

    1Panel 是一个现代化、开源的 Linux 服务器运维管理面板。高效管理,通过 Web 端轻松管理 Linux 服务器,包括主机监控、文件管理、数据库管理、容器管理等 下面我们介绍在Linux 本地安装1Panel 并结合cpolar 内网穿透工具实现远程访问1Panel 管理界面 执行如下命令一键安装 1Panel: 安

    2024年02月04日
    浏览(98)
  • [1Panel]开源,现代化,新一代的 Linux 服务器运维管理面板

    本期测评试用一下1Panel这款面板。1Panel是国内飞致云旗下开源产品。整个界面简洁清爽,后端使用GO开发,前端使用VUE的Element-Plus作为UI框架,整个面板的管理都是基于docker的,想法很先进。官方还提供了视频的使用教程,本期为大家按照本专栏的基本内容进行多方面的测评。

    2024年02月07日
    浏览(94)
  • Linux服务器常见运维性能测试(3)CPU测试super_pi、sysbench

    最近需要测试一批服务器的相关硬件性能,以及在常规环境下的硬件运行稳定情况,需要持续拷机测试稳定性。所以找了一些测试用例。本次测试包括在服务器的高低温下性能记录及压力测试,高低电压下性能记录及压力测试,常规环境下CPU满载稳定运行的功率记录。 这个系

    2024年02月02日
    浏览(55)
  • Linux系统安装Samba服务器

    在实际开发中,我们经常会有跨系统之间文件传递的需求,Samba 便是能够在 Windows 和 Linux 之间传递文件的服务,功能也是非常强大和好用,本篇文章将介绍如何在 Linux 系统上安装 Samba 服务,以 CentOS7 系统为例。 首先,我们通过 yum 包管理工具在 CentOS7 系统上安装 Samba 服务。

    2024年01月22日
    浏览(50)
  • Linux系统安装NFS服务器

    NFS是一种网络文件系统,英文全称Network File System,通过NFS可以让不同的主机系统之间共享文件或目录。通过NFS,用户可以直接在本地NFS客户端读写NFS服务端上的文件,是非常好的共享存储工具。本篇文章将介绍如何在CentOS7上安装NFS服务器,包括服务端和客户端安装两部分。

    2024年01月21日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包