3. 依赖管理概览:编译 Vina 所需的底层库
说实话,我第一次编译 AutoDock Vina 的时候,就踩了个大坑。我以为只要把源码 clone 下来,敲个 make 就完事了。结果呢?编译报错一堆,什么 boost/config.hpp 找不到,Eigen/Dense 头文件缺失,OpenMP 的链接器符号 undefined…… 整整折腾了半天。后来我才意识到,Vina 虽然本体不大,但它的依赖库一个都不能少,版本还得对。这章我就把自己摸索出来的依赖管理经验掰开揉碎了讲给你听。
3.1 依赖库全景图
Vina 的编译依赖其实不算多,一共四个核心库。我习惯把它们分成两类:一类是「编译器配套」的,比如 OpenMP;另一类是「外部数学/工具库」,比如 Boost、Eigen 和 Zlib。下面这个图能让你一眼看明白它们之间的关系。
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 |
| Boost | 1.54+ | 1.53+ | 通常系统包版本都满足 |
| Eigen | 3.3+ | 3.2+ | 关键! Eigen 3.2 的 Eigen/SVD 有bug |
| Zlib | 1.2.8+ | 1.2.5+ | 基本都满足 |
| CMake | 3.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 更新得很快。