mirror of
https://github.com/Pmodules/Pmodules.git
synced 2026-06-27 01:53:08 +02:00
656 lines
16 KiB
Bash
Executable File
656 lines
16 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# The following build specific variables are set and used in libpbuild.bash:
|
|
# ARGS
|
|
# BUILD_SCRIPT
|
|
# BUILDBLOCK_DIR
|
|
#
|
|
#.............................................................................
|
|
|
|
#set -x
|
|
declare VERSION='@PMODULES_VERSION@'
|
|
|
|
# get absolute path of script
|
|
declare mydir=$(dirname "$0")
|
|
declare -r mydir=$(cd ${mydir} && pwd -P)
|
|
|
|
# initialize PATH,
|
|
# add library installation directories to the PATH,
|
|
# so 'source' is able find them
|
|
|
|
if [[ $(uname -s) == 'Darwin' ]]; then
|
|
PATH='/opt/local/bin:'
|
|
else
|
|
PATH=''
|
|
fi
|
|
PATH+='/usr/bin:/bin:/usr/sbin:/sbin'
|
|
PATH+=":${mydir}"
|
|
PATH+=":${mydir}/../lib:${mydir}/../config"
|
|
PATH+=":${mydir}/../libexec"
|
|
|
|
path=$PATH
|
|
|
|
source libstd.bash || {
|
|
echo "Oops: cannot source library -- '$_'" 1>&2; exit 3;
|
|
}
|
|
|
|
if (( ${BASH_VERSINFO[0]} < 5 )); then
|
|
std::info "bash >= 5 is required! You are running bash ${BASH_VERSION} ..."
|
|
std::info "Make sure that bash >= 5 is in your PATH."
|
|
std::info "bash >= 5 is available as Pmodule:"
|
|
std::info " module load System:bash"
|
|
std::die 3 ""
|
|
fi
|
|
|
|
std::def_cmds "${path}" \
|
|
'awk' 'base64' 'find' 'getopt' 'logger' 'mktemp' \
|
|
'rm' 'sort' 'find' 'yq'
|
|
|
|
# can be set in the configuration file
|
|
declare PMODULES_DISTFILESDIR=''
|
|
declare PMODULES_TMPDIR=''
|
|
declare pm_root="${PMODULES_HOME%%/Tools*}"
|
|
|
|
source libpbuild.bash || \
|
|
std::die 3 "Oops: cannot source library -- '$_'"
|
|
source libpmodules.bash || \
|
|
std::die 3 "Oops: cannot source library -- '$_'"
|
|
|
|
# save arguments, (still) required for building dependencies
|
|
declare -r ARGS="$@"
|
|
|
|
shopt -s nocaseglob
|
|
shopt -s extglob
|
|
|
|
declare ol_mod_root
|
|
declare ol_inst_root
|
|
|
|
##############################################################################
|
|
#
|
|
usage() {
|
|
std::error "
|
|
USAGE:
|
|
$0 [options..] [build_script] version
|
|
|
|
MANDATORY ARGUMENTS:
|
|
|
|
version
|
|
Variant of module to build.
|
|
|
|
SELECT VARIANT TO BUILD:
|
|
|
|
--system
|
|
Specify the system for selecting a variants. Defaults to the
|
|
OS version and release like 'rhel6'.
|
|
|
|
--with=P/V
|
|
Select variant to compile. Use multiple '--with' arguments
|
|
to make the selected variant unique.
|
|
|
|
BUILD-STEPS OPTIONS:
|
|
|
|
--prep
|
|
Prepare sources: unpack sources and apply patches only.
|
|
|
|
--configure
|
|
Prepare and configure sources.
|
|
|
|
--compile
|
|
Prepare, configure and compile everything.
|
|
|
|
--install
|
|
Prepare, configure and compile everything. Finally run install
|
|
step. Do not cleanup build and source directory.
|
|
|
|
--all
|
|
Run throu all steps including cleanup.
|
|
|
|
-update-modulefiles
|
|
Only install the modulefile and set the release.
|
|
|
|
MISCELLANEOUS OPTIONS:
|
|
|
|
-? | -h | --help
|
|
Print usage.
|
|
|
|
-V | --version )
|
|
Print version.
|
|
|
|
-v | --verbose )
|
|
Verbose output.
|
|
|
|
-j N | --jobs=N
|
|
Run N parallel make jobs.
|
|
|
|
-f | --force-rebuild
|
|
Force rebuild of module.
|
|
|
|
--dry-run
|
|
Dry run.
|
|
|
|
--disable-cleanup-build
|
|
--enable-cleanup-build
|
|
Cleanup files in the build directory. Default is to remove.
|
|
all files in the build-directory.
|
|
|
|
--disable-cleanup-src
|
|
--enable-cleanup-src
|
|
Cleanup files in the source directory. Default is to
|
|
remove all files in the source directory.
|
|
|
|
--disable-cleanup
|
|
--enable-cleanup
|
|
Cleanup all files in temporary directory. Default is to
|
|
remove all files created during building.
|
|
|
|
--distdir
|
|
Directory where to store and lookup downloaded files.
|
|
|
|
--tmpdir
|
|
Directory used for building a module.
|
|
|
|
--overlay
|
|
Install in this overlay. Defaults to '${PMODULES_HOME%%/Tools*}'.
|
|
"
|
|
exit 1
|
|
}
|
|
|
|
##############################################################################
|
|
#
|
|
# parse options and arguments
|
|
#
|
|
# command line arguments are taken first
|
|
# then configuration file
|
|
# last default
|
|
|
|
# versions to be build, '.*' or none means all
|
|
declare -a versions=()
|
|
declare opt_bootstrap='no'
|
|
declare opt_build_config='Pmodules.yaml'
|
|
declare opt_build_target='all'
|
|
declare opt_dry_run='no'
|
|
declare opt_enable_cleanup_build='yes'
|
|
declare opt_enable_cleanup_src='yes'
|
|
declare opt_force_rebuild='no'
|
|
declare -i opt_jobs=0
|
|
declare opt_update_modulefiles='no'
|
|
declare opt_system=''
|
|
declare opt_overlay=''
|
|
declare opt_verbose='no'
|
|
# array collecting all modules specified on the command line via '--with=module'
|
|
declare -a opt_with_modules=()
|
|
|
|
declare opt_ol_name_or_dir=''
|
|
|
|
echo "parse_args()"
|
|
|
|
parse_args() {
|
|
while (( $# > 0 )); do
|
|
case $1 in
|
|
-j )
|
|
opt_jobs="$2"
|
|
shift
|
|
;;
|
|
--jobs=[0-9]* )
|
|
opt_jobs="${1/--jobs=}"
|
|
;;
|
|
-v | --verbose )
|
|
trap 'echo "$BASH_COMMAND"' DEBUG
|
|
opt_verbose='yes'
|
|
;;
|
|
--debug )
|
|
set -x
|
|
;;
|
|
-f | --force-rebuild )
|
|
opt_force_rebuild='yes'
|
|
;;
|
|
-\? | -h | --help )
|
|
usage
|
|
;;
|
|
-V | --version )
|
|
std::die 0 "\nPmodules version ${VERSION}\nCopyright GNU GPL v2\n"
|
|
;;
|
|
--dry-run )
|
|
opt_dry_run='yes'
|
|
;;
|
|
--config )
|
|
opt_build_config="$2"
|
|
shift 1
|
|
;;
|
|
--config=* )
|
|
opt_build_config="${1#*=}"
|
|
;;
|
|
--enable-cleanup )
|
|
opt_enable_cleanup_build='yes'
|
|
opt_enable_cleanup_src='yes'
|
|
;;
|
|
--disable-cleanup )
|
|
opt_enable_cleanup_build='no'
|
|
opt_enable_cleanup_src='no'
|
|
;;
|
|
--enable-cleanup-build )
|
|
opt_enable_cleanup_build='yes'
|
|
;;
|
|
--disable-cleanup-build )
|
|
opt_enable_cleanup_build='no'
|
|
;;
|
|
--enable-cleanup-src )
|
|
opt_enable_cleanup_src='yes'
|
|
;;
|
|
--disable-cleanup-src )
|
|
opt_enable_cleanup_src='no'
|
|
;;
|
|
--distdir )
|
|
PMODULES_DISTFILESDIR="$2"
|
|
shift
|
|
;;
|
|
--distdir=* )
|
|
PMODULES_DISTFILESDIR="${1/--distdir=}"
|
|
;;
|
|
--tmpdir )
|
|
PMODULES_TMPDIR="$2"
|
|
shift
|
|
;;
|
|
--tmpdir=* )
|
|
PMODULES_TMPDIR="${1/--tmpdir=}"
|
|
;;
|
|
--system | --system=* )
|
|
if [[ $1 == *=* ]]; then
|
|
opt_system="${1#--*=}"
|
|
else
|
|
opt_system="$2"
|
|
shift
|
|
fi
|
|
;;
|
|
--overlay | --overlay=* )
|
|
if [[ $1 == *=* ]]; then
|
|
opt_overlay="${1#--*=}"
|
|
else
|
|
opt_overlay="$2"
|
|
shift
|
|
fi
|
|
;;
|
|
--use-flags )
|
|
USE_FLAGS="y:$2:"
|
|
shift
|
|
;;
|
|
--use-flags=* )
|
|
USE_FLAGS=":${1/--use-flags=}:"
|
|
;;
|
|
--with )
|
|
opt_with_modules+=( "$2" )
|
|
shift
|
|
;;
|
|
--with=*/* )
|
|
m="${1/--with=}"
|
|
opt_with_modules+=( ${m} )
|
|
;;
|
|
--prep | --configure | --compile | --install | --all )
|
|
opt_build_target=${1:2}
|
|
;;
|
|
--bootstrap )
|
|
opt_bootstrap='yes'
|
|
;;
|
|
--update-modulefiles )
|
|
opt_update_modulefiles='yes'
|
|
;;
|
|
-- )
|
|
:
|
|
;;
|
|
-* )
|
|
std::die 1 "Invalid option -- '$1'"
|
|
;;
|
|
[=0-9]* | '.*' )
|
|
versions+=( "$1" )
|
|
;;
|
|
'')
|
|
:
|
|
;;
|
|
* )
|
|
[[ -z "${BUILD_SCRIPT}" ]] || \
|
|
std::die 1 "%s "\
|
|
"Build script already set to" \
|
|
"'${BUILD_SCRIPT}' -- '$1'"
|
|
BUILD_SCRIPT=$(std::get_abspath "$1")
|
|
test -r ${BUILD_SCRIPT} || \
|
|
std::die 1 "%s " \
|
|
"Build script does not exist" \
|
|
"or is not readable -- '$_'"
|
|
BUILDBLOCK_DIR=$(dirname "${BUILD_SCRIPT}")
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
if [[ -z ${BUILD_SCRIPT} ]]; then
|
|
if [[ -r "${PWD}/build" ]]; then
|
|
BUILD_SCRIPT="${PWD}/build"
|
|
BUILDBLOCK_DIR=$(dirname "${BUILD_SCRIPT}")
|
|
else
|
|
std::die 1 "No build-block specified!"
|
|
fi
|
|
fi
|
|
(( ${#versions[@]} > 0)) || versions+=( '.*' )
|
|
}
|
|
|
|
#
|
|
# bash brace expansion of given args. Input args like:
|
|
#
|
|
# "text" "gcc/{9.3.0,10.3.0}" "openmpi/{4.0.5,4.1.0}"
|
|
#
|
|
# will be expanded to the following four lines:
|
|
#
|
|
# "text gcc/9.3.0 openmpi/4.0.5"
|
|
# "text gcc/9.3.0 openmpi/4.1.0"
|
|
# "text gcc/10.3.0 openmpi/4.0.5"
|
|
# "text gcc/10.3.0 openmpi/4.1.0"
|
|
#
|
|
bash_expand(){
|
|
local text="$1"
|
|
shift
|
|
local to_expand=( "${@}" )
|
|
if (( ${#to_expand[@]} == 0 )); then
|
|
echo ${text}
|
|
else
|
|
local list
|
|
eval list=( ${to_expand[0]} )
|
|
local s
|
|
for s in ${list[*]}; do
|
|
bash_expand "${text} ${s}" "${to_expand[@]:1}"
|
|
done;
|
|
fi;
|
|
}
|
|
|
|
build_modules_legacy() {
|
|
find_variants_files(){
|
|
shopt -q nullglob || :
|
|
local -i nullglob_set=$?
|
|
shopt -s nullglob
|
|
local files=( "${BUILDBLOCK_DIR}"/*/"${BNAME_VARIANTS}"\.${opt_system} )
|
|
files+=( "${BUILDBLOCK_DIR}"/*/"${BNAME_VARIANTS}.$(uname -s)" )
|
|
local f
|
|
for f in "${BUILDBLOCK_DIR}"/*/"${BNAME_VARIANTS}"; do
|
|
[[ -e "${f}.${opt_system}" ]] \
|
|
|| [[ -e "${f}.$(uname -s)" ]] \
|
|
|| files+=( "$f" )
|
|
done
|
|
(( nullglob_set == 1 )) && shopt -u nullglob
|
|
std::upvar "$1" "${files[@]}"
|
|
}
|
|
|
|
expand_variants_file(){
|
|
local -r input="$1"
|
|
while read -a toks; do
|
|
# skip empty and comment lines
|
|
[[ -z ${toks} ]] && continue
|
|
[[ ${toke:0:1} == '#' ]] && continue
|
|
local -a deps=( ${toks[*]:2} )
|
|
bash_expand "${toks[0]} ${toks[1]}" "${deps[@]}"
|
|
done < "${input}"
|
|
}
|
|
|
|
local name="$1"
|
|
local version="$2"
|
|
local exact_match='no'
|
|
if [[ "${version:0:1}" == "=" ]]; then
|
|
exact_match='yes'
|
|
version="${version:1}"
|
|
fi
|
|
shift 2
|
|
local with_modules=( $* )
|
|
local files
|
|
find_variants_files files
|
|
|
|
# if we have to build a dependency, we might have less dependencies
|
|
# on it. Or in other words: the list of "with modules" might be
|
|
# overdetermined. In the loop below we check, which dependencies
|
|
# specified with '--with' are required.
|
|
local m
|
|
local pattern="/^${name}\/${version}[[:blank:]]/"
|
|
for m in "${with_modules[@]}"; do
|
|
if [[ -n $(awk "/${m%/*}[\/ ]/" "${files[@]}") ]]; then
|
|
pattern+=" && /${m//\//\\/}/"
|
|
fi
|
|
done
|
|
|
|
local variants=()
|
|
for f in "${files[@]}"; do
|
|
local line=''
|
|
while read line; do
|
|
variants+=( "${line}" )
|
|
done < <(expand_variants_file "${f}" | awk "${pattern}")
|
|
done
|
|
if (( ${#variants[@]} == 0 )); then
|
|
std::info "%s " \
|
|
"${name}/${version}:" \
|
|
"no suitable variant found!"
|
|
std::die 10 "Aborting..."
|
|
elif (( ${#variants[@]} > 1 )) && [[ ${exact_match} == 'yes' ]]; then
|
|
std::info "%s " \
|
|
"Multiple variants found:"
|
|
for variant in "${variants[@]}"; do
|
|
std::info "${variant}"
|
|
done
|
|
std::die 10 "Aborting..."
|
|
fi
|
|
declare ol_name='base'
|
|
declare ol_type='n'
|
|
declare ol_mod_root="${pm_root}"
|
|
declare ol_inst_root="${pm_root}"
|
|
local -i i=0
|
|
local -i num_variants=${#variants[@]}
|
|
for ((i = 0; i < num_variants; i++)); do
|
|
local tokens=( ${variants[i]} )
|
|
local name="${tokens[0]%/*}"
|
|
version="${tokens[0]#*/}"
|
|
release="${tokens[1]}"
|
|
with_modules=( "${tokens[@]:2}" )
|
|
pbuild.build_module \
|
|
"${name}" "${version}" \
|
|
"${release}" "${with_modules[@]}"
|
|
done
|
|
}
|
|
|
|
build_modules_yaml(){
|
|
local fnames=()
|
|
fnames+=( "${BUILDBLOCK_DIR}/files/${BNAME_VARIANTS}.${opt_system}.yaml" )
|
|
fnames+=( "${BUILDBLOCK_DIR}/files/${BNAME_VARIANTS}.yaml" )
|
|
fnames+=( '__zzzzz__' )
|
|
for fname in "${fnames[@]}"; do
|
|
[[ -r "${fname}" ]] && break
|
|
done
|
|
[[ ${fname} == '__zzzzz__' ]] && \
|
|
std::die 3 "No suitable YAML variants file found"
|
|
echo "Using ${fname}..."
|
|
yaml_get_versions(){
|
|
local -n _result="$1"
|
|
local fname="$2"
|
|
local version="$3"
|
|
_result=( $(yq -Ne e \
|
|
"with_entries(select(.key | test(\"^${version}\$\")))|keys" \
|
|
"${fname}" 2>/dev/null | awk '{print $2}') )
|
|
}
|
|
|
|
yaml_get_num_variants(){
|
|
local -n _result="$1"
|
|
local fname="$2"
|
|
local version="$3"
|
|
_result=$(yq -Ne e ".\"${version}\"|length" \
|
|
"${fname}" 2>/dev/null)
|
|
if (( $? != 0 )); then
|
|
_result=0
|
|
fi
|
|
}
|
|
|
|
yaml_get_relstage(){
|
|
local -n _result="$1"
|
|
local fname="$2"
|
|
local version="$3"
|
|
local idx="$4"
|
|
_result=$(yq -Ne e ".\"${version}\"[${idx}].relstage" \
|
|
"${fname}" 2>/dev/null)
|
|
(( $? != 0 )) && relstage='unstable' || :
|
|
}
|
|
|
|
yaml_get_overlay(){
|
|
local -n _result="$1"
|
|
local fname="$2"
|
|
local version="$3"
|
|
local idx="$4"
|
|
_result=$(yq -Ne e ".\"${version}\"[${idx}].overlay" \
|
|
"${fname}" 2>/dev/null)
|
|
(( $? == 0 )) && return
|
|
_result=$(yq -Ne e ".overlay" "${fname}" 2>/dev/null)
|
|
(( $? == 0 )) && return
|
|
_result='base'
|
|
}
|
|
|
|
yaml_get_dependencies(){
|
|
local -n _result="$1"
|
|
local fname="$2"
|
|
local version="$3"
|
|
local idx="$4"
|
|
_result=( $(yq -Ne e ".\"${version}\"[${idx}]|(.with, .dependencies)" \
|
|
"${fname}" 2>/dev/null) )
|
|
if (( $? != 0 )); then
|
|
# neither .with nor .dependencies are set
|
|
_result=()
|
|
return
|
|
fi
|
|
# if one of .with, .dependencies is not set, the vaulue is
|
|
# returned as 'null'.
|
|
local -i i
|
|
for ((i=0; i<${#_result[@]}; i++)); do
|
|
if [[ ${_result[$i]} == 'null' ]]; then
|
|
unset _result[$i]
|
|
fi
|
|
done
|
|
}
|
|
|
|
local name="$1"
|
|
local version="$2"
|
|
shift 2
|
|
local with_modules=( $* )
|
|
|
|
local m
|
|
local pattern="//"
|
|
for m in "${with_modules[@]}"; do
|
|
if [[ -n $(awk "/${m%/*}[\/ ]/" "${fname}") ]]; then
|
|
pattern+=" && /${m//\//\\/}/"
|
|
fi
|
|
done
|
|
|
|
local -a versions
|
|
yaml_get_versions versions "${fname}" "${name}/${version}"
|
|
echo versions=${versions[@]}
|
|
for v in "${versions[@]}"; do
|
|
echo version=$v
|
|
local -i n_variants
|
|
yaml_get_num_variants n_variants "${fname}" "${v}"
|
|
local -i i
|
|
local -a deps=()
|
|
local relstage
|
|
local ol_name
|
|
for (( i=0; i<n_variants; i++)); do
|
|
if [[ -z ${opt_overlay} ]]; then
|
|
yaml_get_overlay ol_name "${fname}" "${v}" $i
|
|
else
|
|
ol_name="${opt_overlay}"
|
|
fi
|
|
if [[ ! -v OverlayInfo[${ol_name}:inst_root] ]]; then
|
|
std::die 3 "Overlay is not defined -- ${ol_name}"
|
|
fi
|
|
yaml_get_relstage relstage "${fname}" "${v}" $i
|
|
yaml_get_dependencies deps "${fname}" "${v}" $i
|
|
ol_inst_root="${OverlayInfo[${ol_name}:inst_root]}"
|
|
ol_mod_root="${OverlayInfo[${ol_name}:mod_root]}"
|
|
|
|
if (( ${#deps[@]} > 0 )); then
|
|
while read -a with_modules; do
|
|
pbuild.build_module \
|
|
"${name}" "${v##*/}" \
|
|
"${relstage}" "${with_modules[@]}"
|
|
done < <(bash_expand "" ${deps[@]}|awk "${pattern}")
|
|
else
|
|
pbuild.build_module \
|
|
"${name}" "${v##*/}" \
|
|
"${relstage}"
|
|
fi
|
|
done
|
|
done
|
|
}
|
|
|
|
|
|
build_modules() {
|
|
if [[ -n $(ls "${BUILDBLOCK_DIR}/files/${BNAME_VARIANTS}"*.yaml 2>/dev/null) ]]; then
|
|
build_modules_yaml "$@"
|
|
else
|
|
build_modules_legacy "$@"
|
|
fi
|
|
}
|
|
|
|
#.............................................................................
|
|
# main
|
|
|
|
parse_args "$@"
|
|
|
|
opt_system="${opt_system:-$(std::get_os_release)}"
|
|
|
|
pbuild.jobs "${opt_jobs}"
|
|
pbuild.force_rebuild "${opt_force_rebuild}"
|
|
pbuild.build_target "${opt_build_target}"
|
|
pbuild.dry_run "${opt_dry_run}"
|
|
pbuild.enable_cleanup_build "${opt_enable_cleanup_build}"
|
|
pbuild.enable_cleanup_src "${opt_enable_cleanup_src}"
|
|
pbuild.update_modulefiles "${opt_update_modulefiles}"
|
|
pbuild.system "${opt_system}"
|
|
pbuild.verbose "${opt_verbose}"
|
|
|
|
#
|
|
# read configuration for modbuild
|
|
#
|
|
if [[ "${opt_bootstrap}" == 'yes' ]]; then
|
|
pm::read_config "${BUILDBLOCK_DIR}/../../config/Pmodules.yaml"
|
|
else
|
|
pm::read_config
|
|
fi
|
|
|
|
# :FIXME: should go dist files to
|
|
# ${pm_root}/var/distfiles
|
|
# or
|
|
# ${overlay}/var/distfiles
|
|
# ?
|
|
: ${PMODULES_DISTFILESDIR:=${pm_root}/var/distfiles}
|
|
: ${PMODULES_TMPDIR:=/var/tmp/${USER}}
|
|
|
|
declare -r BUILD_SCRIPT
|
|
declare -r BUILDBLOCK_DIR
|
|
|
|
# the module name is defined by the directory the build script is in
|
|
IFS=/ read -r -a fname <<< "${BUILD_SCRIPT:1}"
|
|
module_name=${fname[${#fname[@]}-2]}
|
|
|
|
#
|
|
# are we bootstrapping? If yes, go for it...
|
|
#
|
|
if [[ "${opt_bootstrap}" == 'yes' ]]; then
|
|
declare ol_name='base'
|
|
declare ol_type=''
|
|
declare ol_mod_root="${pm_root}"
|
|
declare ol_inst_root="${pm_root}"
|
|
pbuild.bootstrap "${module_name}" "${versions[0]}" 'stable'
|
|
exit $?
|
|
fi
|
|
|
|
#
|
|
# else
|
|
#
|
|
for version in "${versions[@]}"; do
|
|
build_modules "${module_name}" "${version}" "${opt_with_modules[@]}"
|
|
done
|
|
|
|
# Local Variables:
|
|
# mode: sh
|
|
# sh-basic-offset: 8
|
|
# tab-width: 8
|
|
# End:
|