CMA-PI上使用Spack管理软件包
Spack 是一款包管理工具,支持在多种平台环境中管理多个版本。 Spack 的安装和使用均不需要管理员环境,与 Environment Modules 工具搭配,非常适合普通用户在高性能计算机 (HPC) 环境中管理自行安装的软件包。
本文介绍如何在中国气象局超算 CMA-PI 上安装并使用 Spack 管理软件包。
准备
联网
注意:Spack 安装需要连接互联网,请自行确认使用过程符合安全管理规定
使用工作电脑可以搭建连接互联网的代理服务,具体方法请参考《使用CCProxy访问互联网》。
Modules
CMA-PI 上的 Environment Modules 版本太低,不支持 spack 生成的 modulefile,建议从以下网址下载最新版本源代码并编译安装:
https://github.com/cea-hpc/modules/releases/
假设使用 bash,且安装目录为 ${PREFIX}
,需要在 .bashrc 中加入执行初始化脚本的语句,激活新版本的 Modules:
source ${PREFIX}/init/bash
安装
下载 Spack 源码到任意目录,比如 ~/spack
:
git clone https://github.com/spack/spack.git ~/spack
注意:CMA-PI 上 ${HOME}
空间较小,建议安装在 ${WORKDIR}
下。
比如我将 spack 源码放到 /g11/wangdp/spack
,将 ${HOME}/.spack
指向 /g11/wangdp/.spack
。
配置
Spack 默认在临时目录中编译软件,CMA-PI 登录节点上的临时目录 /tmp
空间较小,需要修改配置文件。
Spack 源码中默认配置文件放在 etc/spack/defaults/config.yaml
,可以拷贝到 etc/spack/config.yaml
创建全局配置文件。
修改 config.yaml
中的 build_stage 参数,比如我使用 ${WORKDIR}
作为临时目录:
config:
# ...
build_stage:
- /g11/wangdp/tmp/spack-stage
#- $tempdir/$user/spack-stage
- $user_cache_path/stage
# - $spack/var/spack/stage
CMA-PI 上默认 gcc 版本是 4.8.5,Spack 编译软件需要更高版本的 gcc,建议加载 compiler/gnu/7.2.0 环境编译软件。
module load compiler/gnu/7.2.0
启用
运行安装目录中的启动脚本 setup-env.sh
,会自动设置 spack 运行所需的所有环境
. share/spack/setup-env.sh
安装软件包
安装编译器
列出名字带有 gcc 的包
$ spack list gcc
==> 3 packages.
gcc gccmakedep gccxml
查看 gcc 包信息 (输出信息有省略):
$ spack info gcc
...skip...
Preferred version:
11.2.0 https://ftpmirror.gnu.org/gcc/gcc-11.2.0/gcc-11.2.0.tar.xz
Safe versions:
master [git] git://gcc.gnu.org/git/gcc.git on branch master
11.2.0 https://ftpmirror.gnu.org/gcc/gcc-11.2.0/gcc-11.2.0.tar.xz
11.1.0 https://ftpmirror.gnu.org/gcc/gcc-11.1.0/gcc-11.1.0.tar.xz
10.3.0 https://ftpmirror.gnu.org/gcc/gcc-10.3.0/gcc-10.3.0.tar.xz
...skip...
...skip...
使用 软件包名@版本号
安装特定版本的软件,比如安装 gcc 11.2.0 版本:
spack install gcc@11.2.0
Spack 会自动完成编译安装过程,无需人工干预。
Spack 会自动生成 modulefiles,例如:
---------------------------------------------------------------- /g11/wangdp/spack/share/spack/modules/linux-rhel7-skylake_avx512 -----------------------------------------------------------------
autoconf-2.69-gcc-7.2.0-zlmpner gdbm-1.19-gcc-11.2.0-c5wnfvi libtool-2.4.6-gcc-11.2.0-jjeyy6l perl-data-dumper-2.173-gcc-11.2.0-dysktvj
autoconf-2.69-gcc-11.2.0-lu3hnho gettext-0.21-gcc-11.2.0-a3zthoi libxml2-2.9.12-gcc-11.2.0-cypdhyx pkgconf-1.8.0-gcc-7.2.0-m37i762
autoconf-archive-2019.01.06-gcc-7.2.0-uondeqc gmp-6.2.1-gcc-7.2.0-g2vetpz llvm-13.0.0-gcc-11.2.0-bthtfdd pkgconf-1.8.0-gcc-11.2.0-jl7bsbr
automake-1.16.3-gcc-7.2.0-ncando6 gmp-6.2.1-gcc-11.2.0-7b5cfew m4-1.4.19-gcc-7.2.0-vtxuj4e python-3.9.9-gcc-11.2.0-2uewfga
automake-1.16.3-gcc-11.2.0-d5ihhcj hdf5-1.10.8-gcc-11.2.0-cheztle m4-1.4.19-gcc-11.2.0-3kmxnoq python-3.9.9-gcc-11.2.0-yekpxme
berkeley-db-18.1.40-gcc-7.2.0-cuxl55c hwloc-2.6.0-gcc-11.2.0-ugyr4eu mpc-1.1.0-gcc-7.2.0-qgh6eyh readline-8.1-gcc-7.2.0-sgdutpv
berkeley-db-18.1.40-gcc-11.2.0-24b7a3k icu4c-67.1-gcc-11.2.0-oxmk6pp mpfr-4.1.0-gcc-7.2.0-4v6mafg readline-8.1-gcc-11.2.0-dqkuohg
binutils-2.37-gcc-11.2.0-anqvk75 libbsd-0.11.3-gcc-11.2.0-p4gcdfb ncurses-6.2-gcc-7.2.0-cemjjmi sqlite-3.36.0-gcc-11.2.0-7ciqk43
boost-1.78.0-gcc-11.2.0-g7q4hsk libedit-3.1-20210216-gcc-11.2.0-vqiveik ncurses-6.2-gcc-11.2.0-5bjbpz6 swig-4.0.2-gcc-11.2.0-a5ghqhs
bzip2-1.0.8-gcc-7.2.0-56lfmrw libevent-2.1.12-gcc-11.2.0-tw3n64x netcdf-c-4.8.1-gcc-11.2.0-pynhref tar-1.34-gcc-11.2.0-quhasja
bzip2-1.0.8-gcc-11.2.0-r2uk64t libffi-3.3-gcc-11.2.0-35ihfql ninja-1.10.2-gcc-11.2.0-gfrv6eb texinfo-6.5-gcc-7.2.0-6gws4dg
cmake-3.21.4-gcc-11.2.0-tiz3kfj libiconv-1.16-gcc-7.2.0-65aqasu numactl-2.0.14-gcc-11.2.0-zhxkwvh texinfo-6.5-gcc-11.2.0-dlxnvyt
diffutils-3.8-gcc-7.2.0-q7tlvof libiconv-1.16-gcc-11.2.0-etwypbw openjpeg-2.3.1-gcc-11.2.0-elsfurs util-linux-uuid-2.36.2-gcc-11.2.0-tthbqas
diffutils-3.8-gcc-11.2.0-j6tsybk libmd-1.0.3-gcc-11.2.0-ex5ev2k openmpi-4.1.2-gcc-11.2.0-mkirxv7 util-macros-1.19.3-gcc-11.2.0-tho5udh
eccodes-2.21.0-gcc-11.2.0-t2vu5vf libpciaccess-0.16-gcc-11.2.0-tbib7se openssh-8.7p1-gcc-11.2.0-3bpop23 xz-5.2.5-gcc-11.2.0-kunel7c
expat-2.4.1-gcc-11.2.0-4nw3kmo libpng-1.6.37-gcc-11.2.0-exq2gem openssl-1.1.1l-gcc-11.2.0-saemgxn zlib-1.2.11-gcc-7.2.0-zrous7o
gcc-11.2.0-gcc-7.2.0-owiuisk libsigsegv-2.13-gcc-7.2.0-oa7acu5 pcre-8.44-gcc-11.2.0-iplazxn zlib-1.2.11-gcc-11.2.0-4wtgccg
gdb-11.1-gcc-11.2.0-5jivrfs libsigsegv-2.13-gcc-11.2.0-5dxkjo5 perl-5.34.0-gcc-7.2.0-enxe6m2 zstd-1.5.0-gcc-7.2.0-lospiea
gdbm-1.19-gcc-7.2.0-22ix63b libtool-2.4.6-gcc-7.2.0-jt3d2s4 perl-5.34.0-gcc-11.2.0-o2ui6qe
注册编译器
Spack 无法自动识别安装的编译器,需要手动配置。
使用如下的命令注册 gcc 11.2.0 版本。
spack compiler find $(spack location -i gcc@11.2.0)
查看已安装的编译器
$ spack compilers
==> Available compilers
-- clang rhel7-x86_64 -------------------------------------------
clang@13.0.0
-- gcc rhel7-x86_64 ---------------------------------------------
gcc@11.2.0 gcc@7.2.0 gcc@4.8.5 gcc@4.4.7
使用特定编译器编译软件
在使用 spack install
安装软件时,可以使用 %
指定编译器,spack 会自动配置编译环境,无需手动执行 module
加载。
例如使用 gcc 11.2.0 编译安装 ecCodes 库。
spack install eccodes %gcc@11.2.0
使用软件包编译程序
注:笔者刚开始使用 Spack,应该存在更合适的方法
加载软件包
当使用 Spack 安装的软件包编译自己编写的程序时,需要使用 module
加载需要的环境。
module load gcc-11.2.0-gcc-7.2.0-owiuisk
module load gdb-11.1-gcc-11.2.0-5jivrfs
module load cmake-3.21.4-gcc-11.2.0-tiz3kfj
module load eccodes-2.21.0-gcc-11.2.0-t2vu5vf
编译
编译一个简单的 GRIB2 文件读取程序:
#include <iostream>
#include <string>
#include <cstdio>
#include <eccodes.h>
int main() {
std::string file_path = "/g1/COMMONDATA/OPER/NWPC/GRAPES_GFS_GMF/Prod-grib/2021123000/ORIG/gmf.gra.2021123000072.grb2";
auto grib_file = std::fopen(file_path.c_str(), "r");
if(grib_file == nullptr){
std::cerr << "Unable to open file " << file_path << std::endl;
return 1;
}
int err = 0;
std::cout << "create handler..." << std::endl;
codes_handle* handler = codes_handle_new_from_file(nullptr, grib_file, PRODUCT_GRIB, &err);
if (handler == nullptr) {
std::cerr << "Unable to create grib handler" <<std::endl;
return 1;
}
std::cout << "get discipline..." << std::endl;
long discipline;
err = codes_get_long(handler, "discipline", &discipline);
if (err != 0) {
std::cerr << "codes_get_long has error: " << err << std::endl;
}
std::cout << "discipline: " << discipline << std::endl;
codes_handle_delete(handler);
std::fclose(grib_file);
return 0;
}
CMakeLists.txt 内容
cmake_minimum_required(VERSION 3.18)
project(mofis)
find_package(eccodes REQUIRED)
set(CMAKE_CXX_STANDARD 17)
add_executable(mofis main.cpp)
target_include_directories(mofis PRIVATE ${eccodes_BASE_DIR}/include)
target_link_libraries(mofis PRIVATE ${eccodes_BASE_DIR}/lib64/libeccodes.so)
在 build 目录中编译,CMake 会自动查找库,无需指定 CMAKE_PREFIX_PATH
cmake ../mofis
查看生成的可执行程序需要的动态链接库
$ ldd ./mofis
linux-vdso.so.1 => (0x00007fff1c9dd000)
libeccodes.so => /g11/wangdp/spack/opt/spack/linux-rhel7-skylake_avx512/gcc-11.2.0/eccodes-2.21.0-t2vu5vfqstrivfzixpjx7e3wfsctrv7x/./lib64/libeccodes.so (0x00002b96ec12c000)
libstdc++.so.6 => /g11/wangdp/spack/opt/spack/linux-rhel7-skylake_avx512/gcc-7.2.0/gcc-11.2.0-owiuiskhc5nrcad6yxf72dgci4ib7mhj/lib64/libstdc++.so.6 (0x00002b96ec5e8000)
libm.so.6 => /lib64/libm.so.6 (0x00002b96eca51000)
libgcc_s.so.1 => /g11/wangdp/spack/opt/spack/linux-rhel7-skylake_avx512/gcc-7.2.0/gcc-11.2.0-owiuiskhc5nrcad6yxf72dgci4ib7mhj/lib64/libgcc_s.so.1 (0x00002b96ecd54000)
libc.so.6 => /lib64/libc.so.6 (0x00002b96ecf6d000)
libopenjp2.so.7 => /g11/wangdp/spack/opt/spack/linux-rhel7-skylake_avx512/gcc-11.2.0/openjpeg-2.3.1-elsfursmhv53wzcqc6vw3l4oaj5bumel/lib/libopenjp2.so.7 (0x00002b96ed333000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00002b96ed582000)
libpng16.so.16 => /g11/wangdp/spack/opt/spack/linux-rhel7-skylake_avx512/gcc-11.2.0/libpng-1.6.37-exq2gemert4uzqfq36lrp2rysora2rq4/lib/libpng16.so.16 (0x00002b96ed79f000)
libz.so.1 => /g11/wangdp/spack/opt/spack/linux-rhel7-skylake_avx512/gcc-11.2.0/zlib-1.2.11-4wtgccg5myhb2blq3muae2bb5s2kxjuf/lib/libz.so.1 (0x00002b96ed9d2000)
/lib64/ld-linux-x86-64.so.2 (0x0000564da459e000)
注:后续会尝试编译静态库,以便程序能在 Spack 环境外执行
参考
相关文章: