# ArchLinux编译muduo网络库

最近在学习完了unix网络编程了解到了muduo网络库，打算使用muduo写一个项目练手。但苦于一直编译muduo网络库编译不成功，这里总结以下我在编译过程中遇到的问题。我使用的是ArchLinux，其他发行版应该也能参考。

## 编译时cpp版本过低

具体错误见下:

```bash
/usr/include/absl/base/policy_checks.h:79:2: error: #error "C++ versions less than C++14 are not supported."
   79 | #error "C++ versions less than C++14 are not supported."
```

这种造成这种错误的原因是因为protobuf版本太高了，过高的protobuf版本已经不支持C++14以下的编译器(具体是从哪个版本开始的不知道)。两种安装方式可能造成这种问题：

1. 使用arch包管理器安装protobuf，手动编译muduo网络库。
    
2. 使用arch包管理器直接安装muduo网络库，实际上这种情况与第一种情况相同，因为使用arch包管理器安装muduo网络库时也会同时安装protobuf。
    

所以归纳起来就是protobuf版本过高。我试过了两种解决方案。

### 方案一

手动编译安装protobuf，这样就可以不安装protobuf最新版，我这里因为不知道从哪个版本开始不支持C++11所以安装了一个较低的版本3.3.0。

[protobuf release 下载](https://github.com/protocolbuffers/protobuf/releases)

在release中找到3.3.0版本下载到本地

```bash
wget https://github.com/protocolbuffers/protobuf/releases/download/v3.3.0/protobuf-cpp-3.3.0.tar.gz
```

解压缩后进入源码目录

```bash
tar -zxvf protobuf-cpp-3.3.0.tar.gz
cd protobuf-cpp-3.3.0
```

里面应该会有一个`configure`文件，运行这个文件

```bash
sh ./configure
或者
sh ./configure --prefix=/usr/local/protobuf
```

这里--prefix为可选项，不加--prefix的话会按默认路径安装。

之后执行make命令

```bash
make
make install
ldconfig
```

这就安装完成了，若是指定了--prefix选项可能还需要定义一些环境变量以便系统能找到这些库。在`/etc/profile`文件添加以下内容。

```bash
#(动态库搜索路径) 程序加载运行期间查找动态链接库时指定除了系统默认路径之外的其他路径
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/protobuf/lib/
#(静态库搜索路径) 程序编译期间查找动态链接库时指定查找共享库的路径
export LIBRARY_PATH=$LIBRARY_PATH:/usr/local/protobuf/lib/
#执行程序搜索路径
export PATH=$PATH:/usr/local/protobuf/bin/
#c程序头文件搜索路径
export C_INCLUDE_PATH=$C_INCLUDE_PATH:/usr/local/protobuf/include/
#c++程序头文件搜索路径
export CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH:/usr/local/protobuf/include/
#pkg-config 路径
export PKG_CONFIG_PATH=/usr/local/protobuf/lib/pkgconfig/
```

更新环境变量

```bash
source /etc/profile
```

检验是否安装成功

```bash
protoc --version
```

protobuf安装成功后，不出意外的话就能成功编译安装muduo网络库了。这里可参考网络上安装教程。但需要注意即使低版本的protobuf安装成功后，仍然不能安装aur上的muduo网络库，因为它会默认安装protobuf如果已存在就会更新到最新版。

### 方案二

仍然使用最新版本的protobuf，手动编译muduo网络库。这里需要修改部分源码。

首先将编译器提升到C++14或更高，在muduo源码目录中修改`CMakeList.txt`文件。找到下面内容

```bash
set(CXX_FLAGS
    -g
    # -DVALGRIND
    -DCHECK_PTHREAD_RETURN_VALUE
    -D_FILE_OFFSET_BITS=64
    -Wall
    -Wextra
    -Werror
    -Wconversion
    -Wno-unused-parameter
    -Wold-style-cast
    -Woverloaded-virtual
    -Wpointer-arith
    -Wshadow
    -Wwrite-strings
    -march=native
    # -MMD
    -std=c++11
    -rdynamic)
```

替换成

```bash
set(CXX_FLAGS
    -g
    # -DVALGRIND
    -DCHECK_PTHREAD_RETURN_VALUE
    -D_FILE_OFFSET_BITS=64
    #-Wall
    -Wextra
    -Werror
    -Wconversion
    -Wno-unused-parameter
    -Wold-style-cast
    -Woverloaded-virtual
    -Wpointer-arith
    -Wshadow
    -Wwrite-strings
    -march=native
    # -MMD
    -std=c++20
    -rdynamic)
```

修改完后再编译可能会出现如下问题。

```bash
muduo/net/protobuf/ProtobufCodecLite.cc:112:3: error: ‘GOOGLE_CHECK_EQ’ was not declared in this scope; did you mean ‘ABSL_CHECK_EQ’?
```

这里按编译器提示修改就行，将`GOOGLE_CHECK_EQ` 修改为`ABSL_CHECK_EQ` 。具体有两个文件需要更改,一个是`muduo/net/protorpc/google-inl.h` 中的`ByteSizeConsistencyError`函数。

```cpp
inline void ByteSizeConsistencyError(int byte_size_before_serialization,
                                     int byte_size_after_serialization,
                                     int bytes_produced_by_serialization) {
  GOOGLE_CHECK_EQ(byte_size_before_serialization, byte_size_after_serialization)
      << "Protocol message was modified concurrently during serialization.";
  GOOGLE_CHECK_EQ(bytes_produced_by_serialization,
                  byte_size_before_serialization)
      << "Byte size calculation and serialization were inconsistent.  This "
         "may indicate a bug in protocol buffers or it may be caused by "
         "concurrent modification of the message.";
  GOOGLE_LOG(FATAL) << "This shouldn't be called if all the sizes are equal.";
}

//更改后
inline void ByteSizeConsistencyError(int byte_size_before_serialization,
                                     int byte_size_after_serialization,
                                     int bytes_produced_by_serialization) {
  ABSL_CHECK_EQ(byte_size_before_serialization, byte_size_after_serialization)
      << "Protocol message was modified concurrently during serialization.";
  ABSL_CHECK_EQ(bytes_produced_by_serialization,
                  byte_size_before_serialization)
      << "Byte size calculation and serialization were inconsistent.  This "
         "may indicate a bug in protocol buffers or it may be caused by "
         "concurrent modification of the message.";
  ABSL_LOG(FATAL) << "This shouldn't be called if all the sizes are equal.";
}
```

还有一个是`muduo/net/protobuf/ProtobufCodecLite.cc` 中的`serializeToBuffer`函数

```cpp
  GOOGLE_DCHECK(message.IsInitialized())
      << InitializationErrorMessage("serialize", message);

// 修改为
  ABSL_DCHECK(message.IsInitialized())
      << InitializationErrorMessage("serialize", message);
```

原因推测应该是新版的protobuf中`GOOGLE_`开头的宏被`ABSL_`开头的宏替代了或者说是名字改了。具体原因未知，我只测试了这样能编译通过而。

完成后在执行`./build.sh`应该是能编译通过的。

但还是更推荐第一种做法，毕竟muduo网络库本身就比较老了已经很久没更新了，与老版本的protobuf可能会比较兼容。
