3. 依赖管理概览:编译 Vina 所需的底层库

说实话,我第一次编译 AutoDock Vina 的时候,就踩了个大坑。我以为只要把源码 clone 下来,敲个 make 就完事了。结果呢?编译报错一堆,什么 boost/config.hpp 找不到,Eigen/Dense 头文件缺失,OpenMP 的链接器符号 undefined…… 整整折腾了半天。后来我才意识到,Vina 虽然本体不大,但它的依赖库一个都不能少,版本还得对。这章我就把自己摸索出来的依赖管理经验掰开揉碎了讲给你听。

3.1 依赖库全景图

Vina 的编译依赖其实不算多,一共四个核心库。我习惯把它们分成两类:一类是「编译器配套」的,比如 OpenMP;另一类是「外部数学/工具库」,比如 Boost、Eigen 和 Zlib。下面这个图能让你一眼看明白它们之间的关系。

AutoDock Vina 编译依赖关系 AutoDock Vina OpenMP(并行) Boost(程序库) Eigen(数值计算) Zlib(压缩) 说明:Vina 直接链接这四个库,其中 OpenMP 由编译器提供,其余三个需要手动安装

3.2 每个库到底用来干嘛?

我一个个说清楚。记住,不理解依赖角色,你连报错信息都看不懂。

库名角色说明编译时出现的位置
OpenMP提供多线程并行框架。Vina 的核心打分函数和构象搜索都靠它加速。-fopenmp 编译标志 + -lgomp 链接
Boost主要是 Boost.ProgramOptions 用于命令行参数解析,以及 Boost.Serialization(旧版用)。#include <boost/program_options.hpp>
Eigen高性能线性代数库,Vina 内部用了 Eigen 做矩阵运算和向量化。#include <Eigen/Dense>,头文件库
Zlib压缩/解压库,用于读写 .gz 格式的输出文件(比如 .pdbqt.gz)。-lz 链接

我的经验: 很多人只安装 Boost 和 Eigen 就把其他库忽略了。有一次我给用户提供二进制教程,他在 CentOS 7 上少装了 OpenMP 的运行时库(libgomp),编译过了,一运行就 Segmentation Fault。你想想看,这种问题排查起来多头疼?所以这四个库,一个都不能少。

3.3 系统包管理器一键安装

我强烈建议用系统自带的包管理器装依赖,而不是自己从源码编译。一来省时间,二来版本关系系统帮我们维护好了。下面给出三大主流系统的安装命令。

3.3.1 Ubuntu / Debian(apt)

sudo apt update
sudo apt install build-essential cmake g++   # 编译工具链
sudo apt install libopenmpi-dev               # OpenMP(注意:某些版本用 libomp-dev)
sudo apt install libboost-all-dev             # Boost 全套
sudo apt install libeigen3-dev                # Eigen 头文件
sudo apt install zlib1g-dev                   # Zlib 开发包

嗯,这里要注意:libopenmpi-dev 是 OpenMPI 的包名,但 Vina 用的其实是 GCC 内置的 OpenMP(即 libgomp)。你只需确保 g++ 支持 -fopenmp 就行,不需要额外装 OpenMPI。上面的命令里 build-essential 会自动拉取 libgomp1。

我个人的安装习惯: 我会先执行 apt-cache search eigen3 确认包名是否叫 libeigen3-dev。不同 Ubuntu 版本包名可能略有差异(比如 18.04 叫 libeigen3-dev,20.04 以后也如此)。

3.3.2 CentOS / RHEL / Fedora(dnf / yum)

sudo dnf install epel-release
sudo dnf install gcc-c++ cmake make          # 编译工具
sudo dnf install openmp-devel                # OpenMP 支持
sudo dnf install boost-devel                 # Boost
sudo dnf install eigen3-devel               # Eigen
sudo dnf install zlib-devel                  # Zlib

如果你用的是 CentOS 7 或者比较老的版本,eigen3-devel 可能在 EPEL 仓库里。我建议先 yum install epel-release 再装。曾经我在 CentOS 7 上折腾,默认仓库里的 eigen 版本是 3.2,但 Vina 需要 3.3 以上,最后只能手动从源码装。这个坑我后面会专门讲。

