libpbuild.bash 35.7 KB
Newer Older
1

gsell's avatar
gsell committed
2 3
#!/bin/bash

4 5 6 7 8
#.............................................................................
#
# We need GNU versions of the following utilities. This code works
# well on Linux and Mac OS X with MacPorts.
# :FIXME: implement a smarter, portable solution.
gsell's avatar
gsell committed
9
#
10 11 12 13 14 15 16 17 18
shopt -s expand_aliases
unalias -a

__path=$(which gsed 2>/dev/null || : )
if [[ $__path ]]; then
	alias sed=$__path
else
	alias sed=$(which sed 2>/dev/null)
fi
19
unset __path
20 21 22 23 24 25

#.............................................................................
# disable auto-echo feature of 'cd'
unset CDPATH

#.............................................................................
gsell's avatar
gsell committed
26
#
27 28 29 30 31 32 33 34 35 36 37
# Exit script on errror.
#
# $1	exit code
#
set -o errexit

error_handler() {
	local -i ec=$?

	std::die ${ec} "Oops"
}
gsell's avatar
gsell committed
38

39 40 41 42
trap "error_handler" ERR

###############################################################################
#
gsell's avatar
gsell committed
43 44 45 46 47 48 49
# 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
gsell's avatar
gsell committed
50

gsell's avatar
gsell committed
51 52 53 54 55
unset	CFLAGS
unset	CPPFLAGS
unset	CXXFLAGS
unset	LIBS
unset	LDFLAGS
gsell's avatar
gsell committed
56

gsell's avatar
gsell committed
57 58 59 60 61
unset	CC
unset	CXX
unset	FC
unset	F77
unset	F90
gsell's avatar
gsell committed
62

63 64 65
declare	SOURCE_URLS=()
declare SOURCE_SHA256_SUMS=()
declare SOURCE_NAMES=()
66
declare -A SOURCE_UNPACK_DIRS
67 68 69 70 71 72 73 74

declare	CONFIGURE_ARGS=()
declare SUPPORTED_SYSTEMS=()
declare PATCH_FILES=()
declare PATCH_STRIPS=()
declare PATCH_STRIP_DEFAULT='1'
declare configure_with='undef'	

75 76
declare bootstrap='no'

gsell's avatar
gsell committed
77
#..............................................................................
78
# global variables
79
declare force_rebuild=''
80
pbuild.force_rebuild() {
81
	force_rebuild="$1"
82 83
}

84
declare dry_run=''
85
pbuild.dry_run() {
86
	dry_run="$1"
87 88
}

89
declare enable_cleanup_build=''
90
pbuild.enable_cleanup_build() {
91
	enable_cleanup_build="$1"
92 93
}

94
declare enable_cleanup_src=''
95
pbuild.enable_cleanup_src() {
96
	enable_cleanup_src="$1"
97
}
gsell's avatar
gsell committed
98

99
declare build_target=''
100
pbuild.build_target() {
101
	build_target="$1"
102 103
}

104
declare opt_update_modulefiles=''
105
pbuild.update_modulefiles() {
106
	opt_update_modulefiles="$1"
107 108 109
}

# number of parallel make jobs
110
declare -i JOBS=3
111
pbuild.jobs() {
112
        JOBS="$1"
113 114
}

115
declare system=''
116
pbuild.system() {
117
        system="$1"
118 119
}

120
declare TEMP_DIR=''
121
pbuild.temp_dir() {
122
        TEMP_DIR="$1"
123 124
}

125
declare PMODULES_DISTFILESDIR=''
126
pbuild.pmodules_distfilesdir() {
127
        PMODULES_DISTFILESDIR="$1"
128
}
129 130

declare verbose=''
131
pbuild.verbose() {
132
        verbose="$1"
133
}
134

gsell's avatar
gsell committed
135 136
# module name including path in hierarchy and version
# (ex: 'gcc/6.1.0/openmpi/1.10.2' for openmpi compiled with gcc 6.1.0)
137
declare -x  fully_qualified_module_name=''
gsell's avatar
gsell committed
138 139

# group this module is in (ex: 'Programming')
gsell's avatar
gsell committed
140
declare -x  GROUP=''
gsell's avatar
gsell committed
141

142 143 144
# name, version and release of module
declare	-x  module_name=''
declare	-x  module_version=''
145
declare	-x  module_release=''
gsell's avatar
gsell committed
146 147

