modbuild.in 11.5 KB
Newer Older
gsell's avatar
gsell committed
1
#!/usr/bin/env bash
2 3 4 5 6 7
#
# The following build specific variables are set and used in libpbuild.bash:
#       ARGS
#       BUILD_SCRIPT
#       BUILDBLOCK_DIR
#
8
#.............................................................................
9 10 11

declare VERSION='@PMODULES_VERSION@'

12 13 14
# get absolute path of script
declare	    mydir=$(dirname "$0")
declare -r  mydir=$(cd ${mydir} && pwd -P)
gsell's avatar
gsell committed
15

16 17 18
# initialize PATH,
# add library installation directories to the PATH,
# so 'source' is able find them
gsell's avatar
gsell committed
19 20 21 22 23 24 25

if [[ $(uname -s) == 'Darwin' ]]; then
        PATH='/usr/local/bin:'
else
        PATH=''
fi
PATH+='/usr/bin:/bin:/usr/sbin:/sbin'
26 27
PATH+=":${mydir}"
PATH+=":${mydir}/../lib:${mydir}/../config"
28

29
source libstd.bash    || {
gsell's avatar
gsell committed
30
        echo "Oops: cannot source library -- '$_'" 1>&2; exit 3;
31
}
gsell's avatar
gsell committed
32

33
source libpbuild.bash    || \
gsell's avatar
gsell committed
34
        std::die 3 "Oops: cannot source library -- '$_'"
35

36
# save arguments, (still) required for building dependencies
37 38
declare -r ARGS="$@"

gsell's avatar
gsell committed
39 40 41
##############################################################################
#
usage() {
gsell's avatar
gsell committed
42
	std::error "
gsell's avatar
gsell committed
43 44
USAGE:
        $0 [options..] [build_script] version
gsell's avatar
gsell committed
45

gsell's avatar
gsell committed
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
MANDATORY ARGUMENTS:

version
        Variant of module to build.

SELECT VARIANT TO BUILD:

--system
        Specify the system for selecting a variants. Defaults to the
	output of 'uname -s'.

--with=P/V
        Select variant to compile. Use multiple '--with' arguments
	to make the selected variant unique.

BUILD-STEPS OPTIONS:

--prep
	Prepare sources: unpack sources and apply patches only.

--configure
	Prepare and configure sources.

--compile
	Prepare, configure and compile everything.

--install
	Prepare, configure and compile everything. Finally run install
	step. Do not cleanup build and source directory.

--all
	Run throu all steps including cleanup.

--update-modulefiles
	Only install the modulefile and set the release.

MISCELLANEOUS OPTIONS:
gsell's avatar
gsell committed
83 84

-? | -h | --help
85 86 87 88
        Print usage.

-V | --version )
        Print version.
gsell's avatar
gsell committed
89 90

-v | --verbose )
91
        Verbose output.
gsell's avatar
gsell committed
92 93

-j N | --jobs=N
94
        Run N parallel make jobs.
gsell's avatar
gsell committed
95 96 97 98

-f | --force-rebuild
        Force rebuild of module.

gsell's avatar
gsell committed
99 100 101
--dry-run
	Dry run.

gsell's avatar
gsell committed
102
--disable-cleanup-build
gsell's avatar
gsell committed
103
--enable-cleanup-build
gsell's avatar
gsell committed
104 105
	Cleanup files in the build directory. Default is to remove.
      	all files in the build-directory.
gsell's avatar
gsell committed
106

gsell's avatar
gsell committed
107
--disable-cleanup-src
gsell's avatar
gsell committed
108
--enable-cleanup-src
gsell's avatar
gsell committed
109 110
	Cleanup files in the source directory. Default is to
	remove all files in the source directory.
gsell's avatar
gsell committed
111 112

--disable-cleanup
gsell's avatar
gsell committed
113
--enable-cleanup
114
	Cleanup all files in temporary directory. Default is to
gsell's avatar
gsell committed
115
	remove all files created during building.
gsell's avatar
gsell committed
116

gsell's avatar
gsell committed
117 118
--distdir
	Directory wwhere to store and lookup downloaded files.
gsell's avatar
gsell committed
119

gsell's avatar
gsell committed
120 121
--tmpdir
        Directory used for building a module.