3.3.3 macOS(Homebrew)

brew update
brew install cmake gcc@12                   # 用 GCC 而非 Clang,因为 OpenMP 支持
brew install boost                          # Boost
brew install eigen                          # Eigen
brew install zlib                           # Zlib

macOS 的坑比较多,因为苹果默认的 Clang 编译器不支持 OpenMP。我个人习惯用 brew install gcc 装一个较新版本的 GCC(比如 gcc@12),然后编译时指定 CC=gcc-12 CXX=g++-12。如果你偷懒用系统 Clang,编译会报 OpenMP 相关错误。

警告: macOS 系统自带的 libz 比较老,建议用 Homebrew 的版本。另外,Eigen 在 Homebrew 里是一个 header-only 库,安装后头文件在 /opt/homebrew/include/eigen3(Apple Silicon)或 /usr/local/include/eigen3(Intel)。CMake 需要加 -DEIGEN3_INCLUDE_DIR 指定路径。我当年就忘了指定,CMake 报找不到 Eigen,白花半小时。

3.4 版本要求的硬性底线

Vina 不同版本对依赖版本有要求。我整理了一个速查表,编译前先确认自己的版本是否满足。

依赖库Vina 1.2.x 最低版本Vina 1.1.x 最低版本备注
GCC(含 OpenMP)4.9+4.8+Clang 需加 -fopenmp 且安装 libomp
Boost1.54+1.53+通常系统包版本都满足
Eigen3.3+3.2+关键! Eigen 3.2 的 Eigen/SVD 有bug
Zlib1.2.8+1.2.5+基本都满足
CMake3.10+3.0+建议 3.15+ 以获得更好体验

我曾经踩过的坑: 在 Ubuntu 16.04 上,系统自带的 Eigen 版本是 3.2.9,Vina 1.2.x 编译通过,但运行某些分子时 SVD 分解结果异常。后来发现 Eigen 3.2 有个已知的数值稳定性问题,升级到 3.3 后解决。所以如果你编译 Vina 1.2.x,务必检查 Eigen >= 3.3。

3.5 检查安装是否成功

装完依赖后,我习惯写一个简单的 C++ 文件来验证所有库的可用性。你可以用下面这个片段测试:

// check_deps.cpp
#include <boost/program_options.hpp>
#include <Eigen/Dense>
#include <zlib.h>
#include <omp.h>
#include <iostream>

int main() {
    std::cout << "Boost: OK" << std::endl;
    std::cout << "Eigen: " << EIGEN_WORLD_VERSION << "."
              << EIGEN_MAJOR_VERSION << "."
              << EIGEN_MINOR_VERSION << std::endl;
    std::cout << "Zlib: " << zlibVersion() << std::endl;
    #ifdef _OPENMP
    std::cout << "OpenMP: " << _OPENMP << std::endl;
    #else
    std::cout << "OpenMP: NOT SUPPORTED" << std::endl;
    #endif
    return 0;
}
# 编译并运行
g++ -std=c++11 -fopenmp check_deps.cpp -lboost_program_options -lz -o check_deps
./check_deps

如果输出正常显示版本号,说明依赖到位了。我曾经用这个脚本帮实验室新同学排查环境,一跑就知道缺哪个库,不用去翻混乱的 CMake 报错。

3.6 避坑总结

依赖管理说白了就三件事:缺什么、装什么、版本对不对。我再说几个关键点:

  • 不要混用包管理器——别用 apt 装了 Boost,又手动编译一个 Boost 到 /usr/local,CMake 会乱套。
  • Eigen 是 header-only 库,没有 .so 文件,但 CMake 需要设置 Eigen3_DIR 或 CMAKE_PREFIX_PATH 让它找到 Eigen3Config.cmake。
  • OpenMP 在 macOS 上是个麻烦事,我推荐统一用 Homebrew 的 GCC 来编译 Vina,避免踩 Clang 的坑。
  • 如果系统包版本太低(比如 CentOS 7 的 Eigen 3.2),别犹豫,去官网下载源码编译,或者用 Conda 的环境隔离。Conda 版本的 Eigen 更新得很快。