Files
Pmodules/Pmodules/modbuild.in
T

479 lines
12 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
#
#.............................................................................
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='/usr/local/bin:'
else
PATH=''
fi
PATH+='/usr/bin:/bin:/usr/sbin:/sbin'
PATH+=":${mydir}"
PATH+=":${mydir}/../lib:${mydir}/../config"
source libstd.bash || {
echo "Oops: cannot source library -- '$_'" 1>&2; exit 3;
}
# can be set in the configuration file
declare PMODULES_DISTFILESDIR=''
declare PMODULES_TMPDIR=''
source libpbuild.bash || \
std::die 3 "Oops: cannot source library -- '$_'"
# save arguments, (still) required for building dependencies
declare -r ARGS="$@"
##############################################################################
#
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
output of 'uname -s'.
--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_ROOT}'.
"
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='modbuild.conf'
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_verbose='no'
# array collecting all modules specified on the command line via '--with=module'
declare -a opt_with_modules=()
declare overlay=''
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 )
opt_system="$2"
shift
;;
--system=* )
opt_system="${1/*=}"
;;
--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'
;;
--overlay )
overlay=$2
;;
--overlay=* )
overlay=${1/*=}
;;
-- )
:
;;
-* )
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
[[ -n ${BUILD_SCRIPT} ]] || std::die 1 "No build-block specified!"
(( ${#versions[@]} > 0)) || versions+=( '.*' )
}
shopt -s nocaseglob
find_variants_files(){
shopt -q nullglob || :
local -i nullglob_set=$?
shopt -s nullglob
local files=( "${BUILDBLOCK_DIR}"/*/variants\.${opt_system} )
files+=( "${BUILDBLOCK_DIR}"/*/variants.$(uname -s) )
local f
for f in "${BUILDBLOCK_DIR}"/*/variants; do
[[ -e "${f}.${opt_system}" ]] \
|| [[ -e "${f}.$(uname -s)" ]] \
|| files+=( "$f" )
done
(( nullglob_set == 1 )) && shopt -u nullglob
std::upvar "$1" "${files[@]}"
}
shopt -s extglob
expand_variants_file(){
expand_deps(){
local text="$1"
shift
local deps=( "${@}" )
echo "${deps[@]}"
if (( ${#deps[@]} == 0 )); then
echo ${text}
else
local list
eval list=( ${deps[0]} )
for dep in ${list[*]}; do
expand_deps "${text} ${dep}" "${deps[@]:1}"
done
fi
}
local -r input="$1"
while read -a toks; do
# skip empty and comment lines
[[ -z ${toks} ]] && continue
[[ ${toke:0:1} == '#' ]] && continue
deps=( ${toks[*]:2} )
expand_deps "${toks[0]} ${toks[1]}" "${deps[@]}"
done < "${input}"
}
build_modules() {
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=()
local variants_files=()
for f in "${files[@]}"; do
local line=''
while read line; do
variants+=( "${line}" )
variants_files+=( "$f" )
done < <(expand_variants_file "${f}" | awk "${pattern}")
# here we should add a check, whether the version of the
# found variants are in the right variants files. Example:
# a variant for hdf5/1.10.4 is not allowed in a variants file
# for version 1.8. For this we need the mapping of a variant
# to the variants file in array 'variants_files'
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
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
}
#.............................................................................
# main
parse_args "$@"
if [[ -z "${opt_system}" ]]; then
opt_system=$(std::get_os_release)
fi
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}"
source libpbuild_dyn.bash || \
std::die 3 "Oops: cannot source library -- '$_'"
# source build configuration,
# must be done before sourcing libpbuild!
if [[ "${opt_bootstrap}" == 'yes' ]]; then
test -d "${BUILDBLOCK_DIR}/../../config" && PATH+=":$_"
else
# Please note: if we trap DEBUG a statement like
# test -d ... && PATH+=$_
# does not work (at least on macOS with bash 4 and 5)
if [[ -d "${PMODULES_ROOT}/${PMODULES_CONFIG_DIR}" ]]; then
PATH+=":${PMODULES_ROOT}/${PMODULES_CONFIG_DIR}"
fi
fi
source "${opt_build_config}" || \
std::die 3 "Oops: Cannot source configuration file -- '$_'"
[[ -z "${overlay}" ]] && overlay=${PMODULES_ROOT}
# :FIXME: should go dist files to
# ${PMODULES_ROOT}/var/distfiles
# or
# ${overlay}/var/distfiles
# ?
: ${PMODULES_DISTFILESDIR:=${PMODULES_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
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: