libpbuild.bash 35.5 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}"
638 639 640 641

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

647

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

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

gsell's avatar
gsell committed
663 664
	#......................................................................
	# non-redefinable post-install
gsell's avatar
gsell committed
665
	post_install() {
gsell's avatar
gsell committed
666
		install_doc() {
gsell's avatar
gsell committed
667
			test -n "${MODULE_DOCFILES}" || return 0
668 669 670 671 672 673 674 675 676 677
			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
678
			return 0
gsell's avatar
gsell committed
679 680
		}

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

687 688 689 690 691 692 693 694 695 696 697 698
			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
699 700 701 702 703 704 705 706 707 708

			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"
709 710 711
			std::info \
                                "%s " "${module_name}/${module_version}:" \
                                "writing run-time dependencies to ${fname} ..."
gsell's avatar
gsell committed
712 713 714 715 716 717 718 719 720 721 722 723 724 725 726
			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
727
		# sometimes we need an system depended post-install
gsell's avatar
gsell committed
728
		post_install_linux() {
729 730
			std::info \
                                "%s " "${module_name}/${module_version}:" \
731
                                "running post-installation for ${system} ..."
gsell's avatar
gsell committed
732
			cd "${PREFIX}"
733 734
			# solve multilib problem with LIBRARY_PATH
                        # on 64bit Linux
gsell's avatar
gsell committed
735
			[[ -d "lib" ]] && [[ ! -d "lib64" ]] && ln -s lib lib64
gsell's avatar
gsell committed
736
			return 0
gsell's avatar
gsell committed
737 738
		}

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

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

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

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

773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790
        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}:" \
791 792
                                        "changing release from" \
                                        "'${release}' to '${module_release}' ..."
793 794 795 796 797 798 799 800 801
		                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
        }
802 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

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

		for t in "${targets[@]}"; do
			# We cd into the dir before calling the function -
			# just to be sure we are in the right directory.
854 855 856
			# 
			# Executing the function in a sub-process doesn't
			# work because in some function global variables 
857
			# might/need to be set.
858
			#
859 860 861
			cd "${dir}" && "pbuild::$t" || std::die 42 "Aborting ..."
		done
		touch "${BUILD_DIR}/.${target}"
862 863
	}

gsell's avatar
gsell committed
864
	#......................................................................
865
	# build module ${module_name}/${module_version}
gsell's avatar
gsell committed
866
	build_module() {
867 868 869 870 871 872
                local -r logfile="${BUILD_DIR}/pbuild.log"
                if [[ "${verbose}" = 'yes' ]]; then
                        local -r output="/dev/fd/1"
                else
                        local -r output="/dev/null"
                fi
873 874 875
 		std::info \
                        "%s " "${module_name}/${module_version}:" \
                        "start building ..."
gsell's avatar
gsell committed
876
		[[ ${dry_run} == yes ]] && std::die 0 ""
gsell's avatar
gsell committed
877

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

881 882 883 884
 		std::info \
                        "%s " "${module_name}/${module_version}:" \
                        "preparing sources ..."
		build_target "${SRC_DIR}" prep | tee "${logfile}" > ${output}
885
		[[ "${build_target}" == "prep" ]] && return 0
gsell's avatar
gsell committed
886

887 888 889 890
 		std::info \
                        "%s " "${module_name}/${module_version}:" \
                        "configuring ..."
		build_target "${BUILD_DIR}" configure | tee "${logfile}" >> ${output}
891
		[[ "${build_target}" == "configure" ]] && return 0
gsell's avatar
gsell committed
892

893 894 895 896
 		std::info \
                        "%s " "${module_name}/${module_version}:" \
                        "compiling ..."
		build_target "${BUILD_DIR}" compile | tee "${logfile}" >> ${output}
897
		[[ "${build_target}" == "compile" ]] && return 0
gsell's avatar
gsell committed
898

899 900 901
 		std::info \
                        "%s " "${module_name}/${module_version}:" \
                        "installing ..."
gsell's avatar
gsell committed
902
                mkdir -p "${PREFIX}"
903
		build_target "${BUILD_DIR}" install | tee "${logfile}" >> ${output}
gsell's avatar
gsell committed
904 905
		post_install

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

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

		# assemble name of modulefile
		local dst="${PMODULES_ROOT}/"
		dst+="${GROUP}/"
		dst+="${PMODULES_MODULEFILES_DIR}/"
927
		dst+="${fully_qualified_module_name}"
928 929 930 931 932

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

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

948
	########################################################################
gsell's avatar
gsell committed
949 950 951 952 953 954
	#
	# here we really start with make_all()
	#

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

977
pbuild.init_env() {
978 979 980 981 982 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
        #......................................................................
        #
        # 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}"

1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062