gsell's avatar
gsell committed
122

gsell's avatar
gsell committed
123 124 125 126
"
	exit 1
}

127
##############################################################################
gsell's avatar
gsell committed
128
#
129 130 131 132 133 134 135
# parse options and arguments
#

# multiple version can be passed via comand line
declare -a      versions=()
declare         opt_all_variants='no'
declare         opt_bootstrap='no'
gsell's avatar
gsell committed
136 137 138 139 140 141 142 143 144 145 146 147
declare 	opt_build_config='modbuild.conf'
declare         opt_build_target='all'
declare         opt_distfiles_dir="${PMODULES_ROOT}/var/distfiles"
declare         opt_dry_run='no'
declare         opt_enable_cleanup_build='yes'
declare         opt_enable_cleanup_src='yes'
declare         opt_force_rebuild='no'
declare -i      opt_jobs=3
declare         opt_update_modulefiles='no'
declare         opt_system=''
declare         opt_temp_dir="${PMODULES_TMPDIR:-/var/tmp/${USER}}"
declare         opt_verbose='no'
148 149
# array collecting all modules specified on the command line via '--with=module'
declare -a      opt_with_modules=()
150

151 152 153 154
parse_args() {
	while (( $# > 0 )); do
		case $1 in
		-j )
gsell's avatar
gsell committed
155
                        opt_jobs="$2"
156 157 158
			shift
			;;
		--jobs=[0-9]* )
gsell's avatar
gsell committed
159
			opt_jobs="${1/--jobs=}"
160 161 162
			;;
		-v | --verbose )
			trap 'echo "$BASH_COMMAND"' DEBUG
gsell's avatar
gsell committed
163
                        opt_verbose='yes'
164 165 166 167 168
			;;
		--debug )
			set -x
			;;
		-f | --force-rebuild )
gsell's avatar
gsell committed
169
                        opt_force_rebuild='yes'
170 171 172 173
			;;
		-\? | -h | --help )
			usage
			;;
174 175 176
                -V | --version )
                        std::die 0  "\nPmodules version ${VERSION}\nCopyright GNU GPL v2\n"
                        ;;
177
		--dry-run )
gsell's avatar
gsell committed
178
			opt_dry_run='yes'
179
			;;
180
		--config )
gsell's avatar
gsell committed
181
			opt_build_config="$2"
182 183 184
			shift 1
			;;
		--config=* )
gsell's avatar
gsell committed
185
			opt_build_config="${1#*=}"
186
			;;
187
		--enable-cleanup )
gsell's avatar
gsell committed
188 189
			opt_enable_cleanup_build='yes'
			opt_enable_cleanup_src='yes'
190
			;;
191
		--disable-cleanup )
gsell's avatar
gsell committed
192 193
			opt_enable_cleanup_build='no'
			opt_enable_cleanup_src='no'
194 195
			;;
		--enable-cleanup-build )
gsell's avatar
gsell committed
196
			opt_enable_cleanup_build='yes'
197 198
			;;
		--disable-cleanup-build )
gsell's avatar
gsell committed
199
			opt_enable_cleanup_build='no'
200 201
			;;
		--enable-cleanup-src )
gsell's avatar
gsell committed
202
			opt_enable_cleanup_src='yes'
203 204
			;;
		--disable-cleanup-src )
gsell's avatar
gsell committed
205
			opt_enable_cleanup_src='no'
206 207
			;;
		--distdir )
gsell's avatar
gsell committed
208
			opt_distfiles_dir="$2"
209 210 211
			shift
			;;
		--distdir=* )
gsell's avatar
gsell committed
212
			opt_distfiles_dir="${1/--distdir=}"
213 214
			;;
		--tmpdir )
gsell's avatar
gsell committed
215
                        opt_temp_dir="$2"
216 217 218
			shift
			;;
		--tmpdir=* )
gsell's avatar
gsell committed
219
			opt_temp_dir="${1/--tmpdir=}"
220
			;;
gsell's avatar
gsell committed
221
		--system )
gsell's avatar
gsell committed
222
			opt_system="$2"
223 224
			shift
			;;
gsell's avatar
gsell committed
225
		--system=* )
gsell's avatar
gsell committed
226
			opt_system="${1/*=}"
