1#!/bin/bash -e
2
3[ "${BASH_SOURCE[0]}" ] && SCRIPT_NAME="${BASH_SOURCE[0]}" || SCRIPT_NAME=$0
4SCRIPT_DIR="$(cd "$(dirname "$SCRIPT_NAME")" && pwd -P)"
5
6source "${SCRIPT_DIR}"/common_vars.sh
7source "${SCRIPT_DIR}"/tool_kit.sh
8source "${SCRIPT_DIR}"/signal_trap.sh
9source "${INSTALLDIR}"/toolchain.conf
10source "${INSTALLDIR}"/toolchain.env
11
12# ------------------------------------------------------------------------
13# generate arch file for compiling cp2k
14# ------------------------------------------------------------------------
15
16echo "==================== generating arch files ===================="
17echo "arch files can be found in the ${INSTALLDIR}/arch subdirectory"
18! [ -f "${INSTALLDIR}/arch" ] && mkdir -p ${INSTALLDIR}/arch
19cd ${INSTALLDIR}/arch
20
21# -------------------------
22# set compiler flags
23# -------------------------
24
25# need to switch between FC and MPICC etc in arch file, but cannot use
26# same variable names, so use _arch suffix
27CC_arch="$CC"
28CXX_arch="$CXX"
29FC_arch="IF_MPI(${MPIFC}|${FC})"
30LD_arch="IF_MPI(${MPIFC}|${FC})"
31
32# we always want good line information and backtraces
33BASEFLAGS="-march=native -fno-omit-frame-pointer -g ${TSANFLAGS}"
34OPT_FLAGS="-O3 -funroll-loops"
35NOOPT_FLAGS="-O1"
36
37# those flags that do not influence code generation are used always, the others if debug
38FCDEB_FLAGS="-ffree-form -std=f2008 -fimplicit-none"
39FCDEB_FLAGS_DEBUG="-fsanitize=leak -fcheck=all -ffpe-trap=invalid,zero,overflow -finit-derived -finit-real=snan -finit-integer=-42 -Werror=realloc-lhs -finline-matmul-limit=0"
40
41# code coverage generation flags
42COVERAGE_FLAGS="-O1 -coverage -fkeep-static-functions"
43COVERAGE_DFLAGS="-D__NO_ABORT"
44
45# profile based optimization, see https://www.cp2k.org/howto:pgo
46PROFOPT_FLAGS="\$(PROFOPT)"
47
48# special flags for gfortran
49# https://gcc.gnu.org/onlinedocs/gfortran/Error-and-Warning-Options.html
50# we error out for these warnings (-Werror=uninitialized -Wno-maybe-uninitialized -> error on variables that must be used uninitialized)
51WFLAGS_ERROR="-Werror=aliasing -Werror=ampersand -Werror=c-binding-type -Werror=intrinsic-shadow -Werror=intrinsics-std -Werror=line-truncation -Werror=tabs -Werror=target-lifetime -Werror=underflow -Werror=unused-but-set-variable -Werror=unused-variable -Werror=unused-dummy-argument -Werror=conversion -Werror=zerotrip -Werror=uninitialized -Wno-maybe-uninitialized"
52# we just warn for those (that eventually might be promoted to WFLAGSERROR). It is useless to put something here with 100s of warnings.
53WFLAGS_WARN="-Wuse-without-only"
54# while here we collect all other warnings, some we'll ignore
55WFLAGS_WARNALL="-pedantic -Wall -Wextra -Wsurprising -Wunused-parameter -Warray-temporaries -Wcharacter-truncation -Wconversion-extra -Wimplicit-interface -Wimplicit-procedure -Wreal-q-constant -Wunused-parameter -Walign-commons -Wfunction-elimination -Wrealloc-lhs -Wcompare-reals -Wzerotrip"
56
57# IEEE_EXCEPTIONS dependency
58IEEE_EXCEPTIONS_DFLAGS="-D__HAS_IEEE_EXCEPTIONS"
59
60# check all of the above flags, filter out incompatible flags for the
61# current version of gcc in use
62BASEFLAGS=$(allowed_gfortran_flags         $BASEFLAGS)
63OPT_FLAGS=$(allowed_gfortran_flags         $OPT_FLAGS)
64NOOPT_FLAGS=$(allowed_gfortran_flags       $NOOPT_FLAGS)
65FCDEB_FLAGS=$(allowed_gfortran_flags       $FCDEB_FLAGS)
66FCDEB_FLAGS_DEBUG=$(allowed_gfortran_flags $FCDEB_FLAGS_DEBUG)
67COVERAGE_FLAGS=$(allowed_gfortran_flags    $COVERAGE_FLAGS)
68WFLAGS_ERROR=$(allowed_gfortran_flags      $WFLAGS_ERROR)
69WFLAGS_WARN=$(allowed_gfortran_flags       $WFLAGS_WARN)
70WFLAGS_WARNALL=$(allowed_gfortran_flags    $WFLAGS_WARNALL)
71
72# check if ieee_exeptions module is available for the current version
73# of gfortran being used
74if ! (check_gfortran_module ieee_exceptions) ; then
75    IEEE_EXCEPTIONS_DFLAGS=""
76fi
77
78# concatenate the above flags into WFLAGS, FCDEBFLAGS, DFLAGS and
79# finally into FCFLAGS and CFLAGS
80WFLAGS="$WFLAGS_ERROR $WFLAGS_WARN IF_WARNALL(${WFLAGS_WARNALL}|)"
81FCDEBFLAGS="$FCDEB_FLAGS IF_DEBUG($FCDEB_FLAGS_DEBUG|)"
82DFLAGS="${CP_DFLAGS} IF_DEBUG($IEEE_EXCEPTIONS_DFLAGS -D__CHECK_DIAG|) IF_COVERAGE($COVERAGE_DFLAGS|)"
83# language independent flags
84# valgrind with avx can lead to spurious out-of-bound results
85G_CFLAGS="$BASEFLAGS IF_VALGRIND(-mno-avx -mno-avx2|)"
86G_CFLAGS="$G_CFLAGS IF_COVERAGE($COVERAGE_FLAGS|IF_DEBUG($NOOPT_FLAGS|$OPT_FLAGS))"
87G_CFLAGS="$G_CFLAGS IF_DEBUG(|$PROFOPT_FLAGS)"
88G_CFLAGS="$G_CFLAGS $CP_CFLAGS"
89# FCFLAGS, for gfortran
90FCFLAGS="$G_CFLAGS \$(FCDEBFLAGS) \$(WFLAGS) \$(DFLAGS)"
91# CFLAGS, special flags for gcc (currently none)
92CFLAGS="$G_CFLAGS \$(DFLAGS)"
93
94# Linker flags
95LDFLAGS="\$(FCFLAGS) ${CP_LDFLAGS}"
96
97# Library flags
98# add standard libs
99LIBS="${CP_LIBS} -lstdc++"
100
101# CUDA handling
102CUDA_LIBS="-lcudart -lnvrtc -lcuda -lcufft -lcublas -lrt IF_DEBUG(-lnvToolsExt|)"
103CUDA_DFLAGS="-D__ACC -D__DBCSR_ACC -D__PW_CUDA IF_DEBUG(-D__CUDA_PROFILING|)"
104if [ "${ENABLE_CUDA}" = __TRUE__ ] && [ "${GPUVER}" != no ] ; then
105    LIBS="${LIBS} IF_CUDA(${CUDA_LIBS}|)"
106    DFLAGS="IF_CUDA(${CUDA_DFLAGS}|) ${DFLAGS}"
107    NVFLAGS="-arch sm_${ARCH_NUM} -O3 -Xcompiler='-fopenmp' --std=c++11 \$(DFLAGS)"
108    check_command nvcc "cuda"
109    check_lib -lcudart "cuda"
110    check_lib -lnvrtc "cuda"
111    check_lib -lcuda "cuda"
112    check_lib -lcufft "cuda"
113    check_lib -lcublas "cuda"
114
115    # Set include flags
116    CUDA_CFLAGS=''
117    add_include_from_paths CUDA_CFLAGS "cuda.h" $INCLUDE_PATHS
118    export CUDA_CFLAGS="${CUDA_CFLAGS}"
119    CFLAGS+=" ${CUDA_CFLAGS}"
120
121    # Set LD-flags
122    CUDA_LDFLAGS=''
123    add_lib_from_paths CUDA_LDFLAGS "libcudart.*" $LIB_PATHS
124    add_lib_from_paths CUDA_LDFLAGS "libnvrtc.*" $LIB_PATHS
125    add_lib_from_paths CUDA_LDFLAGS "libcuda.*" $LIB_PATHS
126    add_lib_from_paths CUDA_LDFLAGS "libcufft.*" $LIB_PATHS
127    add_lib_from_paths CUDA_LDFLAGS "libcublas.*" $LIB_PATHS
128    export CUDA_LDFLAGS="${CUDA_LDFLAGS}"
129    LDFLAGS+=" ${CUDA_LDFLAGS}"
130fi
131
132# -------------------------
133# generate the arch files
134# -------------------------
135
136# generator for CP2K ARCH files
137gen_arch_file() {
138    # usage: gen_arch_file file_name flags
139    #
140    # If the flags are present they are assumed to be on, otherwise
141    # they switched off
142    require_env ARCH_FILE_TEMPLATE
143    local __filename=$1
144    shift
145    local __flags=$@
146    local __full_flag_list="MPI OMP DEBUG CUDA WARNALL VALGRIND COVERAGE"
147    local __flag=''
148    for __flag in $__full_flag_list ; do
149        eval "local __${__flag}=off"
150    done
151    for __flag in $__flags ; do
152        eval "__${__flag}=on"
153    done
154    # generate initial arch file
155    cat $ARCH_FILE_TEMPLATE > $__filename
156    # add additional parts
157    if [ "$__CUDA" = "on" ] ; then
158      cat <<EOF >> $__filename
159#
160CXX         = \${CC}
161CXXFLAGS    = \${CXXFLAGS} -I\\\${CUDA_PATH}/include -std=c++11 IF_OMP(-fopenmp|)
162GPUVER      = \${GPUVER}
163NVCC        = \${NVCC}
164NVFLAGS     = \${NVFLAGS}
165EOF
166    fi
167    if [ "$__WARNALL" = "on" ] ; then
168        cat <<EOF >> $__filename
169#
170FCLOGPIPE   =  2> \\\$(notdir \\\$<).warn
171export LC_ALL=C
172EOF
173    fi
174    if [ "$with_gcc" != "__DONTUSE__" ] ; then
175        cat <<EOF >> $__filename
176#
177FYPPFLAGS   = -n --line-marker-format=gfortran5
178EOF
179    fi
180    # replace variable values in output file using eval
181    local __TMPL=$(cat $__filename)
182    eval "printf \"${__TMPL}\n\"" > $__filename
183    # pass this to parsers to replace all of the IF_XYZ statements
184    "${SCRIPTDIR}/parse_if.py" -i -f "${__filename}" $__flags
185    echo "Wrote ${INSTALLDIR}/arch/$__filename"
186}
187
188rm -f ${INSTALLDIR}/arch/local*
189# normal production arch files
190    { gen_arch_file "local.sopt" ;          arch_vers="sopt"; }
191    { gen_arch_file "local.sdbg" DEBUG;     arch_vers="${arch_vers} sdbg"; }
192[ "$ENABLE_OMP" = __TRUE__ ] && \
193    { gen_arch_file "local.ssmp" OMP;       arch_vers="${arch_vers} ssmp"; }
194[ "$MPI_MODE" != no ] && \
195    { gen_arch_file "local.popt" MPI;       arch_vers="${arch_vers} popt"; }
196[ "$MPI_MODE" != no ] && \
197    { gen_arch_file "local.pdbg" MPI DEBUG; arch_vers="${arch_vers} pdbg"; }
198[ "$MPI_MODE" != no ] && \
199[ "$ENABLE_OMP" = __TRUE__ ] && \
200    { gen_arch_file "local.psmp" MPI OMP;   arch_vers="${arch_vers} psmp"; }
201[ "$MPI_MODE" != no ] && \
202[ "$ENABLE_OMP" = __TRUE__ ] && \
203    gen_arch_file "local_warn.psmp" MPI OMP WARNALL
204# cuda enabled arch files
205if [ "$ENABLE_CUDA" = __TRUE__ ] ; then
206    [ "$ENABLE_OMP" = __TRUE__ ] && \
207      gen_arch_file "local_cuda.ssmp"          CUDA OMP
208    [ "$MPI_MODE" != no ] && \
209    [ "$ENABLE_OMP" = __TRUE__ ] && \
210      gen_arch_file "local_cuda.psmp"          CUDA OMP MPI
211    [ "$ENABLE_OMP" = __TRUE__ ] && \
212      gen_arch_file "local_cuda.sdbg"          CUDA DEBUG OMP
213    [ "$MPI_MODE" != no ] && \
214    [ "$ENABLE_OMP" = __TRUE__ ] && \
215      gen_arch_file "local_cuda.pdbg"          CUDA DEBUG OMP MPI
216    [ "$MPI_MODE" != no ] && \
217    [ "$ENABLE_OMP" = __TRUE__ ] && \
218      gen_arch_file "local_cuda_warn.psmp"     CUDA MPI OMP WARNALL
219fi
220# valgrind enabled arch files
221if [ "$ENABLE_VALGRIND" = __TRUE__ ] ; then
222      gen_arch_file "local_valgrind.sopt"      VALGRIND
223    [ "$MPI_MODE" != no ] && \
224      gen_arch_file "local_valgrind.popt"      VALGRIND MPI
225fi
226# coverage enabled arch files
227gen_arch_file "local_coverage.sdbg"            COVERAGE
228[ "$MPI_MODE" != no ] && \
229    gen_arch_file "local_coverage.pdbg"        COVERAGE MPI
230[ "$ENABLE_CUDA" = __TRUE__ ] && \
231    gen_arch_file "local_coverage_cuda.pdbg"   COVERAGE MPI CUDA
232
233cd "${ROOTDIR}"
234
235# -------------------------
236# print out user instructions
237# -------------------------
238
239cat <<EOF
240========================== usage =========================
241Done!
242Now copy:
243  cp ${INSTALLDIR}/arch/* to the cp2k/arch/ directory
244To use the installed tools and libraries and cp2k version
245compiled with it you will first need to execute at the prompt:
246  source ${SETUPFILE}
247To build CP2K you should change directory:
248  cd cp2k/
249  make -j ${NPROCS} ARCH=local VERSION="${arch_vers}"
250
251arch files for GPU enabled CUDA versions are named "local_cuda.*"
252arch files for valgrind versions are named "local_valgrind.*"
253arch files for coverage versions are named "local_coverage.*"
254
255Note that these pre-built arch files are for the GNU compiler, users have to adapt them for other compilers.
256It is possible to use the provided CP2K arch files as guidance.
257EOF
258
259#EOF
260