1.如何使用CMake构建大型项目-c++ linux编程:从0实现muduo库系列

章节规划

MyMuduo是一个基于C++11的多线程网络库,参考陈硕的muduo实现。该库采用Reactor模式,以事件驱动和非阻塞I/O为核心,提供了高性能的网络,章节规划如下所示:

第一部分:基础设施

1.项目概述与环境搭建

  • muduo库整体架构介绍
  • 编译环境配置
  • CMake构建系统
  • 实现:CMakeLists.txt

2.基础类型与工具类

  • C++11特性介绍
  • 实现:Types.h
  • 实现:copyable.h和noncopyable.h
  • 实现:StringPiece.h

3.时间类的实现

  • 时间戳处理
  • 实现:Timestamp.h/cc
  • 实现:Date.h/cc
  • 实现:TimeZone.h/cc

4.异常处理机制

  • C++异常处理
  • 实现:Exception.h/cc
  • 堆栈跟踪的实现

5.日志系统基础

  • 实现:LogStream.h/cc
  • 实现:Logging.h/cc
  • 格式化输出

6.原子操作与互斥量

  • 实现:Atomic.h
  • 实现:Mutex.h
  • 实现:Condition.h/cc

7.线程安全的单例模式

  • 实现:Singleton.h
  • 实现:ThreadLocal.h
  • 实现:ThreadLocalSingleton.h

第二部分:线程库

1.线程基础设施

  • 实现:CurrentThread.h/cc
  • 线程标识符处理

2.线程类的实现

  • 实现:Thread.h/cc
  • RAII线程管理

3.阻塞队列的实现

  • 实现:BlockingQueue.h
  • 实现:BoundedBlockingQueue.h

4.日志系统进阶

  • 实现:AsyncLogging.h/cc
  • 实现:LogFile.h/cc
  • 实现:FileUtil.h/cc
  • 实现:Processinfo.h/cc

5.线程池的实现

  • 实现:ThreadPool.h/cc
  • 线程池调度策略

6.弱回调机制

  • 实现:WeakCallback.h
  • 解决循环引用问题

第三部分:网络库基础

1.网络地址封装

  • 实现:InetAddress.h/cc
  • IPv4/IPv6支持

2.Socket API封装(上)

  • 实现:SocketsOps.h/cc
  • 错误处理

3.Socket API封装(下)

  • 实现:Socket.h/cc
  • 套接字基础操作

4.Buffer设计与实现

  • 实现:Buffer.h/cc
  • 缓冲区管理

5.Channel和Poller设计与实现

  • 实现:Channel.h/cc
  • 实现:Poller.h/cc
  • 实现:poller/PollPoller.h/cc

6.EPollPoller设计与实现

  • 实现:poller/EPollPoller.h/cc

7.定时器实现

  • 实现:Timer.h/cc
  • 实现:TimerId.h
  • 实现:TimerQueue.h/cc
  • 定时任务管理

第四部分:网络库核心

1.接受器实现

  • 实现:Acceptor.h/cc
  • 新连接处理

2.连接器实现

  • 实现:Connector.h/cc
  • 客户端连接

3.事件循环线程

  • 实现:EventLoopThread.h/cc

4.事件循环线程池

  • 实现:EventLoopThreadPool.h/cc
  • 多IO线程架构

5.TCP连接的实现

  • 实现:TcpConnection.h/cc
  • 连接状态管理

6.TCP服务器的实现

  • 实现:TcpServer.h/cc
  • 服务器框架

7.TCP客户端的实现

  • 实现:TcpClient.h/cc
  • 客户端框架

8.事件循环Reactor

  • 测试 单epoll模型
  • 测试单epoll +线程池模型
  • 测试main reactor + sub reactor模型
  • 测试main reactor + sub reactor模型 + 线程池模型

1.本节重点

掌握如何构建大工程即可,CMakeLists.txt的很多细节可以后续有修改时再深入研究。

重点:

视频讲解(源码领取见视频):《C++Linux编程进阶:从0实现muduo》-第1讲.CMake构建大型项目

2.lesson1构建框架

每节课对应一个目录,比如lesson1/lesson2....,每章节新增内容基于前一章节的代码。

创建项目的基本结构。

mkdir -p mymuduo/lesson1

现在让我们创建项目的基本目录结构:

cd mymuduo/lesson1 
mkdir -p base net/poller net/http  examples 
lesson1/
├── CMakeLists.txt          # 主CMakeLists.txt文件
├── README.md               # 项目说明文件
├── base/                   # 基础库目录
│   ├── CMakeLists.txt      # base目录的CMakeLists.txt
│   └── Version.h           # 版本信息头文件
├── net/                    # 网络库目录
│   ├── CMakeLists.txt      # net目录的CMakeLists.txt
│   ├── http/               # HTTP相关代码目录
│   └── poller/             # 轮询器相关代码目录
├── examples/               # 示例代码目录
│   ├── CMakeLists.txt      # examples目录的CMakeLists.txt
│   └── hello-muduo.cc      # hello-muduo示例程序
├── build/                  # 构建输出目录

