# Spack 指令教學
:::success
## 速成表
```
module avail = spack find
+ spack compilers
module list = spack find --loaded
module load = spack load
module info = spack load --sh
module remove = spack unload
module purge = spack unload -a
```
:::
## Intro
[Spack](https://github.com/spack/spack) 是套件管理器,但不同於 apt 懶人打包好,Spack 全部都 Compile from Source,且允許同軟體多版本並存,有 Code 在,問題可控、性能可調,且能享受大家貢獻的 Install Script,唯一缺點就是安裝可能慢了點。
## 為什麼我們需要
- mpich

- netcdf

## 管理員安裝
```
cd /opt/
git clone -c feature.manyFiles=true https://github.com/spack/spack.git
```
## 使用者安裝
- 設定環境變數
```
. /opt/spack/share/spack/setup-env.sh
source /usr/share/modules/init/bash
```
- 查找已經存在的 Compiler
```
spack compiler find
```
- 沒找到的 手動新增 compiler by path
```
spack compiler add /opt/intel/oneapi/compiler/latest/bin/
```
- 查找外部套件,例如 Ubuntu 已經安裝好的,可以節省重複編譯的時間。
```
spack external find
```
> 被找到的套件會被加入 `~/.spack/packages.yaml` 自然而然地跟其他套件列在一起(?
:::spoiler Out of Data
spack compiler add `spack location -i intel-oneapi-compilers`/compiler/latest/linux/bin/intel64
spack compiler add `spack location -i intel-oneapi-compilers`/compiler/latest/linux/bin
> SCC 2022 國網 A100 請用
> . /opt/.spack/Spack/share/spack/setup-env.sh
> 沒為什麼,只是我打到大寫了但我沒發現 =.=[name=WilliamMou]
:::
## 通用規則
- 套件表示法
- `@` 開頭表示版本號
- `%` 開頭表示編譯器
- `^` 開頭表示依賴項
- 遇到套件重複,可以用 `/hash` 來代替 pkg
:::info
- 安裝 22.1.2 版本的 py-pip,並且依賴於 3.10 版本 python
```$ spack install py-pip@22.1.2 ^python@3.10```
- 查看 hash code 為 `/bsfcrrm` 的套件的 spec (套件相依關係)
```$ spack spec /bsfcrrm```
:::
## 常見指令
### spack compilers
找到機器上所有的 compilers
:::info
```$ spack compilers```
==> Available compilers
-- aocc ubuntu20.04-x86_64 --------------------------------------
aocc@3.2.0
-- gcc ubuntu20.04-x86_64 ---------------------------------------
gcc@9.4.0
-- nvhpc ubuntu20.04-x86_64 -------------------------------------
nvhpc@21.5
:::
- 使用 Intel icc 安裝 pkg
```spack install pkg%intel```
- 使用 Intel icx 安裝 pkg
```spack install pkg%oneapi```
### spack list
check all pacakge that could be installed by `spack`
### spack info `pkg`
get detailed information on the `pkg`
### spack spec `pkg`
show what would be installed, given a spec for `pkg`
### spack install `pkg`
安裝,舉例:
- 安裝 GCC
- OpenMPI 5.0.2 版本,用 gcc 編譯,開啟 orterunprefix,底層使用 ucx 通訊:
- `spack install openmpi@5.0.2%gcc+orterunprefix fabrics=ucx`
- 安裝 hdf5 及其依賴
- `spack install --fresh --no-cache --overwrite hdf5+fortran+mpi+hl%nvhpc ^openmpi@4.1.4%nvhpc+orterunprefix+cuda cuda_arch=80 fabrics=xpmem,knem,ucx,hcoll ^ucx@1.13%gcc +thread_multiple+knem+xpmem+cma+rc+ud+dc+mlx5_dv+ib_hw_tm+dm+verbs+gdrcopy+cuda+optimizations+rdmacm cuda_arch=80 ^rdma-core~static`
### spack find `pkg`
找到已經安裝的 pkg
:::info
```$ spack find```
==> In environment cupy
==> Root specs
cuda@11.3.0 cudnn nccl +cuda cuda_arch=70 py-pip@21.3.1 python@3.10.6
==> 61 installed packages
-- linux-ubuntu20.04-zen2 / aocc@3.2.0 --------------------------
berkeley-db@18.1.40 ca-certificates-mozilla@2022-07-19 expat@2.4.8 gettext@0.21 libffi@3.4.2 libmd@1.0.4 ncurses@6.2 perl@5.34.1 py-pip@21.3.1 readline@8.1.2 tar@1.30 xz@5.2.5
bzip2@1.0.8 diffutils@3.7 gdbm@1.19 libbsd@0.11.5 libiconv@1.16 libxml2@2.9.13 openssl@1.1.1q pkgconf@1.8.0 python@3.10.6 sqlite@3.38.5 util-linux-uuid@2.37.4 zlib@1.2.12
-- linux-ubuntu20.04-zen2 / gcc@9.4.0 ---------------------------
berkeley-db@18.1.40 cmake@3.23.2 expat@2.4.8 libbsd@0.11.5 libnl@3.3.0 nccl@2.11.4-1 pkgconf@1.8.0 py-wheel@0.37.1 sqlite@3.38.5 zlib@1.2.12
bison@3.5.1 cuda@11.3.0 flex@2.6.4 libffi@3.4.2 libsigsegv@2.13 ncurses@6.2 py-docutils@0.18.1 python@3.9.13 tar@1.30
bzip2@1.0.8 cudnn@8.2.0.53-11.3 gdbm@1.19 libiconv@1.16 libxml2@2.9.13 openssl@1.1.1q py-pip@22.1.2 rdma-core@39.1 util-linux-uuid@2.37.4
ca-certificates-mozilla@2022-07-19 diffutils@3.8 gettext@0.21 libmd@1.0.4 m4@1.4.19 perl@5.34.1 py-setuptools@63.0.0 readline@8.1.2 xz@5.2.5
:::
> 用 Compiler 來分類套件,所以 `module avail` 會分成 `find` 和 `compilers`
### spack find --load
找到已經 load 的 pkg
### spack load `pkg`
load pkg,可與 module load 同時使用。
> spack load 可以利用上面的套件篩選方式快速找到可用套件,module load 需要完全打對名字。
### spack location -i `pkg`
找到 pkg 的實際安裝位置
:::info
```$ spack location -i python@3.10```
/opt/.spack/Spack/opt/spack/linux-ubuntu20.04-zen2/aocc-3.2.0/python-3.10.6-fomu6zh4rk4h6yxcrkkescvramk53epe
:::
### spack build-env `pkg`
確認當時安裝 pkg 所使用的環境變數
### spack load --sh `pkg`
找到 load pkg 相關的環境變數
>(可以在 srun 用(?)
### spack unload `pkg`
從已經 load 的清單移除 pkg
- `-a` 移除全部
### spack edit `pkg`
手動編輯 package files
## env
用於視覺上得區隔環境,env 內外可以互相引用編譯好得套件。
env 內僅顯示有被 load 和在 env 內安裝的套件,視覺上比較清晰。
另外可以一次移除 env 內安裝的套件。
:::info
- 先建立環境。`-p` 是顯示在 (env) shell 的左側
```$ spack env create cupy```
```$ spack env activate -p cupy```
- 安裝並 load 套件。
```$ spack install cuda@11.3.0```
```$ spack load cuda@11.3.0```
```$ spack install cudnn ^cuda@11.3.0```
```$ spack load cudnn@11.3.0```
```$ spack install nccl+cuda cuda_arch=70```
```$ spack load nccl+cuda cuda_arch=70```
```$ spack install py-pip@21.3.1 ^python@3.10```
```$ spack load py-pip@21.3.1```
- 安裝完成後可使用套件。
```$ pip install cupy-cuda113```
- 離開環境
```$ spack env deactivate```
:::
:::warning
env 在編譯套件的最後,可能會因為合併 prefix 產生 Fatal error,但這屬於 Spack 的 Error,只影響 Spack 的 view,不影響套件的完整性,可繼續使用。(或許關閉 view 可以解決這個問題)
:::
## 將 Binary 或閉源執行檔納入 spack 管理
- 自動尋找系統上已經存在的 lib
```
spack external find
```
- 手動加入已經安裝好的 lib
vim ~/.spack/packages.yaml
```
packages:
openssh:
externals:
- spec: sample@1.0.0%gcc
prefix: /usr
```
:::warning
以上兩種都只會將 lib 放進可以 `^` 的行列,無法直接被 `spack load`
若需要 `load`,需要 spack install `sample@1.0.0%gcc`
:::
## spec matrix
TODO
## ref
https://spack-tutorial.readthedocs.io/en/latest/
https://re-ra.xyz/Spack-%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%97/#%E5%AE%89%E8%A3%85