diff --git a/.gitignore b/.gitignore index c8133ac..1c5135b 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ profile.zsh Downloads tmp tclIndex +pbuild.log *~ diff --git a/CHANGES b/CHANGES new file mode 100644 index 0000000..c6dac62 --- /dev/null +++ b/CHANGES @@ -0,0 +1,20 @@ +Changes in version 1.0.0rc5 (since 1.0.0rc2) + - build-system + * lot of cleanup, refactoring and bugfixes + * '.*' is now a valid version argument + * 'system' isn't a synonym for OS/kernel any more. It defines a target operating system like RHEL6, macOS1014. + * checks for supported system, OS and compiler + * compute default for the number of parallel make jobs + * calling pbuild::make_all in a build-script is now deprecate + + - modulecmd + * --with option of sub-command search now accepts a comma separated list of strings + * better load hints + * log modules loaded to syslog + * PMODULES_ENV is exported only on content changes + * bugfixes and cleanup + +1.0.0rc4 + - never tagged +1.0.0rc3 + - never tagged diff --git a/Pmodules/csh b/Pmodules/csh index 00d781e..be69b42 100644 --- a/Pmodules/csh +++ b/Pmodules/csh @@ -46,3 +46,5 @@ end if (! $?LOADEDMODULES ) then setenv LOADEDMODULES "" endif + +setenv PATH "${PMODULES_HOME}/bin:${PATH}" diff --git a/Pmodules/libpbuild.bash b/Pmodules/libpbuild.bash index 4090639..e1b5f44 100644 --- a/Pmodules/libpbuild.bash +++ b/Pmodules/libpbuild.bash @@ -1,4 +1,3 @@ - #!/bin/bash #............................................................................. @@ -21,6 +20,7 @@ unset __path #............................................................................. # disable auto-echo feature of 'cd' unset CDPATH +declare -A SOURCE_UNPACK_DIRS #............................................................................. # @@ -38,97 +38,84 @@ error_handler() { trap "error_handler" ERR -############################################################################### -# -# unset environment variables used for compiling -unset C_INCLUDE_PATH -unset CPLUS_INCLUDE_PATH -unset CPP_INCLUDE_PATH -unset LIBRARY_PATH -unset LD_LIBRARY_PATH -unset DYLD_LIBRARY_PATH - -unset CFLAGS -unset CPPFLAGS -unset CXXFLAGS -unset LIBS -unset LDFLAGS - -unset CC -unset CXX -unset FC -unset F77 -unset F90 - -declare SOURCE_URLS=() -declare SOURCE_SHA256_SUMS=() -declare SOURCE_NAMES=() -declare -A SOURCE_UNPACK_DIRS - -declare CONFIGURE_ARGS=() -declare SUPPORTED_SYSTEMS=() -declare PATCH_FILES=() -declare PATCH_STRIPS=() -declare PATCH_STRIP_DEFAULT='1' declare configure_with='undef' -declare bootstrap='no' +#.............................................................................. +# +# The following variables are available in build-blocks and set read-only +# :FIXME: do we have to export them? + +# install prefix of module. +declare -x PREFIX='' + +declare -r OS=$(uname -s) + +pbuild::get_num_cores() { + case "${OS}" in + Linux ) + echo $(grep -c ^processor /proc/cpuinfo) + ;; + Darwin ) + echo $(sysctl -n hw.ncpu) + ;; + * ) + std::die 1 "OS ${OS} is not supported\n" + ;; + esac +} #.............................................................................. -# global variables -declare force_rebuild='no' +# global variables which can be set/overwritten by command line args + +declare force_rebuild='' pbuild.force_rebuild() { force_rebuild="$1" } -declare dry_run='no' +declare dry_run='' pbuild.dry_run() { dry_run="$1" } -declare enable_cleanup_build='yes' +declare enable_cleanup_build='' pbuild.enable_cleanup_build() { enable_cleanup_build="$1" } -declare enable_cleanup_src='yes' +declare enable_cleanup_src='' pbuild.enable_cleanup_src() { enable_cleanup_src="$1" } -declare build_target='all' +declare build_target='' pbuild.build_target() { build_target="$1" } -declare opt_update_modulefiles='no' +declare opt_update_modulefiles='' pbuild.update_modulefiles() { opt_update_modulefiles="$1" } # number of parallel make jobs -declare -i JOBS=3 +declare -i JOBS=$(pbuild::get_num_cores) pbuild.jobs() { - JOBS="$1" + if (( $1 == 0 )); then + JOBS=$(pbuild::get_num_cores) + (( JOBS > 10 )) && JOBS=10 || : + else + JOBS="$1" + fi } -declare system=$(uname -s) +declare system='' pbuild.system() { system="$1" } -declare TEMP_DIR="${PMODULES_TMPDIR:-/var/tmp/${USER}}" -pbuild.temp_dir() { - TEMP_DIR="$1" -} - -declare PMODULES_DISTFILESDIR="${PMODULES_ROOT}/var/distfiles" -pbuild.pmodules_distfilesdir() { - PMODULES_DISTFILESDIR="$1" -} -declare verbose='no' +declare verbose='' pbuild.verbose() { - verbose='yes' + verbose="$1" } # module name including path in hierarchy and version @@ -147,21 +134,6 @@ declare -x module_release='' # abs. path is "${PREFIX}/${_docdir}/${module_name}" declare -r _DOCDIR='share/doc' -#.............................................................................. -# -# The following variables are available in build-blocks and set read-only -# :FIXME: do we have to export them? -# - -# install prefix of module. -declare -x PREFIX='' - -# :FIXME: -# OS is still used in some build-scripts. We have to implement a getter -# and use this getter in the build-scripts. -declare -r OS="${system}" - - ############################################################################## # # Set flag to build module in source tree. @@ -178,12 +150,36 @@ pbuild::compile_in_sourcetree() { # Check whether the script is running on a supported OS. # # Arguments: -# $@: supported opertating systems (as printed by 'uname -s') +# $@: supported opertating systems (something like RHEL6, macOS10.14, ...). +# Default is all. # pbuild::supported_systems() { SUPPORTED_SYSTEMS+=( "$@" ) } +############################################################################## +# +# Check whether the script is running on a supported OS. +# +# Arguments: +# $@: supported opertating systems (like Linux, Darwin). +# Default is all. +# +pbuild::supported_os() { + SUPPORTED_OS+=( "$@" ) +} + +############################################################################## +# +# Check whether the loaded compiler is supported. +# +# Arguments: +# $@: supported compiler (like GCC, Intel, PGI). +# Default is all. +# +pbuild::supported_compilers() { + SUPPORTED_COMPILERS+=( "$@" ) +} #...................................................................... # # compute full module name and installation prefix @@ -206,7 +202,9 @@ set_full_module_name_and_prefix() { echo "$*" } - [[ -n ${GROUP} ]] || std::die 1 "${module_name}/${module_version}: group not set." + [[ -n ${GROUP} ]] || std::die 1 \ + "${module_name}/${module_version}:" \ + "group not set." # build module name # :FIXME: this should be read from a configuration file @@ -249,7 +247,7 @@ set_full_module_name_and_prefix() { PREFIX="${overlay}/${GROUP}/" local -i i=0 for ((i=${#name[@]}-1; i >= 0; i--)); do - PREFIX+="${name[i]}/" + PREFIX+="/${name[i]}" done } @@ -327,12 +325,10 @@ pbuild::use_cc() { pbuild::pre_prep() { : } -eval "pbuild::pre_prep_${system}() { :; }" pbuild::post_prep() { : } -eval "pbuild::post_prep_${system}() { :; }" ############################################################################### # @@ -449,7 +445,8 @@ pbuild::prep() { local i=0 for ((_i = 0; _i < ${#PATCH_FILES[@]}; _i++)); do std::info \ - "%s " "${module_name}/${module_version}:" \ + "%s %s\n" \ + "${module_name}/${module_version}:" \ "Appling patch '${PATCH_FILES[_i]}' ..." local -i strip_val="${PATCH_STRIPS[_i]:-${PATCH_STRIP_DEFAULT}}" patch -p${strip_val} < "${BUILDBLOCK_DIR}/${PATCH_FILES[_i]}" @@ -488,7 +485,6 @@ pbuild::add_patch() { PATCH_FILES+=( "$1" ) PATCH_STRIPS+=( "$2" ) } -eval "pbuild::add_patch_${system}() { pbuild::add_patch \"\$@\"; }" pbuild::set_default_patch_strip() { [[ -n "$1" ]] || \ @@ -509,7 +505,6 @@ pbuild::use_flag() { pbuild::pre_configure() { : } -eval "pbuild::pre_configure_${system}() { :; }" pbuild::set_configure_args() { CONFIGURE_ARGS+=( "$@" ) @@ -567,7 +562,8 @@ pbuild::configure() { "cmake failed" else std::info \ - "%s " "${module_name}/${module_version}:" \ + "%s %s\n" \ + "${module_name}/${module_version}:" \ "${FUNCNAME[0]}: skipping..." fi } @@ -575,12 +571,10 @@ pbuild::configure() { pbuild::post_configure() { : } -eval "pbuild::post_configure_${system}() { :; }" pbuild::pre_compile() { : } -eval "pbuild::pre_compile_${system}() { :; }" pbuild::compile() { make -j${JOBS} @@ -589,33 +583,31 @@ pbuild::compile() { pbuild::post_compile() { : } -eval "pbuild::post_compile_${system}() { :; }" pbuild::pre_install() { : } -eval "pbuild::pre_install_${system}() { :; }" pbuild::install() { make install } pbuild::install_shared_libs() { - local -r binary="${PREFIX}/$1" - local -r pattern="${2//\//\\/}" # escape slash - local -r dstdir="${3:-${PREFIX}/lib}" + local -r binary="$1" + local -r dstdir="$2" + local -r pattern="${3//\//\\/}" # escape slash install_shared_libs_Linux() { local libs=( $(ldd "${binary}" | \ awk "/ => \// && /${pattern}/ {print \$3}") ) - cp -avL "${libs[@]}" "${dstdir}" + [[ -n "${libs}" ]] && cp -vL "${libs[@]}" "${dstdir}" } install_shared_libs_Darwin() { # https://stackoverflow.com/questions/33991581/install-name-tool-to-update-a-executable-to-search-for-dylib-in-mac-os-x local libs=( $(otool -L "${binary}" | \ awk "/${pattern}/ {print \$1}")) - cp -avL "${libs[@]}" "${dstdir}" + [[ -n "${libs}" ]] && cp -vL "${libs[@]}" "${dstdir}" } test -e "${binary}" || \ @@ -636,14 +628,28 @@ pbuild::install_shared_libs() { pbuild::post_install() { : } -eval "pbuild::post_install_${system}() { :; }" - # # The 'do it all' function. # pbuild::make_all() { - local -a runtime_dependencies=() + source "${BUILD_SCRIPT}" + + set -e + local -r logfile="${BUILDBLOCK_DIR}/pbuild.log" + + # + # To be able to set environment variables in one of the 'pbuild::TARGET' + # function we cannot use PIPE's like + # pbuild::configure | tee -a ... + # + rm -f "${logfile}" + if [[ "${verbose}" == 'yes' ]]; then + exec > >(tee -a "${logfile}") + else + exec > >(cat >> "${logfile}") + fi + exec 2> >(tee -a "${logfile}" >&2) # # everything set up? @@ -662,13 +668,458 @@ pbuild::make_all() { check_supported_systems() { [[ -z "${SUPPORTED_SYSTEMS}" ]] && return 0 for sys in "${SUPPORTED_SYSTEMS[@]}"; do - [[ ${sys} == ${system} ]] && return 0 + [[ ${sys,,} == ${system,,} ]] && return 0 done std::die 1 \ "%s " "${module_name}/${module_version}:" \ "Not available for ${system}." } + #...................................................................... + check_supported_os() { + [[ -z "${SUPPORTED_OS}" ]] && return 0 + for os in "${SUPPORTED_OS[@]}"; do + [[ ${os,,} == ${OS,,} ]] && return 0 + done + std::die 1 \ + "%s " "${module_name}/${module_version}:" \ + "Not available for ${OS}." + } + + #...................................................................... + check_supported_compilers() { + [[ -z "${SUPPORTED_COMPILERS}" ]] && return 0 + for compiler in "${SUPPORTED_COMPILERS[@]}"; do + [[ ${compiler,,} == ${COMPILER,,} ]] && return 0 + done + std::die 1 \ + "%s " "${module_name}/${module_version}:" \ + "Not available for ${COMPILER}." + } + + #...................................................................... + # non-redefinable post-install + post_install() { + install_doc() { + test -n "${MODULE_DOCFILES}" || return 0 + local -r docdir="${PREFIX}/${_DOCDIR}/${module_name}" + + std::info \ + "%s %s\n" \ + "${module_name}/${module_version}:" \ + "Installing documentation to ${docdir}" + install -m 0755 -d \ + "${docdir}" + install -m0444 \ + "${MODULE_DOCFILES[@]/#/${SRC_DIR}/}" \ + "${docdir}" + return 0 + } + + #.............................................................. + # install build-block + # Skip installation if modulefile does not exist. + install_pmodules_files() { + test -r "${BUILDBLOCK_DIR}/modulefile" || return 0 + + local -r target_dir="${PREFIX}/share/$GROUP/${module_name}" + install -m 0756 \ + -d "${target_dir}/files" + install -m0444 \ + "${BUILD_SCRIPT}" \ + "${target_dir}" + install -m0444 \ + "${BUILDBLOCK_DIR}/modulefile" \ + "${target_dir}" + #install -m0444 \ + # "${variants_file}" \ + # "${target_dir}/files" + + local -r fname="${target_dir}/dependencies" + "${MODULECMD}" bash list -t 2>&1 1>/dev/null | \ + grep -v "Currently Loaded" > "${fname}" || : + } + + #.............................................................. + # write run time dependencies to file + write_runtime_dependencies() { + local -r fname="${PREFIX}/.dependencies" + std::info \ + "%s %s\n" \ + "${module_name}/${module_version}:" \ + "writing run-time dependencies to ${fname} ..." + local dep + echo -n "" > "${fname}" + for dep in "${runtime_dependencies[@]}"; do + [[ -z $dep ]] && continue + if [[ ! $dep =~ .*/.* ]]; then + # no version given: derive the version + # from the currently loaded module + dep=$( "${MODULECMD}" bash list -t 2>&1 1>/dev/null \ + | grep "^${dep}/" ) + fi + echo "${dep}" >> "${fname}" + done + } + + + # sometimes we need an system depended post-install + post_install_linux() { + std::info \ + "%s %s\n" \ + "${module_name}/${module_version}:" \ + "running post-installation for ${OS} ..." + cd "${PREFIX}" + # solve multilib problem with LIBRARY_PATH + # on 64bit Linux + [[ -d "lib" ]] && [[ ! -d "lib64" ]] && ln -s lib lib64 + return 0 + } + + cd "${BUILD_DIR}" + [[ "${OS}" == "Linux" ]] && post_install_linux + install_doc + install_pmodules_files + write_runtime_dependencies + return 0 + } + + #...................................................................... + # Install modulefile + install_modulefile() { + local -r src="${BUILDBLOCK_DIR}/modulefile" + if [[ ! -r "${src}" ]]; then + std::info \ + "%s %s\n" \ + "${module_name}/${module_version}:" \ + "skipping modulefile installation ..." + return + fi + # assemble name of modulefile + local dst="${overlay}/" + dst+="${GROUP}/" + dst+="${PMODULES_MODULEFILES_DIR}/" + dst+="${fully_qualified_module_name}" + + # directory where to install modulefile + local -r dstdir=${dst%/*} + + std::info \ + "%s %s\n" \ + "${module_name}/${module_version}:" \ + "installing modulefile in '${dstdir}' ..." + mkdir -p "${dstdir}" + install -m 0444 "${src}" "${dst}" + } + + install_release_file() { + local dst="${overlay}/" + dst+="${GROUP}/" + dst+="${PMODULES_MODULEFILES_DIR}/" + dst+="${fully_qualified_module_name}" + + # directory where to install release file + local -r dstdir=${dst%/*} + mkdir -p "${dstdir}" + + local -r release_file="${dst%/*}/.release-${module_version}" + + if [[ -r "${release_file}" ]]; then + local release + read release < "${release_file}" + if [[ "${release}" != "${module_release}" ]]; then + std::info \ + "%s %s %s\n" \ + "${module_name}/${module_version}:" \ + "changing release from" \ + "'${release}' to '${module_release}' ..." + echo "${module_release}" > "${release_file}" + fi + else + std::info \ + "%s %s\n" \ + "${module_name}/${module_version}:" \ + "setting release to '${module_release}' ..." + echo "${module_release}" > "${release_file}" + fi + } + + cleanup_build() { + [[ ${enable_cleanup_build} == yes ]] || return 0 + [[ "${BUILD_DIR}" == "${SRC_DIR}" ]] && return 0 + { + cd "/${BUILD_DIR}/.." || std::die 42 "Internal error" + [[ "$(pwd)" == "/" ]] && \ + std::die 1 \ + "%s " "${module_name}/${module_version}:" \ + "Oops: internal error:" \ + "BUILD_DIR is set to '/'" + + std::info \ + "%s %s\n" \ + "${module_name}/${module_version}:" \ + "Cleaning up '${BUILD_DIR}'..." + rm -rf "${BUILD_DIR##*/}" + }; + return 0 + } + + cleanup_src() { + [[ ${enable_cleanup_src} == yes ]] || return 0 + { + cd "/${SRC_DIR}/.." || std::die 42 "Internal error" + [[ $(pwd) == / ]] && \ + std::die 1 \ + "%s " "${module_name}/${module_version}:" \ + "Oops: internal error:" \ + "SRC_DIR is set to '/'" + std::info \ + "%s %s\n" \ + "${module_name}/${module_version}:" \ + "Cleaning up '${SRC_DIR}'..." + rm -rf "${SRC_DIR##*/}" + }; + return 0 + } + + build_target() { + local dir="$1" + local target="$2" + if [[ -e "${BUILD_DIR}/.${target}" ]] && \ + [[ ${force_rebuild} != 'yes' ]]; then + return 0 + fi + local targets=() + targets+=( "pre_${target}_${system}" "pre_${target}_${OS}" "pre_${target}" ) + if typeset -F pbuild::${target}_${system} 1>/dev/null 2>&1; then + targets+=( "${target}_${system}" ) + elif typeset -F pbuild::${target}_${OS} 1>/dev/null 2>&1; then + targets+=( "${target}_${OS}" ) + else + targets+=( "${target}" ) + fi + targets+=( "post_${target}_${system}" "post_${target}_${OS}" "post_${target}" ) + + for t in "${targets[@]}"; do + # We cd into the dir before calling the function - + # just to be sure we are in the right directory. + # + # Executing the function in a sub-process doesn't + # work because in some function global variables + # might/need to be set. + # + cd "${dir}" + "pbuild::$t" + done + touch "${BUILD_DIR}/.${target}" + } + + #...................................................................... + # build module ${module_name}/${module_version} + build_module() { + std::info \ + "%s %s\n" \ + "${module_name}/${module_version}:" \ + "start building ..." + [[ ${dry_run} == yes ]] && std::die 0 "" + + mkdir -p "${SRC_DIR}" + mkdir -p "${BUILD_DIR}" + + std::info \ + "%s %s\n" \ + "${module_name}/${module_version}:" \ + "preparing sources ..." + # write stdout and stderr to logfile, stderr to terminal + # write all to logfile and terminal + build_target "${SRC_DIR}" prep + [[ "${build_target}" == "prep" ]] && return 0 + + std::info \ + "%s %s\n" \ + "${module_name}/${module_version}:" \ + "configuring ..." + build_target "${BUILD_DIR}" configure + [[ "${build_target}" == "configure" ]] && return 0 + + std::info \ + "%s %s\n" \ + "${module_name}/${module_version}:" \ + "compiling ..." + build_target "${BUILD_DIR}" compile + [[ "${build_target}" == "compile" ]] && return 0 + + std::info \ + "%s %s\n" \ + "${module_name}/${module_version}:" \ + "installing ..." + mkdir -p "${PREFIX}" + build_target "${BUILD_DIR}" install + post_install + + [[ "${build_target}" == "install" ]] && return 0 + + install_modulefile + install_release_file + cleanup_build + cleanup_src + std::info \ + "%s %s\n" \ + "${module_name}/${module_version}:" \ + "Done ..." + return 0 + } + remove_module() { + if [[ -d "${PREFIX}" ]]; then + std::info \ + "%s %s\n" \ + "${module_name}/${module_version}:" \ + "removing all files in '${PREFIX}' ..." + [[ "${dry_run}" == 'no' ]] && rm -rf ${PREFIX} + fi + + # assemble name of modulefile + local dst="${overlay}/" + dst+="${GROUP}/" + dst+="${PMODULES_MODULEFILES_DIR}/" + dst+="${fully_qualified_module_name}" + + # directory where to install modulefile + local -r dstdir=${dst%/*} + + if [[ -e "${dst}" ]]; then + std::info \ + "%s %s\n" \ + "${module_name}/${module_version}:" \ + "removing modulefile '${dst}' ..." + [[ "${dry_run}" == 'no' ]] && rm -v "${dst}" + fi + local release_file="${dstdir}/.release-${module_version}" + if [[ -e "${release_file}" ]]; then + std::info \ + "%s %s\n" \ + "${module_name}/${module_version}:" \ + "removing release file '${release_file}' ..." + [[ "${dry_run}" == 'no' ]] && rm -v "${release_file}" + fi + rmdir -p "${dstdir}" 2>/dev/null || : + } + + ######################################################################## + # + # here we really start with make_all() + # + + # setup module specific environment + if [[ "${bootstrap}" == 'no' ]]; then + check_supported_systems + check_supported_os + check_supported_compilers + set_full_module_name_and_prefix + if [[ "${module_release}" == 'removed' ]]; then + remove_module + elif [[ ! -d "${PREFIX}" ]] || \ + [[ "${force_rebuild}" == 'yes' ]]; then + build_module + else + std::info \ + "%s %s\n" \ + "${module_name}/${module_version}:" \ + "already exists, not rebuilding ..." + if [[ "${opt_update_modulefiles}" == "yes" ]]; then + install_modulefile + fi + install_release_file + fi + else + build_module + fi + return 0 +} + +pbuild.init_env() { + #...................................................................... + # + # parse the passed version string + # + # the following global variables will be set in this function: + # V_MAJOR + # V_MINOR + # V_PATCHLVL + # V_RELEASE + # USE_FLAGS + # + parse_version() { + local v="$1" + V_MAJOR='' # first number in version string + V_MINOR='' # second number in version string (or empty) + V_PATCHLVL='' # third number in version string (or empty) + V_RELEASE='' # module release (or empty) + USE_FLAGS='' # architectures (or empty) + + local tmp='' + + if [[ "$v" =~ "_" ]]; then + tmp="${v#*_}" + USE_FLAGS=":${tmp//_/:}:" + v="${v%%_*}" + fi + V_PKG="${v%%-*}" # version without the release number + V_RELEASE="${v#*-}" # release number + + case "${V_PKG}" in + *.*.* ) + V_MAJOR="${V_PKG%%.*}" + tmp="${V_PKG#*.}" + V_MINOR="${tmp%%.*}" + V_PATCHLVL="${tmp#*.}" + ;; + *.* ) + V_MAJOR="${V_PKG%.*}" + V_MINOR="${V_PKG#*.}" + ;; + * ) + V_MAJOR="${V_PKG}" + ;; + esac + } + + local -r module_name="$1" + local -r module_version="$2" + + SRC_DIR="${PMODULES_TMPDIR}/${module_name}-${module_version}/src" + BUILD_DIR="${PMODULES_TMPDIR}/${module_name}-${module_version}/build" + + # P and V can be used in the build-script, so we have to set them here + P="${module_name}" + V="${module_version}" + parse_version "${module_version}" + + SOURCE_URLS=() + SOURCE_SHA256_SUMS=() + SOURCE_NAMES=() + CONFIGURE_ARGS=() + SUPPORTED_SYSTEMS=() + SUPPORTED_OS=() + SUPPORTED_COMPILERS=() + PATCH_FILES=() + PATCH_STRIPS=() + PATCH_STRIP_DEFAULT='1' + MODULE_DOCFILES=() + configure_with='undef' +} + +pbuild.build_module() { + module_name="$1" + module_version="$2" + module_release="$3" + shift 3 + with_modules=( "$@" ) + + # used in pbuild::make_all + declare bootstrap='no' + declare -a runtime_dependencies=() + #...................................................................... # # test whether a module is loaded or not @@ -715,7 +1166,8 @@ pbuild::make_all() { "${m}: module does not exist," \ "cannot continue with dry run..." - std::info "$m: module does not exist, trying to build it..." + std::info "%s\n" \ + "$m: module does not exist, trying to build it..." local args=( '' ) set -- ${ARGS[@]} while (( $# > 0 )); do @@ -816,383 +1268,23 @@ pbuild::make_all() { "since the dependency '$m' is ${release_of_dependency}" fi - echo "Loading module: ${m}" + std::info "Loading module: ${m}\n" module load "${m}" done } - #...................................................................... - # non-redefinable post-install - post_install() { - install_doc() { - test -n "${MODULE_DOCFILES}" || return 0 - local -r docdir="${PREFIX}/${_DOCDIR}/${module_name}" + MODULECMD="${PMODULES_HOME}/bin/modulecmd" + [[ -x ${MODULECMD} ]] || \ + std::die 2 "No such file or executable -- '${MODULECMD}'" - std::info \ - "%s " "${module_name}/${module_version}:" \ - "Installing documentation to ${docdir}" - install -m 0755 -d \ - "${docdir}" - install -m0444 \ - "${MODULE_DOCFILES[@]/#/${SRC_DIR}/}" \ - "${docdir}" - return 0 - } + eval $( "${MODULECMD}" bash use unstable ) + eval $( "${MODULECMD}" bash use deprecated ) + eval $( "${MODULECMD}" bash purge ) - #.............................................................. - # install build-block - # Skip installation if modulefile does not exist. - install_pmodules_files() { - test -r "${BUILDBLOCK_DIR}/modulefile" || return 0 - - local -r target_dir="${PREFIX}/share/$GROUP/${module_name}" - install -m 0756 \ - -d "${target_dir}/files" - install -m0444 \ - "${BUILD_SCRIPT}" \ - "${target_dir}" - install -m0444 \ - "${BUILDBLOCK_DIR}/modulefile" \ - "${target_dir}" - #install -m0444 \ - # "${variants_file}" \ - # "${target_dir}/files" - - local -r fname="${target_dir}/dependencies" - "${MODULECMD}" bash list -t 2>&1 1>/dev/null | \ - grep -v "Currently Loaded" > "${fname}" || : - } - - #.............................................................. - # write run time dependencies to file - write_runtime_dependencies() { - local -r fname="${PREFIX}/.dependencies" - std::info \ - "%s " "${module_name}/${module_version}:" \ - "writing run-time dependencies to ${fname} ..." - local dep - echo -n "" > "${fname}" - for dep in "${runtime_dependencies[@]}"; do - [[ -z $dep ]] && continue - if [[ ! $dep =~ .*/.* ]]; then - # no version given: derive the version - # from the currently loaded module - dep=$( "${MODULECMD}" bash list -t 2>&1 1>/dev/null \ - | grep "^${dep}/" ) - fi - echo "${dep}" >> "${fname}" - done - } - - - # sometimes we need an system depended post-install - post_install_linux() { - std::info \ - "%s " "${module_name}/${module_version}:" \ - "running post-installation for ${system} ..." - cd "${PREFIX}" - # solve multilib problem with LIBRARY_PATH - # on 64bit Linux - [[ -d "lib" ]] && [[ ! -d "lib64" ]] && ln -s lib lib64 - return 0 - } - - cd "${BUILD_DIR}" - [[ "${system}" == "Linux" ]] && post_install_linux - install_doc - install_pmodules_files - write_runtime_dependencies - return 0 - } - - #...................................................................... - # Install modulefile - install_modulefile() { - local -r src="${BUILDBLOCK_DIR}/modulefile" - if [[ ! -r "${src}" ]]; then - std::info \ - "%s " "${module_name}/${module_version}:" \ - "skipping modulefile installation ..." - return - fi - # assemble name of modulefile - local dst="${overlay}/" - dst+="${GROUP}/" - dst+="${PMODULES_MODULEFILES_DIR}/" - dst+="${fully_qualified_module_name}" - - # directory where to install modulefile - local -r dstdir=${dst%/*} - - std::info \ - "%s " "${module_name}/${module_version}:" \ - "installing modulefile in '${dstdir}' ..." - mkdir -p "${dstdir}" - install -m 0444 "${src}" "${dst}" - } - - install_release_file() { - local dst="${overlay}/" - dst+="${GROUP}/" - dst+="${PMODULES_MODULEFILES_DIR}/" - dst+="${fully_qualified_module_name}" - - # directory where to install release file - local -r dstdir=${dst%/*} - mkdir -p "${dstdir}" - - local -r release_file="${dst%/*}/.release-${module_version}" - - if [[ -r "${release_file}" ]]; then - local release - read release < "${release_file}" - if [[ "${release}" != "${module_release}" ]]; then - std::info \ - "%s " "${module_name}/${module_version}:" \ - "changing release from" \ - "'${release}' to '${module_release}' ..." - echo "${module_release}" > "${release_file}" - fi - else - std::info \ - "%s " "${module_name}/${module_version}:" \ - "setting release to '${module_release}' ..." - echo "${module_release}" > "${release_file}" - fi - } - - cleanup_build() { - [[ ${enable_cleanup_build} == yes ]] || return 0 - [[ "${BUILD_DIR}" == "${SRC_DIR}" ]] && return 0 - { - cd "/${BUILD_DIR}/.." || std::die 42 "Internal error" - [[ "$(pwd)" == "/" ]] && \ - std::die 1 \ - "%s " "${module_name}/${module_version}:" \ - "Oops: internal error:" \ - "BUILD_DIR is set to '/'" - - std::info \ - "%s " "${module_name}/${module_version}:" \ - "Cleaning up '${BUILD_DIR}'..." - rm -rf "${BUILD_DIR##*/}" - }; - return 0 - } - - cleanup_src() { - [[ ${enable_cleanup_src} == yes ]] || return 0 - { - cd "/${SRC_DIR}/.." || std::die 42 "Internal error" - [[ $(pwd) == / ]] && \ - std::die 1 \ - "%s " "${module_name}/${module_version}:" \ - "Oops: internal error:" \ - "SRC_DIR is set to '/'" - std::info \ - "%s " "${module_name}/${module_version}:" \ - "Cleaning up '${SRC_DIR}'..." - rm -rf "${SRC_DIR##*/}" - }; - return 0 - } - - build_target() { - local dir="$1" - local target="$2" - if [[ -e "${BUILD_DIR}/.${target}" ]] && \ - [[ ${force_rebuild} != 'yes' ]]; then - return 0 - fi - local targets=() - targets+=( "pre_${target}_${system}" "pre_${target}" ) - targets+=( "${target}" ) - targets+=( "post_${target}_${system}" "post_${target}" ) - - for t in "${targets[@]}"; do - # We cd into the dir before calling the function - - # just to be sure we are in the right directory. - # - # Executing the function in a sub-process doesn't - # work because in some function global variables - # might/need to be set. - # - cd "${dir}" && "pbuild::$t" || std::die 42 "Aborting ..." - done - touch "${BUILD_DIR}/.${target}" - } - - #...................................................................... - # build module ${module_name}/${module_version} - build_module() { - local -r logfile="${BUILD_DIR}/pbuild.log" - if [[ "${verbose}" = 'yes' ]]; then - local -r output="/dev/fd/1" - else - local -r output="/dev/null" - fi - std::info \ - "%s " "${module_name}/${module_version}:" \ - "start building ..." - [[ ${dry_run} == yes ]] && std::die 0 "" - - mkdir -p "${SRC_DIR}" - mkdir -p "${BUILD_DIR}" - - std::info \ - "%s " "${module_name}/${module_version}:" \ - "preparing sources ..." - build_target "${SRC_DIR}" prep | tee "${logfile}" > ${output} - [[ "${build_target}" == "prep" ]] && return 0 - - std::info \ - "%s " "${module_name}/${module_version}:" \ - "configuring ..." - build_target "${BUILD_DIR}" configure | tee "${logfile}" >> ${output} - [[ "${build_target}" == "configure" ]] && return 0 - - std::info \ - "%s " "${module_name}/${module_version}:" \ - "compiling ..." - build_target "${BUILD_DIR}" compile | tee "${logfile}" >> ${output} - [[ "${build_target}" == "compile" ]] && return 0 - - std::info \ - "%s " "${module_name}/${module_version}:" \ - "installing ..." - mkdir -p "${PREFIX}" - build_target "${BUILD_DIR}" install | tee "${logfile}" >> ${output} - post_install - - [[ "${build_target}" == "install" ]] && return 0 - - install_modulefile - install_release_file - cleanup_build - cleanup_src - std::info "%s" "${module_name}/${module_version}: Done ..." - return 0 - } - remove_module() { - if [[ -d "${PREFIX}" ]]; then - std::info \ - "%s " "${module_name}/${module_version}:" \ - "removing all files in '${PREFIX}' ..." - [[ "${dry_run}" == 'no' ]] && rm -rf ${PREFIX} - fi - - # assemble name of modulefile - local dst="${overlay}/" - dst+="${GROUP}/" - dst+="${PMODULES_MODULEFILES_DIR}/" - dst+="${fully_qualified_module_name}" - - # directory where to install modulefile - local -r dstdir=${dst%/*} - - if [[ -e "${dst}" ]]; then - std::info \ - "%s " "${module_name}/${module_version}:" \ - "removing modulefile '${dst}' ..." - [[ "${dry_run}" == 'no' ]] && rm -v "${dst}" - fi - local release_file="${dstdir}/.release-${module_version}" - if [[ -e "${release_file}" ]]; then - std::info \ - "%s " "${module_name}/${module_version}:" \ - "removing release file '${release_file}' ..." - [[ "${dry_run}" == 'no' ]] && rm -v "${release_file}" - fi - rmdir -p --ignore-fail-on-non-empty "${dstdir}" 2>/dev/null - } - - ######################################################################## - # - # here we really start with make_all() - # - - # setup module specific environment - if [[ "${bootstrap}" == 'no' ]]; then - check_supported_systems - load_build_dependencies - set_full_module_name_and_prefix - if [[ "${module_release}" == 'removed' ]]; then - remove_module - elif [[ ! -d "${PREFIX}" ]] || \ - [[ "${force_rebuild}" == 'yes' ]]; then - build_module - else - std::info \ - "%s " "${module_name}/${module_version}:" \ - "already exists, not rebuilding ..." - if [[ "${opt_update_modulefiles}" == "yes" ]]; then - install_modulefile - fi - install_release_file - fi - else - build_module - fi - return 0 -} - -pbuild.init_env() { - #...................................................................... - # - # parse the passed version string - # - # the following global variables will be set in this function: - # V_MAJOR - # V_MINOR - # V_PATCHLVL - # V_RELEASE - # USE_FLAGS - # - parse_version() { - local v="$1" - V_MAJOR='' # first number in version string - V_MINOR='' # second number in version string (or empty) - V_PATCHLVL='' # third number in version string (or empty) - V_RELEASE='' # module release (or empty) - USE_FLAGS='' # architectures (or empty) - - local tmp='' - - if [[ "$v" =~ "_" ]]; then - tmp="${v#*_}" - USE_FLAGS=":${tmp//_/:}:" - v="${v%%_*}" - fi - V_PKG="${v%%-*}" # version without the release number - V_RELEASE="${v#*-}" # release number - - case "${V_PKG}" in - *.*.* ) - V_MAJOR="${V_PKG%%.*}" - tmp="${V_PKG#*.}" - V_MINOR="${tmp%%.*}" - V_PATCHLVL="${tmp#*.}" - ;; - *.* ) - V_MAJOR="${V_PKG%.*}" - V_MINOR="${V_PKG#*.}" - ;; - * ) - V_MAJOR="${V_PKG}" - ;; - esac - } - - local -r module_name="$1" - local -r module_version="$2" - - SRC_DIR="${TEMP_DIR}/${module_name}-${module_version}/src" - BUILD_DIR="${TEMP_DIR}/${module_name}-${module_version}/build" - - # P and V can be used in the build-script, so we have to set them here - P="${module_name}" - V="${module_version}" - parse_version "${module_version}" + # :FIXME: this is a hack!!! + # shouldn't this be set in the build-script? + eval $( "${MODULECMD}" bash use Libraries ) + eval $( "${MODULECMD}" bash use System ) unset C_INCLUDE_PATH unset CPLUS_INCLUDE_PATH @@ -1213,40 +1305,9 @@ pbuild.init_env() { unset F77 unset F90 - SOURCE_URLS=() - SOURCE_SHA256_SUMS=() - SOURCE_NAMES=() - - CONFIGURE_ARGS=() - SUPPORTED_SYSTEMS=() - PATCH_FILES=() - PATCH_STRIPS=() - PATCH_STRIP_DEFAULT='1' - MODULE_DOCFILES=() - configure_with='undef' -} - - -pbuild.build_module() { - module_name="$1" - module_version="$2" - module_release="$3" - shift 3 - with_modules=( "$@" ) - - MODULECMD="${PMODULES_HOME}/bin/modulecmd" - [[ -x ${MODULECMD} ]] || \ - std::die 2 "No such file or executable -- '${MODULECMD}'" - - eval $( "${MODULECMD}" bash use unstable ) - eval $( "${MODULECMD}" bash use deprecated ) - eval $( "${MODULECMD}" bash purge ) - # :FIXME: this is a hack!!! - # shouldn't this be set in the build-script? - eval $( "${MODULECMD}" bash use Libraries ) + load_build_dependencies pbuild.init_env "${module_name}" "${module_version}" - source "${BUILD_SCRIPT}" pbuild::make_all } @@ -1272,7 +1333,6 @@ pbuild.bootstrap() { PATH+=":${PREFIX}/bin" PATH+=":${PREFIX}/sbin" - source "${BUILD_SCRIPT}" pbuild::make_all } diff --git a/Pmodules/libpbuild_dyn.bash b/Pmodules/libpbuild_dyn.bash new file mode 100644 index 0000000..85f1d76 --- /dev/null +++ b/Pmodules/libpbuild_dyn.bash @@ -0,0 +1,24 @@ +#!/bin/bash + +eval "pbuild::pre_prep_${system}() { :; }" +eval "pbuild::pre_prep_${OS}() { :; }" +eval "pbuild::post_prep_${system}() { :; }" +eval "pbuild::post_prep_${OS}() { :; }" + +eval "pbuild::add_patch_${system}() { pbuild::add_patch \"\$@\"; }" +eval "pbuild::add_patch_${OD}() { pbuild::add_patch \"\$@\"; }" + +eval "pbuild::pre_configure_${system}() { :; }" +eval "pbuild::pre_configure_${OS}() { :; }" +eval "pbuild::post_configure_${system}() { :; }" +eval "pbuild::post_configure_${OS}() { :; }" + +eval "pbuild::pre_compile_${system}() { :; }" +eval "pbuild::pre_compile_${OS}() { :; }" +eval "pbuild::post_compile_${system}() { :; }" +eval "pbuild::post_compile_${OS}() { :; }" + +eval "pbuild::pre_install_${system}() { :; }" +eval "pbuild::pre_install_${OS}() { :; }" +eval "pbuild::post_install_${system}() { :; }" +eval "pbuild::post_install_${OS}() { :; }" diff --git a/Pmodules/libstd.bash b/Pmodules/libstd.bash index 846484d..e54f4b7 100644 --- a/Pmodules/libstd.bash +++ b/Pmodules/libstd.bash @@ -271,6 +271,42 @@ There is NO WARRANTY, to the extent permitted by law." done } +std.get_os_release_linux() { + local lsb_release=$(which lsb_release) + local ID='' + local VERSION_ID='' + + if [[ -n $(which lsb_release) ]]; then + ID=$(lsb_release -is) + VERSION_ID=$(lsb_release -rs) + elif [[ -r '/etc/os-release' ]]; then + source /etc/os-release + else + std::die 4 "Cannot determin OS release!\n" + fi + + case "${ID}" in + RedHatEnterpriseServer | RedHatEnterprise | Scientific | rhel | centos | fedora ) + echo "rhel${VERSION_ID%.*}" + ;; + * ) + echo "Unknown" + exit 1 + ;; + esac +} +std.get_os_release_macos() { + VERSION_ID=$(sw_vers -productVersion) + echo "macOS${VERSION_ID%.*}" +} + +std::get_os_release() { + local -A func_map; + func_map['Linux']=std.get_os_release_linux + func_map['Darwin']=std.get_os_release_macos + ${func_map[${OS}]} +} + # Local Variables: # mode: sh # sh-basic-offset: 8 diff --git a/Pmodules/modbuild.in b/Pmodules/modbuild.in index f8ca300..7aa5805 100755 --- a/Pmodules/modbuild.in +++ b/Pmodules/modbuild.in @@ -1,4 +1,4 @@ -#!/usr/bin/env bash -- +#!/usr/bin/env bash # # The following build specific variables are set and used in libpbuild.bash: # ARGS @@ -16,16 +16,26 @@ declare -r mydir=$(cd ${mydir} && pwd -P) # initialize PATH, # add library installation directories to the PATH, # so 'source' is able find them -PATH="/usr/bin:/bin:/usr/sbin:/sbin" + +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: library '$_' cannot be loaded!" 1>&2; exit 3; + 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 -- '$_'" + std::die 3 "Oops: cannot source library -- '$_'" # save arguments, (still) required for building dependencies declare -r ARGS="$@" @@ -124,36 +134,48 @@ MISCELLANEOUS OPTIONS: # # parse options and arguments # +# command line arguments are taken first +# then configuration file +# last default -# multiple version can be passed via comand line +# versions to be build, '.*' or none means all 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_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='' -declare build_config='modbuild.conf' -declare system="$(uname -s)" + parse_args() { while (( $# > 0 )); do case $1 in -j ) - pbuild.jobs "$2" + opt_jobs="$2" shift ;; --jobs=[0-9]* ) - pbuild.jobs "${1/--jobs=}" + opt_jobs="${1/--jobs=}" ;; -v | --verbose ) trap 'echo "$BASH_COMMAND"' DEBUG - pbuild.verbose 'yes' + opt_verbose='yes' ;; --debug ) set -x ;; -f | --force-rebuild ) - pbuild.force_rebuild 'yes' + opt_force_rebuild='yes' ;; -\? | -h | --help ) usage @@ -162,57 +184,55 @@ parse_args() { std::die 0 "\nPmodules version ${VERSION}\nCopyright GNU GPL v2\n" ;; --dry-run ) - pbuild.dry_run 'yes' + opt_dry_run='yes' ;; --config ) - build_config="$2" + opt_build_config="$2" shift 1 ;; --config=* ) - build_config="${1#*=}" + opt_build_config="${1#*=}" ;; --enable-cleanup ) - pbuild.enable_cleanup_build 'yes' - pbuild.enable_cleanup_src 'yes' + opt_enable_cleanup_build='yes' + opt_enable_cleanup_src='yes' ;; --disable-cleanup ) - pbuild.enable_cleanup_build 'no' - pbuild.enable_cleanup_src 'no' + opt_enable_cleanup_build='no' + opt_enable_cleanup_src='no' ;; --enable-cleanup-build ) - pbuild.enable_cleanup_build 'yes' + opt_enable_cleanup_build='yes' ;; --disable-cleanup-build ) - pbuild.enable_cleanup_build 'no' + opt_enable_cleanup_build='no' ;; --enable-cleanup-src ) - pbuild.enable_cleanup_src 'yes' + opt_enable_cleanup_src='yes' ;; --disable-cleanup-src ) - pbuild.enable_cleanup_src 'no' + opt_enable_cleanup_src='no' ;; --distdir ) - pbuild.pmodules_distfilesdir "$2" + PMODULES_DISTFILESDIR="$2" shift ;; --distdir=* ) - pbuild.pmodules_distfilesdir "${1/--distdir=}" + PMODULES_DISTFILESDIR="${1/--distdir=}" ;; --tmpdir ) - pbuild.temp_dir "$2" + PMODULES_TMPDIR="$2" shift ;; --tmpdir=* ) - pbuilf.temp_dir "${1/--tmpdir=}" + PMODULES_TMPDIR="${1/--tmpdir=}" ;; --system ) - system=".$2" - pbuild.system "${system}" + opt_system="$2" shift ;; --system=* ) - system=".${1/*=}" - pbuild.system "${system}" + opt_system="${1/*=}" ;; --with ) opt_with_modules+=( "$2" ) @@ -223,13 +243,13 @@ parse_args() { opt_with_modules+=( ${m} ) ;; --prep | --configure | --compile | --install | --all ) - pbuild.build_target ${1:2} + opt_build_target=${1:2} ;; --bootstrap ) opt_bootstrap='yes' ;; --update-modulefiles ) - pbuild.update_modulefiles 'yes' + opt_update_modulefiles='yes' ;; --overlay ) overlay=$2 @@ -242,7 +262,7 @@ parse_args() { -* ) std::die 1 "Invalid option -- '$1'" ;; - [=0-9]* ) + [=0-9]* | '.*' ) versions+=( "$1" ) ;; '') @@ -264,17 +284,21 @@ parse_args() { shift done [[ -n ${BUILD_SCRIPT} ]] || std::die 1 "No build-block specified!" - (( ${#versions[@]} > 0)) || std::die 1 "Module version not 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.${system} ) + local files=( "${BUILDBLOCK_DIR}"/*/variants\.${opt_system} ) + files+=( "${BUILDBLOCK_DIR}"/*/variants.$(uname -s) ) local f for f in "${BUILDBLOCK_DIR}"/*/variants; do - [[ -e "${f}.${system}" ]] || files+=( "$f" ) + [[ -e "${f}.${opt_system}" ]] \ + || [[ -e "${f}.$(uname -s)" ]] \ + || files+=( "$f" ) done (( nullglob_set == 1 )) && shopt -u nullglob std::upvar "$1" "${files[@]}" @@ -381,20 +405,49 @@ build_modules() { 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}/../../${PMODULES_CONFIG_DIR}" && PATH+=":$_" + test -d "${BUILDBLOCK_DIR}/../../config" && PATH+=":$_" else - test -d "${PMODULES_ROOT}/${PMODULES_CONFIG_DIR}" && PATH+=":$_" + # 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 "${build_config}" || \ - std::die 3 "Oops: Cannot source configuration file -- '${build_config}'" -source libpbuild.bash || \ - std::die 3 "Oops: Cannot source library -- '$_'" + +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 diff --git a/Pmodules/modulecmd.bash.in b/Pmodules/modulecmd.bash.in index d916ab0..dab63f0 100644 --- a/Pmodules/modulecmd.bash.in +++ b/Pmodules/modulecmd.bash.in @@ -55,7 +55,7 @@ print_help() { export_env() { case "${Shell}" in - bash | zsh ) + sh | bash | zsh ) local -r fmt="export %s=\"%s\"; " ;; csh | tcsh ) @@ -343,8 +343,10 @@ subcommand_load() { # 0: module is loadable # 1: either not a modulefile or unsused release # - # Notes: - # The variable 'release' in function 'subcommand_load()' will be set. + # The following variables in the enclosing function are set: + # current_modulefile + # prefix + # release # is_available() { local m=$1 @@ -408,13 +410,7 @@ subcommand_load() { [[ -z ${dep} ]] && continue [[ ${dep:0:1} == \# ]] && continue module_is_loaded "${dep}" && continue - local output=$( subcommand_load 'bash' "${dep}") - eval ${output} - if [[ "${Shell}" == "bash" ]]; then - echo ${output} - else - subcommand_load "${Shell}" "${dep}" - fi + subcommand_load "${dep}" done < "${fname}" } @@ -521,6 +517,8 @@ subcommand_load() { fi local found='' for flag in "${UseFlags[@]/#/_}" ""; do + # :FIXME: this doesn't work if ${m} is a + # modulename without version if is_available "${m}${flag}"; then m+="${flag}" found=':' @@ -533,11 +531,12 @@ subcommand_load() { [[ ${verbosity_lvl} == 'verbose' ]] && output_load_hints std::die 3 "" fi + if [[ ${current_modulefile} =~ ${PMODULES_ROOT} ]] \ + && [[ ! ${m} =~ / ]]; then + m+="/${current_modulefile##*/}" + fi if [[ ":${LOADEDMODULES}:" =~ ":${m}:" ]]; then - std::die 3 "%s %s: %s -- %s\n" \ - "${CMD}" "${subcommand}" \ - "module already loaded" \ - "${m}" + continue fi for root in "${!Overlays[@]}"; do if [[ ${current_modulefile} =~ ${root} ]]; then @@ -552,7 +551,6 @@ subcommand_load() { || std::die 1 "Oops: unable to create tmp file!\n" local output=$("${modulecmd}" 'bash' ${opts} 'load' \ "${current_modulefile}" 2> "${tmpfile}") - eval "${output}" # we do not want to print the error message we got from # modulecmd, they are a bit ugly @@ -573,21 +571,28 @@ subcommand_load() { "${error_txt}" \ "${m}" fi - if [[ "${Shell}" == "bash" ]]; then + if [[ "${Shell}" == "sh" ]]; then + # for sh-like shells just echo echo "${output}" - echo "${error}" 1>&2 else + # re-run with right shell "${modulecmd}" "${Shell}" ${opts} 'load' \ "${current_modulefile}" fi + eval "${output}" + if [[ -n "${error}" ]]; then + echo "${error}" 1>&2 + fi - if [[ ${verbosity_lvl} != silent ]] && \ - [[ ${release} != stable ]]; then - std::info "%s %s: %s -- %s\n" \ + local msg=$(printf "%s %s: %s -- %s" \ "${CMD}" 'load' \ "${release} module has been loaded" \ - "${m}" + "${m}") + if [[ ${verbosity_lvl} != silent ]] && \ + [[ ${release} != stable ]]; then + std::info "%s\n" "${msg}" fi + logger "${msg}" done # fix LOADEDMODULES LOADEDMODULES="${_LMFILES_}" @@ -645,11 +650,14 @@ subcommand_unload() { for arg in "${args[@]}"; do local output=$("${modulecmd}" "${Shell}" 'unload' "${arg}") eval "${output}" - if [[ "${Shell}" == "bash" ]]; then + case ${Shell} in + sh | bash | zsh ) echo "${output}" - else + ;; + * ) "${modulecmd}" "${Shell}" 'unload' "${arg}" - fi + ;; + esac done } @@ -1160,6 +1168,9 @@ subcommand_use() { done fi fi + if [[ -z ${GroupDepths[${arg}]} ]] && [[ -d "${PMODULES_ROOT}/${arg}" ]]; then + scan_groups "${PMODULES_ROOT}" + fi if [[ -n ${GroupDepths[${arg}]} ]] && (( ${GroupDepths[${arg}]} == 0 )); then # argument is group in our root with depth 0 @@ -1851,7 +1862,7 @@ subcommand_search() { # help [module|sub-command] # Subcommands[help]='help' -Options[help]='-o hHV? -l version -l help' +Options[help]='-o hHV\? -l version -l help' Help[help]=' USAGE: module [ switches ] [ subcommand ] [subcommand-args ] @@ -2106,8 +2117,8 @@ subcommand_initclear() { # main # case "$1" in - bash | zsh ) - declare Shell="$1" + sh | bash | zsh ) + declare Shell="sh" ;; csh | tcsh ) declare Shell='csh' diff --git a/build b/build index a858aef..c34dd90 100755 --- a/build +++ b/build @@ -313,6 +313,7 @@ pmodules::install() { install -m 0644 "${SRC_DIR}/libpmodules.bash" "${PMODULES_HOME}/lib" install -m 0644 "${SRC_DIR}/libpbuild.bash" "${PMODULES_HOME}/lib" + install -m 0644 "${SRC_DIR}/libpbuild_dyn.bash" "${PMODULES_HOME}/lib" install -m 0644 "${SRC_DIR}/libstd.bash" "${PMODULES_HOME}/lib" install -m 0755 -d "${PMODULES_HOME}/lib/Pmodules" install -m 0644 "${SRC_DIR}/libmodules.tcl" "${PMODULES_HOME}/lib/Pmodules" diff --git a/config/overlays.conf b/config/overlays.conf new file mode 100644 index 0000000..a0b87fe --- /dev/null +++ b/config/overlays.conf @@ -0,0 +1,32 @@ +#!/bin/bash + +# +# define PMODULES_ROOT only if it has not been passed as argument +# to build/install scripts +# +: ${PMODULES_ROOT:=/opt/psi-overlays} +: ${PMODULES_DISTFILESDIR:=/opt/psi/var/distfiles} +: ${PMODULES_TMPDIR:=/var/tmp/${USER}} + +declare -x PMODULES_CONFIG_DIR='config' +declare -x PMODULES_MODULEFILES_DIR='modulefiles' + +declare -x PMODULES_HOME="${PMODULES_ROOT}/Tools/Pmodules/${PMODULES_VERSION}" + +declare -x PMODULES_DEFAULT_GROUPS='Tools Programming' +declare -x PMODULES_DEFINED_RELEASES=':unstable:stable:deprecated:' +declare -x PMODULES_DEFAULT_RELEASES='stable' + +export PMODULES_DISTFILESDIR +export PMODULES_TMPDIR + +#----------------------------------------------------------------------------- +# OS specific configuration +# +case ${OS} in +Darwin ) + declare -x MACOSX_DEPLOYMENT_TARGET='10.12' + #declare -rx SDKROOT='macosx10.9' + ;; +esac + diff --git a/config/versions.conf b/config/versions.conf index aef2bef..f6eedf4 100644 --- a/config/versions.conf +++ b/config/versions.conf @@ -3,5 +3,5 @@ coreutils 8.31 getopt 1.1.6 gettext 0.19.8 modules 3.2.10.1 -Pmodules 1.0.0rc5 +Pmodules 1.0.0rc6 Tcl 8.6.9