muduo 网络库学习项目引入 Boost 依赖


muduo 这个项目比较老旧了,但是仍然是学习网络库实现的一个不错的参考,所以还是得看看书自己动手实践一下。

没想到跟着书上的代码练手上来就有依赖问题,boost::noncopyable 其实这个就是把拷贝构造函数和拷贝运算符 delete 了的一个基类,就算子类不显式声明拷贝构造函数和拷贝运算符删除,但是实际进行对象的拷贝构造的时候还是会链式构造递归到基类的构造过程,这个时候发现拷贝构造函数被显式地标记为 delete 就会报错了:

/home/fredom/workspace/muduo/test/misc/boost_valid.cpp: In function ‘int main()’:
/home/fredom/workspace/muduo/test/misc/boost_valid.cpp:33:20: error: use of deleted function ‘MyClass::MyClass(const MyClass&)’
   33 |     MyClass obj2 = obj1;  // 这里会报错,尝试拷贝构造
      |                    ^~~~
/home/fredom/workspace/muduo/test/misc/boost_valid.cpp:16:7: note: ‘MyClass::MyClass(const MyClass&)’ is implicitly deleted because the default definition would be ill-formed:
   16 | class MyClass : public NonCopyable {
      |       ^~~~~~~
/home/fredom/workspace/muduo/test/misc/boost_valid.cpp:16:7: error: use of deleted function ‘NonCopyable::NonCopyable(const NonCopyable&)’
/home/fredom/workspace/muduo/test/misc/boost_valid.cpp:11:5: note: declared here
   11 |     NonCopyable(const NonCopyable&) = delete;
      |     ^~~~~~~~~~~
/home/fredom/workspace/muduo/test/misc/boost_valid.cpp:35:12: error: use of deleted function ‘MyClass& MyClass::operator=(const MyClass&)’
   35 |     obj3 = obj1;          // 这里也会报错,尝试拷贝赋值
      |            ^~~~
/home/fredom/workspace/muduo/test/misc/boost_valid.cpp:16:7: note: ‘MyClass& MyClass::operator=(const MyClass&)’ is implicitly deleted because the default definition would be ill-formed:
   16 | class MyClass : public NonCopyable {
      |       ^~~~~~~
/home/fredom/workspace/muduo/test/misc/boost_valid.cpp:16:7: error: use of deleted function ‘NonCopyable& NonCopyable::operator=(const NonCopyable&)’
/home/fredom/workspace/muduo/test/misc/boost_valid.cpp:13:18: note: declared here
   13 |     NonCopyable& operator=(const NonCopyable&) = delete;
      |                  ^~~~~~~~
make[2]: *** [test/CMakeFiles/boost_valid.dir/build.make:76: test/CMakeFiles/boost_valid.dir/misc/boost_valid.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:134: test/CMakeFiles/boost_valid.dir/all] Error 2
make: *** [Makefile:136: all] Error 2
已完成 生成,但出现错误。
#include <boost/filesystem.hpp>
#include <iostream>

class NonCopyable {
public:
    // 默认构造函数和析构函数
    NonCopyable() = default;
    ~NonCopyable() = default;

    // 禁用拷贝构造函数
    NonCopyable(const NonCopyable&) = delete;
    // 禁用拷贝赋值运算符
    NonCopyable& operator=(const NonCopyable&) = delete;
};

class MyClass : public NonCopyable {
public:
    MyClass() = default;
    ~MyClass() = default;
    
    // 其他成员函数可以正常定义
    void doSomething() {
        // 示例操作
    }
};


int main() {
    boost::filesystem::path path(".");
    std::cout << "Current path: " << boost::filesystem::absolute(path) << std::endl;

    MyClass obj1;
    MyClass obj2 = obj1;  // 这里会报错,尝试拷贝构造
    MyClass obj3;
    obj3 = obj1;          // 这里也会报错,尝试拷贝赋值
    
    return 0;
}

但是 Boost 库其实也为使用者提供了一个这样的基类,所以不用用户自己编写直接继承自 Boost 提供的基类完成这个功能也是可以的,而我们确实应该尽量使用公共开源的库避免重复造轮子,一个最重要的原因我认为是这些公开的库经过了社区甚至是生产环境的大量测试和验证,出问题的情况非常少,而我们自己写的轮子往往无法得到充分的测试。

下载 Boost 源码库编译

在这里插入图片描述

![[Pasted image 20240908145830.png]]

![[Pasted image 20240908150756.png]]

这里根据操作系统的平台选择对应的源码压缩包。下载下来之后解压,然后在项目根目录新建 install 目录用于存放编译产物。

./bootstrap
b2 install --prefix=$PWD/install

现在开始编译,前提是系统中已经安装了对应的编译工具链比如 MinGW 或者 GNU gcc/g++ 。这个过程可能需要等一会,然后在 install 目录下就会有编译生成的产物了。

┌[fredom@HM-3080Ti 15:11:31] ~/workspace/boost_1_86_0
└> ls
total 2.8M
-rwxrwxr-x   1 fredom fredom 721K Sep  6 17:32 b2*
drwxrwxr-x   6 fredom fredom 4.0K Sep  6 17:46 bin.v2/
drwxr-xr-x 143 fredom fredom  12K Aug  8 06:43 boost/
-rw-r--r--   1 fredom fredom  851 Aug  8 06:07 boost-build.jam
-rw-r--r--   1 fredom fredom  21K Aug  8 06:07 boostcpp.jam
-rw-r--r--   1 fredom fredom  989 Aug  8 06:07 boost.css
-rw-r--r--   1 fredom fredom 6.2K Aug  8 06:07 boost.png
-rw-r--r--   1 fredom fredom 2.5K Aug  8 06:07 bootstrap.bat
-rwxr-xr-x   1 fredom fredom  11K Aug  8 06:07 bootstrap.sh*
-rw-rw-r--   1 fredom fredom 1.9M Sep  6 17:46 build.log
drwxr-xr-x   8 fredom fredom 4.0K Aug  8 06:43 doc/
-rw-r--r--   1 fredom fredom  769 Aug  8 06:07 index.htm
-rw-r--r--   1 fredom fredom 5.3K Aug  8 06:43 index.html
drwxrwxr-x   4 fredom fredom 4.0K Sep  6 17:45 install/
-rw-r--r--   1 fredom fredom  291 Aug  8 06:07 INSTALL
-rw-r--r--   1 fredom fredom  17K Aug  8 06:07 Jamroot
drwxr-xr-x 152 fredom fredom 4.0K Aug  8 06:43 libs/
-rw-r--r--   1 fredom fredom 1.4K Aug  8 06:07 LICENSE_1_0.txt
drwxr-xr-x   4 fredom fredom 4.0K Aug  8 06:07 more/
-rw-rw-r--   1 fredom fredom  986 Sep  6 17:32 project-config.jam
-rw-r--r--   1 fredom fredom  541 Aug  8 06:07 README.md
-rw-r--r--   1 fredom fredom 2.6K Aug  8 06:07 rst.css
drwxr-xr-x   2 fredom fredom 4.0K Aug  8 06:07 status/
drwxr-xr-x  14 fredom fredom 4.0K Aug  8 06:07 tools/

┌[fredom@HM-3080Ti 15:11:33] ~/workspace/boost_1_86_0
└> duone
1M      ./more
180M    ./boost
287M    ./bin.v2
227M    ./install
5M      ./status
28M     ./tools
613M    ./libs
121M    ./doc
1462M   .

┌[fredom@HM-3080Ti 15:12:27] ~/workspace/boost_1_86_0/install
└> tree . -L 2
.
├── include
│   └── boost
└── lib
    └── cmake

通过 CMake 引入 Boost 项目

Boost 程序库大部分都是头文件库,也就是通过 include 头文件到源文件中直接编译即可获得对应的功能,但是部分常用库还是需要额外的源文件生成的库通过链接之后才能使用,因此需要在 CMake 中指定这些需要链接的库的引入方式。

在配置 Boost 的 CMake 中,学习到了一些 CMake 的相关知识。一般 CMake 引入外部项目都是通过 find_package 完成,然后外部项目对应的需要提供 Find<PackageName>.cmake 或者 <PackageName>Config.cmake / <packagename>-config.cmake 文件,其中前者是比较早期的 CMake 引入项目的模式,现在是推荐使用 config 模式来引入项目,两者对应的用户设置搜索路径为:

  1. module modeset(CMAKE_MODULE_PATH path/to/FindXXX.cmake)
  2. config modeset(CMAKE_PREFIX_PATH) path/to/XXXConfig.cmake)

CMake constructs a set of possible installation prefixes for the package. Under each prefix several directories are searched for a configuration file. The tables below show the directories searched. Each entry is meant for installation trees following Windows (W), UNIX (U), or Apple (A) conventions

EntryConvention
<prefix>/W
<prefix>/(cmake|CMake)/W
<prefix>/<name>*/W
<prefix>/<name>*/(cmake|CMake)/W
<prefix>/<name>*/(cmake|CMake)/<name>*/ 1W
<prefix>/(lib/<arch>|lib*|share)/cmake/<name>*/U
<prefix>/(lib/<arch>|lib*|share)/<name>*/U
<prefix>/(lib/<arch>|lib*|share)/<name>*/(cmake|CMake)/U
<prefix>/<name>*/(lib/<arch>|lib*|share)/cmake/<name>*/W/U
<prefix>/<name>*/(lib/<arch>|lib*|share)/<name>*/W/U
<prefix>/<name>*/(lib/<arch>|lib*|share)/<name>*/(cmake|CMake)/W/U

所以这里我踩了一个坑,把 install/lib/cmake 目录复制到当前的 muduo 学习项目的 cmake 目录中,然后设置 CMAKE_PREFIX_PATH 指向这个目录,虽然这样子确实能找到指定版本的 Boost ,并且设置了变量 Boost_FOUND=TRUE ,但是实际上给出的变量展开的值全都是错误的(比如头文件 include 目录居然指向的是 muduo 项目下一个不存在的目录),可以看一眼 Boost 的头文件查找变量是如何设置的:

┌[fredom@HM-3080Ti 15:22:02] ~/workspace/boost_1_86_0/install/lib/cmake/boost_headers-1.86.0
└> cat boost_headers-config.cmake 
# Generated by Boost 1.86.0

if(TARGET Boost::headers)
  return()
endif()

if(Boost_VERBOSE OR Boost_DEBUG)
  message(STATUS "Found boost_headers ${boost_headers_VERSION} at ${boost_headers_DIR}")
endif()

mark_as_advanced(boost_headers_DIR)

# Compute the include and library directories relative to this file.

get_filename_component(_BOOST_CMAKEDIR "${CMAKE_CURRENT_LIST_DIR}/../" REALPATH)

# If the computed and the original directories are symlink-equivalent, use original
if(EXISTS "/home/fredom/workspace/boost_1_86_0/install/lib/cmake")
  get_filename_component(_BOOST_CMAKEDIR_ORIGINAL "/home/fredom/workspace/boost_1_86_0/install/lib/cmake" REALPATH)
  if(_BOOST_CMAKEDIR STREQUAL _BOOST_CMAKEDIR_ORIGINAL)
    set(_BOOST_CMAKEDIR "/home/fredom/workspace/boost_1_86_0/install/lib/cmake")
  endif()
  unset(_BOOST_CMAKEDIR_ORIGINAL)
endif()

get_filename_component(_BOOST_INCLUDEDIR "${_BOOST_CMAKEDIR}/../../include/" ABSOLUTE)

add_library(Boost::headers INTERFACE IMPORTED)

set_target_properties(Boost::headers PROPERTIES
  INTERFACE_INCLUDE_DIRECTORIES "${_BOOST_INCLUDEDIR}"
)

unset(_BOOST_INCLUDEDIR)
unset(_BOOST_CMAKEDIR)

注意到这一行:

get_filename_component(_BOOST_INCLUDEDIR "${_BOOST_CMAKEDIR}/../../include/" ABSOLUTE)

所以说 Boost 是通过相对于这个 config 文件所在的路径来写死 BOOST_INCLUDE_DIRS ,怪不得移动了 Boost 的 cmake 目录到其他项目下没法用,所以只能额外在项目目录下设置 Boost 库的安装路径(这里有点膈应,万一我想把这个项目和它的依赖都打包到另一个主机上开发怎么办,这路径全都不对了,还必须去另外一台主机上编译安装一遍,我就是因为自己的云服务器性能不够换到实验室的机器上来编译 Boost,但是还是想回云服务器开发的)。

以下是我的 muduo 项目目录 CMakeLists.txt 配置,引入 Boost 1.86.0 。

cmake_minimum_required(VERSION 3.20)
project(muduo)

cmake_policy(SET CMP0167 OLD)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/bin)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/lib)
set(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/install)
set(CMAKE_PREFIX_PATH /home/fredom/workspace/boost_1_86_0/install/lib/cmake)
# set(CMAKE_MODULE_PATH /home/fredom/workspace/boost_1_86_0/install/lib/cmake) # outdated

message("build type ${CMAKE_BUILD_TYPE}")


set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)


include_directories(include)


# other dependencies
find_package(
    Boost 1.86.0 EXACT REQUIRED CONFIG
    COMPONENTS filesystem
               regex
               atomic
               chrono
)
if (Boost_FOUND)
    message("found boost ${Boost_VERSION}")
    message("Boost_INCLUDE_DIRS ${Boost_INCLUDE_DIRS}")
    message("Boost_LIBRARIES ${Boost_LIBRARIES}")
    include_directories(${Boost_INCLUDE_DIRS})
    set(Boost_USE_STATIC_LIBS OFF) 
    set(Boost_USE_MULTITHREADED ON)  
    set(Boost_USE_STATIC_RUNTIME OFF)
endif()


add_subdirectory(src)
add_subdirectory(app)
add_subdirectory(test)

install(
    FILES README.md
    DESTINATION ${CMAKE_INSTALL_PREFIX}/share
)

CMake 配置输出:

[cmake] build type Debug
[cmake] Not searching for unused variables given on the command line.
[cmake] found boost 1.86.0
[cmake] Boost_INCLUDE_DIRS /home/fredom/workspace/boost_1_86_0/install/include
[cmake] Boost_LIBRARIES Boost::filesystem;Boost::regex;Boost::atomic;Boost::chrono
[cmake] -- Configuring done (0.0s)
[cmake] -- Generating done (0.0s)
[cmake] -- Build files have been written to: /home/fredom/workspace/muduo/build

可以看到引入的 COMPONENTS 组件对应的依赖 target 都引入了。

这里我在 find_package 时指定了 EXACT 关键字参数,因为实验室服务器用的人太多了,所以早就安装了另一个版本的 Boost 到 /usr/local/include 里面,这个路径也在 CMake 的默认查找路径里,但是我不想用那个比较旧的版本,所以指定必须搜索用户给定的版本否则报错中止 CMake 配置流程。

SET(
    sub_dir_list

    misc
)

SET(cpp_src_list)
# SET(c_src_list)

FOREACH(_sub_dir ${sub_dir_list})
    FILE(
        GLOB sub_dir_src_list ${_sub_dir}/*.cpp
    )
    LIST(APPEND cpp_src_list ${sub_dir_src_list})

    # FILE(
    #     GLOB sub_dir_src_list ${_sub_dir}/*.c
    # )
    # LIST(APPEND c_src_list ${sub_dir_src_list})
ENDFOREACH()


FOREACH(_src_file ${cpp_src_list})
    GET_FILENAME_COMPONENT(_src_name ${_src_file} NAME_WE)
    ADD_EXECUTABLE(${_src_name} ${_src_file})
    TARGET_LINK_LIBRARIES(${_src_name} PRIVATE ${Boost_LIBRARIES})
ENDFOREACH()

然后在其他源码子目录使用 ${Boost_LIBRARIES} 就可以指代引入的 COMPONENTS 组件的依赖库了,目前“组件”这个概念我还不是很清楚怎么在 CMake 中使用,反正如果自己想做一个开源的项目分发给其他人用,有关 CMake 的打包、安装、组件的知识是必须掌握的,这部分后面要继续学习。如果在 find_package 中没有指定任何 COMPONENTS 那么 ${Boost_LIBRARIES} 变量为空,这有点奇怪,另外 CMake 有没有能在导入项目的时候如果项目设置了 COMPONENTS 自动输出导入了哪些 COMPONENTS ?不然每次使用 Boost 库还要对着网络上的 Boost 文档吗,这也太不方便了,对网络的依赖性太强这可不好,我在公司万一只有内网,主板也没有 WIFI 连接手机热点,那咋办?

Boost 链接库指引文档的问题

官方给的一个链接库的测试例程

![[Pasted image 20240908153540.png]]

问题是 Boost::regex 这个模块不链接动态库/静态库好像也能编译成功啊?我后面是使用 Boost::filesystemBoost::system 完成库链接的验证。

muduo是一个基于Linux的C++网络,它专注于高性能和可伸缩性。根据引用muduo是在Linux操作系统上开发和编译的。因此,它不支持Windows操作系统。 muduo使用了一些Linux特定的系统调用和功能,如timerfd和eventfd,这些功能在Windows中是不可用的。另外,muduo使用了一些Linux特定的和工具链,如g++编译器和CMake构建系统。 引用提到muduo适用于IA32(英特尔32位体系架构)、FreeBSD和Darwin操作系统,分别是基于Intel的32位架构、类UNIX操作系统和苹果的操作系统。Windows操作系统并不在这个列表中。 综上所述,由于muduo的特定设计和依赖于Linux操作系统的功能,Windows操作系统不支持muduo。如果你正在使用Windows系统,并且需要一个类似的网络,你可以考虑其他适用于Windows的替代品,如Boost.Asio。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [muduo网络:18---muduo简介之(muduo的由来、编译安装、目录结构、代码结构、线程模型)](https://blog.csdn.net/qq_41453285/article/details/105104845)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [muduo木铎学习(一)](https://blog.csdn.net/qq_36616692/article/details/88142811)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值