CppGuide社区 CppGuide社区
首页
  • 最新谷歌C++风格指南(含C++17/20)
  • C++17详解
  • C++20完全指南
  • C++23快速入门
  • C++语言面试问题集锦
  • 🔥C/C++后端开发常见面试题解析 (opens new window)
  • 网络编程面试题 (opens new window)
  • 网络编程面试题 答案详解 (opens new window)
  • 聊聊WebServer作面试项目那些事儿 (opens new window)
  • 字节跳动面试官现身说 (opens new window)
  • 技术简历指南 (opens new window)
  • 🔥交易系统开发岗位求职与面试指南 (opens new window)
  • 第1章 高频C++11重难点知识解析
  • 第2章 Linux GDB高级调试指南
  • 第3章 C++多线程编程从入门到进阶
  • 第4章 C++网络编程重难点解析
  • 第5章 网络通信故障排查常用命令
  • 第6章 高性能网络通信协议设计精要
  • 第7章 高性能服务结构设计
  • 第8章 Redis网络通信模块源码分析
  • 第9章 后端服务重要模块设计探索
  • 🚀 全部章节.pdf 下载 (opens new window)
  • 源码分析系列

    • leveldb源码分析
    • libevent源码分析
    • Memcached源码分析
    • TeamTalk源码分析
    • 优质源码分享 (opens new window)
    • 🔥远程控制软件gh0st源码分析
  • 从零手写C++项目系列

    • C++游戏编程入门(零基础学C++)
    • 🔥使用C++17从零开发一个调试器 (opens new window)
    • 🔥使用C++20从零构建一个完整的低延迟交易系统 (opens new window)
    • 🔥使用C++从零写一个C语言编译器 (opens new window)
    • 从零用C语言写一个Redis
  • Windows 10系统编程
  • Go语言特性

    • Go开发实用指南
    • Go系统接口编程
    • 高效Go并发编程
    • Go性能调优
    • Go项目架构设计
  • Go项目实战

    • 使用Go从零开发一个数据库
    • 🔥使用Go从零开发一个编译器 (opens new window)
    • 🔥使用Go从零开发一个解释器 (opens new window)
    • 🔥用Go从零写一个编排器(类Kubernetes) (opens new window)
  • Rust编程

    • Rust编程指南
  • 数据库

    • SQL零基础指南
    • MySQL开发与调试指南
  • Linux内核

    • 心中的内核 —— 在阅读内核代码之前先理解内核
    • 🔥Linux 5.x内核开发与调试 完全指南 (opens new window)
    • TCP源码实现超详细注释版.pdf (opens new window)
GitHub (opens new window)
首页
  • 最新谷歌C++风格指南(含C++17/20)
  • C++17详解
  • C++20完全指南
  • C++23快速入门
  • C++语言面试问题集锦
  • 🔥C/C++后端开发常见面试题解析 (opens new window)
  • 网络编程面试题 (opens new window)
  • 网络编程面试题 答案详解 (opens new window)
  • 聊聊WebServer作面试项目那些事儿 (opens new window)
  • 字节跳动面试官现身说 (opens new window)
  • 技术简历指南 (opens new window)
  • 🔥交易系统开发岗位求职与面试指南 (opens new window)
  • 第1章 高频C++11重难点知识解析
  • 第2章 Linux GDB高级调试指南
  • 第3章 C++多线程编程从入门到进阶
  • 第4章 C++网络编程重难点解析
  • 第5章 网络通信故障排查常用命令
  • 第6章 高性能网络通信协议设计精要
  • 第7章 高性能服务结构设计
  • 第8章 Redis网络通信模块源码分析
  • 第9章 后端服务重要模块设计探索
  • 🚀 全部章节.pdf 下载 (opens new window)
  • 源码分析系列

    • leveldb源码分析
    • libevent源码分析
    • Memcached源码分析
    • TeamTalk源码分析
    • 优质源码分享 (opens new window)
    • 🔥远程控制软件gh0st源码分析
  • 从零手写C++项目系列

    • C++游戏编程入门(零基础学C++)
    • 🔥使用C++17从零开发一个调试器 (opens new window)
    • 🔥使用C++20从零构建一个完整的低延迟交易系统 (opens new window)
    • 🔥使用C++从零写一个C语言编译器 (opens new window)
    • 从零用C语言写一个Redis
  • Windows 10系统编程
  • Go语言特性

    • Go开发实用指南
    • Go系统接口编程
    • 高效Go并发编程
    • Go性能调优
    • Go项目架构设计
  • Go项目实战

    • 使用Go从零开发一个数据库
    • 🔥使用Go从零开发一个编译器 (opens new window)
    • 🔥使用Go从零开发一个解释器 (opens new window)
    • 🔥用Go从零写一个编排器(类Kubernetes) (opens new window)
  • Rust编程

    • Rust编程指南
  • 数据库

    • SQL零基础指南
    • MySQL开发与调试指南
  • Linux内核

    • 心中的内核 —— 在阅读内核代码之前先理解内核
    • 🔥Linux 5.x内核开发与调试 完全指南 (opens new window)
    • TCP源码实现超详细注释版.pdf (opens new window)
GitHub (opens new window)
  • 第1章高频C++11重难点知识解析

  • 第2章Linux GDB高级调试指南

    • 2.1 SSH 工具与 FTP 工具
    • 2.2 Makefile 与 cmake
      • 2.3 使用Visual Studio管理和阅读开源项目代码
      • 2.4 gdb 调试准备
      • 2.5 gdb常用命令详解——利用gdb调试redis
      • 2.6 使用gdb调试多线程程序
      • 2.7 使用gdb调试多进程程序——以调试nginx为例
      • 2.8 gdb实用调试技巧
      • 2.9 gdb tui——gdb图形化界面
      • 2.10 gdb 的升级版——cgdb
      • 2.11 使用VisualGDB调试
      • 2.12 本章总结与扩展阅读
    • 第3章C++多线程编程从入门到进阶

    • 第4章C++网络编程重难点解析

    • 第5章网络通信故障排查常用命令

    • 第6章高性能网络通信协议设计精要

    • 第7章高性能服务结构设计

    • 第8章Redis 网络通信模块源码分析

    • 第9章后端服务重要模块设计探索

    • C++后端开发进阶
    • 第2章Linux GDB高级调试指南
    zhangxf
    2023-04-05
    目录

    2.2 Makefile 与 cmake

    # 2.2.1 Makefile 与 cmake

    在 Windows 上编译和调试 C/C++ 程序我们可以使用 Visual Studio,在 Linux 机器上编译 C/C++ 程序最终使用的是 gcc/g++,当然调试使用 gdb,我们使用 makefile 文件组织大型 C/C++ 或者含有多个 C/C++ 文件的项目,本节不会介绍 makefile 的语法,因为网络上已经有太多的这方面的资料了。有人认为 makefile 仍然不太方便,于是发明了 cmake 工具,cmake 工具将含有 cmake 指令的文件生成 makefile 文件,含有 cmake 指令的文件一般文件名是 CMakeLists.txt。这是实际开发中大多数 C/C++ 项目的组织方式,也适用于大多数开源 C/C++ 的项目。

    对于大多数 Linux 下的 C/C++ 开源项目,一般执行 configure 命令后会生成 CMakeLists.txt 文件,接着执行 cmake 指令会生成 makefile 文件,之后执行 make 命令利用 gcc/g++ 对项目进行编译。

    对于 Windows 系统可以直接从 cmake 官网 https://cmake.org/ 下载相应的安装包进行安装即可,对于 Linux 系统,以 CentOS 为例,执行如下命令即可安装 cmake:

    yum install cmake
    
    1

    安装好 cmake 工具之后,我们需要编写 CMakeList.txt 文件, CMakeLists.txt 样例如下:

    样例一

    cmake_minimum_required(VERSION 2.6)
    
    project (FLAMGINGO_SERVER)
    
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -g -Wall -O0 -Wno-unused-variable -pthread")
    
    link_directories(
        ${PROJECT_SOURCE_DIR}/lib
    	/usr/lib64/mysql/
    )
    
    set(net_srcs 
    base/AsyncLog.cpp
    base/ConfigFileReader.cpp
    base/Platform.cpp
    base/Timestamp.cpp
    
    net/Acceptor.cpp
    net/ByteBuffer.cpp
    net/Channel.cpp
    net/Connector.cpp
    net/EpollPoller.cpp
    net/EventLoop.cpp
    net/EventLoopThread.cpp
    net/EventLoopThreadPool.cpp
    net/InetAddress.cpp
    net/Poller.cpp
    net/PollPoller.cpp
    net/ProtocolStream.cpp
    net/SelectPoller.cpp
    net/Sockets.cpp
    net/TcpClient.cpp
    net/TcpConnection.cpp
    net/TcpServer.cpp
    net/Timer.cpp
    net/TimerQueue.cpp
    )
    
    set(mysqlapi_srcs
    mysqlapi/DatabaseMysql.cpp
    mysqlapi/Field.cpp
    mysqlapi/QueryResult.cpp
    )
    
    set(mysqlmgr_srcs
    mysqlmgr/MysqlManager.cpp
    mysqlmgr/MysqlThrd.cpp
    mysqlmgr/MysqlThrdMgr.cpp
    mysqlmgr/TaskList.cpp
    )
    
    set(json_srcs
    jsoncpp1.9.0/json_reader.cpp
    jsoncpp1.9.0/json_value.cpp
    jsoncpp1.9.0/json_writer.cpp
    )
    
    set(zlib_srcs
    zlib1.2.11/zutil.c
    zlib1.2.11/uncompr.c
    zlib1.2.11/trees.c
    zlib1.2.11/inftrees.c
    zlib1.2.11/inflate.c
    zlib1.2.11/inffast.c
    zlib1.2.11/infback.c
    zlib1.2.11/gzwrite.c
    zlib1.2.11/gzread.c
    zlib1.2.11/gzlib.c
    zlib1.2.11/gzclose.c
    zlib1.2.11/deflate.c
    zlib1.2.11/crc32.c
    zlib1.2.11/compress.c
    zlib1.2.11/adler32.c
    zlib1.2.11/ZlibUtil.cpp
    )
    
    set(utils_srcs
    utils/StringUtil.cpp
    utils/URLEncodeUtil.cpp
    utils/MD5.cpp
    utils/DaemonRun.cpp
    )
    
    set(chatserver_srcs
    chatserversrc/main.cpp
    chatserversrc/ChatServer.cpp
    chatserversrc/ChatSession.cpp
    chatserversrc/UserManager.cpp
    chatserversrc/MsgCacheManager.cpp
    chatserversrc/TcpSession.cpp
    chatserversrc/MonitorSession.cpp
    chatserversrc/MonitorServer.cpp
    chatserversrc/HttpSession.cpp
    chatserversrc/HttpServer.cpp
    chatserversrc/BussinessLogic.cpp)
    
    set(fileserver_srcs
    fileserversrc/main.cpp
    fileserversrc/FileServer.cpp
    fileserversrc/FileSession.cpp
    fileserversrc/FileManager.cpp
    fileserversrc/TcpSession.cpp)
    
    set(imgserver_srcs
    imgserversrc/main.cpp
    fileserversrc/FileServer.cpp
    fileserversrc/FileSession.cpp
    fileserversrc/FileManager.cpp
    fileserversrc/TcpSession.cpp)
    
    
    add_executable(chatserver ${net_srcs} ${json_srcs}  ${chatserver_srcs} ${mysqlapi_srcs} ${mysqlmgr_srcs} ${zlib_srcs} ${utils_srcs})
    #光包含库目录是没用的,还必须使用TARGET_LINK_LIBRARIES链接该库
    TARGET_LINK_LIBRARIES(chatserver mysqlclient)
    
    add_executable(fileserver ${net_srcs}  ${fileserver_srcs} ${utils_srcs})
    TARGET_LINK_LIBRARIES(fileserver)
    
    add_executable(imgserver ${net_srcs}  ${imgserver_srcs} ${utils_srcs})
    TARGET_LINK_LIBRARIES(imgserver)
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120

    样例二

    PROJECT(TRADE)
    
    AUX_SOURCE_DIRECTORY(./ SRC_LIST)
    SET(EXECUTABLE_OUTPUT_PATH ../bin)
    
    ADD_DEFINITIONS(-g -O0 -W -Wall -D_REENTRANT -D_FILE_OFFSET_BITS=64 -DAC_HAS_INFO -DAC_HAS_WARNING -DAC_HAS_ERROR -DAC_HAS_CRITICAL -DTIXML_USE_STL -DHAVE_CXX_STDHEADERS -Wno-deprecated ${CMAKE_CXX_FLAGS})
    
    
    INCLUDE_DIRECTORIES(
    ./
    /usr/local/include/commonlib/dbapi
    /usr/local/include/commonlib/json2
    /usr/local/include/commonlib/mysql
    )
    
    LINK_DIRECTORIES(
    ./
    /usr/local/lib/commonlib
    )
    
    ADD_EXECUTABLE(trade ${SRC_LIST})
    
    TARGET_LINK_LIBRARIES(trade pthread netutil json2 mysqlclient dbapi )
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    • 首行 cmake_minimum_required 指令指定支持该 CMakeLists.txt 文件的 cmake 最低版本号;

    • project 指令指定该项目的名称,注意项目名称不是最终生成的二进制程序名,一个项目下面可以生成多个二进制程序名;

    • set 定义和设置各种变量,set 括号后第一个名称是定义的变量名称,其后是变量的值,如上述文件定义了 CMAKE_CXX_FLAGS、net_srcs、mysqlapi_src、mysqlmgr_srcs 、json_srcs、zlib_srcs、utils_srcs、chatserver_srcs、fileserver_srcs、imgserver_srcs 一共 10 个变量,之后引用这些变量可以使用 ${变量名} 来引用这些变量,这些变量可以是内置变量,如 CMAKE_CXX_FLAGS 指定 g++ 编译选项,EXECUTABLE_OUTPUT_PATH 指定输出的二进制文件路径,也可以是自定义变量,如 chatserver_srcs、fileserver_srcs 等;

    • cmake 使用 aux_source_directory 指令指定源码目录,使用 include_directories 指令指定包含目录,使用

      link_directories 指定 lib 目录;

    • cmake 使用 指令指定生成的动态或静态库的名称,其格式如下:

      add_library(libname [SHARED|STATIC|MODULE] [EXCLUDE_FROM_ALL] source1 source2 … sourceN)
      
      1

      例如:

      add_library(hello hello1.cpp hello2.cpp)
      
      1

      你不需要写全 libhello.so 或 libhello.a,只需要填写 hello 即可,cmake 系统会自动为你生成 libhello.X。类型有三种:

      • SHARED,动态库(扩展名为 .so)
      • STATIC,静态库(扩展名为 .a)
      • MODULE,在使用 dyld 的系统有效,如果不支持dyld,则被当作 SHARED 对待。

      EXCLUDE_FROM_ALL 参数的意思是这个库不会被默认构建,除非有其他的组件依赖或者手工构建。 下面命令会生成一个叫 libkafkawrapper.so 的文件,且 libkafkawrapper.so 的生成依赖 librdkafka.so、librdkafka++.so、libcrypto.so、libssl.so 四个库。

      add_library(kafkawrapper SHARED ${kafka_wrapper_srcs})
      TARGET_LINK_LIBRARIES(kafkawrapper rdkafka rdkafka++ crypto ssl)
      
      1
      2
    • TARGET_LINK_LIBRARIES 指定生成的二进制文件以来的其他库,上文已有介绍;

    编写完 CMakeLists.txt 文件后,进入 CMakeLists.txt 文件依次执行如下命令即可生成最终的二进制文件:

    # 利用cmake生成makefile
    cmake .
    # 执行make命令,利用gcc/g++编译生成最终的二进制文件
    make
    
    1
    2
    3
    4

    CMakeLists.txt 也支持递归编译,父目录的 CMakeLists 先执行再接着执行子目录的 CMakeLists.txt 文件。

    cmake 更多的信息可以参考 cmake 官网。

    # 2.2.2 利用 cmake 工具生成 Visual Studio 工程文件

    对于习惯了 Visual Studio 强大的管理项目、编码和调试功能的读者来说,在 Linux 下使用 gcc/g++ 编译、使用 gdb 调试是一件何其痛苦的事情,对于大多数的开源 C/C++ 项目,如果我们不在意 Windows 和 Linux 在一些底层 API 接口上的使用差别,想熟悉该项目的执行脉络和原理,在 Windows 上使用 Visual Studio 调试该项目也未尝不可。凡是可以使用 CMake 工具编译的 Linux 程序(即提供了 CMakeLists.txt 文件),我们同样也可以利用 CMake 工具生成 Windows 上的 Visual Studio 工程文件。

    这里我们以著名的开源网络库 libuv 为例。

    从 libuv 的官方地址提供的下载链接:https://dist.libuv.org/dist/ 下载最新的 libuv 的源码得到文件 libuv-v1.31.0.tar.gz(笔者写作此书时,libuv 最新版本是 1.31.0),解压该文件。作者的机器上我将代码解压至 **F:\mycode\libuv-v1.31.0\ **,解压后的目录中确实存在一个 CMakeLists.txt 文件,如下图所示:

    启动 Windows 上的 CMake 图形化工具(cmake-gui),按下图进行设置:

    设置完成之后,点击界面上的Configure 按钮,会提示 vsprojects 目录不存在,提示是否创建,我们点击 Yes 进行创建。

    如果您的机器上安装了多个版本的Visual Studio,接下来会弹窗对话框让我们选择要生成的工程文件对应的 Visual Studio 版本号。读者可以根据自己的实际情况按需选择。我这里选择 Visual Studio 2019。

    点击 Finish 按钮后开始启动 CMake 的检测和配置工作。等待一会儿,CMake 底部的输出框中提示 “Configuring Done” 表示配置工作已经完成。

    接下来点击 Generate 按钮即可生成所选版本的 Visual Studio 工程文件,生成的文件位于 vsprojects 目录。

    我们可以在界面上点击按钮 Open Project 按钮直接打开工程文件,也可以找到对应目录下的 libuv.sln 打开。

    打开后如下图所示:

    接下来,我们就可以使用 Visual Studio 愉快地进行编译和调试了。

    让我们再深入聊一下上述过程:在点击 Configure 按钮之后,和在 Linux 下执行 cmake 命令一样,CMake 工具也是在检测所在的系统环境是否匹配 CMakeLists.txt 中定义的各种环境,本质上是生成了一份可以在 Windows 上编译和运行的代码(也就是说该源码支持在 Windows 上运行) 。因此,对于很多虽然提供了 CMakeLists.txt 文件但并不支持在 Windows 上运行的的 Linux 工程,虽然利用上述方法也能最终生成 Visual Studio 工程文件,但是这些文件并不能在 Windows 上直接无错编译和调试。

    由于不同的 CMake 版本支持的 CMakeLists.txt 中的语法可能略有细微差别,有些 CMakeLists.txt 文件在使用上述方法 configure 时可能会产生一些错误,需要读者做些修改才能通过。

    上次更新: 2025/05/19, 16:52:22
    2.1 SSH 工具与 FTP 工具
    2.3 使用Visual Studio管理和阅读开源项目代码

    ← 2.1 SSH 工具与 FTP 工具 2.3 使用Visual Studio管理和阅读开源项目代码→

    最近更新
    01
    第二章 关键字static及其不同用法
    03-27
    02
    第一章 auto与类型推导
    03-27
    03
    第四章 Lambda函数
    03-27
    更多文章>
    Copyright © 2024-2025 沪ICP备2023015129号 张小方 版权所有
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式