# relative path of documentation
148
# abs. path is "${PREFIX}/${_docdir}/${module_name}"
gsell's avatar
gsell committed
149 150 151
declare -r  _DOCDIR='share/doc'

#..............................................................................
gsell's avatar
gsell committed
152
#
gsell's avatar
gsell committed
153 154
# The following variables are available in build-blocks and set read-only
# :FIXME: do we have to export them?
gsell's avatar
gsell committed
155
#
gsell's avatar
gsell committed
156 157 158 159

# install prefix of module.
declare -x  PREFIX=''

gsell's avatar
gsell committed
160
declare -r  OS=$(uname -s)
161 162


gsell's avatar
gsell committed
163 164
##############################################################################
#
gsell's avatar
gsell committed
165 166 167 168
# Set flag to build module in source tree.
#
# Arguments:
#   none
gsell's avatar
gsell committed
169 170
#
pbuild::compile_in_sourcetree() {
gsell's avatar
gsell committed
171
	BUILD_DIR="${SRC_DIR}"
gsell's avatar
gsell committed
172 173
}

gsell's avatar
gsell committed
174 175
##############################################################################
#
gsell's avatar
gsell committed
176
# Check whether the script is running on a supported OS.
gsell's avatar
gsell committed
177
#
gsell's avatar
gsell committed
178 179
# Arguments:
#   $@: supported opertating systems (as printed by 'uname -s')
gsell's avatar
gsell committed
180
#
gsell's avatar
gsell committed
181 182
pbuild::supported_systems() {
	SUPPORTED_SYSTEMS+=( "$@" )
gsell's avatar
gsell committed
183 184
}

185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
#......................................................................
#
# compute full module name and installation prefix
#
# The following variables are expected to be set:
#	GROUP	    module group
#	P		    module name
#	V		    module version
#       variables defining the hierarchical environment like
#	COMPILER and COMPILER_VERSION
#
# The following variables are set in this function
#	fully_qualified_module_name
#	PREFIX
#
set_full_module_name_and_prefix() {
	join_by() {
		local IFS="$1"
		shift
		echo "$*"
	}

gsell's avatar
gsell committed
207 208 209
	[[ -n ${GROUP} ]] || std::die 1 \
                                      "${module_name}/${module_version}:" \
                                      "group not set."
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 246 247 248 249 250 251 252 253 254 255
	
	# build module name
	# :FIXME: this should be read from a configuration file
	local name=()
	case ${GROUP} in
	Compiler )
		name+=( "${COMPILER}/${COMPILER_VERSION}" )
	        name+=( "${module_name}/${module_version}" )
		;;
	MPI )
		name+=( "${COMPILER}/${COMPILER_VERSION}" )
		name+=( "${MPI}/${MPI_VERSION}" )
		name+=( "${module_name}/${module_version}" )
		;;
	HDF5 )
		name+=( "${COMPILER}/${COMPILER_VERSION}" )
		name+=( "${MPI}/${MPI_VERSION}" )
		name+=( "${HDF5}/${HDF5_VERSION}" )
		name+=( "${module_name}/${module_version}" )
		;;
	OPAL )
		name+=( "${COMPILER}/${COMPILER_VERSION}" )
		name+=( "${MPI}/${MPI_VERSION}" )
		name+=( "${OPAL}/${OPAL_VERSION}" )
		name+=( "${module_name}/${module_version}" )
		;;
	HDF5_serial )
		name+=( "${COMPILER}/${COMPILER_VERSION}" )
		name+=( "hdf5_serial/${HDF5_SERIAL_VERSION}" )
		name+=( "${module_name}/${module_version}" )
		;;
	* )
		name+=("${module_name}/${module_version}" )
		;;
	esac

	# set full module name
	fully_qualified_module_name=$( join_by '/' "${name[@]}" )
	# set PREFIX of module
	PREFIX="${PMODULES_ROOT}/${GROUP}/"
        local -i i=0
	for ((i=${#name[@]}-1; i >= 0; i--)); do
		PREFIX+="${name[i]}/"
	done
}

gsell's avatar
gsell committed
256 257
##############################################################################
#
gsell's avatar
gsell committed
258
# Install module in given group.
gsell's avatar
gsell committed
259
#
gsell's avatar
gsell committed
260 261
# Arguments:
#   $1: group
gsell's avatar
gsell committed
262 263 264
#
pbuild::add_to_group() {
	if [[ -z ${1} ]]; then
265 266 267
		std::die 42 \
                         "%s " "${module_name}/${module_version}:" \
                         "${FUNCNAME}: missing group argument."
gsell's avatar
gsell committed
268
	fi
gsell's avatar
gsell committed
269
	GROUP="$1"
gsell's avatar
gsell committed
270
	set_full_module_name_and_prefix
gsell's avatar
gsell committed
271 272 273 274
}

##############################################################################
#
gsell's avatar
gsell committed
275
# Set documentation file to be installed.
gsell's avatar
gsell committed
276
#
gsell's avatar
gsell committed
277 278
# Arguments:
#   $@: documentation files relative to source
gsell's avatar
gsell committed
279
#
gsell's avatar
gsell committed
280
pbuild::install_docfiles() {
gsell's avatar
gsell committed
281 282
	MODULE_DOCFILES+=("$@")
}
gsell's avatar
gsell committed
283

284 285
##############################################################################
#
gsell's avatar
gsell committed
286 287
# Test whether a module with the given name is available. If yes, return
# release
288 289 290
#
# Arguments:
#   $1: module name
291
#   $2: optional variable name to return release via upvar
292 293 294 295 296
#
# Notes:
#   The passed module name must be NAME/VERSION! 
#
pbuild::module_is_avail() {
gsell's avatar
gsell committed
297 298
	local "$2"
	local uvar="$2"
gsell's avatar
gsell committed
299
	[[ -n "${uvar}" ]] || uvar="__unused__"
300 301
	local output=( $("${MODULECMD}" bash avail -a -m "$1" \
                                        2>&1 1>/dev/null) )
gsell's avatar
gsell committed
302
	[[ "${output[0]}" == "$1" ]] && std::upvar "${uvar}" "${output[1]}"
303 304
}

gsell's avatar
gsell committed
305
pbuild::set_download_url() {
306 307 308
	local -i _i=${#SOURCE_URLS[@]}
	SOURCE_URLS[_i]="$1"
	SOURCE_NAMES[_i]="$2"
gsell's avatar
gsell committed
309 310 311 312
}

pbuild::set_sha256sum() {
	SOURCE_SHA256_SUMS+=("$1")
gsell's avatar
gsell committed
313 314
}

315 316 317 318
pbuild::set_unpack_dir() {
        SOURCE_UNPACK_DIRS[$1]=$2
}

gsell's avatar
gsell committed
319
pbuild::use_cc() {
320 321 322 323
	[[ -x "$1" ]] || std::die 3 \
                                  "%s " "${module_name}/${module_version}:" \
                                  "Error in setting CC:" \
                                  "'$1' is not an executable!"
gsell's avatar
gsell committed
324 325 326
	CC="$1"
}

327 328 329 330 331 332 333 334 335
pbuild::pre_prep() {
	:
}

pbuild::post_prep() {
	:
}

###############################################################################
Achim Gsell's avatar
Achim Gsell committed
336
#
337
# extract sources. For the time being only tar-files are supported.
Achim Gsell's avatar
Achim Gsell committed
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
pbuild::prep() {
        #......................................................................
        #
        # Find/download tarball for given module.
        #
        # Arguments:
        #   $1:	    store file name with upvar here
        #   $2:	    download URL 
        #   $3:	    output filename (can be empty string)
        #   $4...:  download directories
        #
        # Returns:
        #   0 on success otherwise a value > 0
        #
        download_with_curl() {
                local -r output="$1"
                local -r url="$2"
		curl \
			-L \
			--output "${output}" \
			"${url}"
		if (( $? != 0 )); then
			curl \
				--insecure \
				--output "${output}" \
				"${url}"
		fi
        }
        
gsell's avatar
gsell committed
368 369 370 371 372 373 374 375 376 377
	check_hash_sum() {
		local -r fname="$1"
		local -r expected_hash_sum="$2"
		local hash_sum=''

		if which 'sha256sum' 1>/dev/null; then
			hash_sum=$(sha256sum "${fname}" | awk '{print $1}')
		elif which 'shasum' 1>/dev/null; then
			hash_sum=$(shasum -a 256 "${fname}" | awk '{print $1}')
		else
378 379 380
			std::die 42 \
                                 "%s " "${module_name}/${module_version}:" \
                                 "Binary to compute SHA256 sum missing!"
gsell's avatar
gsell committed
381
		fi
382 383 384 385
		test "${hash_sum}" == "${expected_hash_sum}" || \
                        std::die 42 \
			         "%s " "${module_name}/${module_version}:" \
                                 "hash-sum missmatch for file '%s'" "${fname}"
gsell's avatar
gsell committed
386 387
	}

388 389 390 391 392 393 394 395 396 397 398 399 400 401 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
        download_source_file() {
	        local "$1"
	        local var="$1"
	        local -r url="$2"
	        local    fname="$3"
	        shift 3
	        dirs+=( "$@" )

	        [[ -n "${fname}" ]] || fname="${url##*/}"
	        local expr='s/.*\(.tar.bz2\|.tbz2\|.tar.gz\|.tgz\|.tar.xz\|.zip\)/\1/'
	        local -r extension=$(echo ${fname} | sed "${expr}")
	        local dir=''
	        dirs+=( 'not found' )
	        for dir in "${dirs[@]}"; do
		        [[ -r "${dir}/${fname}" ]] && break
	        done
	        if [[ "${dir}" == 'not found' ]]; then
		        dir="${dirs[0]}"
		        local -r method="${url%:*}"
		        case "${method}" in
			        http | https | ftp )
                                        download_with_curl "${dir}/${fname}" "${url}"
				        ;;
			        * )
				        std::die 4 \
                                                 "%s " "${module_name}/${module_version}:" \
                                                 "Error in download URL:" \
					         "unknown download method '${method}'!"
				        ;;
                        esac
	        fi
	        local sha256_sum=''
	        local hash=''
	        for hash in "${SOURCE_SHA256_SUMS[@]}"; do
		        if [[ ${hash} =~ $fname: ]]; then
			        sha256_sum="${hash#*:}"
		        fi
	        done
	        if [[ -n "${sha256_sum}" ]]; then
		        check_hash_sum "${dir}/${fname}" "${sha256_sum}"
	        fi
	        std::upvar "${var}" "${dir}/${fname}"
	        [[ -r "${dir}/${fname}" ]]
        }
gsell's avatar
gsell committed
432

433
        unpack() {
gsell's avatar
gsell committed
434
		local -r file="$1"
435
		local -r dir="${2:-${SRC_DIR}}"
gsell's avatar
gsell committed
436 437 438 439 440 441 442 443 444 445 446
		(
			if [[ -n "${dir}" ]]; then
				mkdir -p "${dir}"
				cd "${dir}"
			fi
			tar -xv --strip-components 1 -f "${file}"
		)
	}

	patch_sources() {
		cd "${SRC_DIR}"
447 448 449 450 451 452 453
                local i=0
		for ((_i = 0; _i < ${#PATCH_FILES[@]}; _i++)); do
			std::info \
                                "%s " "${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]}"
gsell's avatar
gsell committed
454 455 456
		done
	}

457 458 459 460
	[[ -z "${SOURCE_URLS}" ]] && \
                std::die 3 \
                         "%s " "${module_name}/${module_version}:" \
                         "Download source not set!"
461
        mkdir -p "${PMODULES_DISTFILESDIR}"
462
        local i=0
463
        local source_fname
gsell's avatar
gsell committed
464 465
	for ((i = 0; i < ${#SOURCE_URLS[@]}; i++)); do
		download_source_file \
466
		    source_fname \
gsell's avatar
gsell committed
467 468 469 470
		    "${SOURCE_URLS[i]}" \
		    "${SOURCE_NAMES[i]}" \
		    "${PMODULES_DISTFILESDIR}" \
		    "${BUILDBLOCK_DIR}" ||
471 472 473
		        std::die 4 \
                                 "%s " "${module_name}/${module_version}:" \
                                 "sources for not found."
474
		unpack "${source_fname}" "${SOURCE_UNPACK_DIRS[${source_fname##*/}]}"
gsell's avatar
gsell committed
475
	done
gsell's avatar
gsell committed
476
	patch_sources
gsell's avatar
gsell committed
477
	# create build directory
gsell's avatar
gsell committed
478
	mkdir -p "${BUILD_DIR}"
gsell's avatar
gsell committed
479 480
}

gsell's avatar
gsell committed
481
pbuild::add_patch() {
482 483 484 485
	[[ -z "$1" ]] && \
                std::die 1 \
                         "%s " "${module_name}/${module_version}:" \
                         "${FUNCNAME}: missing argument!"
gsell's avatar
gsell committed
486 487
	PATCH_FILES+=( "$1" )
	PATCH_STRIPS+=( "$2" )
gsell's avatar
gsell committed
488
}
gsell's avatar
gsell committed
489

gsell's avatar
gsell committed
490
pbuild::set_default_patch_strip() {
491 492 493 494 495
	[[ -n "$1" ]] || \
                std::die 1 \
                         "%s " "${module_name}/${module_version}:" \
                         "${FUNCNAME}: missing argument!"

gsell's avatar
gsell committed
496 497 498
	PATCH_STRIP_DEFAULT="$1"
}

gsell's avatar
gsell committed
499 500 501 502
pbuild::use_flag() {
	[[ "${USE_FLAGS}" =~ ":${1}:" ]]
}

gsell's avatar
gsell committed
503 504 505
###############################################################################
#
#
gsell's avatar
gsell committed
506 507 508
pbuild::pre_configure() {
	:
}
gsell's avatar
gsell committed
509 510 511 512

pbuild::set_configure_args() {
	CONFIGURE_ARGS+=( "$@" )
}
gsell's avatar
gsell committed
513

514 515 516 517
pbuild::add_configure_args() {
	CONFIGURE_ARGS+=( "$@" )
}

gsell's avatar
gsell committed
518
pbuild::use_autotools() {
519
	configure_with='autotools'
gsell's avatar
gsell committed
520 521 522
}

pbuild::use_cmake() {
523
	configure_with='cmake'
gsell's avatar
gsell committed
524
}
525

gsell's avatar
gsell committed
526
pbuild::configure() {
527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
        case "${configure_with}" in
                autotools )
        	        if [[ ! -r "${SRC_DIR}/configure" ]]; then
		                std::die 3 \
                                         "%s " "${module_name}/${module_version}:" \
                                         "${FNCNAME[0]}:" \
                                         "autotools configuration not available, aborting..."
	                fi
                        ;;
                cmake )
                        if [[ ! -r "${SRC_DIR}/CMakeLists.txt" ]]; then
		                std::die 3 \
                                         "%s " "${module_name}/${module_version}:" \
                                         "${FNCNAME[0]}:" \
                                         "CMake script not available, aborting..."
	                fi
                        ;;
        esac
545 546
	if [[ -r "${SRC_DIR}/configure" ]] && \
                   [[ "${configure_with}" == 'undef' ]] || \
gsell's avatar
gsell committed
547
		   [[ "${configure_with}" == 'autotools' ]]; then
gsell's avatar
gsell committed
548 549
		${SRC_DIR}/configure \
			--prefix="${PREFIX}" \
550 551 552 553 554 555
			"${CONFIGURE_ARGS[@]}" || \
                        std::die 3 \
                                 "%s " "${module_name}/${module_version}:" \
                                 "configure failed"
	elif [[ -r "${SRC_DIR}/CMakeLists.txt" ]] && \
                     [[ "${configure_with}" == 'undef' ]] || \
gsell's avatar
gsell committed
556
		     [[ "${configure_with}" == "cmake" ]]; then
gsell's avatar
gsell committed
557 558 559
		cmake \
			-DCMAKE_INSTALL_PREFIX="${PREFIX}" \
			"${CONFIGURE_ARGS[@]}" \
560 561 562 563
			"${SRC_DIR}" || \
                        std::die 3 \
                                 "%s " "${module_name}/${module_version}:" \
                                 "cmake failed"
gsell's avatar
gsell committed
564
	else
565 566 567
		std::info \
                        "%s " "${module_name}/${module_version}:" \
                        "${FUNCNAME[0]}: skipping..."
gsell's avatar
gsell committed
568
	fi
gsell's avatar
gsell committed
569 570
}

gsell's avatar
gsell committed
571 572 573 574
pbuild::post_configure() {
	:
}

575
pbuild::pre_compile() {
gsell's avatar
gsell committed
576 577 578
	:
}

579
pbuild::compile() {
gsell's avatar
gsell committed
580
	make -j${JOBS}
gsell's avatar
gsell committed
581 582
}

583
pbuild::post_compile() {
gsell's avatar
gsell committed
584 585 586 587 588 589 590
	:
}

pbuild::pre_install() {
	:
}

gsell's avatar
gsell committed
591 592 593
pbuild::install() {
	make install
}
gsell's avatar
gsell committed
594

595 596
pbuild::install_shared_libs() {
	local -r binary="${PREFIX}/$1"
597
	local -r pattern="${2//\//\\/}" # escape slash
598 599
	local -r dstdir="${3:-${PREFIX}/lib}"

600 601 602 603 604 605 606 607 608 609 610 611 612
        install_shared_libs_Linux() {
                local libs=( $(ldd "${binary}" | \
                                       awk "/ => \// && /${pattern}/ {print \$3}") )
	        cp -avL "${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}"
        }

613 614 615 616
	test -e "${binary}" || \
                std::die 3 \
                         "%s " "${module_name}/${module_version}:" \
                         "${binary}: does not exist or is not executable!"
617
	mkdir -p "${dstdir}"
618 619 620 621 622 623 624 625
        case "${OS}" in
                Linux )
                        install_shared_libs_Linux
                        ;;
                Darwin )
                        install_shared_libs_Darwin
                        ;;
        esac
626 627
}

gsell's avatar
gsell committed
628 629 630 631 632 633 634 635
pbuild::post_install() {
	:
}

#
# The 'do it all' function.
#
pbuild::make_all() {
gsell's avatar
gsell committed
636
	local -a runtime_dependencies=()
637
        source "${BUILD_SCRIPT}"
gsell's avatar
gsell committed
638
        local -r logfile="${BUILD_DIR}/pbuild.log"
639 640 641 642

	#
	# everything set up?
	#
643 644 645 646
	[[ -n ${GROUP} ]] || \
                std::die 5 \
                         "%s " "${module_name}/${module_version}:" \
                         "Module group not set! Aborting ..."
647

648

gsell's avatar
gsell committed
649 650 651 652
	#
	# helper functions
	#

gsell's avatar
gsell committed
653 654
	#......................................................................
	check_supported_systems() {
655
		[[ -z "${SUPPORTED_SYSTEMS}" ]] && return 0
gsell's avatar
gsell committed
656
		for sys in "${SUPPORTED_SYSTEMS[@]}"; do
657
			[[ ${sys} == ${system} ]] && return 0
gsell's avatar
gsell committed
658
		done
659 660
		std::die 1 \
                         "%s " "${module_name}/${module_version}:" \
661
                         "Not available for ${system}."
gsell's avatar
gsell committed
662 663
	}

gsell's avatar
gsell committed
664 665
	#......................................................................
	# non-redefinable post-install
gsell's avatar
gsell committed
666
	post_install() {
gsell's avatar
gsell committed
667
		install_doc() {
gsell's avatar
gsell committed
668
			test -n "${MODULE_DOCFILES}" || return 0
669 670 671 672 673 674 675 676 677 678
			local -r docdir="${PREFIX}/${_DOCDIR}/${module_name}"

			std::info \
                                "%s " "${module_name}/${module_version}:" \
                                "Installing documentation to ${docdir}"
			install -m 0755 -d \
                                "${docdir}"
			install -m0444 \
                                "${MODULE_DOCFILES[@]/#/${SRC_DIR}/}" \
				"${docdir}"
gsell's avatar
gsell committed
679
			return 0
gsell's avatar
gsell committed
680 681
		}

gsell's avatar
gsell committed
682 683 684 685 686 687
		#..............................................................
		# install build-block
		# Skip installation if modulefile does not exist.
		install_pmodules_files() {
			test -r "${BUILDBLOCK_DIR}/modulefile" || return 0

688 689 690 691 692 693 694 695 696 697 698 699
			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"
gsell's avatar
gsell committed
700 701 702 703 704 705 706 707 708 709

			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"
710 711 712
			std::info \
                                "%s " "${module_name}/${module_version}:" \
                                "writing run-time dependencies to ${fname} ..."
gsell's avatar
gsell committed
713 714 715 716 717 718 719 720 721 722 723 724 725 726 727
			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
		}


gsell's avatar
gsell committed
728
		# sometimes we need an system depended post-install
gsell's avatar
gsell committed
729
		post_install_linux() {
730 731
			std::info \
                                "%s " "${module_name}/${module_version}:" \
gsell's avatar
gsell committed
732
                                "running post-installation for ${OS} ..."
gsell's avatar
gsell committed
733
			cd "${PREFIX}"
734 735
			# solve multilib problem with LIBRARY_PATH
                        # on 64bit Linux
gsell's avatar
gsell committed
736
			[[ -d "lib" ]] && [[ ! -d "lib64" ]] && ln -s lib lib64
gsell's avatar
gsell committed
737
			return 0
gsell's avatar
gsell committed
738 739
		}

gsell's avatar
gsell committed
740
		cd "${BUILD_DIR}"
gsell's avatar
gsell committed
741
		[[ "${OS}" == "Linux" ]] && post_install_linux
gsell's avatar
gsell committed
742
		install_doc
gsell's avatar
gsell committed
743 744
		install_pmodules_files
		write_runtime_dependencies
gsell's avatar
gsell committed
745 746 747
		return 0
	}

gsell's avatar
gsell committed
748
 	#......................................................................
749
	# Install modulefile
750
	install_modulefile() {
gsell's avatar
gsell committed
751
		local -r src="${BUILDBLOCK_DIR}/modulefile"
gsell's avatar
gsell committed
752
		if [[ ! -r "${src}" ]]; then
753 754 755
			std::info \
                                "%s " "${module_name}/${module_version}:" \
                                "skipping modulefile installation ..."
gsell's avatar
gsell committed
756 757
			return
		fi
758 759
		# assemble name of modulefile
		local dst="${PMODULES_ROOT}/"
gsell's avatar
gsell committed
760
		dst+="${GROUP}/"
761
		dst+="${PMODULES_MODULEFILES_DIR}/"
762
		dst+="${fully_qualified_module_name}"
763

764
		# directory where to install modulefile
765 766
 		local -r dstdir=${dst%/*}

767 768 769
		std::info \
                        "%s " "${module_name}/${module_version}:" \
                        "installing modulefile in '${dstdir}' ..."
770 771
		mkdir -p "${dstdir}"
		install -m 0444 "${src}" "${dst}"
gsell's avatar
gsell committed
772
	}
gsell's avatar
gsell committed
773

774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791
        install_release_file() {
		local dst="${PMODULES_ROOT}/"
		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}:" \
792 793
                                        "changing release from" \
                                        "'${release}' to '${module_release}' ..."
794 795 796 797 798 799 800 801 802
		                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
        }
803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837

        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
838
        }
839
        
840 841 842
	build_target() {
		local dir="$1"
		local target="$2"
843 844 845 846 847
		if [[ -e "${BUILD_DIR}/.${target}" ]] && \
			   [[ ${force_rebuild} != 'yes' ]]; then
                        return 0
                fi
		local targets=()
gsell's avatar
gsell committed
848
		targets+=( "pre_${target}_${system}" "pre_${target}_${OS}" "pre_${target}" )
849
		targets+=( "${target}" )
gsell's avatar
gsell committed
850
		targets+=( "post_${target}_${system}" "post_${target}_${OS}" "post_${target}" )
851 852 853 854

		for t in "${targets[@]}"; do
			# We cd into the dir before calling the function -
			# just to be sure we are in the right directory.
855 856 857
			# 
			# Executing the function in a sub-process doesn't
			# work because in some function global variables 
858
			# might/need to be set.
859
			#
gsell's avatar
gsell committed
860 861 862 863 864 865 866
			cd "${dir}"
                        if [[ "${verbose}" = 'yes' ]]; then
                                "pbuild::$t" 2>&1 | tee -a "${logfile}"
                        else
                                { "pbuild::$t" >> "${logfile}"; } 2>&1 | tee -a "${logfile}"
                        fi
                        (( ${PIPESTATUS[0]} == 0 )) || std::die 42 "Aborting ..."
867 868
		done
		touch "${BUILD_DIR}/.${target}"
869 870
	}

gsell's avatar
gsell committed
871
	#......................................................................
872
	# build module ${module_name}/${module_version}
gsell's avatar
gsell committed
873
	build_module() {
874 875 876
 		std::info \
                        "%s " "${module_name}/${module_version}:" \
                        "start building ..."
gsell's avatar
gsell committed
877
		[[ ${dry_run} == yes ]] && std::die 0 ""
gsell's avatar
gsell committed
878

879
		mkdir -p "${SRC_DIR}"
gsell's avatar
gsell committed
880
		mkdir -p "${BUILD_DIR}"
gsell's avatar
gsell committed
881

gsell's avatar
gsell committed
882 883
                echo -n > "${logfile}"

884 885 886
 		std::info \
                        "%s " "${module_name}/${module_version}:" \
                        "preparing sources ..."
gsell's avatar
gsell committed
887 888 889
                # write stdout and stderr to logfile, stderr to terminal
                # write all to logfile and terminal
		build_target "${SRC_DIR}" prep
890
		[[ "${build_target}" == "prep" ]] && return 0
gsell's avatar
gsell committed
891

892 893 894
 		std::info \
                        "%s " "${module_name}/${module_version}:" \
                        "configuring ..."
gsell's avatar
gsell committed
895
		build_target "${BUILD_DIR}" configure
896
		[[ "${build_target}" == "configure" ]] && return 0
gsell's avatar
gsell committed
897

898 899 900
 		std::info \
                        "%s " "${module_name}/${module_version}:" \
                        "compiling ..."
gsell's avatar
gsell committed
901
		build_target "${BUILD_DIR}" compile
902
		[[ "${build_target}" == "compile" ]] && return 0
gsell's avatar
gsell committed
903

904 905 906
 		std::info \
                        "%s " "${module_name}/${module_version}:" \
                        "installing ..."
gsell's avatar
gsell committed
907
                mkdir -p "${PREFIX}"
gsell's avatar
gsell committed
908
		build_target "${BUILD_DIR}" install
gsell's avatar
gsell committed
909 910
		post_install

911
		[[ "${build_target}" == "install" ]] && return 0
gsell's avatar
gsell committed
912

913 914
		install_modulefile
                install_release_file
915 916 917
	        cleanup_build
		cleanup_src
                std::info "%s" "${module_name}/${module_version}: Done ..."
gsell's avatar
gsell committed
918
		return 0
gsell's avatar
gsell committed
919
	}
920 921
	remove_module() {
		if [[ -d "${PREFIX}" ]]; then
922 923 924
			std::info \
                                "%s " "${module_name}/${module_version}:" \
                                "removing all files in '${PREFIX}' ..."
925 926 927 928 929 930 931
			[[ "${dry_run}" == 'no' ]] && rm -rf ${PREFIX}
		fi

		# assemble name of modulefile
		local dst="${PMODULES_ROOT}/"
		dst+="${GROUP}/"
		dst+="${PMODULES_MODULEFILES_DIR}/"
932
		dst+="${fully_qualified_module_name}"
933 934 935 936 937

		# directory where to install modulefile
 		local -r dstdir=${dst%/*}

		if [[ -e "${dst}" ]]; then
938 939 940
			std::info \
                                "%s " "${module_name}/${module_version}:" \
                                "removing modulefile '${dst}' ..."
941 942
			[[ "${dry_run}" == 'no' ]] && rm -v "${dst}"
		fi
943
		local release_file="${dstdir}/.release-${module_version}"
944
		if [[ -e "${release_file}" ]]; then
945 946 947
			std::info \
                                "%s " "${module_name}/${module_version}:" \
                                "removing release file '${release_file}' ..."
948 949
			[[ "${dry_run}" == 'no' ]] && rm -v "${release_file}"
		fi
950
		rmdir -p --ignore-fail-on-non-empty "${dstdir}" 2>/dev/null
951 952
	}

953
	########################################################################
gsell's avatar
gsell committed
954 955 956 957 958 959
	#
	# here we really start with make_all()
	#

	# setup module specific environment
	if [[ "${bootstrap}" == 'no' ]]; then
gsell's avatar
gsell committed
960
		check_supported_systems
gsell's avatar
gsell committed
961
		set_full_module_name_and_prefix
962
		if [[ "${module_release}" == 'removed' ]]; then
963
			remove_module
964 965
		elif [[ ! -d "${PREFIX}" ]] || \
                             [[ "${force_rebuild}" == 'yes' ]]; then
gsell's avatar
gsell committed
966 967
			build_module
		else
968 969 970
 			std::info \
                                "%s " "${module_name}/${module_version}:" \
                                "already exists, not rebuilding ..."
gsell's avatar
gsell committed
971
			if [[ "${opt_update_modulefiles}" == "yes" ]]; then
972
				install_modulefile
gsell's avatar
gsell committed
973
			fi
974
                        install_release_file
gsell's avatar
gsell committed
975
		fi
gsell's avatar
gsell committed
976
	else
gsell's avatar
gsell committed
977
		build_module
gsell's avatar
gsell committed
978 979 980 981
	fi
	return 0
}

982
pbuild.init_env() {
983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039
        #......................................................................
        #
        # 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}"