1. 为什么要在 OneAPI 下同时编译 cp2k 9.1 和 2023.1
做第一性原理计算的朋友大概率都遇到过这个场景:服务器上跑着不同课题组、不同年份的算例,有的老输入文件只认 cp2k 9.1 的解析规则,新买的机时又希望用 2023.1 的新特性。于是同一台 Rocky Linux 机器上并存两个版本就成了刚需。但真正动手时你会发现,麻烦不在 cp2k 本身,而在 Intel OneAPI 这套工具链的环境变量:MPI 的I_MPI_ROOT、MKL 的MKLROOT、编译器的PATH和LD_LIBRARY_PATH一旦被某个版本的工具链脚本覆盖,另一个版本的编译就会莫名其妙地链接到错误的库。
我这次的目标很明确:在 OneAPI 2023 环境下,用mpiifort+ MKL 分别编译 cp2k 9.1 和 cp2k 2023.1,并且把两个版本依赖下载、编译验证过程中反复要改的环境变量和 API 入口统一收敛到 TaoToken 通道,避免每次切换版本都要手动改一堆配置。TaoToken 在这里扮演的角色是统一的 Key 通道和 API 入口,官网是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 入口是 https://taotoken.net/api 。它不替代你的编译器,也不替代 cp2k,只是让你在多个版本、多台机器之间共享同一套凭据和调用方式,省掉重复配置的力气。
先说清楚环境基线,后面所有命令都基于它:
cat /etc/redhat-release # Rocky Linux release 8.6 (Green Obsidian) uname -r # 4.18.0-425.19.2.el8_7.x86_64 gcc --version | head -1 # gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-16)OneAPI 通过 module 载入,版本是 2023:
module load compiler mkl mpi ifort --version | head -1 # ifort (IFORT) 2021.8.0 20221119 mpiifort --version | head -1 # ifort (IFORT) 2021.8.0 20221119这里有个关键点:module load compiler mkl mpi之后,I_MPI_ROOT、MKLROOT、FI_PROVIDER_PATH这些变量会被写进当前 shell。如果你在同一个 shell 里先编译 9.1 再编译 2023.1,第二次的 toolchain 脚本可能会读到第一次残留的CP2K_*变量。我的做法是每个版本开一个干净的登录 shell,或者用module purge清干净再重新 load。这一步看起来啰嗦,但能省掉后面 80% 的“为什么链接到了旧库”的排查时间。
cp2k 的编译分两段:先用tools/toolchain/install_cp2k_toolchain.sh把依赖(libint、libxc、ELPA、cosma 等)编好,再用make ARCH=local编 cp2k 本体。9.1 和 2023.1 的差异主要集中在 toolchain 参数和源码里几个 Fortran 声明上,下面逐段拆。
2. TaoToken 统一 Key 通道的前置准备
在动手编译之前,先把 TaoToken 这条通道铺好。原因很实际:cp2k 的 toolchain 在下载依赖时经常因为网络抖动中断,而我们在多台机器、多个版本之间切换时,如果每次都去改tool_kit.sh里的下载地址,既容易出错又难维护。把 API 入口和 Key 统一到 TaoToken,后续无论是脚本拉取依赖、还是用 coding agent 辅助改 arch 文件,都只需要维护一份凭据。
第一步是拿到 Key。打开 https://taotoken.net/api-keys ,登录后创建一个新的 API Key,复制出来形如sk-xxxxxxxx。这个 Key 就是后面所有请求的凭据,不要写进会提交到 git 的文件里,建议放在~/.taotoken/env并chmod 600。
mkdir -p ~/.taotoken cat > ~/.taotoken/env <<'EOF' export TAOTOKEN_API_KEY="sk-你的实际Key" export TAOTOKEN_BASE_URL="https://taotoken.net/api" EOF chmod 600 ~/.taotoken/env source ~/.taotoken/env第二步是确认通道可用。TaoToken 提供模型对话入口,地址是 https://taotoken.net/models ,你可以直接在浏览器里选一个模型发一条消息验证 Key 是否生效。命令行侧可以用 curl 打一次:
curl -sS https://taotoken.net/api/v1/models \ -H "Authorization: Bearer ${TAOTOKEN_API_KEY}" \ | head -c 400返回 JSON 里能看到模型列表就说明 Key 和 Base URL 都对。这一步别跳过,因为后面 toolchain 下载依赖如果失败,你要能快速区分是网络问题还是 Key 问题。
第三步,如果你打算用 Claude Code 这类编码工具来辅助改cp_fm_types.F或者生成 arch 文件,需要把 Base URL、Key、Model ID 三件套配全。以 Claude Code 为例,它的配置走settings.json,路径通常在~/.claude/settings.json:
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "sk-你的实际Key", "ANTHROPIC_MODEL": "claude-sonnet-4-20250514" } }注意ANTHROPIC_BASE_URL填的是https://taotoken.net/api,不要带 UTM 参数,也不要多加/v1,具体以接入文档为准,文档入口在 https://taotoken.net/doc 。Model ID 要和你账号里可用的模型一致,写错会直接报 404 或 model not found。
如果你用的是 Cline 或 Roo 这类带 MCP 的插件,配置项名字不同但三件套一样:Base URL 用https://taotoken.net/api,API Key 用上面那个,Model ID 按文档填。Cline 的 MCP 配置里如果出现local proxy failed,九成是 Base URL 写成了带路径的完整 endpoint,改成纯https://taotoken.net/api即可。
对于长期跑编译、需要 agent 反复读日志改代码的场景,可以考虑 Coding Plan,入口在 https://taotoken.net/coding-plan 。它的价值在于把多轮对话的额度打包,比按次调用更适合“编译报错→贴日志→改代码→再编译”这种循环。
把这条通道铺好之后,回到 cp2k。下面所有涉及下载、改配置、验证的步骤,都可以复用同一份~/.taotoken/env,不用每个版本重配。
3. cp2k 9.1 与 2023.1 的可复制配置与 arch 片段
这一节是全文最干的部分,直接给可复制的命令和文件片段。先编 9.1。
3.1 cp2k 9.1 的 toolchain 与 arch
下载解压:
cd ~/cp2k wget https://github.com/cp2k/cp2k/releases/download/v9.1.0/cp2k-9.1.tar.bz2 tar -xvjf cp2k-9.1.tar.bz2 cd cp2k-9.1/tools/toolchain9.1 的特点是串行依赖用 gcc 编,并行依赖和 cp2k 本体用 Intel 的mpiifort/mpiicc,数学库用 MKL。toolchain 参数如下:
./install_cp2k_toolchain.sh \ --with-gcc=system \ --math-mode=mkl \ --with-mkl=system \ --with-intelmpi=system \ --with-scalapack=no \ --with-sirius=no \ --with-plumed=install跑完看到Done!之后,按提示拷贝 arch 并 source 环境:
cp install/arch/* ../../arch/ source install/setup cd ../../ make -j 48 ARCH=local VERSION="ssmp psmp"9.1 我实测ssmp和psmp能过,pdbg没过,sdbg缺liblsan,补一个包就行:
sudo yum install -y liblsan make -j 48 ARCH=local VERSION="sdbg"编完在exe/local下能看到:
ls -lh exe/local/ # cp2k.popt -> cp2k.psmp # cp2k.psmp 509M # cp2k.sdbg 339M # cp2k.ssmp 292Mcp2k.popt是软链到cp2k.psmp的,日常用这个。
3.2 cp2k 2023.1 的 toolchain 与 arch
2023.1 串行和并行都用 OneAPI 编译器加 MKL,toolchain 参数少了--with-gcc=system:
module purge module load compiler mkl mpi cd ~/cp2k/cp2k-2023.1/tools/toolchain ./install_cp2k_toolchain.sh \ --math-mode=mkl \ --with-intelmpi=system \ --with-scalapack=no \ --with-sirius=no \ --with-plumed=install成功后同样拷贝、source、编译:
cp install/arch/* ../../arch/ source install/setup cd ../../ make -j 48 ARCH=local VERSION="ssmp sdbg psmp pdbg"3.3 arch 文件片段
toolchain 生成的 arch 文件在arch/local.*,核心是编译器、MPI、MKL 的路径。以local.psmp为例,关键片段如下(路径按你实际安装位置替换):
CC = mpiicc FC = mpiifort LD = mpiifort AR = ar -r CFLAGS = -O2 -fopenmp -march=native FCFLAGS = -O2 -fopenmp -march=native -I${MKLROOT}/include LDFLAGS = -L${MKLROOT}/lib/intel64 LIBS = -lmkl_intel_lp64 -lmkl_sequential -lmkl_core -lpthread -lm这里MKLROOT由module load mkl提供,不要写死绝对路径,否则换机器就废。-march=native在跨节点集群上要慎用,如果编译节点和计算节点 CPU 不同,改成-xHost或具体指令集。
3.4 把 API 入口写进环境变量清单
为了让两个版本的编译脚本共享同一套凭据,我把 TaoToken 相关变量也放进~/.taotoken/env,并在每次编译前 source:
# ~/.taotoken/env export TAOTOKEN_API_KEY="sk-你的实际Key" export TAOTOKEN_BASE_URL="https://taotoken.net/api" export TAOTOKEN_MODEL="claude-sonnet-4-20250514"编译前:
source ~/.taotoken/env module purge module load compiler mkl mpi这样无论编 9.1 还是 2023.1,Key 通道都是同一份,切换版本时只需要module purge再 load,不用碰 Key。
4. 验证请求与编译成功结果
编完不算完,得验证二进制真能跑。cp2k 自带make test,但全量测试很慢,我一般先跑一个最小输入。
4.1 最小输入验证
建一个test.inp:
&GLOBAL PROJECT test RUN_TYPE ENERGY &END GLOBAL &FORCE_EVAL METHOD QS &DFT BASIS_SET_FILE_NAME BASIS_MOLOPT POTENTIAL_FILE_NAME GTH_POTENTIALS &MGRID CUTOFF 300 &END MGRID &QS EPS_DEFAULT 1.0E-10 &END QS &SCF SCF_GUESS ATOMIC EPS_SCF 1.0E-5 MAX_SCF 20 &END SCF &XC &XC_FUNCTIONAL PBE &END XC_FUNCTIONAL &END XC &END DFT &SUBSYS &CELL ABC 10.0 10.0 10.0 &END CELL &COORD H 0.0 0.0 0.0 H 0.0 0.0 0.74 &END COORD &KIND H BASIS_SET DZVP-MOLOPT-GTH POTENTIAL GTH-PBE-q1 &END KIND &END SUBSYS &END FORCE_EVAL用 9.1 的 psmp 跑:
source ~/cp2k/cp2k-9.1/tools/toolchain/install/setup mpirun -np 4 ~/cp2k/cp2k-9.1/exe/local/cp2k.psmp -i test.inp -o test.out tail -20 test.out看到PROGRAM ENDED AT和ENERGY| Total FORCE_EVAL就说明二进制正常。2023.1 同理,换路径即可。
4.2 用 TaoToken 通道验证模型侧
编译验证和 Key 通道验证是两条线。Key 通道这边,我习惯用一次模型对话确认:
curl -sS https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer ${TAOTOKEN_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "'"${TAOTOKEN_MODEL}"'", "messages": [{"role":"user","content":"回复 ok 两个字母"}], "max_tokens": 16 }' | head -c 300返回里有choices字段就说明通道通。如果返回401,检查 Key 是否复制完整;如果返回reading choices相关解析错误,多半是响应被截断,加-sS看完整输出。
4.3 两个版本并存的目录结构
我最终把两个版本放在同一父目录下,各自独立:
~/cp2k/ ├── cp2k-9.1/ │ ├── exe/local/cp2k.psmp │ └── tools/toolchain/install/setup └── cp2k-2023.1/ ├── exe/local/cp2k.psmp └── tools/toolchain/install/setup切换版本时,先module purge,再 source 对应版本的setup,最后module load compiler mkl mpi。顺序很重要:setup会设置CP2K_DATA_DIR等变量,如果先 load module 再 source,某些变量会被覆盖。
5. 本篇常见报错排查
编译 cp2k 的报错五花八门,这里挑几个我实际踩到的,对照真实报错给修复动作。
5.1 libint 的 undefined reference to std::ios_base::Init
这是 9.1 编依赖时最经典的坑。报错长这样:
libint2_static_init.cc:(.text+0xc): undefined reference to `std::ios_base::Init::Init()' libint2_static_init.cc:(.text+0x21): undefined reference to `std::ios_base::Init::~Init()' undefined reference to `__gxx_personality_v0' make[1]: *** [Makefile:35: fortran_example] Error 1原因是 libint 的 fortran 示例链接时没带上 libstdc++。修复分三步:
cd ~/cp2k/cp2k-9.1/tools/toolchain/build/libint-v2.6.0-cp2k-lmax-5/fortran vi Makefile.in把fortran_example那行的链接命令末尾加上-lstdc++:
fortran_example: fortran_example.o libint_f.o $(LTLINK) $(CXX) $(CXXFLAGS) $(LDFLAGS) $(COMPUTE_LIB) $(SYSLIBS) $(FCLIBS) -lstdc++ -o $@ $^然后:
make make install再回到 cp2k 根目录重新make。注意Makefile.in改了之后,如果 toolchain 重跑会覆盖,所以改完尽快编完 cp2k。
5.2 cp_fm_types.F 的 INTENT(IN) 报错
2023.1 编ssmp和sdbg时会遇到:
cp_fm_types.F(2261): error #6780: A dummy argument with the INTENT(IN) attribute shall not be defined nor become undefined. [FM] READ (unit) fm%local_data(:, j)这是源码里cp_fm_read_unformatted对一个声明为INTENT(IN)的变量做了赋值。临时修复:
vi src/fm/cp_fm_types.F找到cp_fm_read_unformatted里的声明:
TYPE(cp_fm_type), INTENT(IN) :: fm改成:
TYPE(cp_fm_type), INTENT(INOUT) :: fm这个改动不改变运行逻辑,只是让编译器不再报错。改完重新make -j 48 ARCH=local VERSION="ssmp sdbg psmp pdbg"。
5.3 local proxy failed 与 401
如果你在配置 Claude Code 或 Cline 时看到local proxy failed,先检查ANTHROPIC_BASE_URL是不是写成了https://taotoken.net/api/v1这种带路径的形式。正确写法是https://taotoken.net/api,具体以 https://taotoken.net/doc 为准。401则是 Key 问题,重新从 https://taotoken.net/api-keys 复制,注意别把首尾空格带进去。
5.4 OAuth 相关报错
有些工具走 OAuth 流程,如果报OAuth token expired或invalid_grant,说明凭据过期。重新在 console 里生成 Key,入口 https://taotoken.net/console 。生成后更新~/.taotoken/env,重新 source。
5.5 toolchain 下载中断
toolchain 下载依赖时如果中断,build目录里会留下不完整的压缩包,下次解压报错。处理办法是删掉对应包重下:
cd ~/cp2k/cp2k-9.1/tools/toolchain/build rm -f libint-v2.6.0-cp2k-lmax-5.tgz如果下载太慢,可以手动下载后拷进build,但文件名和版本必须严格对应,脚本靠文件名判断是否已下载。另一种方式是给 wget 加参数,但涉及网络配置,这里不展开,建议优先用稳定的镜像源。
6. 把两个版本和统一 Key 通道固化下来
编译完只是开始,真正省事的是把配置固化。我的做法是写一个switch_cp2k.sh,放在~/bin下:
#!/bin/bash # 用法: source switch_cp2k.sh 9.1 或 source switch_cp2k.sh 2023.1 VER=$1 module purge source ~/.taotoken/env module load compiler mkl mpi if [ "$VER" = "9.1" ]; then source ~/cp2k/cp2k-9.1/tools/toolchain/install/setup export CP2K_EXE=~/cp2k/cp2k-9.1/exe/local/cp2k.psmp elif [ "$VER" = "2023.1" ]; then source ~/cp2k/cp2k-2023.1/tools/toolchain/install/setup export CP2K_EXE=~/cp2k/cp2k-2023.1/exe/local/cp2k.psmp else echo "用法: source switch_cp2k.sh [9.1|2023.1]" return 1 fi echo "已切换到 cp2k $VER, 可执行文件: $CP2K_EXE"这样每次切换只需要source switch_cp2k.sh 9.1,Key 通道和 module 环境一起就位。跑算例时:
mpirun -np 32 $CP2K_EXE -i input.inp -o output.out最后提一个实用技巧:把编好的依赖和源码一起打包,下次换机器直接解压,省掉几小时编译。打包前记得把tools/toolchain/install和exe/local都带上,同时把~/.taotoken/env单独备份,不要打进包里。如果后续要用 coding agent 辅助调 arch 文件或读编译日志,Coding Plan 的入口在 https://taotoken.net/coding-plan ,模型对话验证在 https://taotoken.net/models ,接入文档在 https://taotoken.net/doc ,按需取用即可。