227 228
			;;
		--with )
229
			opt_with_modules+=( "$2" )
230 231 232 233
			shift
			;;
		--with=*/* )
			m="${1/--with=}"
234
			opt_with_modules+=( ${m} )
235 236
			;;
		--prep | --configure | --compile | --install | --all )
gsell's avatar
gsell committed
237
			opt_build_target=${1:2}
238 239
			;;
		--bootstrap )
240
			opt_bootstrap='yes'
241
			;;
gsell's avatar
gsell committed
242
		--update-modulefiles )
gsell's avatar
gsell committed
243
			opt_update_modulefiles='yes'
244
			;;
245 246 247
                -- )
                        :
                        ;;
248
		-* )
249
			std::die 1 "Invalid option -- '$1'"
250
			;;
251
		[=0-9]* )
252
			versions+=( "$1" )
253
			;;
254 255 256
		'')	
			:
			;;
257 258
		* )
			[[ -z "${BUILD_SCRIPT}" ]] || \
259
				std::die 1 "%s "\
260 261
					 "Build script already set to" \
					 "'${BUILD_SCRIPT}' -- '$1'"
262 263
		        BUILD_SCRIPT=$(std::get_abspath "$1")
			test -r ${BUILD_SCRIPT} || \
264
				std::die 1 "%s " \
265 266
					 "Build script does not exist" \
					 "or is not readable -- '$_'"
267 268 269 270 271
			BUILDBLOCK_DIR=$(dirname "${BUILD_SCRIPT}")
			;;
		esac
		shift
	done	
272
	[[ -n ${BUILD_SCRIPT} ]] || std::die 1 "No build-block specified!"
273
	(( ${#versions[@]} > 0)) || std::die 1 "Module version not specified!"
gsell's avatar
gsell committed
274
}
275

276
find_variants_files(){
277 278 279
        shopt -q nullglob || :
        local -i nullglob_set=$?
        shopt -s nullglob
gsell's avatar
gsell committed
280 281
        local files=( "${BUILDBLOCK_DIR}"/*/variants.${opt_system} )
        files+=( "${BUILDBLOCK_DIR}"/*/variants.$(uname -s) )
282 283
        local f
	for f in "${BUILDBLOCK_DIR}"/*/variants; do
gsell's avatar
gsell committed
284 285 286
		[[ -e "${f}.${opt_system}" ]] \
                        || [[ -e "${f}.$(uname -s)" ]] \
                        || files+=( "$f" )
287
	done
288
        (( nullglob_set == 1 )) && shopt -u nullglob
289
	std::upvar "$1" "${files[@]}"
290 291
}

292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
shopt -s extglob
expand_variants_file(){
	expand_deps(){
		local text="$1"
                shift
		local deps=( "${@}" )
                echo "${deps[@]}"
                if (( ${#deps[@]} == 0 )); then
                        echo ${text}
		else
                        local list
		        eval list=( ${deps[0]} )
			for dep in ${list[*]}; do
				expand_deps "${text} ${dep}" "${deps[@]:1}"
			done
		fi
	}

	local -r input="$1"
	while read -a toks; do
		# skip empty and comment lines
		[[ -z ${toks} ]] && continue
		[[ ${toke:0:1} == '#' ]] && continue

		deps=( ${toks[*]:2} )
		expand_deps "${toks[0]} ${toks[1]}" "${deps[@]}"
	done < "${input}"
}

321 322 323 324 325 326 327 328 329 330 331 332
build_modules() {
        local name="$1"
        local version="$2"
        local exact_match='no'
        if [[ "${version:0:1}" == "=" ]]; then
                exact_match='yes'
                version="${version:1}"
        fi
        shift 2
        local with_modules=( $* )
        local files
        find_variants_files files
333 334 335 336 337

        # if we have to build a dependency, we might have less dependencies
        # on it. Or in other words: the list of "with modules" might be
        # overdetermined. In the loop below we check, which dependencies
        # specified with '--with' are required.
338 339
        local m
	local pattern="/^${name}\/${version}[[:blank:]]/"
340
	for m in "${with_modules[@]}"; do
341
                if [[ -n $(awk "/${m%/*}[\/ ]/" "${files[@]}") ]]; then
342 343
		        pattern+=" && /${m//\//\\/}/"
                fi
344
	done
345 346

        
347 348 349
        local variants=()
        local variants_files=()
        for f in "${files[@]}"; do
350
                local line=''
351
                while read line; do
352
                        variants+=( "${line}" )
353
                        variants_files+=( "$f" )
354
                done < <(expand_variants_file "${f}" | awk "${pattern}")
355 356 357
                # here we should add a check, whether the version of the
                # found variants are in the right variants files. Example:
                # a variant for hdf5/1.10.4 is not allowed in a variants file
358 359
                # for version 1.8. For this we need the mapping of a variant
                # to the variants file in array 'variants_files'
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
        done
        if (( ${#variants[@]} == 0 )); then
		std::info "%s " \
			 "${name}/${version}:" \
			 "no suitable variant found!"
                std::die 10 "Aborting..."
        elif (( ${#variants[@]} > 1 )) && [[ ${exact_match} == 'yes' ]]; then
		std::info "%s " \
			 "Multiple variants found:"
                for variant in "${variants[@]}"; do
                        std::info "${variant}"
                done
                std::die 10 "Aborting..."
        fi
        local -i i=0
        local -i num_variants=${#variants[@]}
        for ((i = 0; i < num_variants; i++)); do
                local tokens=( ${variants[i]} )
                local name="${tokens[0]%/*}"
                version="${tokens[0]#*/}"
                release="${tokens[1]}"
                with_modules=( "${tokens[@]:2}" )
                pbuild.build_module \
                        "${name}" "${version}" \
                        "${release}" "${with_modules[@]}"
        done
386 387 388 389
}

#.............................................................................
# main
390

391 392
parse_args "$@"

gsell's avatar
gsell committed
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
if [[ -z "${opt_system}" ]]; then
        opt_system=$(std::get_os_release)
fi

pbuild.jobs "${opt_jobs}"
pbuild.force_rebuild "${opt_force_rebuild}"
pbuild.build_target "${opt_build_target}"
pbuild.dry_run "${opt_dry_run}"
pbuild.enable_cleanup_build "${opt_enable_cleanup_build}"
pbuild.enable_cleanup_src "${opt_enable_cleanup_src}"
pbuild.pmodules_distfilesdir "${opt_distfiles_dir}"
pbuild.update_modulefiles "${opt_update_modulefiles}"
pbuild.temp_dir "${opt_temp_dir}"
pbuild.system "${opt_system}"
pbuild.verbose "${opt_verbose}"

source libpbuild_dyn.bash    || \
        std::die 3 "Oops: cannot source library -- '$_'"

412 413 414
# source build configuration,
# must be done before sourcing libpbuild!
if [[ "${opt_bootstrap}" == 'yes' ]]; then
415
        test -d "${BUILDBLOCK_DIR}/../../${PMODULES_CONFIG_DIR}" && PATH+=":$_"
416
else
gsell's avatar
gsell committed
417 418 419 420 421 422
        # 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
423
fi
gsell's avatar
gsell committed
424 425
source "${opt_build_config}" || \
        std::die 3 "Oops: Cannot source configuration file -- '$_'"
426

427 428
declare -r BUILD_SCRIPT
declare -r BUILDBLOCK_DIR
429

430
# the module name is defined by the directory the build script is in
431 432
IFS=/ read -r -a fname <<< "${BUILD_SCRIPT:1}"
module_name=${fname[${#fname[@]}-2]}
Achim Gsell's avatar
Achim Gsell committed
433

434
#
435
# are we bootstrapping? If yes, go for it...
436
#
437 438
if [[ "${opt_bootstrap}" == 'yes' ]]; then
	pbuild.bootstrap "${module_name}"  "${versions[0]}" 'stable'
439 440
        exit $?
fi
gsell's avatar
gsell committed
441

442
#
443
# else
444
#
445
for version in "${versions[@]}"; do
446
        build_modules "${module_name}" "${version}" "${opt_with_modules[@]}"
447
done
gsell's avatar
gsell committed
448

gsell's avatar
gsell committed
449 450 451 452 453
# Local Variables:
# mode: sh
# sh-basic-offset: 8
# tab-width: 8
# End: