#!/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; } 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 wwhere to store and lookup downloaded files. --tmpdir Directory used for building a module. " exit 1 } ############################################################################## # # parse options and arguments # # multiple version can be passed via comand line declare -a versions=() declare opt_all_variants='no' declare opt_bootstrap='no' declare opt_build_config='modbuild.conf' declare opt_build_target='all' declare opt_distfiles_dir="${PMODULES_ROOT}/var/distfiles" 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=3 declare opt_update_modulefiles='no' declare opt_system='' declare opt_temp_dir="${PMODULES_TMPDIR:-/var/tmp/${USER}}" declare opt_verbose='no' # array collecting all modules specified on the command line via '--with=module' declare -a opt_with_modules=() 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 ) opt_distfiles_dir="$2" shift ;; --distdir=* ) opt_distfiles_dir="${1/--distdir=}" ;; --tmpdir ) opt_temp_dir="$2" shift ;; --tmpdir=* ) opt_temp_dir="${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' ;; -- ) : ;; -* ) 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)) || std::die 1 "Module version not specified!" } 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.pmodules_distfilesdir "${opt_distfiles_dir}" pbuild.update_modulefiles "${opt_update_modulefiles}" pbuild.temp_dir "${opt_temp_dir}" 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}/../../${PMODULES_CONFIG_DIR}" && 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 -- '$_'" 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: