生成完整的LAPACK

KML_LAPACK依赖于开源的Netlib LAPACK以提供完整的LAPACK接口功能。因此安装KML_LAPACK后需自行获取开源的Netlib LAPACK v3.12.0的源代码包。

操作步骤

  1. 下载Netlib LAPACK v3.12.0的源代码包。保存在编译机器可访问的路径中,假设位于“/data/Download/lapack-3.12.0.tar.gz”

    可从此处下载:https://github.com/Reference-LAPACK/lapack/archive/refs/tags/v3.12.0.tar.gz

  2. 假设libklapack.a位于“/usr/local/kml/lib/libklapack.a”,使用以下脚本编译原始的Netlib LAPACK库,并在当前目录的lapack_adapt子目录下生成适配的liblapack_adapt.a。

    set -eE
    
    echo "LAPACK_SRC_DIR         ${LAPACK_SRC_DIR:-<undefined>}"
    echo "LAPACK_TGZ             ${LAPACK_TGZ:=/data/Download/lapack-3.12.0.tar.gz}"
    echo "LIBKLAPACK_A           ${LIBKLAPACK_A:=/usr/local/kml/lib/libklapack.a}"
    echo "LIBKSERVICE_A          ${LIBKSERVICE_A:=${LIBKLAPACK_A/klapack/kservice}}"
    echo "ADAPT_DIR              ${ADAPT_DIR:=./lapack_adapt}"
    echo "CMAKE_BUILD_TYPE       ${CMAKE_BUILD_TYPE:=Release}"
    echo "LIBLAPACK_ADAPT_A      ${LIBLAPACK_ADAPT_A:=liblapack_adapt.a}"
    echo "LIBKLAPACK_FULL_SO     ${LIBKLAPACK_FULL_SO:=libklapack_full.so}"
    echo "CC                     ${CC:=gcc}"
    echo "FC                     ${FC:=gfortran}"
    
    mkdir -p ${ADAPT_DIR}
    cd ${ADAPT_DIR}
    
    # build netlib lapack
    if [ ! -r "${LAPACK_SRC_DIR}/CMakeLists.txt" ]; then
        mkdir -p netlib
        ( cd netlib ; tar xzpf ${LAPACK_TGZ} )
        LAPACK_SRC_DIR=$(cd netlib/l* ; pwd)
    fi
    
    mkdir -p build
    cmake_flags=(
        -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
        -DCMAKE_POSITION_INDEPENDENT_CODE=ON
        -DCMAKE_C_COMPILER=${CC}
        -DCMAKE_Fortran_COMPILER=${FC}
        -DCMAKE_RULE_MESSAGES=off
        -DBUILD_DEPRECATED=on
        -DBUILD_TESTING=off
    )
    ( cd build ; cmake ${cmake_flags[*]} ${LAPACK_SRC_DIR} )
    ( cd build ; make -j )
    
    cp build/lib/liblapack.a ${LIBLAPACK_ADAPT_A}
    
    # get symbols defined both in klapack and netlib lapack
    nm -g ${LIBLAPACK_ADAPT_A} | grep 'T ' | grep -oP '\K\w+(?=_$)' | sort | uniq > netlib.sym
    nm -g ${LIBKLAPACK_A} | grep 'T ' | grep -oP '\K\w+(?=_$)' | sort | uniq > klapack.sym
    comm -12 klapack.sym netlib.sym > comm.sym
    
    # update symbols name of ${LIBLAPACK_ADAPT_A}
    while read sym; do
        (
            if ! nm ${LIBLAPACK_ADAPT_A} | grep -qe " T ${sym}_\$"; then
                continue
            fi
            ar x ${LIBLAPACK_ADAPT_A} ${sym}.f.o
            mv ${sym}.f.o ${sym}_netlib.f.o
    
            objcopy --redefine-sym ${sym}_=${sym}_netlib_ ${sym}_netlib.f.o
        ) &
    done < comm.sym
    wait
    ar d ${LIBLAPACK_ADAPT_A} $(sed -ne 's/$/.f.o/p' comm.sym)
    ar d ${LIBLAPACK_ADAPT_A} xerbla.f.o
    ar ru ${LIBLAPACK_ADAPT_A} *_netlib.f.o
    rm *_netlib.f.o

  3. (可选)生成完整功能的单一KML_LAPACK动态库。

    某些应用场景可能只允许链接单个LAPACK动态链接库,此时可采用以下方法将上一节生成的libklapack_xxx.a和liblapack_adapt.a合成单一的libklapack_full.so。

    假设KML_LAPACK库为“/usr/local/kml/lib/libklapack.a和/usr/local/kml/lib/libkservice.a”,适配后的Netlib LAPACK库为当前目录下的liblapack_adapt.a。
    ${FC} -o ${LIBKLAPACK_FULL_SO} -shared -fPIC -Wl,--whole-archive ${LIBKLAPACK_A} ${LIBLAPACK_ADAPT_A} -Wl,--no-whole-archive ${LIBKSERVICE_A} -fopenmp -lpthread -lm

    执行完成后当前目录下会生成libklapack_full.so,可以单独链接此so得到LAPACK-3.12.0的全部接口功能。

    此时仍然需要单独链接KML_BLAS库以及libgfortran等系统库。

安装后验证

使用时,假设环境变量KML_LAPACK_ROOT为libklapack.*所在目录,ADAPT_ROOT为适配后Netlib LAPACK库所在目录。用户应用可以选择使用动态链接库或静态链接库。编译应用源代码时需要链接到KML_LAPACK、Netlib LAPACK、Netlib BLAS和gfortran库并开启OpenMP支持。