Newer
Older
################################################################################
# Copyright 2018-2022, Barcelona Supercomputing Center (BSC), Spain #
# Copyright 2015-2022, Johannes Gutenberg Universitaet Mainz, Germany #
# #
# This software was partially supported by the #
# EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). #
# #
# This software was partially supported by the #
# ADA-FS project under the SPPEXA project funded by the DFG. #
# #
# This file is part of GekkoFS. #
# #
# GekkoFS is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# GekkoFS is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with GekkoFS. If not, see <https://www.gnu.org/licenses/>. #
# #
# SPDX-License-Identifier: GPL-3.0-or-later #
################################################################################
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DEPENDENCY=""
CORES=""
SOURCE_DIR=""
INSTALL_DIR=""
PERFORM_TEST=
EXECUTION_MODE=
DEFAULT_PROFILE="default"
DEFAULT_VERSION="latest"
PROFILE_NAME=${DEFAULT_PROFILE}
PROFILE_VERSION=${DEFAULT_VERSION}
PROFILES_DIR="${SCRIPT_DIR}/profiles"
declare -a PROFILE_DEP_LIST
declare -A PROFILE_DEP_NAMES
declare -A PROFILE_WGETDEPS PROFILE_CLONEDEPS PROFILE_SOURCES PROFILE_EXTRA_INSTALL_ARGS
declare -A PROFILE_CLONEDEPS_ARGS PROFILE_CLONEDEPS_PATCHES
usage_short() {
echo "
usage: compile_dep.sh -h |
-p PROFILE_NAME[:PROFILE_VERSION] |
-d DEPENDENCY_NAME[[@PROFILE_NAME][:PROFILE_VERSION]] |
-l [PROFILE_NAME:[PROFILE_VERSION]] |
-h
[ -P PROFILES_DIR ] [ -j COMPILE_CORES] [ -n ]
"
}
help_msg() {
This script compiles all GekkoFS dependencies (excluding the fs itself)
positional arguments:
SOURCES_PATH path to the downloaded sources for the dependencies
INSTALL_PATH path to the installation directory for the built dependencies
optional arguments:
-h, --help Shows this help message and exits
-l, --list-dependencies [[PROFILE_NAME:]PROFILE_VERSION]
List dependencies available for building and installation
-p, --profile PROFILE_NAME[:PROFILE_VERSION]
Allows installing a pre-defined set of dependencies as defined
in \${PROFILES_DIR}/PROFILE_NAME.specs. This is useful to
deploy specific library versions and/or configurations,
using a recognizable name. Optionally, PROFILE_NAME may include
a specific version for the profile, e.g. 'mogon2:latest' or
'ngio:0.9.1', which will download the dependencies defined for
that specific version. If unspecified, the 'default:latest' profile
will be used, which should include all the possible dependencies.
-d, --dependency DEPENDENCY_NAME[[@PROFILE_NAME][:PROFILE_VERSION]]
Build and install a specific dependency, ignoring any --profile
option provided. If PROFILE_NAME is unspecified, the 'default'
profile will be used. Similarly, if PROFILE_VERSION is
unspecified, the 'latest' version of the specified profile will
be used.
-j, --compilecores COMPILE_CORES
Set the number of cores that will be used to compile the
dependencies. If unspecified, defaults to the number of
available cores.
-t, --test Perform libraries tests.
-P, --profiles-dir PROFILES_DIR
Choose the directory to be used when searching for profiles.
If unspecified, PROFILES_DIR defaults to \${PWD}/profiles.
-n, --dry-run
Do not actually run, print only what would be done.
}
exec_mode_error() {
echo "ERROR: --profile and --dependency options are mutually exclusive"
usage_short
exit 1
}
if [[ ! -d "${PROFILES_DIR}" ]]; then
echo "Directory '${PROFILES_DIR}' does not exist. No profiles available."
exit 1
fi
declare -A versions
while IFS= read -r -d '' filename; do
id="$(basename $(dirname ${filename}))"
profile="$(basename ${filename%%.specs})"
versions[$id]+="${profile} "
done < <(find -L "${PROFILES_DIR}" -type f -name "*.specs" -print0 | sort -z)
echo -e "Available versions and configuration profiles:\n"
for id in "${!versions[@]}"; do
echo " ${id}:"
echo -e " ${versions[${id}]}\n"
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
exit 0
}
list_profiles() {
local TAG=$1
if [[ "$TAG" =~ ^(.*):(.*)$ ]]; then
PROFILE="${BASH_REMATCH[1]}.specs"
if [[ -n ${BASH_REMATCH[2]} ]]; then
VERSION="${BASH_REMATCH[2]}"
else
VERSION="latest"
fi
else
VERSION="${TAG}"
fi
if [[ ! -d "${PROFILES_DIR}" ]]; then
echo "Directory '${PROFILES_DIR}' does not exist. No configuration profiles found."
exit 1
fi
if [[ ! -d "${PROFILES_DIR}/${VERSION}" ]]; then
echo "Version ${VERSION} does not exist. No configuration profiles found."
exit 1
fi
echo -e "Configuration profiles for '${VERSION}':\n"
find "${PROFILES_DIR}/${VERSION}/${PROFILE}" -type f -name "*.specs" -print0 | sort -z | while IFS= read -r -d '' filename; do
basename=$(basename "${filename}")
version=$(basename $(dirname "${filename}"))
profile="${basename%.*}"
echo "* ${profile}:${version} (${filename})"
source "${filename}"
if [[ -n "${comment}" ]]; then
echo -e "\n ${comment}\n"
fi
for d in "${order[@]}";
do
if [[ -n ${wgetdeps[${d}]} ]]; then
echo " ${d}: ${wgetdeps[${d}]}"
elif [[ -n ${clonedeps[${d}]} ]]; then
echo " ${d}: ${clonedeps[${d}]}"
else
echo " ${d}: ???"
fi
done
echo ""
unset wgetdeps
unset clonedeps
unset clonedeps_args
unset clonedeps_patches
unset comment
unset order
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
exit 0
}
load_profile() {
local profile=$1
local version=$2
shift
# make sure we are in a known state
PROFILE_DEP_NAMES=()
PROFILE_DEP_LIST=()
PROFILE_CLONEDEPS=()
PROFILE_CLONEDEPS_ARGS=()
PROFILE_CLONEDEPS_PATCHES=()
PROFILE_WGETDEPS=()
local filename="${PROFILES_DIR}/${version}/${profile}.specs"
if [[ ! -f "${filename}" ]]; then
echo "Profile '${profile}:${version}' does not exist."
exit 1
fi
source "${filename}"
# some checks
if [[ -z "${wgetdeps[*]}" && -z "${clonedeps[*]}" ]]; then
echo "Profile '${profile}' is invalid."
exit 1
fi
if [[ -z "${order[*]}" ]]; then
echo "Profile '${profile}' is invalid."
exit 1
fi
if [[ "$((${#wgetdeps[@]}+${#clonedeps[@]}))" -ne "${#order[@]}" ]]; then
echo "Profile '${profile}' is invalid."
exit 1
fi
# propagate results outside of function
for i in "${!order[@]}"; do
PROFILE_DEP_LIST[$i]="${order[${i}]}"
PROFILE_DEP_NAMES["${order[$i]}"]="$i"
for k in "${!clonedeps[@]}"; do
PROFILE_CLONEDEPS["${k}"]="${clonedeps[${k}]}"
for k in "${!clonedeps_args[@]}"; do
PROFILE_CLONEDEPS_ARGS["${k}"]="${clonedeps_args[${k}]}"
for k in "${!clonedeps_patches[@]}"; do
PROFILE_CLONEDEPS_PATCHES["${k}"]="${clonedeps_patches[${k}]}"
for k in "${!wgetdeps[@]}"; do
PROFILE_WGETDEPS["${k}"]="${wgetdeps[${k}]}"
done
for k in "${!extra_install_args[@]}"; do
PROFILE_EXTRA_INSTALL_ARGS["${k}"]="${extra_install_args["${k}"]}"
done
prepare_build_dir() {
if [ ! -d "$1/build" ]; then
mkdir "$1"/build
fi
rm -rf "$1"/build/*
}
local CMAKE
CMAKE=$(command -v cmake3 || command -v cmake)
echo >&2 "ERROR: could not find cmake"
echo "${CMAKE}"
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
determine_compiler() {
compiler_is_gnu() {
COMPILER_NAME="g++"
if ! COMPILER_FULL_VERSION="$(g++ -dumpfullversion 2>&1)"; then
echo -e "ERROR: Failed to determine compiler version."
echo -e ">> ${COMPILER_FULL_VERSION}"
exit 1
fi
COMPILER_MAJOR_VERSION="${COMPILER_FULL_VERSION%%.*}"
}
compiler_is_clang() {
COMPILER_NAME="clang"
if ! COMPILER_FULL_VERSION="$(clang -dumpversion 2>&1)"; then
echo -e "ERROR: Failed to determine compiler version."
echo -e ">> ${COMPILER_FULL_VERSION}"
exit 1
fi
COMPILER_MAJOR_VERSION="${COMPILER_FULL_VERSION%%.*}"
}
# We honor the CXX environment variable if defined.
# Otherwise, we try to find the compiler by using `command -v`.
if [[ -n "${CXX}" && ! "${CXX}" =~ ^.*(g\+\+|clang)$ ]]; then
echo "ERROR: Unknown compiler '${CXX}'"
exit 1
fi
if [[ -n "${CXX}" && "${CXX}" =~ ^.*g\+\+$ ]]; then
elif [[ -n "${CXX}" && "$CXX" =~ ^.*clang$ ]]; then
compiler_is_clang
elif [[ $(command -v g++) ]]; then
compiler_is_gnu
elif [[ $(command -v clang) ]]; then
compiler_is_clang
else
echo "ERROR: Unable to determine compiler."
exit 1
fi
}
Alberto Miranda
committed
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
# Check whether the loaded profile defines a particular dependency name.
# The function requires a valid bash regex argument to do the search. The
# function is meant to be used in a conditional context.
#
# Examples:
# 1. Check whether any flavor of 'libfabric' is defined by the profile:
#
# if profile_has_dependency "^libfabric%.*$"; then
# echo "libfabric found"
# fi
#
# 2. Check whether a specific flavor of 'libfabric' is defined by the profile:
#
# if profile_has_dependency "^libfabric%experimental$"; then
# echo "libfabric.experimental found"
# fi
profile_has_dependency() {
if [[ "$#" -ne 1 ]]; then
>&2 echo "FATAL: Missing argument in profile_has_dependency()"
exit 1
fi
regex="$1"
for name in "${PROFILE_DEP_LIST[@]}"; do
if [[ "${name}" =~ ${regex} ]]; then
return 0
fi
done
return 1
}
while [[ $# -gt 0 ]]; do
key="$1"
case ${key} in
[ -n "${EXECUTION_MODE}" ] && exec_mode_error || EXECUTION_MODE='profile'
if [[ -z "$2" ]]; then
echo "ERROR: Missing argument for -p/--profile option"
exit 1
fi
if [[ "$2" =~ ^(.*):(.*)$ ]]; then
PROFILE_NAME="${BASH_REMATCH[1]}"
PROFILE_VERSION="${BASH_REMATCH[2]}"
else
PROFILE_NAME="$2"
PROFILE_VERSION="${DEFAULT_VERSION}"
shift # past argument
shift # past value
;;
-d | --dependency)
[ -n "${EXECUTION_MODE}" ] && exec_mode_error || EXECUTION_MODE='dependency'
if [[ -z "$2" ]]; then
echo "ERROR: Missing argument for -d/--dependency option"
exit
fi
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
PROFILE_NAME=${DEFAULT_PROFILE}
PROFILE_VERSION=${DEFAULT_VERSION}
# e.g. mercury@mogon1:latest
if [[ "$2" =~ ^(.*)@(.*):(.*)$ ]]; then
if [[ -n "${BASH_REMATCH[1]}" ]]; then
DEPENDENCY="${BASH_REMATCH[1]}"
fi
if [[ -n "${BASH_REMATCH[2]}" ]]; then
PROFILE_NAME="${BASH_REMATCH[2]}"
fi
if [[ -n "${BASH_REMATCH[3]}" ]]; then
PROFILE_VERSION="${BASH_REMATCH[3]}"
fi
# e.g. mercury@mogon1
elif [[ "$2" =~ ^(.*)@(.*)$ ]]; then
if [[ -n "${BASH_REMATCH[1]}" ]]; then
DEPENDENCY="${BASH_REMATCH[1]}"
fi
if [[ -n "${BASH_REMATCH[2]}" ]]; then
PROFILE_NAME="${BASH_REMATCH[2]}"
fi
# e.g. mercury
else
DEPENDENCY="$2"
fi
if [[ ! -n "${DEPENDENCY}" ]]; then
echo "ERROR: Missing dependency name."
exit 1
fi
shift # past argument
shift # past value
;;
-j | --compilecores)
CORES="$2"
shift # past argument
shift # past value
;;
-t | --test)
PERFORM_TEST=true
shift
;;
-P | --profiles-dir)
if [[ ! -d "$2" ]]; then
echo "ERROR: PROFILES_DIR '$2' does not exist or is not a directory."
exit 1
fi
PROFILES_DIR="$2"
shift # past argument
shift # past value
-l | --list-dependencies)
if [[ -z "$2" ]]; then
list_versions
else
list_profiles "$2"
fi
;;
-h | --help)
help_msg
exit
;;
-n | --dry-run)
DRY_RUN=true
shift
;;
*) # unknown option
POSITIONAL+=("$1") # save it in an array for later
shift # past argument
;;
esac
done
set -- "${POSITIONAL[@]}" # restore positional parameters
# deal with positional arguments
if [[ (-z ${1+x}) || (-z ${2+x}) ]]; then
echo "ERROR: Positional arguments missing."
SOURCE_DIR="$(readlink -mn "${1}")"
INSTALL_DIR="$(readlink -mn "${2}")"
# deal with optional arguments
if [[ "${CORES}" == "" ]]; then
CORES=$(grep -c ^processor /proc/cpuinfo)
echo "CORES = ${CORES} (default)"
if [[ ! "${CORES}" -gt "0" ]]; then
echo "ERROR: CORES set to ${CORES} which is invalid.
Input must be numeric and greater than 0."
usage_short
exit
else
echo CORES = "${CORES}"
fi
load_profile "${PROFILE_NAME}" "${PROFILE_VERSION}"
CMAKE=$(find_cmake)
CMAKE="${CMAKE} -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}"
echo "Sources download path = ${SOURCE_DIR}"
echo "Installation path = ${INSTALL_DIR}"
echo "Profile name: ${PROFILE_NAME}"
echo "Profile version: ${PROFILE_VERSION}"
echo "------------------------------------"
######### From now on exits on any error ########
set -e
export CPATH="${CPATH}:${INSTALL_DIR}/include"
export LIBRARY_PATH="${LIBRARY_PATH}:${INSTALL_DIR}/lib:${INSTALL_DIR}/lib64"
export PKG_CONFIG_PATH="${INSTALL_DIR}/lib/pkgconfig:${PKG_CONFIG_PATH}"
if [[ -n "${DEPENDENCY}" && ! -n "${PROFILE_DEP_NAMES[${DEPENDENCY}]}" ]]; then
echo "Dependency '${DEPENDENCY}' not found in '${PROFILE_NAME}:${PROFILE_VERSION}'"
exit 1
for dep_name in "${PROFILE_DEP_LIST[@]}"; do
# in dependency mode, skip any dependencies != DEPENDENCY
if [[ -n "${DEPENDENCY}" && "${dep_name}" != "${DEPENDENCY}" ]]; then
install_script="${PROFILES_DIR}/${PROFILE_VERSION}/install/${dep_name}.install"
echo -e "\n\n######## Installing: ${dep_name} ###############################\n"
if [[ -f "${install_script}" ]]; then
[[ "$DRY_RUN" == true ]] || source "${install_script}"
echo "WARNING: Install script for '${dep_name}' not found. Skipping."
[ "${PERFORM_TEST}" ] && pkg_check
fi