☰
Linux平台下C++ muduo网络库源码编译安装实战指南
2026/10/5 9:49:48 网站建设 项目流程

C++ muduo网络库知识分享01 - Linux平台下muduo网络库源码编译安装

做C++后端开发的,迟早会碰到muduo这个库。不管你是校招准备面经、社招想补一补网络编程的底子,还是在公司里要用它做高并发服务,陈硕的muduo几乎都是绕不开的一站。网上聊muduo源码分析的文章一抓一大把,但很多人第一步就卡住了——库都编译不过去,后面全是纸上谈兵。

这篇文章就专注解决一件事:在Linux平台上把muduo从源码编译安装跑通。我会把环境准备、源码获取、编译选项、安装路径、验证方法全部过一遍,中间会把我在实际编译中踩过的坑、查过的错误、翻过的源码都交代清楚。文章面向的是准备入门muduo、或者编译失败正在找解决办法的朋友,已经能熟练编译各种C++库的老手可以重点看后面几节的坑和验证思路。

1. 编译前的环境准备:别急着clone代码

我在很多技术群里见过一种现象:拿到一个开源项目,二话不说先git clone,然后./build.sh一把梭,报错就开始搜"error: xxx"。这种做法不是不行,只是效率太低。编译muduo之前,有几个前置问题值得先搞清楚。

1.1 muduo的版本差异与依赖关系

muduo在GitHub上有两个主要分支:master和c++11。master分支是陈硕早期基于C++03标准写的原始版本,c++11分支则是在其基础上做了现代化改造,用到了C++11的特性。

这里有一个关键点很多人不清楚:c++11分支其实是社区维护的版本,陈硕本人在GitHub上明确说过master分支不再维护,推荐用户使用c++11分支。但国内很多教程、面经、书籍讲解的都是master分支的代码,这就导致了一个尴尬——你照着书上的代码写,clone下来却是另一个分支,编译选项和代码结构都略有不同。

我个人的建议是:学原理看master分支的书和文章,实际编译安装用c++11分支。原因不复杂,c++11分支修复了很多老代码在较新编译器(GCC 7以上)下的编译问题,比如一些隐式类型转换、模板推导的变化。如果你用的是Ubuntu 20.04以上系统,自带的GCC 9/10/11编译老版本master分支,大概率会碰到各种各样的编译报错,光是修这些错误就够你喝一壶的,反而不利于聚焦学习网络库本身。

依赖方面,muduo主要依赖两个库:

  • boost:muduo大量使用了boost库,包括boost::bind、boost::function、boost::noncopyable等。虽然后期版本减少了对boost的依赖,但编译仍然需要引导头文件。
  • cmake:muduo的构建系统基于CMake,需要3.0以上版本。
  • zlib:如果启用HTTP服务相关功能,可能需要zlib开发包。

1.2 我用的是什么环境

这篇文章的实际编译环境是:

项目版本
操作系统Ubuntu 22.04 LTS
内核5.15.x
GCC11.4.0
CMake3.22.1
Boost1.74.0
muduo分支c++11

这里要单独说一下:很多人在编译失败后会怪环境"太新",觉得旧代码就该配旧编译器。其实muduo c++11分支在GCC 11下编译是没有问题的,如果你在更新的环境(比如GCC 12/13、Boost 1.80+)下遇到问题,大概率是其他原因,后面我会专门讲。

在Ubuntu/Debian系系统上,安装依赖就三行命令:

sudo apt update sudo apt install -y cmake g++ git sudo apt install -y libboost-dev libboost-test-dev

CentOS/RHEL系的话把apt换成yum/dnf,包名略有不同:

sudo dnf install -y cmake gcc-c++ git sudo dnf install -y boost-devel boost-test

安装完成后可以用g++ --version和cmake --version确认版本号,确保基础环境没问题。

提示:不要跳过我说的依赖安装直接clone编译。muduo的CMakeLists里虽然会对boost做检测,但缺头文件时报错信息是"boost/noncopyable.hpp: No such file or directory"一类,容易让人误以为是源码本身的问题,其实只是系统里没装boost开发包。

2. 克隆源码与分支选择:一次到位不折腾

依赖装好后,接下来就是获取源码。这一步看似简单,但分支选错了会直接影响后续所有操作。

2.1 从GitHub拉取代码的具体操作

在正式命令之前,先说说为什么我不建议直接git clone --depth=1。muduo这个项目的历史提交里有非常详细的commit记录和代码演进过程,对于学习者来说,git log、git diff是理解设计思路的好工具。如果你--depth=1浅克隆,就丢失了这些历史信息。当然,如果你只是急着编译用,浅克隆确实更快,这个完全看个人需求。

我推荐的做法是:

# 在你的工作目录下执行 git clone https://github.com/chenshuo/muduo.git cd muduo git branch -a # 看一下所有本地和远程分支 git checkout c++11 # 切换到c++11分支

如果你的网络环境访问GitHub比较慢,可以用镜像站或者代理方式加速,这里不做展开。clone完成后,git log --oneline -5看一下最新的提交,确认你拿到的是最近维护的版本。

2.2 master分支与c++11分支的编译差异

这两条分支不只是代码风格的区别,CMake配置层面也有不同。

master分支用的是老式CMakeLists写法,支持直接在项目根目录下:

./build.sh

这个脚本会编译并在build/release/目录下生成库文件。而c++11分支更新了CMake组织方式,你可以使用标准的CMake流程:

mkdir build cd build cmake .. make -j$(nproc)

这里有一个容易踩的坑:c++11分支默认编译参数里带了-Werror,也就是说编译器警告会被当作错误处理。在高版本GCC下,muduo的某些代码可能产生新的警告(比如C++17之后引入的-Wnoexcept-type、-Wdeprecated-copy等),这些警告在老编译器下不存在,于是就会直接编译失败。

如果你碰到了这类报错,不要慌,解决办法有两个:

  1. 在CMake时手动关掉Werror:cmake -DCMAKE_CXX_FLAGS="-Wno-error" ..
  2. 修改CMakeLists.txt,找到-Werror相关行注释掉。

我个人更推荐第一种,因为不改源码,后续想恢复更容易。不过需要说明的是,当前muduo c++11最近的代码在GCC 11下编译是干净的,理论上你不一定会碰到这个坑,但一旦碰到,知道解法总比到处搜答案强。

2.3 目录结构速览:先知道代码在哪

编译前花两分钟认识一下目录,这对后续自己找头文件、链接库非常有帮助:

muduo/ ├── CMakeLists.txt # 根CMake配置,定义了整体构建 ├── build.sh # master分支的构建脚本 ├── muduo/ # 核心代码目录 │ ├── base/ # 基础库:Timestamp、Logging、Thread等 │ ├── net/ # 网络库核心:EventLoop、TcpServer等 │ ├── net/http/ # HTTP服务相关的封装 │ ├── net/inspect/ # 内建监控接口 │ └── net/protorpc/ # RPC相关实现 ├── examples/ # 各种示例程序 │ ├── asio/chat/ # 聊天室例子 │ ├── fastcgi/ # FastCGI例子 │ ├── filetransfer/ # 文件传输 │ ├── ... # 还有不少,不一一列举 └── tests/ # 单元测试

muduo/base是底层基础设施,不依赖网络功能;muduo/net才是大家常说的"网络库"。编译时整个项目会一起构建,但你在写自己的程序时只需要链接muduo_net和muduo_base两个库,后面第三节会具体讲。

3. 编译安装全过程:从cmake到make install

环境就绪、源码到位,接下来就是重头戏——编译。这一节我不会只给命令,还会解释每个步骤在干什么,这样即使CMake报错,你也知道该去哪看。

3.1 执行CMake配置

在muduo项目根目录下:

mkdir build && cd build cmake ..

命令执行后,CMake会读取项目根目录的CMakeLists.txt,检查系统环境、找到boost头文件、确定编译器、生成Makefile。执行成功的输出末尾大致长这样:

-- Configuring done -- Generating done -- Build files have been written to: /home/yourname/muduo/build

如果报错,最常见的就是找不到boost相关的头文件,错误形如:

CMake Error at CMakeLists.txt:xx (message): Could NOT find Boost

这时候回到第一节,把libboost-dev装好,重新执行cmake ..即可。

另外需要注意一点:CMake配置阶段的警告信息不要完全无视。比如我在某次编译时看到过:

CMake Warning at muduo/net/CMakeLists.txt:xx (add_library): Cannot generate a safe runtime search path for target muduo_net because files in some directories may conflict with those in directories...

这个警告一般不影响编译结果,可以忽略。但如果出现了红色的CMake Error,那就必须解决。

3.2 编译库文件

配置成功后,执行编译:

make -j$(nproc)

-j$(nproc)是利用多核并行编译,nproc命令会返回你机器的CPU核心数。如果机器内存不太够,可以减半用-j$(expr $(nproc) / 2),避免编译时内存耗尽导致OOM。

整个muduo编译过程在一般配置的电脑上大约1~3分钟,属于比较轻量的项目。编译完成后,在build/目录下会生成若干子目录,主要库文件在build/lib下。用ls build/lib查看,你会看到类似这样的文件:

libmuduo_base.a libmuduo_net.a libmuduo_http.a libmuduo_inspect.a

这些.a文件就是静态库。如果你只想要最核心的网络库功能,其实只要libmuduo_base.a和libmuduo_net.a就够了。

3.3 安装到系统目录

按标准的CMake流程,接下来是安装:

sudo make install

默认安装路径是/usr/local,头文件会被拷贝到/usr/local/include/muduo/,库文件拷贝到/usr/local/lib下。这样我们后续自己写代码时,编译器会默认搜索这些路径,不需要额外指定-I和-L参数。

不过这里有个问题值得提:很多Linux发行版(尤其是Ubuntu 22.04+)的默认库搜索路径并不包含/usr/local/lib。在较老版本里/usr/local/lib默认不在/etc/ld.so.conf的配置中,或者说gcc默认不会在这个目录下查找动态库。muduo默认编译的是静态库,影响不大;但如果你之后自己修改CMake选项编出了动态库(.so),运行程序时可能遇到:

error while loading shared libraries: libmuduo_net.so: cannot open shared object file: No such file or directory

解决办法是执行:

sudo ldconfig

或者把/usr/local/lib写进/etc/ld.so.conf.d/local.conf,然后执行sudo ldconfig。

另外,在你自己的CMake工程中使用muduo时,CMake默认找库路径也未必包含/usr/local/lib,可能需要手动设置:

link_directories(/usr/local/lib)

3.4 用自带例子验证编译结果

验证编译成功最直接的方式是编译运行muduo自带的example。我推荐先跑一个最经典的回显服务器(echo server),代码在examples/asio/chat/目录下。

cd ../examples/asio/chat ls

你会看到server.cc和client.cc两个源文件。要编译它们,需要链接muduo库。以server.cc为例:

g++ -o server server.cc -I/usr/local/include -L/usr/local/lib -lmuduo_net -lmuduo_base -lpthread

然后运行:

./server

正常的话程序会在监听端口(默认为2019)上等待连接,终端不会输出太多内容。再开一个终端,用系统自带的telnet或nc测试:

nc localhost 2019

输入任意一行字符、回车,你会看到同样的内容被回显出来。这说明服务器已经正常工作了。如果这一步通了,那你的muduo就没有白装。

提示:如果你在链接阶段报错说找不到libmuduo_net.a,先确认是否执行过sudo make install,以及/usr/local/lib下是否有这几个.a文件。也可以用find / -name "libmuduo_net.a" 2>/dev/null全局查一下库文件的真实位置。

4. 编译过程中的常见报错与对应解法

这一节专门解决问题。我把编译中实际遇到和网上高频出现的问题汇总成一张表,再说说排查的思路。很多人说muduo老了、编译不过去,其实绝大概率是下面某一类原因。

4.1 报错快速定位表

报错信息根本原因解决方案
fatal error: boost/noncopyable.hpp: No such file or directory缺少boost开发包sudo apt install libboost-dev
Could NOT find Boost (missing: Boost_INCLUDE_DIR)boost装错位置/未装检查/usr/include/boost是否存在;重新安装
error: ‘shared_ptr’ does not name a typeC++版本不对,未开启C++11检查CMakeLists中编译器选项,或手动加-std=c++11
undefined reference topthread_create'`链接时缺少pthreadg++命令末尾加-lpthread
cannot find -lmuduo_net库未安装或路径未指定确认/usr/local/lib下存在库文件;或指定-L/usr/local/lib
Error: required C++ standard is C++11CMake版本过老或编译器过老升级GCC到5.0以上,CMake 3.1以上
error: ISO C++ forbids declaration of ‘xxx’ with no type编译器版本过老升级编译器,避免使用远古GCC 4.x
undefined reference toboost::system::...'`链接时缺少boost_system在链接参数中加-lboost_system(老版本需要)

表中的第二类(Could NOT find Boost)需要展开多说几句。Ubuntu 22.04的libboost-dev安装后头文件在/usr/include/boost,这个路径是CMake默认搜索路径,所以理论上不会找不到。但如果你用的是手动编译安装的boost到/usr/local/ssl之类的非标准路径,CMake就找不到,这时需要:

cmake -DBOOST_ROOT=/path/to/boost ..

或者用-DCMAKE_INCLUDE_PATH告诉CMake头文件所在目录。

4.2 最隐蔽的一个坑:多个GCC版本共存

我在实际编译时踩过最隐蔽的坑,是系统里同时存在多个版本GCC导致的。Ubuntu 22.04自带GCC 11,但你可能因为某些项目装了GCC 9,并改了update-alternatives的默认版本。这时候CMake找到的编译器和实际运行的可能不是你预期的那一个。症状是:照网上教程一步步做,就是编译失败,而且报错位置飘忽不定。

排查方法很简单:

which gcc g++ gcc --version cmake .. | grep -i compiler # 看CMake实际使用的编译器

如果发现问题,要么把/usr/bin/gcc软链指到期望版本,要么在CMake时明确指定:

cmake -DCMAKE_C_COMPILER=/usr/bin/gcc-11 -DCMAKE_CXX_COMPILER=/usr/bin/g++-11 ..

这个问题不仅发生在muduo上,编译任何C++项目都值得先确认环境,推测问题上"玄学化"。

4.3 高版本GCC下的编译警告变错误问题

前面提到了-Werror的问题,这里补充一个我看到过很多次的报错实例:

cc1plus: warning: ‘template<class> class std::auto_ptr’ is deprecated [-Wdeprecated-declarations] error: ‘std::auto_ptr’ is deprecated: use std::unique_ptr instead [-Werror=deprecated-declarations]

这是比较典型的老代码在GCC 11下编译失败的场景。muduo c++11分支中已经用std::unique_ptr替换了大部分auto_ptr,但个别示例代码可能遗留了。报错明确指出了文件和行号,但我的建议是不要急着改源码,先加-Wno-error把它跳过去。原因很简单:你现在的首要目标是把整个库编译通、能跑起来,理解代码之后再去修正警告也不迟。改源码可能引入新的问题,反而让排查难度上升。

4.4 链接时找不到pthread的坑

muduo的链接,在不少例子里需要加-lpthread。GCC从5.x版本开始,-pthread不是一个单独的库链接,而是编译和链接选项同时起作用。如果你编译时用了-lpthread但漏了-pthread,某些老版本编译器也可能出问题。建议统一在g++命令中写:

g++ -std=c++11 -pthread -o server server.cc -lmuduo_net -lmuduo_base

还有一点,muduo静态库的依赖顺序很重要。在链接时如果你写成-lmuduo_base -lmuduo_net,编译器会报一堆undefined reference,因为静态库的符号解析是单遍的。正确的做法是先写依赖别人的库,再写被依赖的库(即先net后base)。

5. 编译完之后的体系建设:头文件、链接配置与CLion/VSCode

编译安装成功不是终点,咱们的目的是"能用它写代码"。很多朋友在命令行下编译能过,但一打开IDE就找不到头文件,这里分享几个环境配置经验。

5.1 头文件路径与Makefile/CMake的标准写法

如果只是命令行编译,最简单的方式是:

g++ -std=c++11 -I/usr/local/include -L/usr/local/lib -lmuduo_net -lmuduo_base -pthread -o myapp main.cpp

如果你用CMake写自己的工程,推荐在CMakeLists.txt里维护一个干净的查找逻辑:

cmake_minimum_required(VERSION 3.10) project(MyMuduoApp CXX) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) include_directories(/usr/local/include) link_directories(/usr/local/lib) add_executable(myapp main.cpp) target_link_libraries(myapp muduo_net muduo_base pthread)

这样做比较"傻瓜",但也有不足之处:直接写死路径,换台机器可能就跑不通。更规范的方案是写一个CMake find module或通过pkg-config管理,不过对于学习阶段,上面这份足够直接了。

5.2 VSCode配置C/C++扩展会碰到的问题

用VSCode写C++的人很多,这里有一个非常经典的问题:VSCode的C/C++插件默认不会自动找/usr/local/include下的头文件。结果就是你在命令行能编译通过,VSCode里却满屏红波浪线。

解决方法是创建.vscode/c_cpp_properties.json,在includePath中加上/usr/local/include:

{ "configurations": [ { "name": "Linux", "includePath": [ "${workspaceFolder}/**", "/usr/local/include" ], "defines": [], "compilerPath": "/usr/bin/g++", "cStandard": "c11", "cppStandard": "c++11", "intelliSenseMode": "linux-gcc-x64" } ], "version": 4 }

如果是用tasks.json做编译任务,也需要把-I/usr/local/include和-L/usr/local/lib加进去。很多初学者把命令行编译和IDE编译当成两件事,其实IDE底层还是会调用g++,只是参数配置藏在配置文件里。

5.3 确认安装是否成功的终极测试

在写完这些配置之后,建议做一次终极验证:写一个最小的muduo程序,编译运行。比如使用TcpServer的回调打印:

#include <muduo/net/TcpServer.h> #include <muduo/net/EventLoop.h> #include <muduo/base/Logging.h> using namespace muduo; using namespace muduo::net; int main() { EventLoop loop; TcpServer server(&loop, InetAddress(8888), "TestServer"); server.setMessageCallback([](const TcpConnectionPtr& conn, Buffer* buf, Timestamp time) { conn->send(buf->retrieveAllAsString()); }); server.start(); loop.loop(); return 0; }

编译时使用之前提到的g++命令或CMake流程,运行后访问8888端口,发送什么回显什么,说明整个muduo已经从源码变成可用状态了。这一步通了,接下来再深入源码、读EventLoop的runInLoop逻辑,就有踏实的基础了。

6. 安装成功后的调试思路与路上建议

整体流程走完,你在muduo上的第一关就算过了。不过我想多说几句关于"编译安装"这个环节的心态认知,因为它会直接影响你后面读源码的效率。

6.1 读懂编译日志比背命令重要

我见过不少人编译失败之后的操作:复制报错最后一行去搜索引擎,然后试人家给的命令,不行再复制下一行,再来一轮。这种做法偶尔有效,但治标不治本。

正确的方式是这样:遇到报错,先看是哪个文件哪一行,然后往回翻编译日志,找到第一条出错信息而不是最后一条。因为编译器常常会在第一个错误之后产生连锁且混乱的后续报错,真正的病根往往在最前面。

比如上文提到boost头文件缺失,报错可能不止一条,但第一条一定是boost/noncopyable.hpp: No such file or directory。理解了这一点,你就知道这不是muduo自身的问题,而是系统的头文件路径不完整。学会"顺藤摸瓜"之后,大部分编译问题都能自己解决,不用再去各种社区求助。

6.2 构建目录和源码目录分离的小习惯

在muduo根目录直接make出来的产物会和源码混在一起,搜索文件时格外不舒服。我更喜欢把build目录建在源码目录外,比如:

mkdir ~/build/muduo cd ~/build/muduo cmake ~/src/muduo make -j$(nproc)

这样源码目录保持干净,以后想重新编译、换分支、改选项,直接删掉build目录重新来一遍,完全不污染源码。

6.3 安装后如何卸载,什么时候需要重装

有些朋友安装了muduo之后,又改了源码想重新编译,结果编译出来还是旧版本。这个问题的本质是安装路径里已经有一份库文件,而新编译的库在build目录下,没有覆盖过去。

如果你改了源码想覆盖安装:

cd build sudo make install

如果想彻底卸载:

sudo rm -rf /usr/local/include/muduo sudo rm -f /usr/local/lib/libmuduo_*.*

在开发阶段我不太建议频繁install,直接把build/lib路径通过CMake的link_directories指过去就够了。这样每次改动源码后只需要重新make,不用重复安装。

6.4 几个值得继续深入的路线

编译装好只是认识muduo的开始。根据我的经验,后续的学习路线大致是这样:先跑通TcpServer和EventLoop的例子,从TcpConnection收发数据开始看;接下来看一下EventLoop的poll/epoll事件分发机制,理解one loop per thread;再深入TcpServer的连接管理、定时器TimerQueue的实现;最后有余力可以研究buffer的设计和日志库的异步落盘逻辑。网络编程的核心概念(非阻塞IO、事件驱动、反应器模式)都会在源码里具象化,装好库只是把舞台搭好而已。

说实话,muduo的编译安装这件事本身技术含量不算高,但它确实是一道门槛——跨过去,后面的代码分析才有物质基础。你在编译过程中遇到的问题越多、排查得越仔细,对编译器、CMake、库链接这套流程的理解就越深。很多看起来是在"浪费时间"的报错排查,其实都是变相在给自己加经验值。如果这篇文章能帮你少踩几个坑,那就值了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询