本质是通过add_subdirectory(子目录) 命令添加子目录的编译。

2.1 CMakeLists.txt指令说明

2.1.1 主要CMake指令说明

  • cmake_minimum_required(VERSION 3.10) - 指定CMake的最低版本要求
  • project(mymuduo C CXX) - 定义项目名称和使用的语言
  • set(CMAKE_CXX_STANDARD 17) - 设置C++标准为C++17
  • set(CMAKE_BUILD_TYPE "Release") - 设置构建类型为Release
  • set(CXX_FLAGS ...) - 设置C++编译选项
  • string(REPLACE ";" " " CMAKE_CXX_FLAGS "${CXX_FLAGS}") - 将列表转换为字符串
  • set(EXECUTABLE_OUTPUT_PATH ...) - 设置可执行文件输出路径
  • set(LIBRARY_OUTPUT_PATH ...) - 设置库文件输出路径
  • include_directories(${PROJECT_SOURCE_DIR}) - 添加包含目录
  • add_subdirectory(base) - 添加子目录base
  • add_subdirectory(net) - 添加子目录net
  • option(BUILD_EXAMPLES "Build examples" ON) - 定义是否构建示例的选项
  • add_subdirectory(examples) - 添加示例子目录
  • message(STATUS ...) - 打印状态信息

2.1.2 子目录CMakeLists.txt中的指令

base/CMakeLists.txt

  • set(base_SRCS ...) - 设置base库的源文件列表(暂时注释)
  • add_library(mymuduo_base ${base_SRCS}) - 添加库目标(暂时注释)
  • target_link_libraries(mymuduo_base pthread rt) - 链接库(暂时注释)
  • install(TARGETS mymuduo_base DESTINATION lib) - 安装目标(暂时注释)
  • file(GLOB HEADERS "*.h") - 收集所有头文件
  • install(FILES ${HEADERS} DESTINATION include/mymuduo/base) - 安装头文件

net/CMakeLists.txt

  • set(net_SRCS ...) - 设置net库的源文件列表(暂时注释)
  • add_library(mymuduo_net ${net_SRCS}) - 添加库目标(暂时注释)
  • target_link_libraries(mymuduo_net mymuduo_base pthread) - 链接库(暂时注释)
  • install(TARGETS mymuduo_net DESTINATION lib) - 安装目标(暂时注释)
  • file(GLOB HEADERS "*.h") - 收集所有头文件
  • install(FILES ${HEADERS} DESTINATION include/mymuduo/net) - 安装头文件
  • add_subdirectory(http) - 添加http子目录
  • add_subdirectory(poller) - 添加poller子目录

examples/CMakeLists.txt

  • if(NOT CMAKE_BUILD_NO_EXAMPLES) - 条件判断是否构建示例
  • add_executable(hello-muduo hello-muduo.cc) - 添加可执行文件目标

2.1.3 编译参数说明

让我为您解释这三个 CMake 变量的作用和关系:

1.CMAKE_CXX_FLAGS

  • 这是基础的 C++ 编译选项
  • 这些选项会应用到所有的构建类型(Debug、Release 等)
  • 通常包含一些通用的编译选项,比如警告级别、架构设置等
  • 在我们的例子中,包含了 -Wall、-Wextra 等通用选项

2.CMAKE_CXX_FLAGS_DEBUG

  • 这是 Debug 模式特有的编译选项
  • 只在 Debug 构建时使用
  • 通常包含调试相关的选项,如 -g(生成调试信息)
  • 在我们的例子中,设置了 -g -O0 -DDEBUG
  • 这些选项会与 CMAKE_CXX_FLAGS 中的选项合并

3.CMAKE_CXX_FLAGS_RELEASE

  • 这是 Release 模式特有的编译选项
  • 只在 Release 构建时使用
  • 通常包含优化相关的选项,如 -O2(优化级别)
  • 在我们的例子中,设置了 -O2 -DNDEBUG
  • 这些选项也会与 CMAKE_CXX_FLAGS 中的选项合并

它们的关系是:

  • 当构建 Debug 版本时,最终的编译选项是:CMAKE_CXX_FLAGS + CMAKE_CXX_FLAGS_DEBUG
  • 当构建 Release 版本时,最终的编译选项是:CMAKE_CXX_FLAGS + CMAKE_CXX_FLAGS_RELEASE

例如,在我们的配置中:

  • Debug 模式下的完整编译选项会是:
-Wall -Wextra -Werror ... (来自CMAKE_CXX_FLAGS)
-g -O0 -DDEBUG (来自CMAKE_CXX_FLAGS_DEBUG)
  • Release 模式下的完整编译选项会是:
-Wall -Wextra -Werror ... (来自CMAKE_CXX_FLAGS)
-O2 -DNDEBUG (来自CMAKE_CXX_FLAGS_RELEASE)

这种设计允许我们:

  1. 在 CMAKE_CXX_FLAGS 中设置所有构建类型共用的选项
  2. 在 CMAKE_CXX_FLAGS_DEBUG 和 CMAKE_CXX_FLAGS_RELEASE 中设置特定构建类型的选项
  3. 通过切换 CMAKE_BUILD_TYPE 来使用不同的编译选项组合

2.2 范例测试

lesson1/base/Version.h

让我们创建一个简单的版本头文件,用于定义库的版本信息:

#ifndef MYMUDUO_BASE_VERSION_H
#define MYMUDUO_BASE_VERSION_H

namespace mymuduo
{

inline const char* version()
{
    return "1.0.0";
}

}  // namespace mymuduo

#endif  // MYMUDUO_BASE_VERSION_H 

对应测试文件

lesson1/examples/hello-muduo.cc

#include <iostream>
#include "base/Version.h"
using namespace mymuduo;
int main() {
    std::cout << "Hello, Muduo!" << std::endl;
    std::cout << "muduo version: " << version() << std::endl;
    return 0;
}

要验证环境配置是否正确,可以执行以下命令:

cd mymuduo/lesson1
mkdir build
cd build
cmake ..
make

执行命令

./bin/hello-muduo

打印:

3 小节

这一章节大致理解cmake构建框架就行,不需要一下子就读懂每一行CMakeLists.txt,这个是没有必要的,只需要理解在各个CMakeLists.txt依赖关系就行。

4 进阶参考

这里只是作为后续在使用cmake构建项目时不知道如何规划时可以作为参考,目前不用花时间去研究。

4.1 CMake常见目录变量及其区别

PROJECT_SOURCE_DIR

  • 表示当前项目的源代码根目录
  • 指向包含顶层CMakeLists.txt的目录
  • 在我们的项目中,指向lesson1目录

其他常见CMake目录变量

1.CMAKE_SOURCE_DIR

  • 表示整个源代码树的根目录
  • 指向最顶层的CMakeLists.txt所在目录
  • 在单项目中与PROJECT_SOURCE_DIR相同,在多项目中指向最顶层项目

2.CMAKE_CURRENT_SOURCE_DIR

  • 表示当前处理的CMakeLists.txt所在的目录
  • 在子目录中会改变,如在lesson1/base/CMakeLists.txt中指向lesson1/base

3.PROJECT_BINARY_DIR

  • 表示当前项目的构建目录
  • 在我们的项目中,指向lesson1/build

4.CMAKE_BINARY_DIR

  • 表示整个构建树的根目录
  • 指向CMake执行的目录
  • 在单项目中与PROJECT_BINARY_DIR相同

5.CMAKE_CURRENT_BINARY_DIR

  • 表示当前处理的CMakeLists.txt对应的构建目录
  • 在子目录中会改变,如在lesson1/base/CMakeLists.txt中指向lesson1/build/base

6.CMAKE_INSTALL_PREFIX

  • 表示安装目标的根目录
  • 默认为/usr/local(Unix系统)或c:/Program Files/${PROJECT_NAME}(Windows系统)

7.CMAKE_MODULE_PATH

  • 表示CMake模块的搜索路径
  • 用于查找额外的CMake模块

8.CMAKE_CURRENT_LIST_DIR

  • 表示当前正在处理的CMake文件的完整目录
  • 与CMAKE_CURRENT_SOURCE_DIR类似,但在include()命令中更可靠

框图说明

4.2 我们项目中的实际应用

在muduo项目中的目录变量具体值

muduo项目中CMake目录变量的具体值(文本形式)

  • CMAKE_SOURCE_DIR: /home/lqf/long/spark_muduo/lesson1
  • PROJECT_SOURCE_DIR: /home/lqf/long/spark_muduo/lesson1
  • CMAKE_CURRENT_SOURCE_DIR:
  • 根目录CMakeLists.txt中: /home/lqf/long/spark_muduo/lesson1
  • base/CMakeLists.txt中: /home/lqf/long/spark_muduo/lesson1/base
  • net/CMakeLists.txt中: /home/lqf/long/spark_muduo/lesson1/net
  • CMAKE_BINARY_DIR: /home/lqf/long/spark_muduo/lesson1/build
  • PROJECT_BINARY_DIR: /home/lqf/long/spark_muduo/lesson1/build
  • CMAKE_CURRENT_BINARY_DIR:
  • 根目录CMakeLists.txt中: /home/lqf/long/spark_muduo/lesson1/build
  • base/CMakeLists.txt中: /home/lqf/long/spark_muduo/lesson1/build/base
  • net/CMakeLists.txt中: /home/lqf/long/spark_muduo/lesson1/build/net
  • EXECUTABLE_OUTPUT_PATH: /home/lqf/long/spark_muduo/lesson1/build/bin
  • LIBRARY_OUTPUT_PATH: /home/lqf/long/spark_muduo/lesson1/build/lib

这些变量在CMake构建系统中帮助我们引用正确的路径,使项目构建更加灵活和可移植。

#实习##校招##c++后端##牛客创作赏金赛#
全部评论

相关推荐

评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客企业服务