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 环境外执行

参考

Spack 官方文档

Spack 官方教程

Environment Modules 文档

相关文章:

使用CCProxy访问互联网