C++服务器框架开发11——编译调试1/cmake学习

news2024/11/21 2:30:23

该专栏记录了在学习一个开发项目的过程中遇到的疑惑和问题。
其教学视频见:[C++高级教程]从零开始开发服务器框架(sylar)

上一篇:C++服务器框架开发10——日志系统1~9代码

C++服务器框架开发11——编译调试1/cmake学习

  • 目前进度
  • ubuntu下的cmake学习
    • 简单样例
    • 同一目录下多个源文件
    • 不同目录下多个源文件
    • 正式一点的组织结构
    • 动态库和静态库的编译控制
    • 对库进行链接
    • 添加编译选项
    • 添加控制选项
      • 本来要生成多个bin或库文件,现在只想生成部分指定的bin或库文件
      • 对于同一个bin文件,只想编译其中部分代码(使用宏来控制)
  • 回顾图1

目前进度

学习到第6个视频的00:59,由于不了解编译,这次先学习下cmake。下图是CMakeLists.txt中的内容。
在这里插入图片描述

ubuntu下的cmake学习

参考自文章1
“CMake是一个跨平台的编译(Build)工具, 不同平台之间的编译方式遵循不同的规则,彼此不通用。因此 Cmake被提出,他统一了一套规则, 来描述所有平台的编译过程。
它允许开发者编写一种平台无关的 CMakeLists.txt 文件来定制整个编译流程,然后再根据目标用户的平台进一步生成所需的本地化 Makefile 和工程文件,如 Unix 的 Makefile 或 Windows 的 Visual Studio 工程。”
以下内容基本上都是学习的文章1。

简单样例

在这里插入图片描述
在文件目录下创建这两个文件,内容如下:
main.c,输出一个字符串。

#include <stdio.h>

int main(void)
{
	printf("Hello World\n");

	return 0;
}

CMakeLists.txt,其中各行的意思都有进行注释说明。

# 指定所需 CMake 的最低版本
cmake_minimum_required (VERSION 2.8)
# 项目的名称 demo
project (demo)
# 将名为 main.c 的源文件编译成一个名称为 main 的可执行文件
add_executable(main main.c)

在该目录下打开一个终端,执行cmake ./得到makefile。
执行过程:
在这里插入图片描述
执行后目录下的文件:
在这里插入图片描述
执行make进行编译。
执行过程:
在这里插入图片描述
执行后目录下多了一个main的可执行文件。
在这里插入图片描述
运行main看看效果:
在这里插入图片描述
如果想重新生成,可以先执行make clean来删除已有的main文件。

同一目录下多个源文件

上面的例子是只有一个源文件的,如果有多个的话,如下:
在这里插入图片描述

main.c调用调用testFunc.h里声明的函数func()。
main.c:

#include <stdio.h>

#include "testFunc.h"

int main(void)
{
	func(100);

	return 0;
}

testFunc.h:

/*
** testFunc.h
*/

#ifndef _TEST_FUNC_H_
#define _TEST_FUNC_H_

void func(int data);

#endif

testFunc.c:

/*
** testFunc.c
*/

#include <stdio.h>
#include "testFunc.h"

void func(int data)
{
	printf("data is %d\n", data);
}

CMakeLists.txt:

# 指定所需 CMake 的最低版本
cmake_minimum_required (VERSION 2.8)
# 项目的名称 demo  
project (demo)
# 将名为 main.c 和testFunc.c的源文件编译成一个名称为 main 的可执行文件
add_executable(main main.c testFunc.c)

cmake 和make:
在这里插入图片描述
运行:
在这里插入图片描述
如果有很多源文件,这种方法就不太方便。可以使用aux_source_directory(dir var),这个命令将目录dir下的所有源文件存储在变量var中。
例子:
在这里插入图片描述
main.c:

#include <stdio.h>

#include "testFunc.h"
#include "testFunc1.h"

int main(void)
{
	func(100);
	func1(200);

	return 0;
}

testFunc1.c:

/*
** testFunc1.c
*/

#include <stdio.h>
#include "testFunc1.h"

void func1(int data)
{
	printf("data is %d\n", data);
}

testFunc1.h:

/*
** testFunc1.h
*/

#ifndef _TEST_FUNC1_H_
#define _TEST_FUNC1_H_

void func1(int data);

#endif

CMakeLists.txt:

# 指定所需 CMake 的最低版本
cmake_minimum_required (VERSION 2.8)
# 项目的名称 demo  
project (demo)
#把当前目录下的源文件存放到变量SRC_LIST里
aux_source_directory(. SRC_LIST)
# 将SRC_LIST里的源文件编译成一个名称为 main 的可执行文件
add_executable(main ${SRC_LIST})

cmake 和make,并执行:
在这里插入图片描述
如果不想把所有源文件都进行编译,可以用set来指定想要编译的源文件,对应的CMakeLists.txt可以修改为如下:

# 指定所需 CMake 的最低版本
cmake_minimum_required (VERSION 2.8)
# 项目的名称 demo  
project (demo)
#把当前目录下的源文件存放到变量SRC_LIST里
set( SRC_LIST
	 ./main.c
	 ./testFunc1.c
	 ./testFunc.c)
# 将SRC_LIST里的源文件编译成一个名称为 main 的可执行文件
add_executable(main ${SRC_LIST})

不同目录下多个源文件

假设文件目录如下:
在这里插入图片描述
修改CMakeLists.txt

# 指定所需 CMake 的最低版本
cmake_minimum_required (VERSION 2.8)
# 项目的名称 demo  
project (demo)
#由于main.c中include了两个.h文件,所以需要添加头文件的搜索路径
include_directories (test_func test_func1)
#把两个目录下的源文件分别存放到变量SRC_LIST和SRC_LIST1里
aux_source_directory (test_func SRC_LIST)
aux_source_directory (test_func1 SRC_LIST1)
# 将SRC_LIST里的源文件编译成一个名称为 main 的可执行文件
add_executable(main ${SRC_LIST} ${SRC_LIST1})

其中的include_directories (test_func test_func1)作用已经在注释里了。

正式一点的组织结构

src:源文件目录
include:头文件目录
build:生成的对象文件
bin:可执行文件。
结构调整如下:
在这里插入图片描述
CMakeLists.txt:

# 指定所需 CMake 的最低版本
cmake_minimum_required (VERSION 2.8)
# 项目的名称 demo  
project (demo)
#添加并构建子目录src
add_subdirectory(./src)

其中的add_subdirectory(src)指定src为源文件的存放位置,camke时回去src目录进行编译。
src/CMakeLists.txt:


#添加头文件的搜索路径
include_directories (../include)
#把源文件存放到变量SRC_LIST里
aux_source_directory (. SRC_LIST)
# 将SRC_LIST里的源文件编译成一个名称为 main 的可执行文件
add_executable(main ${SRC_LIST} )
#设置存放可执行文件的位置
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

其中set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)把存放可执行文件的位置设置为工程根目录下的bin目录。

为了让生成的对象文件放在build里,需要再build目录下打开终端,然后执行cmake ..,接着make
在这里插入图片描述
在这里插入图片描述
另一种方法,可以把子目录src中的cmakelists内容放到外层目录中来,只用一个camkelists。如下:
CMakeLists.txt:

# 指定所需 CMake 的最低版本
cmake_minimum_required (VERSION 2.8)
# 项目的名称 demo  
project (demo)

#添加头文件的搜索路径
include_directories (./include)
#把源文件存放到变量SRC_LIST里
aux_source_directory (./src SRC_LIST)
# 将SRC_LIST里的源文件编译成一个名称为 main 的可执行文件
add_executable(main ${SRC_LIST} )
#设置存放可执行文件的位置
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

build目录下cmake ../, 然后make,最后执行。
在这里插入图片描述

动态库和静态库的编译控制

目录结构如下
在这里插入图片描述
把生成的库放在lib里。

CMakeLists.txt:

# 指定所需 CMake 的最低版本
cmake_minimum_required (VERSION 2.8)
# 项目的名称 demo  
project (demo)

#把文件testFunc.c存放到变量SRC_LIST里
set (SRC_LIST ${PROJECT_SOURCE_DIR}/testFunc/testFunc.c)

#生成库,库名字为testFunc_shared,设置为SHARED(动态库,不设置的话默认为静态),源文件为SRC_LIST
add_library (testFunc_shared SHARED ${SRC_LIST})
#生成库,库名字为testFunc_static,设置为STATIC(静态库,不设置的话默认为静态),源文件为SRC_LIST
add_library (testFunc_static STATIC ${SRC_LIST})

#设置动态库testFunc_shared文件名称为libtestFunc.so
set_target_properties (testFunc_shared PROPERTIES OUTPUT_NAME "testFunc")
#设置静态库testFunc_static文件名称为libtestFunc.a
set_target_properties (testFunc_static PROPERTIES OUTPUT_NAME "testFunc")

#设置库文件的输出路径为./lib
set (LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)

add_library: 生成动态库或静态库。
set_target_properties: 设置最终生成的库的名称。
LIBRARY_OUTPUT_PATH: 库文件的默认输出路径。

build目录下cmake ../, 然后make
在这里插入图片描述
查看子目录lib
在这里插入图片描述

对库进行链接

重新构建如下工程,并把上一小节的生成的库放到./testFunc/lib下。
在这里插入图片描述
main.c:

#include <stdio.h>

#include "testFunc.h"

int main(void)
{
    func(100);
    
    return 0;
}

testFunc.h:

/*
** testFunc.h
*/

#ifndef _TEST_FUNC_H_
#define _TEST_FUNC_H_

void func(int data);

#endif

CMakeLists.txt:

# 指定所需 CMake 的最低版本
cmake_minimum_required (VERSION 2.8)
# 项目的名称 demo  
project (demo)

#设置可执行文件的输出路径为./bin
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
#把文件main.c存放到变量SRC_LIST里
set (SRC_LIST ${PROJECT_SOURCE_DIR}/src/main.c)
# 添加头文件的搜索路径
include_directories (${PROJECT_SOURCE_DIR}/testFunc/inc)
#在指定目录./testFunc/lib查找制定库testFunc
find_library(TESTFUNC_LIB testFunc HINTS ${PROJECT_SOURCE_DIR}/testFunc/lib)
#将SRC_LIST里的源文件编译成一个名称为 main 的可执行文件
add_executable (main ${SRC_LIST})
#把目标文件与库文件进行链接
target_link_libraries (main ${TESTFUNC_LIB})


find_library: 在指定目录下查找指定库。
target_link_libraries: 把目标文件与库文件进行链接。

build目录下cmake ../, 然后make,最后执行。
在这里插入图片描述

查看可执行文件使用了那些库readelf -d ../bin/main
在这里插入图片描述

添加编译选项

有时编译程序时想添加一些编译选项,如-Wall-std=c++11等,就可以使用add_compile_options来进行操作。
这里可以去看原文章的简单示例。

添加控制选项

如果想要在编译代码时只编译一些指定的源码,可以使用cmake的option命令。

本来要生成多个bin或库文件,现在只想生成部分指定的bin或库文件

如下结构:
在这里插入图片描述
main1.c:

// main1.c
#include <stdio.h>

int main(void)
{
    printf("hello, this main1\n");
    
    return 0;
}

main2.c:

// main2.c
#include <stdio.h>

int main(void)
{
    printf("hello, this main2\n");
    
    return 0;
}

CMakeLists.txt:

# 指定所需 CMake 的最低版本
cmake_minimum_required (VERSION 2.8)
# 项目的名称 demo  
project (demo)
#设置一个option,名称为MYDEBUG,提示为"enable debug compilation",第3个参数的默认值是OFF。
option(MYDEBUG "enable debug compilation" OFF)
#设置存放可执行文件的位置
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
#添加并构建子目录src
add_subdirectory(./src)

./src/CMakeLists.txt:

# 指定所需 CMake 的最低版本
cmake_minimum_required (VERSION 2.8)

#将源文件main1.c编译成一个名称为 main1 的可执行文件
add_executable(main1 main1.c)
#如果MYDEBUG为NO则将源文件main2.c编译成一个名称为 main2 的可执行文件
if (MYDEBUG)
    add_executable(main2 main2.c)
else()
    message(STATUS "Currently is not in debug mode")    
endif()

build目录下cmake ../, 然后make,最后查看bin目录。
在这里插入图片描述

对于同一个bin文件,只想编译其中部分代码(使用宏来控制)

结构如下:
在这里插入图片描述
main.c:

#include <stdio.h>

int main(void)
{
#ifdef WWW1
    printf("hello world1\n");
#endif    

#ifdef WWW2     
    printf("hello world2\n");
#endif

    return 0;
}

CMakeLists.txt:

# 指定所需 CMake 的最低版本
cmake_minimum_required (VERSION 2.8)
# 项目的名称 demo  
project (demo)

#设置存放可执行文件的位置
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
#设置一个option,名称为WWW1,提示为"print one message",第3个参数的默认值是OFF。
option(WWW1 "print one message" OFF)
#设置一个option,名称为WWW2,提示为"print another message",第3个参数的默认值是OFF。
option(WWW2 "print another message" OFF)

#使用add_definitions()函数控制代码的开启和关闭
if (WWW1)
    add_definitions(-DWWW1)
endif()

if (WWW2)
    add_definitions(-DWWW2)
endif()
#将源文件main.c编译成一个名称为 main 的可执行文件
add_executable(main main.c)

只想编译WWW1里的内容:
build目录下cmake ../ -DWWW1=ON -DWWW2=OFF, 然后make,最后执行。
在这里插入图片描述
只想编译WWW2里的内容:
build目录下cmake ../ -DWWW1=OFF -DWWW2=ON, 然后make,最后执行。
在这里插入图片描述
编译WWW1和WWW2里的内容:
build目录下cmake ../ -DWWW1=ON -DWWW2=ON, 然后make,最后执行。
在这里插入图片描述
:每次重新编译时,记得把build和bin中的文件删掉,否则build中的文件会影响下次编译,比如我第一次编译设置了WWW1,如果我没有删除build中文件,那么如果我第二次编译时没设置WWW1,WWW1将是上次编译时的设置。

这是我对cmake的所有学习记录,学习资料来自https://blog.csdn.net/whahu1989/article/details/82078563。这篇文章非常详细,我基本上理解清楚了cmake的基本用法。

回顾图1

在这里插入图片描述
set(CMAKE_VERBOSE_MAKEFILE ON)是显示原始编译信息,用于定位链接报错。
set(CMAKE_CXX_FLAGS "$ENV{CXXFLAGS} -rdynamic -O3 -fPIC -ggdb -std=c++11 -Wall -Wno-deprecated -Werror -Wno-unused-function")是编译选项设置,具体可以看这两篇文章:2和3。
add_dependencies(test sylar)是因为,编译可执行文件test时需要链接依sylar,而sylar也是通过编译得到的。所以设置这个后,当检测到依赖库sylar还没编译时,会先编译依赖库,然后再编译test。

这次笔记时隔很久,一是其他事情耽搁了,二是camke原先根本不会,三是这个笔记有点长。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/755491.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【论文笔记】SINE: SINgle Image Editing with Text-to-Image Diffusion Models

声明 不定期更新自己精度论文&#xff0c;通俗易懂&#xff0c;初级小白也可以理解 涉及范围&#xff1a;深度学习方向&#xff0c;包括 CV、NLP 论文标题&#xff1a;SINE: SINgle Image Editing with Text-to-Image Diffusion Models 论文链接&#xff1a;https://www.seman…

ESXI 安装win10详细步骤

在esix安装win10安装过程遇到了坑&#xff0c;发现必须对具体选项进行设置后才可&#xff0c;做下记录&#xff1a; 1、CPU设置 &#xff12;、硬盘 3、网络适配器 4、驱动器 5、虚拟机选项

LangChain大型语言模型(LLM)应用开发(四):QA over Documents

LangChain是一个基于大语言模型&#xff08;如ChatGPT&#xff09;用于构建端到端语言模型应用的 Python 框架。它提供了一套工具、组件和接口&#xff0c;可简化创建由大型语言模型 (LLM) 和聊天模型提供支持的应用程序的过程。LangChain 可以轻松管理与语言模型的交互&#x…

动手学深度学习——图像分类数据集(代码详解)

目录 1. 图像分类数据集1.1 读取数据集1.2 读取小批量1.3 整合所有组件1.4 小结 1. 图像分类数据集 这里采用Fashion-MNIST数据集 torchvision&#xff1a;torch类型的可视化包&#xff0c;一般计算机视觉和数据可视化需要使用from torchvision import transforms&#xff1a;…

kotlin forEach循环return/break

kotlin forEach循环return/break fun main(args: Array<String>) {var a mutableListOf("0", "1", "2", "3", "4")var b mutableListOf<String>()a.forEachIndexed { index, s ->if (index > 2) {retu…

CGY-OS 正式开源!

一个初中生自己编写的一个很LOW的“OS”&#xff0c;编写不易&#xff0c;不喜勿喷&#xff1b;耗时巨大&#xff0c;引用时请说明。 接下来&#xff0c;让我们一起学习使用cgyOS。 零、配置 下载本程序后&#xff0c;在Python3.10环境下使用pip安装pygame和keyboard的最新版本…

Java二叉树

目录 一、树形结构 1.1 概念 1.2 树的性质 1.3 树的表示形式 二、二叉树 2.1 概念 2.2 两种特殊的二叉树 2.3 二叉树的性质 2.4 二叉树的存储 2.5 二叉树的基本操作 2.5.1 二叉树的遍历 2.5.2 二叉树的基本操作 一、树形结构 1.1 概念 树是一种非线性的数据结构&#xff0…

H3C-Cloud Lab-实验-DHCP中继实验

实验需求&#xff1a; 1、按照图示配置IP地址 2、配置R1为DHCP服务器&#xff0c;能够跨网段为192.168.2.0/24网段自动分配IP地址。要求分配DNS地址为202.103.24.68和202.103.0.117 3、PC3获取IP地址后&#xff0c;能够访问到192.168.1.1 实验拓扑图&#xff1a; 连接CRT 设…

Linux5.97 Ceph集群

文章目录 计算机系统5G云计算第四章 LINUX Ceph集群一、Ceph1.存储基础1&#xff09;单机存储设备2&#xff09;单机存储的问题3&#xff09;商业存储解决方案4&#xff09;分布式存储&#xff08;软件定义的存储 SDS&#xff09;5&#xff09;分布式存储的类型 2.Ceph 简介3.C…

tmux安装及使用

tmux安装及使用 tmux是一款很好使用的终端工具&#xff0c;配合shell脚本使用非常方便。 一、tmux安装 终端输入命令&#xff1a; sudo apt-get install tmux二、tmux使用 首先需要对tmux使用的名词有一个基本了解&#xff1a; session &#xff1a;会话 window : 窗口 pa…

职责链(Chain of responsibility)模式

目录 处理过程应用场景参与者协作效果实现相关模式应用与思考类图 职责链(Chain of responsibility)是一种对象行为模式&#xff0c;可以使多个对象都有机会处理请求&#xff0c;从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链&#xff0c;并沿着这条链传递…

快速配置 Rust 开发环境并编写一个小应用

安装: curl --proto https --tlsv1.2 -sSf https://sh.rustup.rs | sh 更新: Rust 的升级非常频繁. 如果安装 Rustup 后已有一段时间,那么很可能 Rust 版本已经过时, 运行 rustup update 获取最新版本的 Rust rustc&#xff1a;编译Rust程序 rustc只适合简单的Rust程序&#xf…

5G全网通工业三防平板Windows移动电脑

当今科技领域的快速发展为我们的生活带来了许多便利和高效性能。在这个数字化时代&#xff0c;移动设备已成为我们生活的重要组成部分。在这一领域&#xff0c;搭载全新第12代英特尔酷睿Mi5-1235U/i7-1255U处理器的工业三防平板Windows移动电脑无疑是一款引人注目的产品。 这款…

mysql获取附近的店并显示当前距离并由近到远显示

1、创建测试数据 CREATE TABLE store (id int(11) NOT NULL AUTO_INCREMENT,name varchar(50) NOT NULL COMMENT 商家名称,address varchar(200) NOT NULL COMMENT 商家地址,coordinates varchar(50) NOT NULL COMMENT 经纬度,PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT…

阿卡西斯 USB4 雷电4 移动硬盘盒做Mac系统盘 体验

硬盘盒(USB4 JHL7440 RTL9210B) 无风扇版本(型号 TBU405 659RMB). 发热大 所以官方出了带风扇版本,我的是不带风扇的. 我是三星990pro组合. 我是把mac系统直接安装到硬盘盒的硬盘里面里面 这是刚买时候的速度 这是当系统重度使用(写代码 大数据环境) 4个月后的硬盘速度测试…

DBeaver设置主题

一、下载包 帮助-》Install new software Eclipse Update Site 勾选一直下一步&#xff0c;直到安装完&#xff0c;会提示重启&#xff0c;重启设置主题即可 二、设置主题 窗口-》首选项-》DevStyle

快速上手一个I2C传感器 | MAX6884

老老实实看DataSheet吧&#xff0c;查找手册有以下几种途径&#xff1a; 1&#xff09;到芯片厂商官网去下载资料&#xff1b; 2&#xff09;在芯片器件采购平台搜索&#xff0c;如立创商城、半导小芯&#xff1b; 有原厂或代理翻译的中文手册&#xff0c;或者国产芯片中文手…

leetcode 450. 删除二叉搜索树中的节点

2023.7.14 搜索二叉树相关的题一般都能用递归解决。 本体大致思路是&#xff1a;使用递归的方式&#xff0c;在树中查找目标节点&#xff0c;并根据节点的情况进行删除操作。如果目标节点是叶子节点&#xff0c;直接删除它&#xff1b;如果目标节点只有一个子树&#xff0c;将子…

H3C-Cloud Lab-实验-ACL实验

实验拓扑图&#xff1a; 网段分布情况&#xff1a; 实验需求&#xff1a; 1. 按照图示配置 IP 地址 2. 全网路由互通 3. 在 SERVER1 上配置开启 TELNET 和 FTP 服务 4. 配置 ACL 实现如下效果 1&#xff09;192.168.1.0/24 网段不允许访问 192.168.2.0/24 网段&#xff0c…

【雕爷学编程】Arduino动手做(162)---OPT101模拟光照传感器模块3

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…