From 5d618886570e98e6745593701246b877998a5367 Mon Sep 17 00:00:00 2001 From: Erik Schnetter Date: Mon, 23 Nov 2015 16:51:16 -0500 Subject: Correct Spack cc script --- lib/spack/env/cc | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/spack/env/cc b/lib/spack/env/cc index 75a63f6fac..f3fadfcf45 100755 --- a/lib/spack/env/cc +++ b/lib/spack/env/cc @@ -126,6 +126,11 @@ if [ -z "$mode" ]; then elif [ "$arg" = -c ]; then mode=cc break + elif [ "$arg" = -S ]; then + mode=as + echo "spac cc mode as" "$@" + exit 1 + break fi done fi @@ -155,6 +160,7 @@ libraries=() libs=() rpaths=() other_args=() +all_args=("$@") while [ -n "$1" ]; do case "$1" in @@ -178,6 +184,8 @@ while [ -n "$1" ]; do if [ -z "$arg" ]; then shift; arg="$1"; fi if [[ "$arg" = -rpath=* ]]; then rpaths+=("${arg#-rpath=}") + elif [[ "$arg" = -rpath,* ]]; then + rpaths+=("${arg#-rpath,}") elif [[ "$arg" = -rpath ]]; then shift; arg="$1" if [[ "$arg" != -Wl,* ]]; then @@ -193,6 +201,8 @@ while [ -n "$1" ]; do if [ -z "$arg" ]; then shift; arg="$1"; fi if [[ "$arg" = -rpath=* ]]; then rpaths+=("${arg#-rpath=}") + elif [[ "$arg" = -rpath,* ]]; then + rpaths+=("${arg#-rpath,}") elif [[ "$arg" = -rpath ]]; then shift; arg="$1" if [[ "$arg" != -Xlinker,* ]]; then @@ -247,25 +257,46 @@ IFS=':' read -ra deps <<< "$SPACK_DEPENDENCIES" for dep in "${deps[@]}"; do if [ -d "$dep/include" ]; then includes+=("$dep/include") + all_args=("-I$dep/include" ${all_args[@]}) fi if [ -d "$dep/lib" ]; then libraries+=("$dep/lib") rpaths+=("$dep/lib") + if [ "$mode" = ccld ]; then + all_args=("-L$dep/lib" "-Wl,-rpath,$dep/lib" ${all_args[@]}) + elif [ "$mode" = ld ]; then + all_args=("-L$dep/lib" "-rpath" "$dep/lib" ${all_args[@]}) + fi fi if [ -d "$dep/lib64" ]; then libraries+=("$dep/lib64") rpaths+=("$dep/lib64") + if [ "$mode" = ccld ]; then + all_args=("-L$dep/lib" "-Wl,-rpath,$dep/lib" ${all_args[@]}) + elif [ "$mode" = ld ]; then + all_args=("-L$dep/lib" "-rpath" "$dep/lib" ${all_args[@]}) + fi fi done # Include all -L's and prefix/whatever dirs in rpath for dir in "${libraries[@]}"; do [[ dir = $SPACK_INSTALL* ]] && rpaths+=("$dir") + if [ "$mode" = ccld ]; then + [[ dir = $SPACK_INSTALL* ]] && all_args=("-Wl,-rpath,$dir" ${all_args[@]}) + elif [ "$mode" = ld ]; then + [[ dir = $SPACK_INSTALL* ]] && all_args=("-rpath" "$dir" ${all_args[@]}) + fi done rpaths+=("$SPACK_PREFIX/lib") rpaths+=("$SPACK_PREFIX/lib64") +if [ "$mode" = ccld ]; then + all_args=("-Wl,-rpath,$SPACK_PREFIX/lib" "-Wl,-rpath,$SPACK_PREFIX/lib64" ${all_args[@]}) +elif [ "$mode" = ld ]; then + all_args=("-rpath" "$SPACK_PREFIX/lib" "-rpath" "$SPACK_PREFIX/lib64" ${all_args[@]}) +fi # Put the arguments together args=() @@ -317,7 +348,8 @@ done export PATH full_command=("$command") -full_command+=("${args[@]}") +# full_command+=("${args[@]}") +full_command+=("${all_args[@]}") # # Write the input and output commands to debug logs if it's asked for. -- cgit v1.2.3-70-g09d2 From ba22fc8b78841728500966d471db7b5bfd26cf56 Mon Sep 17 00:00:00 2001 From: Erik Schnetter Date: Mon, 21 Dec 2015 10:21:33 -0500 Subject: Simplify Spack cc script --- lib/spack/env/cc | 283 +++++++++++++++++++++++++------------------------------ 1 file changed, 130 insertions(+), 153 deletions(-) (limited to 'lib') diff --git a/lib/spack/env/cc b/lib/spack/env/cc index f3fadfcf45..053295f42d 100755 --- a/lib/spack/env/cc +++ b/lib/spack/env/cc @@ -65,7 +65,7 @@ function die { } for param in $parameters; do - if [ -z "${!param}" ]; then + if [[ -z ${!param} ]]; then die "Spack compiler must be run from spack! Input $param was missing!" fi done @@ -114,114 +114,118 @@ case "$command" in esac # Finish setting up the mode. -if [ -z "$mode" ]; then +if [[ -z $mode ]]; then mode=ccld for arg in "$@"; do - if [ "$arg" = -v -o "$arg" = -V -o "$arg" = --version -o "$arg" = -dumpversion ]; then - mode=vcheck - break - elif [ "$arg" = -E ]; then - mode=cpp - break - elif [ "$arg" = -c ]; then - mode=cc - break - elif [ "$arg" = -S ]; then - mode=as - echo "spac cc mode as" "$@" - exit 1 - break - fi + case "$arg" in + -v|-V|--version|-dumpversion) + mode=vcheck + break + ;; + -E) + mode=cpp + break + ;; + -c) + mode=cc + break + ;; + -S) + mode=as + break + ;; + esac done fi # Dump the version and exist if we're in testing mode. -if [ "$SPACK_TEST_COMMAND" = "dump-mode" ]; then +if [[ $SPACK_TEST_COMMAND = dump-mode ]]; then echo "$mode" exit fi # Check that at least one of the real commands was actually selected, # otherwise we don't know what to execute. -if [ -z "$command" ]; then +if [[ -z $command ]]; then die "ERROR: Compiler '$SPACK_COMPILER_SPEC' does not support compiling $language programs." fi # Save original command for debug logging input_command="$@" +args=("$@") -# -# Now do real parsing of the command line args, trying hard to keep -# non-rpath linker arguments in the proper order w.r.t. other command -# line arguments. This is important for things like groups. -# -includes=() -libraries=() -libs=() -rpaths=() -other_args=() -all_args=("$@") +# Dump parsed values for unit testing if asked for +if [[ -n $SPACK_TEST_COMMAND ]]; then -while [ -n "$1" ]; do - case "$1" in - -I*) - arg="${1#-I}" - if [ -z "$arg" ]; then shift; arg="$1"; fi - includes+=("$arg") - ;; - -L*) - arg="${1#-L}" - if [ -z "$arg" ]; then shift; arg="$1"; fi - libraries+=("$arg") - ;; - -l*) - arg="${1#-l}" - if [ -z "$arg" ]; then shift; arg="$1"; fi - libs+=("$arg") - ;; - -Wl,*) - arg="${1#-Wl,}" - if [ -z "$arg" ]; then shift; arg="$1"; fi - if [[ "$arg" = -rpath=* ]]; then - rpaths+=("${arg#-rpath=}") - elif [[ "$arg" = -rpath,* ]]; then - rpaths+=("${arg#-rpath,}") - elif [[ "$arg" = -rpath ]]; then - shift; arg="$1" - if [[ "$arg" != -Wl,* ]]; then - die "-Wl,-rpath was not followed by -Wl,*" + # + # Now do real parsing of the command line args, trying hard to keep + # non-rpath linker arguments in the proper order w.r.t. other command line + # arguments. This is important for things like groups. + # + includes=() + libraries=() + libs=() + rpaths=() + other_args=() + + while [[ -n $1 ]]; do + case "$1" in + -I*) + arg="${1#-I}" + if [[ -z $arg ]]; then shift; arg="$1"; fi + includes+=("$arg") + ;; + -L*) + arg="${1#-L}" + if [[ -z $arg ]]; then shift; arg="$1"; fi + libraries+=("$arg") + ;; + -l*) + arg="${1#-l}" + if [[ -z $arg ]]; then shift; arg="$1"; fi + libs+=("$arg") + ;; + -Wl,*) + arg="${1#-Wl,}" + if [[ -z $arg ]]; then shift; arg="$1"; fi + if [[ $arg = -rpath=* ]]; then + rpaths+=("${arg#-rpath=}") + elif [[ $arg = -rpath,* ]]; then + rpaths+=("${arg#-rpath,}") + elif [[ $arg = -rpath ]]; then + shift; arg="$1" + if [[ $arg != -Wl,* ]]; then + die "-Wl,-rpath was not followed by -Wl,*" + fi + rpaths+=("${arg#-Wl,}") + else + other_args+=("-Wl,$arg") fi - rpaths+=("${arg#-Wl,}") - else - other_args+=("-Wl,$arg") - fi - ;; - -Xlinker,*) - arg="${1#-Xlinker,}" - if [ -z "$arg" ]; then shift; arg="$1"; fi - if [[ "$arg" = -rpath=* ]]; then - rpaths+=("${arg#-rpath=}") - elif [[ "$arg" = -rpath,* ]]; then - rpaths+=("${arg#-rpath,}") - elif [[ "$arg" = -rpath ]]; then - shift; arg="$1" - if [[ "$arg" != -Xlinker,* ]]; then - die "-Xlinker,-rpath was not followed by -Xlinker,*" + ;; + -Xlinker,*) + arg="${1#-Xlinker,}" + if [[ -z $arg ]]; then shift; arg="$1"; fi + if [[ $arg = -rpath=* ]]; then + rpaths+=("${arg#-rpath=}") + elif [[ $arg = -rpath,* ]]; then + rpaths+=("${arg#-rpath,}") + elif [[ $arg = -rpath ]]; then + shift; arg="$1" + if [[ $arg != -Xlinker,* ]]; then + die "-Xlinker,-rpath was not followed by -Xlinker,*" + fi + rpaths+=("${arg#-Xlinker,}") + else + other_args+=("-Xlinker,$arg") fi - rpaths+=("${arg#-Xlinker,}") - else - other_args+=("-Xlinker,$arg") - fi - ;; - *) - other_args+=("$1") - ;; - esac - shift -done + ;; + *) + other_args+=("$1") + ;; + esac + shift + done -# Dump parsed values for unit testing if asked for -if [ -n "$SPACK_TEST_COMMAND" ]; then IFS=$'\n' case "$SPACK_TEST_COMMAND" in dump-includes) echo "${includes[*]}";; @@ -246,8 +250,8 @@ if [ -n "$SPACK_TEST_COMMAND" ]; then echo "${other_args[*]}" ;; *) - echo "ERROR: Unknown test command" - exit 1 ;; + die "ERROR: Unknown test command" + ;; esac exit fi @@ -255,66 +259,44 @@ fi # Read spack dependencies from the path environment variable IFS=':' read -ra deps <<< "$SPACK_DEPENDENCIES" for dep in "${deps[@]}"; do - if [ -d "$dep/include" ]; then - includes+=("$dep/include") - all_args=("-I$dep/include" ${all_args[@]}) + if [[ -d $dep/include ]]; then + args=("-I$dep/include" "${args[@]}") fi - if [ -d "$dep/lib" ]; then - libraries+=("$dep/lib") - rpaths+=("$dep/lib") - if [ "$mode" = ccld ]; then - all_args=("-L$dep/lib" "-Wl,-rpath,$dep/lib" ${all_args[@]}) - elif [ "$mode" = ld ]; then - all_args=("-L$dep/lib" "-rpath" "$dep/lib" ${all_args[@]}) - fi + if [[ -d $dep/lib ]]; then + # libraries+=("$dep/lib") + if [[ $mode = ccld ]]; then + args=("-L$dep/lib" "-Wl,-rpath,$dep/lib" "${args[@]}") + elif [[ $mode = ld ]]; then + args=("-L$dep/lib" "-rpath" "$dep/lib" "${args[@]}") + fi fi - if [ -d "$dep/lib64" ]; then - libraries+=("$dep/lib64") - rpaths+=("$dep/lib64") - if [ "$mode" = ccld ]; then - all_args=("-L$dep/lib" "-Wl,-rpath,$dep/lib" ${all_args[@]}) - elif [ "$mode" = ld ]; then - all_args=("-L$dep/lib" "-rpath" "$dep/lib" ${all_args[@]}) - fi + if [[ -d $dep/lib64 ]]; then + # libraries+=("$dep/lib64") + if [[ $mode = ccld ]]; then + args=("-L$dep/lib" "-Wl,-rpath,$dep/lib" "${args[@]}") + elif [[ $mode = ld ]]; then + args=("-L$dep/lib" "-rpath" "$dep/lib" "${args[@]}") + fi fi done # Include all -L's and prefix/whatever dirs in rpath -for dir in "${libraries[@]}"; do - [[ dir = $SPACK_INSTALL* ]] && rpaths+=("$dir") - if [ "$mode" = ccld ]; then - [[ dir = $SPACK_INSTALL* ]] && all_args=("-Wl,-rpath,$dir" ${all_args[@]}) - elif [ "$mode" = ld ]; then - [[ dir = $SPACK_INSTALL* ]] && all_args=("-rpath" "$dir" ${all_args[@]}) - fi -done -rpaths+=("$SPACK_PREFIX/lib") -rpaths+=("$SPACK_PREFIX/lib64") -if [ "$mode" = ccld ]; then - all_args=("-Wl,-rpath,$SPACK_PREFIX/lib" "-Wl,-rpath,$SPACK_PREFIX/lib64" ${all_args[@]}) -elif [ "$mode" = ld ]; then - all_args=("-rpath" "$SPACK_PREFIX/lib" "-rpath" "$SPACK_PREFIX/lib64" ${all_args[@]}) -fi - -# Put the arguments together -args=() -for dir in "${includes[@]}"; do args+=("-I$dir"); done -args+=("${other_args[@]}") -for dir in "${libraries[@]}"; do args+=("-L$dir"); done -for lib in "${libs[@]}"; do args+=("-l$lib"); done - -if [ "$mode" = ccld ]; then - for dir in "${rpaths[@]}"; do - args+=("-Wl,-rpath") - args+=("-Wl,$dir"); - done -elif [ "$mode" = ld ]; then - for dir in "${rpaths[@]}"; do - args+=("-rpath") - args+=("$dir"); - done +if [[ $mode = ccld ]]; then + # for dir in "${libraries[@]}"; do + # if [[ dir = $SPACK_INSTALL* ]]; then + # args=("-Wl,-rpath,$dir" "${args[@]}") + # fi + # done + args=("-Wl,-rpath,$SPACK_PREFIX/lib" "-Wl,-rpath,$SPACK_PREFIX/lib64" ${args[@]}) +elif [[ $mode = ld ]]; then + # for dir in "${libraries[@]}"; do + # if [[ dir = $SPACK_INSTALL* ]]; then + # args=("-rpath" "$dir" "${args[@]}") + # fi + # done + args=("-rpath" "$SPACK_PREFIX/lib" "-rpath" "$SPACK_PREFIX/lib64" ${args[@]}) fi # @@ -330,34 +312,29 @@ unset DYLD_LIBRARY_PATH # IFS=':' read -ra env_path <<< "$PATH" IFS=':' read -ra spack_env_dirs <<< "$SPACK_ENV_PATH" -spack_env_dirs+=(".") +spack_env_dirs+=("" ".") PATH="" for dir in "${env_path[@]}"; do remove="" for rm_dir in "${spack_env_dirs[@]}"; do - if [ "$dir" = "$rm_dir" ]; then remove=True; fi + if [[ $dir = $rm_dir ]]; then remove=True; fi done - if [ -z "$remove" ]; then - if [ -z "$PATH" ]; then - PATH="$dir" - else - PATH="$PATH:$dir" - fi + if [[ -z $remove ]]; then + PATH="${PATH:+$PATH:}$dir" fi done export PATH full_command=("$command") -# full_command+=("${args[@]}") -full_command+=("${all_args[@]}") +full_command+=("${args[@]}") # # Write the input and output commands to debug logs if it's asked for. # -if [ "$SPACK_DEBUG" = "TRUE" ]; then +if [[ $SPACK_DEBUG = TRUE ]]; then input_log="$SPACK_DEBUG_LOG_DIR/spack-cc-$SPACK_SHORT_SPEC.in.log" output_log="$SPACK_DEBUG_LOG_DIR/spack-cc-$SPACK_SHORT_SPEC.out.log" - echo "$input_command" >> $input_log + echo "$input_command" >> $input_log echo "$mode ${full_command[@]}" >> $output_log fi -- cgit v1.2.3-70-g09d2 From 3427174eb065a6e74fc279076423c2c5c5e8e737 Mon Sep 17 00:00:00 2001 From: Erik Schnetter Date: Tue, 22 Dec 2015 15:49:14 -0500 Subject: Correct quoting --- lib/spack/env/cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/spack/env/cc b/lib/spack/env/cc index 565f959ca4..4ac8f2e7f4 100755 --- a/lib/spack/env/cc +++ b/lib/spack/env/cc @@ -265,7 +265,7 @@ for dep in "${deps[@]}"; do if [[ -d $dep/lib ]]; then # libraries+=("$dep/lib") - if [[ $mode = ccld ]]; then + if [[ $mode = ccld ]]; then args=("-L$dep/lib" "-Wl,-rpath,$dep/lib" "${args[@]}") elif [[ $mode = ld ]]; then args=("-L$dep/lib" "-rpath" "$dep/lib" "${args[@]}") @@ -289,14 +289,14 @@ if [[ $mode = ccld ]]; then # args=("-Wl,-rpath,$dir" "${args[@]}") # fi # done - args=("-Wl,-rpath,$SPACK_PREFIX/lib" "-Wl,-rpath,$SPACK_PREFIX/lib64" ${args[@]}) + args=("-Wl,-rpath,$SPACK_PREFIX/lib" "-Wl,-rpath,$SPACK_PREFIX/lib64" "${args[@]}") elif [[ $mode = ld ]]; then # for dir in "${libraries[@]}"; do # if [[ dir = $SPACK_INSTALL* ]]; then # args=("-rpath" "$dir" "${args[@]}") # fi # done - args=("-rpath" "$SPACK_PREFIX/lib" "-rpath" "$SPACK_PREFIX/lib64" ${args[@]}) + args=("-rpath" "$SPACK_PREFIX/lib" "-rpath" "$SPACK_PREFIX/lib64" "${args[@]}") fi # @@ -325,8 +325,7 @@ for dir in "${env_path[@]}"; do done export PATH -full_command=("$command") -full_command+=("${args[@]}") +full_command=("$command" "${args[@]}") # # Write the input and output commands to debug logs if it's asked for. -- cgit v1.2.3-70-g09d2 From ff81aff2540f9eadd8d0ce123ae3143ebcb68789 Mon Sep 17 00:00:00 2001 From: Erik Schnetter Date: Fri, 12 Feb 2016 13:05:42 -0500 Subject: Remove source-code optimization and cleanup --- lib/spack/env/cc | 106 +++++++++++++++++++++++-------------------------------- 1 file changed, 44 insertions(+), 62 deletions(-) (limited to 'lib') diff --git a/lib/spack/env/cc b/lib/spack/env/cc index b83731404b..ac8f717cc7 100755 --- a/lib/spack/env/cc +++ b/lib/spack/env/cc @@ -65,7 +65,7 @@ function die { } for param in $parameters; do - if [[ -z ${!param} ]]; then + if [ -z "${!param}" ]; then die "Spack compiler must be run from spack! Input $param was missing!" fi done @@ -114,39 +114,31 @@ case "$command" in esac # Finish setting up the mode. -if [[ -z $mode ]]; then +if [ -z "$mode" ]; then mode=ccld for arg in "$@"; do - case "$arg" in - -v|-V|--version|-dumpversion) - mode=vcheck - break - ;; - -E) - mode=cpp - break - ;; - -c) - mode=cc - break - ;; - -S) - mode=as - break - ;; - esac + if [ "$arg" = -v -o "$arg" = -V -o "$arg" = --version -o "$arg" = -dumpversion ]; then + mode=vcheck + break + elif [ "$arg" = -E ]; then + mode=cpp + break + elif [ "$arg" = -c ]; then + mode=cc + break + fi done fi # Dump the version and exist if we're in testing mode. -if [[ $SPACK_TEST_COMMAND = dump-mode ]]; then +if [ "$SPACK_TEST_COMMAND" = "dump-mode" ]; then echo "$mode" exit fi # Check that at least one of the real commands was actually selected, # otherwise we don't know what to execute. -if [[ -z $command ]]; then +if [ -z "$command" ]; then die "ERROR: Compiler '$SPACK_COMPILER_SPEC' does not support compiling $language programs." fi @@ -159,8 +151,8 @@ if [[ -n $SPACK_TEST_COMMAND ]]; then # # Now do real parsing of the command line args, trying hard to keep - # non-rpath linker arguments in the proper order w.r.t. other command line - # arguments. This is important for things like groups. + # non-rpath linker arguments in the proper order w.r.t. other command + # line arguments. This is important for things like groups. # includes=() libraries=() @@ -168,33 +160,31 @@ if [[ -n $SPACK_TEST_COMMAND ]]; then rpaths=() other_args=() - while [[ -n $1 ]]; do + while [ -n "$1" ]; do case "$1" in -I*) arg="${1#-I}" - if [[ -z $arg ]]; then shift; arg="$1"; fi + if [ -z "$arg" ]; then shift; arg="$1"; fi includes+=("$arg") ;; -L*) arg="${1#-L}" - if [[ -z $arg ]]; then shift; arg="$1"; fi + if [ -z "$arg" ]; then shift; arg="$1"; fi libraries+=("$arg") ;; -l*) arg="${1#-l}" - if [[ -z $arg ]]; then shift; arg="$1"; fi + if [ -z "$arg" ]; then shift; arg="$1"; fi libs+=("$arg") ;; -Wl,*) arg="${1#-Wl,}" - if [[ -z $arg ]]; then shift; arg="$1"; fi - if [[ $arg = -rpath=* ]]; then + if [ -z "$arg" ]; then shift; arg="$1"; fi + if [[ "$arg" = -rpath=* ]]; then rpaths+=("${arg#-rpath=}") - elif [[ $arg = -rpath,* ]]; then - rpaths+=("${arg#-rpath,}") - elif [[ $arg = -rpath ]]; then + elif [[ "$arg" = -rpath ]]; then shift; arg="$1" - if [[ $arg != -Wl,* ]]; then + if [[ "$arg" != -Wl,* ]]; then die "-Wl,-rpath was not followed by -Wl,*" fi rpaths+=("${arg#-Wl,}") @@ -204,14 +194,12 @@ if [[ -n $SPACK_TEST_COMMAND ]]; then ;; -Xlinker,*) arg="${1#-Xlinker,}" - if [[ -z $arg ]]; then shift; arg="$1"; fi - if [[ $arg = -rpath=* ]]; then + if [ -z "$arg" ]; then shift; arg="$1"; fi + if [[ "$arg" = -rpath=* ]]; then rpaths+=("${arg#-rpath=}") - elif [[ $arg = -rpath,* ]]; then - rpaths+=("${arg#-rpath,}") - elif [[ $arg = -rpath ]]; then + elif [[ "$arg" = -rpath ]]; then shift; arg="$1" - if [[ $arg != -Xlinker,* ]]; then + if [[ "$arg" != -Xlinker,* ]]; then die "-Xlinker,-rpath was not followed by -Xlinker,*" fi rpaths+=("${arg#-Xlinker,}") @@ -250,8 +238,8 @@ if [[ -n $SPACK_TEST_COMMAND ]]; then echo "${other_args[*]}" ;; *) - die "ERROR: Unknown test command" - ;; + echo "ERROR: Unknown test command" + exit 1 ;; esac exit fi @@ -259,12 +247,11 @@ fi # Read spack dependencies from the path environment variable IFS=':' read -ra deps <<< "$SPACK_DEPENDENCIES" for dep in "${deps[@]}"; do - if [[ -d $dep/include ]]; then + if [ -d "$dep/include" ]; then args=("-I$dep/include" "${args[@]}") fi - if [[ -d $dep/lib ]]; then - # libraries+=("$dep/lib") + if [ -d "$dep/lib" ]; then if [[ $mode = ccld ]]; then args=("-L$dep/lib" "-Wl,-rpath,$dep/lib" "${args[@]}") elif [[ $mode = ld ]]; then @@ -272,7 +259,7 @@ for dep in "${deps[@]}"; do fi fi - if [[ -d $dep/lib64 ]]; then + if [ -d "$dep/lib64" ]; then # libraries+=("$dep/lib64") if [[ $mode = ccld ]]; then args=("-L$dep/lib" "-Wl,-rpath,$dep/lib" "${args[@]}") @@ -284,18 +271,8 @@ done # Include all -L's and prefix/whatever dirs in rpath if [[ $mode = ccld ]]; then - # for dir in "${libraries[@]}"; do - # if [[ dir = $SPACK_INSTALL* ]]; then - # args=("-Wl,-rpath,$dir" "${args[@]}") - # fi - # done args=("-Wl,-rpath,$SPACK_PREFIX/lib" "-Wl,-rpath,$SPACK_PREFIX/lib64" "${args[@]}") elif [[ $mode = ld ]]; then - # for dir in "${libraries[@]}"; do - # if [[ dir = $SPACK_INSTALL* ]]; then - # args=("-rpath" "$dir" "${args[@]}") - # fi - # done args=("-rpath" "$SPACK_PREFIX/lib" "-rpath" "$SPACK_PREFIX/lib64" "${args[@]}") fi @@ -317,23 +294,28 @@ PATH="" for dir in "${env_path[@]}"; do remove="" for rm_dir in "${spack_env_dirs[@]}"; do - if [[ $dir = $rm_dir ]]; then remove=True; fi + if [ "$dir" = "$rm_dir" ]; then remove=True; fi done - if [[ -z $remove ]]; then - PATH="${PATH:+$PATH:}$dir" + if [ -z "$remove" ]; then + if [ -z "$PATH" ]; then + PATH="$dir" + else + PATH="$PATH:$dir" + fi fi done export PATH -full_command=("$command" "${args[@]}") +full_command=("$command") +full_command+=("${args[@]}") # # Write the input and output commands to debug logs if it's asked for. # -if [[ $SPACK_DEBUG = TRUE ]]; then +if [ "$SPACK_DEBUG" = "TRUE" ]; then input_log="$SPACK_DEBUG_LOG_DIR/spack-cc-$SPACK_SHORT_SPEC.in.log" output_log="$SPACK_DEBUG_LOG_DIR/spack-cc-$SPACK_SHORT_SPEC.out.log" - echo "$input_command" >> $input_log + echo "$input_command" >> $input_log echo "$mode ${full_command[@]}" >> $output_log fi -- cgit v1.2.3-70-g09d2 From 1d70b590fc4579c4e6b4bd592bc58eabf330fd9b Mon Sep 17 00:00:00 2001 From: alalazo Date: Fri, 11 Mar 2016 13:20:57 +0100 Subject: build_environment : fixed minor spelling errors and a few style issues --- lib/spack/spack/build_environment.py | 37 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 19 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py index 87fc310b5a..392ba7ea4d 100644 --- a/lib/spack/spack/build_environment.py +++ b/lib/spack/spack/build_environment.py @@ -3,7 +3,7 @@ This module contains all routines related to setting up the package build environment. All of this is set up by package.py just before install() is called. -There are two parts to the bulid environment: +There are two parts to the build environment: 1. Python build environment (i.e. install() method) @@ -13,7 +13,7 @@ There are two parts to the bulid environment: the package's module scope. Ths allows package writers to call them all directly in Package.install() without writing 'self.' everywhere. No, this isn't Pythonic. Yes, it makes the code more - readable and more like the shell script from whcih someone is + readable and more like the shell script from which someone is likely porting. 2. Build execution environment @@ -27,17 +27,16 @@ There are two parts to the bulid environment: Skimming this module is a nice way to get acquainted with the types of calls you can make from within the install() function. """ -import os -import sys -import shutil import multiprocessing +import os import platform -from llnl.util.filesystem import * +import shutil +import sys import spack -import spack.compilers as compilers -from spack.util.executable import Executable, which +from llnl.util.filesystem import * from spack.util.environment import * +from spack.util.executable import Executable, which # # This can be set by the user to globally disable parallel builds. @@ -107,18 +106,19 @@ def set_compiler_environment_variables(pkg): if compiler.fc: os.environ['SPACK_FC'] = compiler.fc - os.environ['SPACK_COMPILER_SPEC'] = str(pkg.spec.compiler) + os.environ['SPACK_COMPILER_SPEC'] = str(pkg.spec.compiler) def set_build_environment_variables(pkg): - """This ensures a clean install environment when we build packages. + """ + This ensures a clean install environment when we build packages """ # Add spack build environment path with compiler wrappers first in # the path. We add both spack.env_path, which includes default # wrappers (cc, c++, f77, f90), AND a subdirectory containing # compiler-specific symlinks. The latter ensures that builds that # are sensitive to the *name* of the compiler see the right name - # when we're building wtih the wrappers. + # when we're building with the wrappers. # # Conflicts on case-insensitive systems (like "CC" and "cc") are # handled by putting one in the /case-insensitive @@ -296,23 +296,23 @@ def fork(pkg, function): # do stuff build_env.fork(pkg, child_fun) - Forked processes are run with the build environemnt set up by + Forked processes are run with the build environment set up by spack.build_environment. This allows package authors to have - full control over the environment, etc. without offecting + full control over the environment, etc. without affecting other builds that might be executed in the same spack call. - If something goes wrong, the child process is expected toprint + If something goes wrong, the child process is expected to print the error and the parent process will exit with error as well. If things go well, the child exits and the parent carries on. """ try: pid = os.fork() - except OSError, e: + except OSError as e: raise InstallError("Unable to fork build process: %s" % e) if pid == 0: - # Give the child process the package's build environemnt. + # Give the child process the package's build environment. setup_package(pkg) try: @@ -323,7 +323,7 @@ def fork(pkg, function): # which interferes with unit tests. os._exit(0) - except spack.error.SpackError, e: + except spack.error.SpackError as e: e.die() except: @@ -338,8 +338,7 @@ def fork(pkg, function): # message. Just make the parent exit with an error code. pid, returncode = os.waitpid(pid, 0) if returncode != 0: - raise InstallError("Installation process had nonzero exit code." - .format(str(returncode))) + raise InstallError("Installation process had nonzero exit code.".format(str(returncode))) class InstallError(spack.error.SpackError): -- cgit v1.2.3-70-g09d2 From f9923452b3365e1472a4f1bd63712c57fea0ee0d Mon Sep 17 00:00:00 2001 From: alalazo Date: Mon, 14 Mar 2016 14:35:48 +0100 Subject: environment : added machinery to collect modifications to the environment and apply them later --- lib/spack/spack/environment.py | 157 ++++++++++++++++++++++++++++++++++++ lib/spack/spack/test/__init__.py | 3 +- lib/spack/spack/test/environment.py | 50 ++++++++++++ 3 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 lib/spack/spack/environment.py create mode 100644 lib/spack/spack/test/environment.py (limited to 'lib') diff --git a/lib/spack/spack/environment.py b/lib/spack/spack/environment.py new file mode 100644 index 0000000000..7d3d7af0de --- /dev/null +++ b/lib/spack/spack/environment.py @@ -0,0 +1,157 @@ +import os +import os.path +import collections + + +class SetEnv(object): + def __init__(self, name, value, **kwargs): + self.name = name + self.value = value + for key, value in kwargs.items(): + setattr(self, key, value) + + def execute(self): + os.environ[self.name] = str(self.value) + + +class UnsetEnv(object): + def __init__(self, name, **kwargs): + self.name = name + for key, value in kwargs.items(): + setattr(self, key, value) + + def execute(self): + os.environ.pop(self.name, None) # Avoid throwing if the variable was not set + + +class AppendPath(object): + def __init__(self, name, path, **kwargs): + self.name = name + self.path = path + for key, value in kwargs.items(): + setattr(self, key, value) + + def execute(self): + environment_value = os.environ.get(self.name, '') + directories = environment_value.split(':') if environment_value else [] + # TODO : Check if this is a valid directory name + directories.append(os.path.normpath(self.path)) + os.environ[self.name] = ':'.join(directories) + + +class PrependPath(object): + def __init__(self, name, path, **kwargs): + self.name = name + self.path = path + for key, value in kwargs.items(): + setattr(self, key, value) + + def execute(self): + environment_value = os.environ.get(self.name, '') + directories = environment_value.split(':') if environment_value else [] + # TODO : Check if this is a valid directory name + directories = [os.path.normpath(self.path)] + directories + os.environ[self.name] = ':'.join(directories) + + +class RemovePath(object): + def __init__(self, name, path, **kwargs): + self.name = name + self.path = path + for key, value in kwargs.items(): + setattr(self, key, value) + + def execute(self): + environment_value = os.environ.get(self.name, '') + directories = environment_value.split(':') if environment_value else [] + directories = [os.path.normpath(x) for x in directories if x != os.path.normpath(self.path)] + os.environ[self.name] = ':'.join(directories) + + +class EnvironmentModifications(object): + """ + Keeps track of requests to modify the current environment + """ + + def __init__(self): + self.env_modifications = [] + + def __iter__(self): + return iter(self.env_modifications) + + def set_env(self, name, value, **kwargs): + """ + Stores in the current object a request to set an environment variable + + Args: + name: name of the environment variable to be set + value: value of the environment variable + """ + item = SetEnv(name, value, **kwargs) + self.env_modifications.append(item) + + def unset_env(self, name, **kwargs): + """ + Stores in the current object a request to unset an environment variable + + Args: + name: name of the environment variable to be set + """ + item = UnsetEnv(name, **kwargs) + self.env_modifications.append(item) + + def append_path(self, name, path, **kwargs): + """ + Stores in the current object a request to append a path to a path list + + Args: + name: name of the path list in the environment + path: path to be appended + """ + item = AppendPath(name, path, **kwargs) + self.env_modifications.append(item) + + def prepend_path(self, name, path, **kwargs): + """ + Same as `append_path`, but the path is pre-pended + + Args: + name: name of the path list in the environment + path: path to be pre-pended + """ + item = PrependPath(name, path, **kwargs) + self.env_modifications.append(item) + + def remove_path(self, name, path, **kwargs): + """ + Stores in the current object a request to remove a path from a path list + + Args: + name: name of the path list in the environment + path: path to be removed + """ + item = RemovePath(name, path, **kwargs) + self.env_modifications.append(item) + + +def validate_environment_modifications(env): + modifications = collections.defaultdict(list) + for item in env: + modifications[item.name].append(item) + return modifications + + +def apply_environment_modifications(env): + """ + Modifies the current environment according to the request in env + + Args: + env: object storing modifications to the environment + """ + modifications = validate_environment_modifications(env) + + # Cycle over the environment variables that will be modified + for variable, actions in modifications.items(): + # Execute all the actions in the order they were issued + for x in actions: + x.execute() diff --git a/lib/spack/spack/test/__init__.py b/lib/spack/spack/test/__init__.py index d5d8b64765..cd842561e6 100644 --- a/lib/spack/spack/test/__init__.py +++ b/lib/spack/spack/test/__init__.py @@ -66,7 +66,8 @@ test_names = ['versions', 'database', 'namespace_trie', 'yaml', - 'sbang'] + 'sbang', + 'environment'] def list_tests(): diff --git a/lib/spack/spack/test/environment.py b/lib/spack/spack/test/environment.py new file mode 100644 index 0000000000..dff3863d32 --- /dev/null +++ b/lib/spack/spack/test/environment.py @@ -0,0 +1,50 @@ +import unittest +import os +from spack.environment import EnvironmentModifications, apply_environment_modifications + + +class EnvironmentTest(unittest.TestCase): + def setUp(self): + os.environ.clear() + os.environ['UNSET_ME'] = 'foo' + os.environ['EMPTY_PATH_LIST'] = '' + os.environ['PATH_LIST'] = '/path/second:/path/third' + os.environ['REMOVE_PATH_LIST'] = '/a/b:/duplicate:/a/c:/remove/this:/a/d:/duplicate/:/f/g' + + def test_set_env(self): + env = EnvironmentModifications() + env.set_env('A', 'dummy value') + env.set_env('B', 3) + apply_environment_modifications(env) + self.assertEqual('dummy value', os.environ['A']) + self.assertEqual(str(3), os.environ['B']) + + def test_unset_env(self): + env = EnvironmentModifications() + self.assertEqual('foo', os.environ['UNSET_ME']) + env.unset_env('UNSET_ME') + apply_environment_modifications(env) + self.assertRaises(KeyError, os.environ.__getitem__, 'UNSET_ME') + + def test_path_manipulation(self): + env = EnvironmentModifications() + + env.append_path('PATH_LIST', '/path/last') + env.prepend_path('PATH_LIST', '/path/first') + + env.append_path('EMPTY_PATH_LIST', '/path/middle') + env.append_path('EMPTY_PATH_LIST', '/path/last') + env.prepend_path('EMPTY_PATH_LIST', '/path/first') + + env.append_path('NEWLY_CREATED_PATH_LIST', '/path/middle') + env.append_path('NEWLY_CREATED_PATH_LIST', '/path/last') + env.prepend_path('NEWLY_CREATED_PATH_LIST', '/path/first') + + env.remove_path('REMOVE_PATH_LIST', '/remove/this') + env.remove_path('REMOVE_PATH_LIST', '/duplicate/') + + apply_environment_modifications(env) + self.assertEqual('/path/first:/path/second:/path/third:/path/last', os.environ['PATH_LIST']) + self.assertEqual('/path/first:/path/middle:/path/last', os.environ['EMPTY_PATH_LIST']) + self.assertEqual('/path/first:/path/middle:/path/last', os.environ['NEWLY_CREATED_PATH_LIST']) + self.assertEqual('/a/b:/a/c:/a/d:/f/g', os.environ['REMOVE_PATH_LIST']) -- cgit v1.2.3-70-g09d2 From f20247ae55362424d1d5543840a21142017661af Mon Sep 17 00:00:00 2001 From: alalazo Date: Tue, 15 Mar 2016 10:08:54 +0100 Subject: environment : refactoreded set_compiler_environment_variables --- lib/spack/spack/build_environment.py | 38 ++++++++++++++++++++---------------- lib/spack/spack/environment.py | 17 +++++++++++++++- lib/spack/spack/test/database.py | 1 + lib/spack/spack/test/environment.py | 9 +++++++++ 4 files changed, 47 insertions(+), 18 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py index 392ba7ea4d..e91a8a1997 100644 --- a/lib/spack/spack/build_environment.py +++ b/lib/spack/spack/build_environment.py @@ -35,6 +35,7 @@ import sys import spack from llnl.util.filesystem import * +from spack.environment import EnvironmentModifications, apply_environment_modifications from spack.util.environment import * from spack.util.executable import Executable, which @@ -83,30 +84,32 @@ class MakeExecutable(Executable): def set_compiler_environment_variables(pkg): - assert(pkg.spec.concrete) - compiler = pkg.compiler - + assert pkg.spec.concrete # Set compiler variables used by CMake and autotools - assert all(key in pkg.compiler.link_paths - for key in ('cc', 'cxx', 'f77', 'fc')) + assert all(key in pkg.compiler.link_paths for key in ('cc', 'cxx', 'f77', 'fc')) + # Populate an object with the list of environment modifications + # and return it + # TODO : add additional kwargs for better diagnostics, like requestor, ttyout, ttyerr, etc. + env = EnvironmentModifications() link_dir = spack.build_env_path - os.environ['CC'] = join_path(link_dir, pkg.compiler.link_paths['cc']) - os.environ['CXX'] = join_path(link_dir, pkg.compiler.link_paths['cxx']) - os.environ['F77'] = join_path(link_dir, pkg.compiler.link_paths['f77']) - os.environ['FC'] = join_path(link_dir, pkg.compiler.link_paths['fc']) - + env.set_env('CC', join_path(link_dir, pkg.compiler.link_paths['cc'])) + env.set_env('CXX', join_path(link_dir, pkg.compiler.link_paths['cxx'])) + env.set_env('F77', join_path(link_dir, pkg.compiler.link_paths['f77'])) + env.set_env('FC', join_path(link_dir, pkg.compiler.link_paths['fc'])) # Set SPACK compiler variables so that our wrapper knows what to call + compiler = pkg.compiler if compiler.cc: - os.environ['SPACK_CC'] = compiler.cc + env.set_env('SPACK_CC', compiler.cc) if compiler.cxx: - os.environ['SPACK_CXX'] = compiler.cxx + env.set_env('SPACK_CXX', compiler.cxx) if compiler.f77: - os.environ['SPACK_F77'] = compiler.f77 + env.set_env('SPACK_F77', compiler.f77) if compiler.fc: - os.environ['SPACK_FC'] = compiler.fc + env.set_env('SPACK_FC', compiler.fc) - os.environ['SPACK_COMPILER_SPEC'] = str(pkg.spec.compiler) + env.set_env('SPACK_COMPILER_SPEC', str(pkg.spec.compiler)) + return env def set_build_environment_variables(pkg): @@ -264,9 +267,10 @@ def parent_class_modules(cls): def setup_package(pkg): """Execute all environment setup routines.""" - set_compiler_environment_variables(pkg) + env = EnvironmentModifications() + env.extend(set_compiler_environment_variables(pkg)) + apply_environment_modifications(env) set_build_environment_variables(pkg) - # If a user makes their own package repo, e.g. # spack.repos.mystuff.libelf.Libelf, and they inherit from # an existing class like spack.repos.original.libelf.Libelf, diff --git a/lib/spack/spack/environment.py b/lib/spack/spack/environment.py index 7d3d7af0de..3b73f1c7a2 100644 --- a/lib/spack/spack/environment.py +++ b/lib/spack/spack/environment.py @@ -73,12 +73,24 @@ class EnvironmentModifications(object): Keeps track of requests to modify the current environment """ - def __init__(self): + def __init__(self, other=None): self.env_modifications = [] + if other is not None: + self._check_other(other) + self.env_modifications.extend(other.env_modifications) def __iter__(self): return iter(self.env_modifications) + def extend(self, other): + self._check_other(other) + self.env_modifications.extend(other.env_modifications) + + @staticmethod + def _check_other(other): + if not isinstance(other, EnvironmentModifications): + raise TypeError('other must be an instance of EnvironmentModifications') + def set_env(self, name, value, **kwargs): """ Stores in the current object a request to set an environment variable @@ -138,6 +150,9 @@ def validate_environment_modifications(env): modifications = collections.defaultdict(list) for item in env: modifications[item.name].append(item) + # TODO : once we organized the modifications into a dictionary that maps an environment variable + # TODO : to a list of action to be done on it, we may easily spot inconsistencies and warn the user if + # TODO : something suspicious is happening return modifications diff --git a/lib/spack/spack/test/database.py b/lib/spack/spack/test/database.py index 9a57e1f03e..ce6e8a0552 100644 --- a/lib/spack/spack/test/database.py +++ b/lib/spack/spack/test/database.py @@ -26,6 +26,7 @@ These tests check the database is functioning properly, both in memory and in its file """ +import os.path import multiprocessing import shutil import tempfile diff --git a/lib/spack/spack/test/environment.py b/lib/spack/spack/test/environment.py index dff3863d32..17061c8fd0 100644 --- a/lib/spack/spack/test/environment.py +++ b/lib/spack/spack/test/environment.py @@ -48,3 +48,12 @@ class EnvironmentTest(unittest.TestCase): self.assertEqual('/path/first:/path/middle:/path/last', os.environ['EMPTY_PATH_LIST']) self.assertEqual('/path/first:/path/middle:/path/last', os.environ['NEWLY_CREATED_PATH_LIST']) self.assertEqual('/a/b:/a/c:/a/d:/f/g', os.environ['REMOVE_PATH_LIST']) + + def test_extra_arguments(self): + env = EnvironmentModifications() + env.set_env('A', 'dummy value', who='Pkg1') + apply_environment_modifications(env) + self.assertEqual('dummy value', os.environ['A']) + + def test_copy(self): + pass -- cgit v1.2.3-70-g09d2 From bcea1df01ce145aea5e49eaaceb7a063b44ddf80 Mon Sep 17 00:00:00 2001 From: alalazo Date: Tue, 15 Mar 2016 10:49:33 +0100 Subject: environment : refactoreded set_build_environment_variables --- lib/spack/spack/build_environment.py | 56 +++++++++++----------- lib/spack/spack/environment.py | 3 ++ .../repos/builtin/packages/mvapich2/package.py | 2 +- 3 files changed, 33 insertions(+), 28 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py index e91a8a1997..770e191ac9 100644 --- a/lib/spack/spack/build_environment.py +++ b/lib/spack/spack/build_environment.py @@ -35,7 +35,7 @@ import sys import spack from llnl.util.filesystem import * -from spack.environment import EnvironmentModifications, apply_environment_modifications +from spack.environment import EnvironmentModifications, apply_environment_modifications, concatenate_paths from spack.util.environment import * from spack.util.executable import Executable, which @@ -127,44 +127,45 @@ def set_build_environment_variables(pkg): # handled by putting one in the /case-insensitive # directory. Add that to the path too. env_paths = [] - def add_env_path(path): - env_paths.append(path) - ci = join_path(path, 'case-insensitive') - if os.path.isdir(ci): env_paths.append(ci) - add_env_path(spack.build_env_path) - add_env_path(join_path(spack.build_env_path, pkg.compiler.name)) - - path_put_first("PATH", env_paths) - path_set(SPACK_ENV_PATH, env_paths) - - # Prefixes of all of the package's dependencies go in - # SPACK_DEPENDENCIES + for item in [spack.build_env_path, join_path(spack.build_env_path, pkg.compiler.name)]: + env_paths.append(item) + ci = join_path(item, 'case-insensitive') + if os.path.isdir(ci): + env_paths.append(ci) + + env = EnvironmentModifications() + for item in reversed(env_paths): + env.prepend_path('PATH', item) + env.set_env(SPACK_ENV_PATH, concatenate_paths(env_paths)) + + # Prefixes of all of the package's dependencies go in SPACK_DEPENDENCIES dep_prefixes = [d.prefix for d in pkg.spec.traverse(root=False)] - path_set(SPACK_DEPENDENCIES, dep_prefixes) + env.set_env(SPACK_DEPENDENCIES, concatenate_paths(dep_prefixes)) + env.set_env('CMAKE_PREFIX_PATH', concatenate_paths(dep_prefixes)) # Add dependencies to CMAKE_PREFIX_PATH # Install prefix - os.environ[SPACK_PREFIX] = pkg.prefix + env.set_env(SPACK_PREFIX, pkg.prefix) # Install root prefix - os.environ[SPACK_INSTALL] = spack.install_path + env.set_env(SPACK_INSTALL, spack.install_path) # Remove these vars from the environment during build because they # can affect how some packages find libraries. We want to make # sure that builds never pull in unintended external dependencies. - pop_keys(os.environ, "LD_LIBRARY_PATH", "LD_RUN_PATH", "DYLD_LIBRARY_PATH") + env.unset_env('LD_LIBRARY_PATH') + env.unset_env('LD_RUN_PATH') + env.unset_env('DYLD_LIBRARY_PATH') # Add bin directories from dependencies to the PATH for the build. - bin_dirs = ['%s/bin' % prefix for prefix in dep_prefixes] - path_put_first('PATH', [bin for bin in bin_dirs if os.path.isdir(bin)]) + bin_dirs = reversed(filter(os.path.isdir, ['%s/bin' % prefix for prefix in dep_prefixes])) + for item in bin_dirs: + env.prepend_path('PATH', item) # Working directory for the spack command itself, for debug logs. if spack.debug: - os.environ[SPACK_DEBUG] = "TRUE" - os.environ[SPACK_SHORT_SPEC] = pkg.spec.short_spec - os.environ[SPACK_DEBUG_LOG_DIR] = spack.spack_working_dir - - # Add dependencies to CMAKE_PREFIX_PATH - path_set("CMAKE_PREFIX_PATH", dep_prefixes) + env.set_env(SPACK_DEBUG, 'TRUE') + env.set_env(SPACK_SHORT_SPEC, pkg.spec.short_spec) + env.set_env(SPACK_DEBUG_LOG_DIR, spack.spack_working_dir) # Add any pkgconfig directories to PKG_CONFIG_PATH pkg_config_dirs = [] @@ -173,8 +174,9 @@ def set_build_environment_variables(pkg): pcdir = join_path(p, libdir, 'pkgconfig') if os.path.isdir(pcdir): pkg_config_dirs.append(pcdir) - path_set("PKG_CONFIG_PATH", pkg_config_dirs) + env.set_env('PKG_CONFIG_PATH', concatenate_paths(pkg_config_dirs)) + return env def set_module_variables_for_package(pkg, m): """Populate the module scope of install() with some useful functions. @@ -269,8 +271,8 @@ def setup_package(pkg): """Execute all environment setup routines.""" env = EnvironmentModifications() env.extend(set_compiler_environment_variables(pkg)) + env.extend(set_build_environment_variables(pkg)) apply_environment_modifications(env) - set_build_environment_variables(pkg) # If a user makes their own package repo, e.g. # spack.repos.mystuff.libelf.Libelf, and they inherit from # an existing class like spack.repos.original.libelf.Libelf, diff --git a/lib/spack/spack/environment.py b/lib/spack/spack/environment.py index 3b73f1c7a2..18fef1ef12 100644 --- a/lib/spack/spack/environment.py +++ b/lib/spack/spack/environment.py @@ -146,6 +146,9 @@ class EnvironmentModifications(object): self.env_modifications.append(item) +def concatenate_paths(paths): + return ':'.join(str(item) for item in paths) + def validate_environment_modifications(env): modifications = collections.defaultdict(list) for item in env: diff --git a/var/spack/repos/builtin/packages/mvapich2/package.py b/var/spack/repos/builtin/packages/mvapich2/package.py index af5ed1b088..e4e95f92af 100644 --- a/var/spack/repos/builtin/packages/mvapich2/package.py +++ b/var/spack/repos/builtin/packages/mvapich2/package.py @@ -123,7 +123,7 @@ class Mvapich2(Package): count += 1 if count > 1: raise RuntimeError('network variants are mutually exclusive (only one can be selected at a time)') - + network_options = [] # From here on I can suppose that only one variant has been selected if self.enabled(Mvapich2.PSM) in spec: network_options = ["--with-device=ch3:psm"] -- cgit v1.2.3-70-g09d2 From c85888eb5763d453af7b7255b6d8c3461082362f Mon Sep 17 00:00:00 2001 From: alalazo Date: Tue, 15 Mar 2016 13:36:41 +0100 Subject: package : added `environment_modifications` --- lib/spack/spack/build_environment.py | 7 ++++--- lib/spack/spack/package.py | 4 ++++ var/spack/repos/builtin/packages/mpich/package.py | 16 ++++++++++------ .../builtin/packages/netlib-scalapack/package.py | 3 +-- .../repos/builtin/packages/openmpi/package.py | 14 ++++++++------ var/spack/repos/builtin/packages/python/package.py | 20 +++++++++++--------- var/spack/repos/builtin/packages/qt/package.py | 12 +++++++----- var/spack/repos/builtin/packages/ruby/package.py | 22 +++++++++++++--------- 8 files changed, 58 insertions(+), 40 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py index 770e191ac9..d321a0e495 100644 --- a/lib/spack/spack/build_environment.py +++ b/lib/spack/spack/build_environment.py @@ -178,6 +178,7 @@ def set_build_environment_variables(pkg): return env + def set_module_variables_for_package(pkg, m): """Populate the module scope of install() with some useful functions. This makes things easier for package writers. @@ -272,7 +273,6 @@ def setup_package(pkg): env = EnvironmentModifications() env.extend(set_compiler_environment_variables(pkg)) env.extend(set_build_environment_variables(pkg)) - apply_environment_modifications(env) # If a user makes their own package repo, e.g. # spack.repos.mystuff.libelf.Libelf, and they inherit from # an existing class like spack.repos.original.libelf.Libelf, @@ -284,8 +284,9 @@ def setup_package(pkg): # Allow dependencies to set up environment as well. for dep_spec in pkg.spec.traverse(root=False): - dep_spec.package.setup_dependent_environment( - pkg.module, dep_spec, pkg.spec) + env.extend(dep_spec.package.environment_modifications(pkg.module, dep_spec, pkg.spec)) + dep_spec.package.setup_dependent_environment(pkg.module, dep_spec, pkg.spec) + apply_environment_modifications(env) def fork(pkg, function): diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index 696adaf896..224d7f8f4b 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -63,6 +63,7 @@ import spack.build_environment import spack.url import spack.util.web import spack.fetch_strategy as fs +from spack.environment import EnvironmentModifications from spack.version import * from spack.stage import Stage, ResourceStage, StageComposite from spack.util.compression import allowed_archive, extension @@ -983,6 +984,9 @@ class Package(object): fromlist=[self.__class__.__name__]) + def environment_modifications(self, module, spec, dependent_spec): + return EnvironmentModifications() + def setup_dependent_environment(self, module, spec, dependent_spec): """Called before the install() method of dependents. diff --git a/var/spack/repos/builtin/packages/mpich/package.py b/var/spack/repos/builtin/packages/mpich/package.py index e2b3654c19..c85e8febf3 100644 --- a/var/spack/repos/builtin/packages/mpich/package.py +++ b/var/spack/repos/builtin/packages/mpich/package.py @@ -46,14 +46,18 @@ class Mpich(Package): provides('mpi@:3.0', when='@3:') provides('mpi@:1.3', when='@1:') + def environment_modifications(self, module, spec, dependent_spec): + env = super(Mpich, self).environment_modifications(module, spec, dependent_spec) + env.set_env('MPICH_CC', os.environ['CC']) + env.set_env('MPICH_CXX', os.environ['CXX']) + env.set_env('MPICH_F77', os.environ['F77']) + env.set_env('MPICH_F90', os.environ['FC']) + env.set_env('MPICH_FC', os.environ['FC']) + return env + def setup_dependent_environment(self, module, spec, dep_spec): """For dependencies, make mpicc's use spack wrapper.""" - os.environ['MPICH_CC'] = os.environ['CC'] - os.environ['MPICH_CXX'] = os.environ['CXX'] - os.environ['MPICH_F77'] = os.environ['F77'] - os.environ['MPICH_F90'] = os.environ['FC'] - os.environ['MPICH_FC'] = os.environ['FC'] - + # FIXME : is this necessary ? Shouldn't this be part of a contract with MPI providers? module.mpicc = join_path(self.prefix.bin, 'mpicc') def install(self, spec, prefix): diff --git a/var/spack/repos/builtin/packages/netlib-scalapack/package.py b/var/spack/repos/builtin/packages/netlib-scalapack/package.py index 22d538560e..6dbf367475 100644 --- a/var/spack/repos/builtin/packages/netlib-scalapack/package.py +++ b/var/spack/repos/builtin/packages/netlib-scalapack/package.py @@ -46,5 +46,4 @@ class NetlibScalapack(Package): spec['scalapack'].fc_link = '-L%s -lscalapack' % spec['scalapack'].prefix.lib spec['scalapack'].cc_link = spec['scalapack'].fc_link - spec['scalapack'].libraries = [join_path(spec['scalapack'].prefix.lib, - 'libscalapack%s' % lib_suffix)] + spec['scalapack'].libraries = [join_path(spec['scalapack'].prefix.lib, 'libscalapack%s' % lib_suffix)] diff --git a/var/spack/repos/builtin/packages/openmpi/package.py b/var/spack/repos/builtin/packages/openmpi/package.py index e4484af8c5..83a3fe7a4f 100644 --- a/var/spack/repos/builtin/packages/openmpi/package.py +++ b/var/spack/repos/builtin/packages/openmpi/package.py @@ -41,12 +41,14 @@ class Openmpi(Package): def url_for_version(self, version): return "http://www.open-mpi.org/software/ompi/v%s/downloads/openmpi-%s.tar.bz2" % (version.up_to(2), version) - def setup_dependent_environment(self, module, spec, dep_spec): - """For dependencies, make mpicc's use spack wrapper.""" - os.environ['OMPI_CC'] = 'cc' - os.environ['OMPI_CXX'] = 'c++' - os.environ['OMPI_FC'] = 'f90' - os.environ['OMPI_F77'] = 'f77' + def environment_modifications(self, module, spec, dependent_spec): + env = super(Openmpi, self).environment_modifications(module, spec, dependent_spec) + # FIXME : the compilers should point to the current wrappers, not to generic cc etc. + env.set_env('OMPI_CC', 'cc') + env.set_env('OMPI_CXX', 'c++') + env.set_env('OMPI_FC', 'f90') + env.set_env('OMPI_F77', 'f77') + return env def install(self, spec, prefix): config_args = ["--prefix=%s" % prefix, diff --git a/var/spack/repos/builtin/packages/python/package.py b/var/spack/repos/builtin/packages/python/package.py index dd240d1ea0..39ced0a120 100644 --- a/var/spack/repos/builtin/packages/python/package.py +++ b/var/spack/repos/builtin/packages/python/package.py @@ -90,6 +90,17 @@ class Python(Package): return os.path.join(self.python_lib_dir, 'site-packages') + def environment_modifications(self, module, spec, dependent_spec): + env = super(Python, self).environment_modifications(module, spec, dependent_spec) + # Set PYTHONPATH to include site-packages dir for the + # extension and any other python extensions it depends on. + python_paths = [] + for d in ext_spec.traverse(): + if d.package.extends(self.spec): + python_paths.append(os.path.join(d.prefix, self.site_packages_dir)) + env.set_env['PYTHONPATH'] = ':'.join(python_paths) + + def setup_dependent_environment(self, module, spec, ext_spec): """Called before python modules' install() methods. @@ -111,15 +122,6 @@ class Python(Package): # Make the site packages directory if it does not exist already. mkdirp(module.site_packages_dir) - # Set PYTHONPATH to include site-packages dir for the - # extension and any other python extensions it depends on. - python_paths = [] - for d in ext_spec.traverse(): - if d.package.extends(self.spec): - python_paths.append(os.path.join(d.prefix, self.site_packages_dir)) - os.environ['PYTHONPATH'] = ':'.join(python_paths) - - # ======================================================================== # Handle specifics of activating and deactivating python modules. # ======================================================================== diff --git a/var/spack/repos/builtin/packages/qt/package.py b/var/spack/repos/builtin/packages/qt/package.py index 91afa420c1..373623cd95 100644 --- a/var/spack/repos/builtin/packages/qt/package.py +++ b/var/spack/repos/builtin/packages/qt/package.py @@ -52,11 +52,13 @@ class Qt(Package): depends_on("mesa", when='@4:+mesa') depends_on("libxcb") - - def setup_dependent_environment(self, module, spec, dep_spec): - """Dependencies of Qt find it using the QTDIR environment variable.""" - os.environ['QTDIR'] = self.prefix - + def environment_modifications(self, module, spec, dep_spec): + """ + Dependencies of Qt find it using the QTDIR environment variable + """ + env = super(Qt, self).environment_modifications(module, spec, dep_spec) + env.set_env['QTDIR'] = self.prefix + return env def patch(self): if self.spec.satisfies('@4'): diff --git a/var/spack/repos/builtin/packages/ruby/package.py b/var/spack/repos/builtin/packages/ruby/package.py index 6b6242362c..9ec0afa268 100644 --- a/var/spack/repos/builtin/packages/ruby/package.py +++ b/var/spack/repos/builtin/packages/ruby/package.py @@ -15,10 +15,21 @@ class Ruby(Package): def install(self, spec, prefix): configure("--prefix=%s" % prefix) - make() make("install") + def environment_modifications(self, module, spec, ext_spec): + env = super(Ruby, self).environment_modifications(module, spec, ext_spec) + # Set GEM_PATH to include dependent gem directories + ruby_paths = [] + for d in ext_spec.traverse(): + if d.package.extends(self.spec): + ruby_paths.append(d.prefix) + env.set_env('GEM_PATH', concatenate_paths(ruby_paths)) + # The actual installation path for this gem + env.set_env('GEM_HOME', ext_spec.prefix) + return env + def setup_dependent_environment(self, module, spec, ext_spec): """Called before ruby modules' install() methods. Sets GEM_HOME and GEM_PATH to values appropriate for the package being built. @@ -31,11 +42,4 @@ class Ruby(Package): module.ruby = Executable(join_path(spec.prefix.bin, 'ruby')) module.gem = Executable(join_path(spec.prefix.bin, 'gem')) - # Set GEM_PATH to include dependent gem directories - ruby_paths = [] - for d in ext_spec.traverse(): - if d.package.extends(self.spec): - ruby_paths.append(d.prefix) - os.environ['GEM_PATH'] = ':'.join(ruby_paths) - # The actual installation path for this gem - os.environ['GEM_HOME'] = ext_spec.prefix + -- cgit v1.2.3-70-g09d2 From 572cb93bf8131d222d2d08bca13fd9de6fded1f4 Mon Sep 17 00:00:00 2001 From: alalazo Date: Tue, 15 Mar 2016 14:05:30 +0100 Subject: package : renamed `setup_dependent_environment` to `module_modifications` --- lib/spack/spack/build_environment.py | 4 ++-- lib/spack/spack/package.py | 4 ++-- var/spack/repos/builtin/packages/mpich/package.py | 6 +++--- .../repos/builtin/packages/netlib-scalapack/package.py | 2 +- var/spack/repos/builtin/packages/openmpi/package.py | 4 ++-- var/spack/repos/builtin/packages/python/package.py | 10 ++++------ var/spack/repos/builtin/packages/qt/package.py | 7 ++----- var/spack/repos/builtin/packages/ruby/package.py | 13 ++++++------- 8 files changed, 22 insertions(+), 28 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py index d321a0e495..e86a7c413a 100644 --- a/lib/spack/spack/build_environment.py +++ b/lib/spack/spack/build_environment.py @@ -284,8 +284,8 @@ def setup_package(pkg): # Allow dependencies to set up environment as well. for dep_spec in pkg.spec.traverse(root=False): - env.extend(dep_spec.package.environment_modifications(pkg.module, dep_spec, pkg.spec)) - dep_spec.package.setup_dependent_environment(pkg.module, dep_spec, pkg.spec) + dep_spec.package.module_modifications(pkg.module, dep_spec, pkg.spec) + env.extend(dep_spec.package.environment_modifications(pkg.spec)) apply_environment_modifications(env) diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index 224d7f8f4b..c1a5c912be 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -984,10 +984,10 @@ class Package(object): fromlist=[self.__class__.__name__]) - def environment_modifications(self, module, spec, dependent_spec): + def environment_modifications(self, dependent_spec): return EnvironmentModifications() - def setup_dependent_environment(self, module, spec, dependent_spec): + def module_modifications(self, module, spec, dependent_spec): """Called before the install() method of dependents. Default implementation does nothing, but this can be diff --git a/var/spack/repos/builtin/packages/mpich/package.py b/var/spack/repos/builtin/packages/mpich/package.py index c85e8febf3..d298981c92 100644 --- a/var/spack/repos/builtin/packages/mpich/package.py +++ b/var/spack/repos/builtin/packages/mpich/package.py @@ -46,8 +46,8 @@ class Mpich(Package): provides('mpi@:3.0', when='@3:') provides('mpi@:1.3', when='@1:') - def environment_modifications(self, module, spec, dependent_spec): - env = super(Mpich, self).environment_modifications(module, spec, dependent_spec) + def environment_modifications(self, dependent_spec): + env = super(Mpich, self).environment_modifications(dependent_spec) env.set_env('MPICH_CC', os.environ['CC']) env.set_env('MPICH_CXX', os.environ['CXX']) env.set_env('MPICH_F77', os.environ['F77']) @@ -55,7 +55,7 @@ class Mpich(Package): env.set_env('MPICH_FC', os.environ['FC']) return env - def setup_dependent_environment(self, module, spec, dep_spec): + def module_modifications(self, module, spec, dep_spec): """For dependencies, make mpicc's use spack wrapper.""" # FIXME : is this necessary ? Shouldn't this be part of a contract with MPI providers? module.mpicc = join_path(self.prefix.bin, 'mpicc') diff --git a/var/spack/repos/builtin/packages/netlib-scalapack/package.py b/var/spack/repos/builtin/packages/netlib-scalapack/package.py index 6dbf367475..ecdea46442 100644 --- a/var/spack/repos/builtin/packages/netlib-scalapack/package.py +++ b/var/spack/repos/builtin/packages/netlib-scalapack/package.py @@ -40,7 +40,7 @@ class NetlibScalapack(Package): make() make("install") - def setup_dependent_environment(self, module, spec, dependent_spec): + def module_modifications(self, module, spec, dependent_spec): # TODO treat OS that are not Linux... lib_suffix = '.so' if '+shared' in spec['scalapack'] else '.a' diff --git a/var/spack/repos/builtin/packages/openmpi/package.py b/var/spack/repos/builtin/packages/openmpi/package.py index 83a3fe7a4f..3a14170457 100644 --- a/var/spack/repos/builtin/packages/openmpi/package.py +++ b/var/spack/repos/builtin/packages/openmpi/package.py @@ -41,8 +41,8 @@ class Openmpi(Package): def url_for_version(self, version): return "http://www.open-mpi.org/software/ompi/v%s/downloads/openmpi-%s.tar.bz2" % (version.up_to(2), version) - def environment_modifications(self, module, spec, dependent_spec): - env = super(Openmpi, self).environment_modifications(module, spec, dependent_spec) + def environment_modifications(self, dependent_spec): + env = super(Openmpi, self).environment_modifications(dependent_spec) # FIXME : the compilers should point to the current wrappers, not to generic cc etc. env.set_env('OMPI_CC', 'cc') env.set_env('OMPI_CXX', 'c++') diff --git a/var/spack/repos/builtin/packages/python/package.py b/var/spack/repos/builtin/packages/python/package.py index 39ced0a120..307cec726b 100644 --- a/var/spack/repos/builtin/packages/python/package.py +++ b/var/spack/repos/builtin/packages/python/package.py @@ -89,19 +89,17 @@ class Python(Package): def site_packages_dir(self): return os.path.join(self.python_lib_dir, 'site-packages') - - def environment_modifications(self, module, spec, dependent_spec): - env = super(Python, self).environment_modifications(module, spec, dependent_spec) + def environment_modifications(self, extension_spec): + env = super(Python, self).environment_modifications(extension_spec) # Set PYTHONPATH to include site-packages dir for the # extension and any other python extensions it depends on. python_paths = [] - for d in ext_spec.traverse(): + for d in extension_spec.traverse(): if d.package.extends(self.spec): python_paths.append(os.path.join(d.prefix, self.site_packages_dir)) env.set_env['PYTHONPATH'] = ':'.join(python_paths) - - def setup_dependent_environment(self, module, spec, ext_spec): + def module_modifications(self, module, spec, ext_spec): """Called before python modules' install() methods. In most cases, extensions will only need to have one line:: diff --git a/var/spack/repos/builtin/packages/qt/package.py b/var/spack/repos/builtin/packages/qt/package.py index 373623cd95..8391ded3e0 100644 --- a/var/spack/repos/builtin/packages/qt/package.py +++ b/var/spack/repos/builtin/packages/qt/package.py @@ -52,11 +52,8 @@ class Qt(Package): depends_on("mesa", when='@4:+mesa') depends_on("libxcb") - def environment_modifications(self, module, spec, dep_spec): - """ - Dependencies of Qt find it using the QTDIR environment variable - """ - env = super(Qt, self).environment_modifications(module, spec, dep_spec) + def environment_modifications(self, dependent_spec): + env = super(Qt, self).environment_modifications(dependent_spec) env.set_env['QTDIR'] = self.prefix return env diff --git a/var/spack/repos/builtin/packages/ruby/package.py b/var/spack/repos/builtin/packages/ruby/package.py index 9ec0afa268..9caea30ef4 100644 --- a/var/spack/repos/builtin/packages/ruby/package.py +++ b/var/spack/repos/builtin/packages/ruby/package.py @@ -1,6 +1,5 @@ from spack import * -import spack -import os + class Ruby(Package): """A dynamic, open source programming language with a focus on @@ -18,19 +17,19 @@ class Ruby(Package): make() make("install") - def environment_modifications(self, module, spec, ext_spec): - env = super(Ruby, self).environment_modifications(module, spec, ext_spec) + def environment_modifications(self, extension_spec): + env = super(Ruby, self).environment_modifications(extension_spec) # Set GEM_PATH to include dependent gem directories ruby_paths = [] - for d in ext_spec.traverse(): + for d in extension_spec.traverse(): if d.package.extends(self.spec): ruby_paths.append(d.prefix) env.set_env('GEM_PATH', concatenate_paths(ruby_paths)) # The actual installation path for this gem - env.set_env('GEM_HOME', ext_spec.prefix) + env.set_env('GEM_HOME', extension_spec.prefix) return env - def setup_dependent_environment(self, module, spec, ext_spec): + def module_modifications(self, module, spec, ext_spec): """Called before ruby modules' install() methods. Sets GEM_HOME and GEM_PATH to values appropriate for the package being built. -- cgit v1.2.3-70-g09d2 From cc3d9f4eb751fe028db5a074fc7bc52fbe0a962a Mon Sep 17 00:00:00 2001 From: alalazo Date: Tue, 15 Mar 2016 15:09:35 +0100 Subject: environment : added test, modified docs --- lib/spack/spack/environment.py | 59 ++++++++++++++++++++++++++----------- lib/spack/spack/package.py | 45 +++++++++++++++++----------- lib/spack/spack/test/environment.py | 10 +++++-- lib/spack/spack/util/environment.py | 8 ++--- 4 files changed, 79 insertions(+), 43 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/environment.py b/lib/spack/spack/environment.py index 18fef1ef12..5a68e10c99 100644 --- a/lib/spack/spack/environment.py +++ b/lib/spack/spack/environment.py @@ -3,33 +3,40 @@ import os.path import collections -class SetEnv(object): +class AttributeHolder(object): + """ + Policy that permits to store any kind of attribute on self. The attributes must be passed as key/value pairs + during the initialization of the instance. + """ + def __init__(self, **kwargs): + for key, value in kwargs.items(): + setattr(self, key, value) + + +class SetEnv(AttributeHolder): def __init__(self, name, value, **kwargs): + super(SetEnv, self).__init__(**kwargs) self.name = name self.value = value - for key, value in kwargs.items(): - setattr(self, key, value) def execute(self): os.environ[self.name] = str(self.value) -class UnsetEnv(object): +class UnsetEnv(AttributeHolder): def __init__(self, name, **kwargs): + super(UnsetEnv, self).__init__(**kwargs) self.name = name - for key, value in kwargs.items(): - setattr(self, key, value) def execute(self): os.environ.pop(self.name, None) # Avoid throwing if the variable was not set -class AppendPath(object): +class AppendPath(AttributeHolder): def __init__(self, name, path, **kwargs): + super(AppendPath, self).__init__(**kwargs) self.name = name self.path = path - for key, value in kwargs.items(): - setattr(self, key, value) def execute(self): environment_value = os.environ.get(self.name, '') @@ -39,12 +46,11 @@ class AppendPath(object): os.environ[self.name] = ':'.join(directories) -class PrependPath(object): +class PrependPath(AttributeHolder): def __init__(self, name, path, **kwargs): + super(PrependPath, self).__init__(**kwargs) self.name = name self.path = path - for key, value in kwargs.items(): - setattr(self, key, value) def execute(self): environment_value = os.environ.get(self.name, '') @@ -54,12 +60,11 @@ class PrependPath(object): os.environ[self.name] = ':'.join(directories) -class RemovePath(object): +class RemovePath(AttributeHolder): def __init__(self, name, path, **kwargs): + super(RemovePath, self).__init__(**kwargs) self.name = name self.path = path - for key, value in kwargs.items(): - setattr(self, key, value) def execute(self): environment_value = os.environ.get(self.name, '') @@ -70,18 +75,26 @@ class RemovePath(object): class EnvironmentModifications(object): """ - Keeps track of requests to modify the current environment + Keeps track of requests to modify the current environment. """ def __init__(self, other=None): + """ + Initializes a new instance, copying commands from other if it is not None + + Args: + other: another instance of EnvironmentModifications from which (optional) + """ self.env_modifications = [] if other is not None: - self._check_other(other) - self.env_modifications.extend(other.env_modifications) + self.extend(other) def __iter__(self): return iter(self.env_modifications) + def __len__(self): + return len(self.env_modifications) + def extend(self, other): self._check_other(other) self.env_modifications.extend(other.env_modifications) @@ -147,8 +160,18 @@ class EnvironmentModifications(object): def concatenate_paths(paths): + """ + Concatenates an iterable of paths into a column separated string + + Args: + paths: iterable of paths + + Returns: + column separated string + """ return ':'.join(str(item) for item in paths) + def validate_environment_modifications(env): modifications = collections.defaultdict(list) for item in env: diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index c1a5c912be..5d8258d4cf 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -985,30 +985,41 @@ class Package(object): def environment_modifications(self, dependent_spec): - return EnvironmentModifications() + """ + Called before the install() method of dependents. - def module_modifications(self, module, spec, dependent_spec): - """Called before the install() method of dependents. + Return the list of environment modifications needed by dependents (or extensions). Default implementation does + nothing, but this can be overridden by an extendable package to set up the install environment for its + extensions. This is useful if there are some common steps to installing all extensions for a certain package. - Default implementation does nothing, but this can be - overridden by an extendable package to set up the install - environment for its extensions. This is useful if there are - some common steps to installing all extensions for a - certain package. + Example : - Some examples: + 1. Installing python modules generally requires `PYTHONPATH` to point to the lib/pythonX.Y/site-packages + directory in the module's install prefix. This could set that variable. - 1. Installing python modules generally requires PYTHONPATH to - point to the lib/pythonX.Y/site-packages directory in the - module's install prefix. This could set that variable. + 2. A lot of Qt extensions need `QTDIR` set. This can be used to do that. - 2. Extensions often need to invoke the 'python' interpreter - from the Python installation being extended. This routine can - put a 'python' Execuable object in the module scope for the - extension package to simplify extension installs. + Args: + dependent_spec: dependent (or extension) of this spec + + Returns: + instance of environment modifications + """ + return EnvironmentModifications() + + def module_modifications(self, module, spec, dependent_spec): + """ + Called before the install() method of dependents. + + Default implementation does nothing, but this can be overridden by an extendable package to set up the module of + its extensions. This is useful if there are some common steps to installing all extensions for a + certain package. - 3. A lot of Qt extensions need QTDIR set. This can be used to do that. + Example : + 1. Extensions often need to invoke the 'python' interpreter from the Python installation being extended. + This routine can put a 'python' Executable object in the module scope for the extension package to simplify + extension installs. """ pass diff --git a/lib/spack/spack/test/environment.py b/lib/spack/spack/test/environment.py index 17061c8fd0..97581ecb76 100644 --- a/lib/spack/spack/test/environment.py +++ b/lib/spack/spack/test/environment.py @@ -55,5 +55,11 @@ class EnvironmentTest(unittest.TestCase): apply_environment_modifications(env) self.assertEqual('dummy value', os.environ['A']) - def test_copy(self): - pass + def test_extend(self): + env = EnvironmentModifications() + env.set_env('A', 'dummy value') + env.set_env('B', 3) + copy_construct = EnvironmentModifications(env) + self.assertEqual(len(copy_construct), 2) + for x, y in zip(env, copy_construct): + self.assertIs(x, y) diff --git a/lib/spack/spack/util/environment.py b/lib/spack/spack/util/environment.py index ae8e5708be..00cda8d508 100644 --- a/lib/spack/spack/util/environment.py +++ b/lib/spack/spack/util/environment.py @@ -40,11 +40,13 @@ def env_flag(name): return False +# FIXME : remove this function ? def path_set(var_name, directories): path_str = ":".join(str(dir) for dir in directories) os.environ[var_name] = path_str +# FIXME : remove this function ? def path_put_first(var_name, directories): """Puts the provided directories first in the path, adding them if they're not already there. @@ -59,12 +61,6 @@ def path_put_first(var_name, directories): path_set(var_name, new_path) -def pop_keys(dictionary, *keys): - for key in keys: - if key in dictionary: - dictionary.pop(key) - - def dump_environment(path): """Dump the current environment out to a file.""" with open(path, 'w') as env_file: -- cgit v1.2.3-70-g09d2 From ccced9f290bc213561209db2479bccfb5605366d Mon Sep 17 00:00:00 2001 From: alalazo Date: Tue, 15 Mar 2016 15:12:39 +0100 Subject: package : optimized imports --- lib/spack/spack/package.py | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index 5d8258d4cf..042833964a 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -34,41 +34,34 @@ rundown on spack and how it differs from homebrew, look at the README. """ import os -import errno import re -import shutil -import time -import itertools -import subprocess -import platform as py_platform -import multiprocessing -from urlparse import urlparse, urljoin import textwrap -from StringIO import StringIO +import time import llnl.util.tty as tty -from llnl.util.tty.log import log_output -from llnl.util.link_tree import LinkTree -from llnl.util.filesystem import * -from llnl.util.lang import * - import spack -import spack.error +import spack.build_environment import spack.compilers -import spack.mirror -import spack.hooks import spack.directives +import spack.error +import spack.fetch_strategy as fs +import spack.hooks +import spack.mirror import spack.repository -import spack.build_environment import spack.url import spack.util.web -import spack.fetch_strategy as fs +from StringIO import StringIO +from llnl.util.filesystem import * +from llnl.util.lang import * +from llnl.util.link_tree import LinkTree +from llnl.util.tty.log import log_output from spack.environment import EnvironmentModifications -from spack.version import * from spack.stage import Stage, ResourceStage, StageComposite -from spack.util.compression import allowed_archive, extension -from spack.util.executable import ProcessError +from spack.util.compression import allowed_archive from spack.util.environment import dump_environment +from spack.util.executable import ProcessError +from spack.version import * +from urlparse import urlparse """Allowed URL schemes for spack packages.""" _ALLOWED_URL_SCHEMES = ["http", "https", "ftp", "file", "git"] -- cgit v1.2.3-70-g09d2 From c8cc6f4fc111d5dd2d55295e569a10cd5739ceee Mon Sep 17 00:00:00 2001 From: alalazo Date: Tue, 15 Mar 2016 16:59:29 +0100 Subject: test : fix for python 2.6 --- lib/spack/spack/test/environment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/spack/spack/test/environment.py b/lib/spack/spack/test/environment.py index 97581ecb76..f44282d6f3 100644 --- a/lib/spack/spack/test/environment.py +++ b/lib/spack/spack/test/environment.py @@ -62,4 +62,4 @@ class EnvironmentTest(unittest.TestCase): copy_construct = EnvironmentModifications(env) self.assertEqual(len(copy_construct), 2) for x, y in zip(env, copy_construct): - self.assertIs(x, y) + assert x is y -- cgit v1.2.3-70-g09d2 From b45ec3f04e3627dbe3633239560873ae01bf3beb Mon Sep 17 00:00:00 2001 From: alalazo Date: Wed, 16 Mar 2016 10:55:28 +0100 Subject: environment : simplified modification of the environment --- lib/spack/spack/build_environment.py | 12 +++-- lib/spack/spack/cmd/module.py | 2 +- lib/spack/spack/environment.py | 58 +++++++++++----------- lib/spack/spack/test/environment.py | 12 +++-- lib/spack/spack/util/environment.py | 2 +- var/spack/repos/builtin/packages/python/package.py | 1 + 6 files changed, 47 insertions(+), 40 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py index e86a7c413a..e5d256a2e0 100644 --- a/lib/spack/spack/build_environment.py +++ b/lib/spack/spack/build_environment.py @@ -35,7 +35,7 @@ import sys import spack from llnl.util.filesystem import * -from spack.environment import EnvironmentModifications, apply_environment_modifications, concatenate_paths +from spack.environment import EnvironmentModifications, concatenate_paths from spack.util.environment import * from spack.util.executable import Executable, which @@ -283,10 +283,12 @@ def setup_package(pkg): set_module_variables_for_package(pkg, mod) # Allow dependencies to set up environment as well. - for dep_spec in pkg.spec.traverse(root=False): - dep_spec.package.module_modifications(pkg.module, dep_spec, pkg.spec) - env.extend(dep_spec.package.environment_modifications(pkg.spec)) - apply_environment_modifications(env) + for dependency_spec in pkg.spec.traverse(root=False): + dependency_spec.package.module_modifications(pkg.module, dependency_spec, pkg.spec) + env.extend(dependency_spec.package.environment_modifications(pkg.spec)) + # TODO : implement validation + #validate(env) + env.apply_modifications() def fork(pkg, function): diff --git a/lib/spack/spack/cmd/module.py b/lib/spack/spack/cmd/module.py index 1d6867c1d9..315d9fc926 100644 --- a/lib/spack/spack/cmd/module.py +++ b/lib/spack/spack/cmd/module.py @@ -80,7 +80,7 @@ def module_find(mtype, spec_array): if not os.path.isfile(mod.file_name): tty.die("No %s module is installed for %s" % (mtype, spec)) - print mod.use_name + print(mod.use_name) def module_refresh(): diff --git a/lib/spack/spack/environment.py b/lib/spack/spack/environment.py index 5a68e10c99..b557bf0bbc 100644 --- a/lib/spack/spack/environment.py +++ b/lib/spack/spack/environment.py @@ -158,41 +158,43 @@ class EnvironmentModifications(object): item = RemovePath(name, path, **kwargs) self.env_modifications.append(item) + def group_by_name(self): + """ + Returns a dict of the modifications grouped by variable name + + Returns: + dict mapping the environment variable name to the modifications to be done on it + """ + modifications = collections.defaultdict(list) + for item in self: + modifications[item.name].append(item) + return modifications + + def clear(self): + """ + Clears the current list of modifications + """ + self.env_modifications.clear() + + def apply_modifications(self): + """ + Applies the modifications and clears the list + """ + modifications = self.group_by_name() + # Apply the modifications to the environment variables one variable at a time + for name, actions in sorted(modifications.items()): + for x in actions: + x.execute() + def concatenate_paths(paths): """ - Concatenates an iterable of paths into a column separated string + Concatenates an iterable of paths into a string of column separated paths Args: paths: iterable of paths Returns: - column separated string + string """ return ':'.join(str(item) for item in paths) - - -def validate_environment_modifications(env): - modifications = collections.defaultdict(list) - for item in env: - modifications[item.name].append(item) - # TODO : once we organized the modifications into a dictionary that maps an environment variable - # TODO : to a list of action to be done on it, we may easily spot inconsistencies and warn the user if - # TODO : something suspicious is happening - return modifications - - -def apply_environment_modifications(env): - """ - Modifies the current environment according to the request in env - - Args: - env: object storing modifications to the environment - """ - modifications = validate_environment_modifications(env) - - # Cycle over the environment variables that will be modified - for variable, actions in modifications.items(): - # Execute all the actions in the order they were issued - for x in actions: - x.execute() diff --git a/lib/spack/spack/test/environment.py b/lib/spack/spack/test/environment.py index f44282d6f3..d0b093b054 100644 --- a/lib/spack/spack/test/environment.py +++ b/lib/spack/spack/test/environment.py @@ -1,6 +1,6 @@ import unittest import os -from spack.environment import EnvironmentModifications, apply_environment_modifications +from spack.environment import EnvironmentModifications class EnvironmentTest(unittest.TestCase): @@ -15,7 +15,7 @@ class EnvironmentTest(unittest.TestCase): env = EnvironmentModifications() env.set_env('A', 'dummy value') env.set_env('B', 3) - apply_environment_modifications(env) + env.apply_modifications() self.assertEqual('dummy value', os.environ['A']) self.assertEqual(str(3), os.environ['B']) @@ -23,7 +23,7 @@ class EnvironmentTest(unittest.TestCase): env = EnvironmentModifications() self.assertEqual('foo', os.environ['UNSET_ME']) env.unset_env('UNSET_ME') - apply_environment_modifications(env) + env.apply_modifications() self.assertRaises(KeyError, os.environ.__getitem__, 'UNSET_ME') def test_path_manipulation(self): @@ -43,7 +43,7 @@ class EnvironmentTest(unittest.TestCase): env.remove_path('REMOVE_PATH_LIST', '/remove/this') env.remove_path('REMOVE_PATH_LIST', '/duplicate/') - apply_environment_modifications(env) + env.apply_modifications() self.assertEqual('/path/first:/path/second:/path/third:/path/last', os.environ['PATH_LIST']) self.assertEqual('/path/first:/path/middle:/path/last', os.environ['EMPTY_PATH_LIST']) self.assertEqual('/path/first:/path/middle:/path/last', os.environ['NEWLY_CREATED_PATH_LIST']) @@ -52,7 +52,9 @@ class EnvironmentTest(unittest.TestCase): def test_extra_arguments(self): env = EnvironmentModifications() env.set_env('A', 'dummy value', who='Pkg1') - apply_environment_modifications(env) + for x in env: + assert hasattr(x, 'who') + env.apply_modifications() self.assertEqual('dummy value', os.environ['A']) def test_extend(self): diff --git a/lib/spack/spack/util/environment.py b/lib/spack/spack/util/environment.py index 00cda8d508..1485992b0f 100644 --- a/lib/spack/spack/util/environment.py +++ b/lib/spack/spack/util/environment.py @@ -64,5 +64,5 @@ def path_put_first(var_name, directories): def dump_environment(path): """Dump the current environment out to a file.""" with open(path, 'w') as env_file: - for key,val in sorted(os.environ.items()): + for key, val in sorted(os.environ.items()): env_file.write("%s=%s\n" % (key, val)) diff --git a/var/spack/repos/builtin/packages/python/package.py b/var/spack/repos/builtin/packages/python/package.py index 307cec726b..2f9948d451 100644 --- a/var/spack/repos/builtin/packages/python/package.py +++ b/var/spack/repos/builtin/packages/python/package.py @@ -98,6 +98,7 @@ class Python(Package): if d.package.extends(self.spec): python_paths.append(os.path.join(d.prefix, self.site_packages_dir)) env.set_env['PYTHONPATH'] = ':'.join(python_paths) + return env def module_modifications(self, module, spec, ext_spec): """Called before python modules' install() methods. -- cgit v1.2.3-70-g09d2 From 597727f8bedc894330dfd26eab1a82859980f2f1 Mon Sep 17 00:00:00 2001 From: alalazo Date: Wed, 16 Mar 2016 15:19:13 +0100 Subject: tclmodules : added hooks to process EnvironmentModifications objects --- lib/spack/spack/modules.py | 151 +++++++++++++++------ var/spack/repos/builtin/packages/mpich/package.py | 25 +++- var/spack/repos/builtin/packages/python/package.py | 15 +- 3 files changed, 137 insertions(+), 54 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/modules.py b/lib/spack/spack/modules.py index c27043db8c..1a0a0fd4d6 100644 --- a/lib/spack/spack/modules.py +++ b/lib/spack/spack/modules.py @@ -47,18 +47,18 @@ of module file. __all__ = ['EnvModule', 'Dotkit', 'TclModule'] import os +import os.path import re -import textwrap import shutil +import textwrap from glob import glob import llnl.util.tty as tty -from llnl.util.filesystem import join_path, mkdirp - import spack +from spack.environment import * +from llnl.util.filesystem import join_path, mkdirp -"""Registry of all types of modules. Entries created by EnvModule's - metaclass.""" +# Registry of all types of modules. Entries created by EnvModule's metaclass module_types = {} @@ -79,6 +79,32 @@ def print_help(): "") +class PathInspector(object): + dirname2varname = { + 'bin': ('PATH',), + 'man': ('MANPATH',), + 'lib': ('LIBRARY_PATH', 'LD_LIBRARY_PATH'), + 'lib64': ('LIBRARY_PATH', 'LD_LIBRARY_PATH'), + 'include': ('CPATH',), + 'pkgconfig': ('PKG_CONFIG_PATH',) + } + + def __call__(self, env, directory, names): + for name in names: + variables = PathInspector.dirname2varname.get(name, None) + if variables is None: + continue + absolute_path = join_path(os.path.abspath(directory), name) + for variable in variables: + env.prepend_path(variable, absolute_path) + + +def inspect_path(path): + env, inspector = EnvironmentModifications(), PathInspector() + os.path.walk(path, inspector, env) + return env + + class EnvModule(object): name = 'env_module' @@ -88,21 +114,27 @@ class EnvModule(object): if cls.name != 'env_module': module_types[cls.name] = cls - def __init__(self, spec=None): # category in the modules system # TODO: come up with smarter category names. self.category = "spack" - # Descriptions for the module system's UI - self.short_description = "" - self.long_description = "" - # dict pathname -> list of directories to be prepended to in # the module file. self._paths = None self.spec = spec + self.pkg = spec.package # Just stored for convenience + + # short description default is just the package + version + # packages can provide this optional attribute + self.short_description = spec.format("$_ $@") + if hasattr(self.pkg, 'short_description'): + self.short_description = self.pkg.short_description + # long description is the docstring with reduced whitespace. + self.long_description = None + if self.spec.package.__doc__: + self.long_description = re.sub(r'\s+', ' ', self.spec.package.__doc__) @property def paths(self): @@ -130,26 +162,19 @@ class EnvModule(object): add_path(var, directory) # Add python path unless it's an actual python installation - # TODO: is there a better way to do this? + # TODO : is there a better way to do this? + # FIXME : add PYTHONPATH to every python package if self.spec.name != 'python': site_packages = glob(join_path(self.spec.prefix.lib, "python*/site-packages")) if site_packages: add_path('PYTHONPATH', site_packages[0]) + # FIXME : Same for GEM_PATH if self.spec.package.extends(spack.spec.Spec('ruby')): - add_path('GEM_PATH', self.spec.prefix) - - # short description is just the package + version - # TODO: maybe packages can optionally provide it. - self.short_description = self.spec.format("$_ $@") - - # long description is the docstring with reduced whitespace. - if self.spec.package.__doc__: - self.long_description = re.sub(r'\s+', ' ', self.spec.package.__doc__) + add_path('GEM_PATH', self.spec.prefix) return self._paths - def write(self): """Write out a module file for this object.""" module_dir = os.path.dirname(self.file_name) @@ -160,9 +185,18 @@ class EnvModule(object): if not self.paths: return - with open(self.file_name, 'w') as f: - self._write(f) + # Construct the changes that needs to be done on the environment for + env = inspect_path(self.spec.prefix) + # FIXME : move the logic to inspection + env.prepend_path('CMAKE_PREFIX_PATH', self.spec.prefix) + # FIXME : decide how to distinguish between calls done in the installation and elsewhere + env.extend(self.spec.package.environment_modifications(None)) + # site_specific = ...` + if not env: + return + with open(self.file_name, 'w') as f: + self._write(f, env) def _write(self, stream): """To be implemented by subclasses.""" @@ -175,14 +209,12 @@ class EnvModule(object): where this module lives.""" raise NotImplementedError() - @property def use_name(self): """Subclasses should implement this to return the name the module command uses to refer to the package.""" raise NotImplementedError() - def remove(self): mod_file = self.file_name if os.path.exists(mod_file): @@ -205,7 +237,7 @@ class Dotkit(EnvModule): self.spec.compiler.version, self.spec.dag_hash()) - def _write(self, dk_file): + def _write(self, dk_file, env): # Category if self.category: dk_file.write('#c %s\n' % self.category) @@ -231,6 +263,10 @@ class Dotkit(EnvModule): class TclModule(EnvModule): name = 'tcl' path = join_path(spack.share_path, "modules") + formats = { + PrependPath: 'prepend-path {0.name} \"{0.path}\"\n', + SetEnv: 'setenv {0.name} \"{0.value}\"\n' + } @property def file_name(self): @@ -244,25 +280,56 @@ class TclModule(EnvModule): self.spec.compiler.version, self.spec.dag_hash()) - - def _write(self, m_file): - # TODO: cateogry? - m_file.write('#%Module1.0\n') - + def process_environment_command(self, env): + for command in env: + # FIXME : how should we handle errors here? + yield self.formats[type(command)].format(command) + + def _write(self, module_file, env): + """ + Writes a TCL module file for this package + + Args: + module_file: module file stream + env: list of environment modifications to be written in the module file + """ + # TCL Modulefile header + module_file.write('#%Module1.0\n') + # TODO : category ? # Short description if self.short_description: - m_file.write('module-whatis \"%s\"\n\n' % self.short_description) + module_file.write('module-whatis \"%s\"\n\n' % self.short_description) # Long description if self.long_description: - m_file.write('proc ModulesHelp { } {\n') + module_file.write('proc ModulesHelp { } {\n') doc = re.sub(r'"', '\"', self.long_description) - m_file.write("puts stderr \"%s\"\n" % doc) - m_file.write('}\n\n') - - # Path alterations - for var, dirs in self.paths.items(): - for directory in dirs: - m_file.write("prepend-path %s \"%s\"\n" % (var, directory)) - - m_file.write("prepend-path CMAKE_PREFIX_PATH \"%s\"\n" % self.spec.prefix) + module_file.write("puts stderr \"%s\"\n" % doc) + module_file.write('}\n\n') + + # Environment modifications + for line in self.process_environment_command(env): + module_file.write(line) + + # FIXME : REMOVE + # def _write(self, m_file): + # # TODO: cateogry? + # m_file.write('#%Module1.0\n') + # + # # Short description + # if self.short_description: + # m_file.write('module-whatis \"%s\"\n\n' % self.short_description) + # + # # Long description + # if self.long_description: + # m_file.write('proc ModulesHelp { } {\n') + # doc = re.sub(r'"', '\"', self.long_description) + # m_file.write("puts stderr \"%s\"\n" % doc) + # m_file.write('}\n\n') + # + # # Path alterations + # for var, dirs in self.paths.items(): + # for directory in dirs: + # m_file.write("prepend-path %s \"%s\"\n" % (var, directory)) + # + # m_file.write("prepend-path CMAKE_PREFIX_PATH \"%s\"\n" % self.spec.prefix) diff --git a/var/spack/repos/builtin/packages/mpich/package.py b/var/spack/repos/builtin/packages/mpich/package.py index d298981c92..4c34d0308f 100644 --- a/var/spack/repos/builtin/packages/mpich/package.py +++ b/var/spack/repos/builtin/packages/mpich/package.py @@ -25,6 +25,7 @@ from spack import * import os + class Mpich(Package): """MPICH is a high performance and widely portable implementation of the Message Passing Interface (MPI) standard.""" @@ -48,11 +49,25 @@ class Mpich(Package): def environment_modifications(self, dependent_spec): env = super(Mpich, self).environment_modifications(dependent_spec) - env.set_env('MPICH_CC', os.environ['CC']) - env.set_env('MPICH_CXX', os.environ['CXX']) - env.set_env('MPICH_F77', os.environ['F77']) - env.set_env('MPICH_F90', os.environ['FC']) - env.set_env('MPICH_FC', os.environ['FC']) + + if dependent_spec is None: + # We are not using compiler wrappers + cc = self.compiler.cc + cxx = self.compiler.cxx + f77 = self.compiler.f77 + f90 = fc = self.compiler.fc + else: + # Spack compiler wrappers + cc = os.environ['CC'] + cxx = os.environ['CXX'] + f77 = os.environ['F77'] + f90 = fc = os.environ['FC'] + + env.set_env('MPICH_CC', cc) + env.set_env('MPICH_CXX', cxx) + env.set_env('MPICH_F77', f77) + env.set_env('MPICH_F90', f90) + env.set_env('MPICH_FC', fc) return env def module_modifications(self, module, spec, dep_spec): diff --git a/var/spack/repos/builtin/packages/python/package.py b/var/spack/repos/builtin/packages/python/package.py index 2f9948d451..acb3651726 100644 --- a/var/spack/repos/builtin/packages/python/package.py +++ b/var/spack/repos/builtin/packages/python/package.py @@ -91,13 +91,14 @@ class Python(Package): def environment_modifications(self, extension_spec): env = super(Python, self).environment_modifications(extension_spec) - # Set PYTHONPATH to include site-packages dir for the - # extension and any other python extensions it depends on. - python_paths = [] - for d in extension_spec.traverse(): - if d.package.extends(self.spec): - python_paths.append(os.path.join(d.prefix, self.site_packages_dir)) - env.set_env['PYTHONPATH'] = ':'.join(python_paths) + if extension_spec is not None: + # Set PYTHONPATH to include site-packages dir for the + # extension and any other python extensions it depends on. + python_paths = [] + for d in extension_spec.traverse(): + if d.package.extends(self.spec): + python_paths.append(os.path.join(d.prefix, self.site_packages_dir)) + env.set_env['PYTHONPATH'] = ':'.join(python_paths) return env def module_modifications(self, module, spec, ext_spec): -- cgit v1.2.3-70-g09d2 From ac762e95a6213e1514f29d3d6501e4a95dd3e1d4 Mon Sep 17 00:00:00 2001 From: alalazo Date: Wed, 16 Mar 2016 16:23:02 +0100 Subject: modules : removed dead code --- lib/spack/spack/modules.py | 205 +++++++++++++++------------------------------ 1 file changed, 66 insertions(+), 139 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/modules.py b/lib/spack/spack/modules.py index 1a0a0fd4d6..b64a8b3226 100644 --- a/lib/spack/spack/modules.py +++ b/lib/spack/spack/modules.py @@ -22,14 +22,12 @@ # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ############################################################################## -"""This module contains code for creating environment modules, which -can include dotkits, tcl modules, lmod, and others. +""" +This module contains code for creating environment modules, which can include dotkits, tcl modules, lmod, and others. -The various types of modules are installed by post-install hooks and -removed after an uninstall by post-uninstall hooks. This class -consolidates the logic for creating an abstract description of the -information that module systems need. Currently that includes a -number of directories to be appended to paths in the user's environment: +The various types of modules are installed by post-install hooks and removed after an uninstall by post-uninstall hooks. +This class consolidates the logic for creating an abstract description of the information that module systems need. +Currently that includes a number of directories to be appended to paths in the user's environment: * /bin directories to be appended to PATH * /lib* directories for LD_LIBRARY_PATH @@ -37,26 +35,23 @@ number of directories to be appended to paths in the user's environment: * /man* and /share/man* directories for MANPATH * the package prefix for CMAKE_PREFIX_PATH -This module also includes logic for coming up with unique names for -the module files so that they can be found by the various -shell-support files in $SPACK/share/spack/setup-env.*. +This module also includes logic for coming up with unique names for the module files so that they can be found by the +various shell-support files in $SPACK/share/spack/setup-env.*. -Each hook in hooks/ implements the logic for writing its specific type -of module file. +Each hook in hooks/ implements the logic for writing its specific type of module file. """ -__all__ = ['EnvModule', 'Dotkit', 'TclModule'] - import os import os.path import re import shutil import textwrap -from glob import glob import llnl.util.tty as tty import spack -from spack.environment import * from llnl.util.filesystem import join_path, mkdirp +from spack.environment import * + +__all__ = ['EnvModule', 'Dotkit', 'TclModule'] # Registry of all types of modules. Entries created by EnvModule's metaclass module_types = {} @@ -79,34 +74,35 @@ def print_help(): "") -class PathInspector(object): - dirname2varname = { - 'bin': ('PATH',), - 'man': ('MANPATH',), - 'lib': ('LIBRARY_PATH', 'LD_LIBRARY_PATH'), - 'lib64': ('LIBRARY_PATH', 'LD_LIBRARY_PATH'), - 'include': ('CPATH',), - 'pkgconfig': ('PKG_CONFIG_PATH',) - } - - def __call__(self, env, directory, names): - for name in names: - variables = PathInspector.dirname2varname.get(name, None) - if variables is None: - continue - absolute_path = join_path(os.path.abspath(directory), name) - for variable in variables: - env.prepend_path(variable, absolute_path) - - def inspect_path(path): + class PathInspector(object): + dirname2varname = { + 'bin': ('PATH',), + 'man': ('MANPATH',), + 'lib': ('LIBRARY_PATH', 'LD_LIBRARY_PATH'), + 'lib64': ('LIBRARY_PATH', 'LD_LIBRARY_PATH'), + 'include': ('CPATH',), + 'pkgconfig': ('PKG_CONFIG_PATH',) + } + + def __call__(self, env, directory, names): + for name in names: + variables = PathInspector.dirname2varname.get(name, None) + if variables is None: + continue + absolute_path = join_path(os.path.abspath(directory), name) + for variable in variables: + env.prepend_path(variable, absolute_path) + env, inspector = EnvironmentModifications(), PathInspector() os.path.walk(path, inspector, env) + env.prepend_path('CMAKE_PREFIX_PATH', path) return env class EnvModule(object): name = 'env_module' + formats = {} class __metaclass__(type): def __init__(cls, name, bases, dict): @@ -119,9 +115,6 @@ class EnvModule(object): # TODO: come up with smarter category names. self.category = "spack" - # dict pathname -> list of directories to be prepended to in - # the module file. - self._paths = None self.spec = spec self.pkg = spec.package # Just stored for convenience @@ -136,44 +129,21 @@ class EnvModule(object): if self.spec.package.__doc__: self.long_description = re.sub(r'\s+', ' ', self.spec.package.__doc__) - @property - def paths(self): - if self._paths is None: - self._paths = {} - - def add_path(path_name, directory): - path = self._paths.setdefault(path_name, []) - path.append(directory) - - # Add paths if they exist. - for var, directory in [ - ('PATH', self.spec.prefix.bin), - ('MANPATH', self.spec.prefix.man), - ('MANPATH', self.spec.prefix.share_man), - ('LIBRARY_PATH', self.spec.prefix.lib), - ('LIBRARY_PATH', self.spec.prefix.lib64), - ('LD_LIBRARY_PATH', self.spec.prefix.lib), - ('LD_LIBRARY_PATH', self.spec.prefix.lib64), - ('CPATH', self.spec.prefix.include), - ('PKG_CONFIG_PATH', join_path(self.spec.prefix.lib, 'pkgconfig')), - ('PKG_CONFIG_PATH', join_path(self.spec.prefix.lib64, 'pkgconfig'))]: - - if os.path.isdir(directory): - add_path(var, directory) - - # Add python path unless it's an actual python installation - # TODO : is there a better way to do this? - # FIXME : add PYTHONPATH to every python package - if self.spec.name != 'python': - site_packages = glob(join_path(self.spec.prefix.lib, "python*/site-packages")) - if site_packages: - add_path('PYTHONPATH', site_packages[0]) - - # FIXME : Same for GEM_PATH - if self.spec.package.extends(spack.spec.Spec('ruby')): - add_path('GEM_PATH', self.spec.prefix) - - return self._paths + # @property + # def paths(self): + # # Add python path unless it's an actual python installation + # # TODO : is there a better way to do this? + # # FIXME : add PYTHONPATH to every python package + # if self.spec.name != 'python': + # site_packages = glob(join_path(self.spec.prefix.lib, "python*/site-packages")) + # if site_packages: + # add_path('PYTHONPATH', site_packages[0]) + # + # # FIXME : Same for GEM_PATH + # if self.spec.package.extends(spack.spec.Spec('ruby')): + # add_path('GEM_PATH', self.spec.prefix) + # + # return self._paths def write(self): """Write out a module file for this object.""" @@ -181,14 +151,9 @@ class EnvModule(object): if not os.path.exists(module_dir): mkdirp(module_dir) - # If there are no paths, no need for a dotkit. - if not self.paths: - return - - # Construct the changes that needs to be done on the environment for + # Environment modifications guessed by inspecting the installation prefix env = inspect_path(self.spec.prefix) - # FIXME : move the logic to inspection - env.prepend_path('CMAKE_PREFIX_PATH', self.spec.prefix) + # Package-specific environment modifications # FIXME : decide how to distinguish between calls done in the installation and elsewhere env.extend(self.spec.package.environment_modifications(None)) # site_specific = ...` @@ -196,12 +161,17 @@ class EnvModule(object): return with open(self.file_name, 'w') as f: - self._write(f, env) + self.write_header(f) + for line in self.process_environment_command(env): + f.write(line) - def _write(self, stream): - """To be implemented by subclasses.""" + def write_header(self, stream): raise NotImplementedError() + def process_environment_command(self, env): + for command in env: + # FIXME : how should we handle errors here? + yield self.formats[type(command)].format(command) @property def file_name(self): @@ -225,10 +195,14 @@ class Dotkit(EnvModule): name = 'dotkit' path = join_path(spack.share_path, "dotkit") + formats = { + PrependPath: 'dk_alter {0.name} {0.path}\n', + SetEnv: 'dk_setenv {0.name} {0.value}\n' + } + @property def file_name(self): - return join_path(Dotkit.path, self.spec.architecture, - '%s.dk' % self.use_name) + return join_path(Dotkit.path, self.spec.architecture, '%s.dk' % self.use_name) @property def use_name(self): @@ -237,7 +211,7 @@ class Dotkit(EnvModule): self.spec.compiler.version, self.spec.dag_hash()) - def _write(self, dk_file, env): + def write_header(self, dk_file): # Category if self.category: dk_file.write('#c %s\n' % self.category) @@ -251,18 +225,11 @@ class Dotkit(EnvModule): for line in textwrap.wrap(self.long_description, 72): dk_file.write("#h %s\n" % line) - # Path alterations - for var, dirs in self.paths.items(): - for directory in dirs: - dk_file.write("dk_alter %s %s\n" % (var, directory)) - - # Let CMake find this package. - dk_file.write("dk_alter CMAKE_PREFIX_PATH %s\n" % self.spec.prefix) - class TclModule(EnvModule): name = 'tcl' path = join_path(spack.share_path, "modules") + formats = { PrependPath: 'prepend-path {0.name} \"{0.path}\"\n', SetEnv: 'setenv {0.name} \"{0.value}\"\n' @@ -272,7 +239,6 @@ class TclModule(EnvModule): def file_name(self): return join_path(TclModule.path, self.spec.architecture, self.use_name) - @property def use_name(self): return "%s-%s-%s-%s-%s" % (self.spec.name, self.spec.version, @@ -280,19 +246,7 @@ class TclModule(EnvModule): self.spec.compiler.version, self.spec.dag_hash()) - def process_environment_command(self, env): - for command in env: - # FIXME : how should we handle errors here? - yield self.formats[type(command)].format(command) - - def _write(self, module_file, env): - """ - Writes a TCL module file for this package - - Args: - module_file: module file stream - env: list of environment modifications to be written in the module file - """ + def write_header(self, module_file): # TCL Modulefile header module_file.write('#%Module1.0\n') # TODO : category ? @@ -306,30 +260,3 @@ class TclModule(EnvModule): doc = re.sub(r'"', '\"', self.long_description) module_file.write("puts stderr \"%s\"\n" % doc) module_file.write('}\n\n') - - # Environment modifications - for line in self.process_environment_command(env): - module_file.write(line) - - # FIXME : REMOVE - # def _write(self, m_file): - # # TODO: cateogry? - # m_file.write('#%Module1.0\n') - # - # # Short description - # if self.short_description: - # m_file.write('module-whatis \"%s\"\n\n' % self.short_description) - # - # # Long description - # if self.long_description: - # m_file.write('proc ModulesHelp { } {\n') - # doc = re.sub(r'"', '\"', self.long_description) - # m_file.write("puts stderr \"%s\"\n" % doc) - # m_file.write('}\n\n') - # - # # Path alterations - # for var, dirs in self.paths.items(): - # for directory in dirs: - # m_file.write("prepend-path %s \"%s\"\n" % (var, directory)) - # - # m_file.write("prepend-path CMAKE_PREFIX_PATH \"%s\"\n" % self.spec.prefix) -- cgit v1.2.3-70-g09d2 From 9cdd79e33f8463699fcea0b668eafac1c9fae1d4 Mon Sep 17 00:00:00 2001 From: alalazo Date: Thu, 17 Mar 2016 14:14:18 +0100 Subject: modules : restored previous logic for path inspection --- lib/spack/spack/modules.py | 54 ++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 23 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/modules.py b/lib/spack/spack/modules.py index b64a8b3226..7e395736e4 100644 --- a/lib/spack/spack/modules.py +++ b/lib/spack/spack/modules.py @@ -74,29 +74,37 @@ def print_help(): "") -def inspect_path(path): - class PathInspector(object): - dirname2varname = { - 'bin': ('PATH',), - 'man': ('MANPATH',), - 'lib': ('LIBRARY_PATH', 'LD_LIBRARY_PATH'), - 'lib64': ('LIBRARY_PATH', 'LD_LIBRARY_PATH'), - 'include': ('CPATH',), - 'pkgconfig': ('PKG_CONFIG_PATH',) - } - - def __call__(self, env, directory, names): - for name in names: - variables = PathInspector.dirname2varname.get(name, None) - if variables is None: - continue - absolute_path = join_path(os.path.abspath(directory), name) - for variable in variables: - env.prepend_path(variable, absolute_path) - - env, inspector = EnvironmentModifications(), PathInspector() - os.path.walk(path, inspector, env) - env.prepend_path('CMAKE_PREFIX_PATH', path) +def inspect_path(prefix): + """ + Inspects the prefix of an installation to search for common layouts. Issues a request to modify the environment + accordingly when an item is found. + + Args: + prefix: prefix of the installation + + Returns: + instance of EnvironmentModifications containing the requested modifications + """ + env = EnvironmentModifications() + # Inspect the prefix to check for the existence of common directories + prefix_inspections = { + 'bin': ('PATH',), + 'man': ('MANPATH',), + 'lib': ('LIBRARY_PATH', 'LD_LIBRARY_PATH'), + 'lib64': ('LIBRARY_PATH', 'LD_LIBRARY_PATH'), + 'include': ('CPATH',) + } + for attribute, variables in prefix_inspections.items(): + expected = getattr(prefix, attribute) + if os.path.isdir(expected): + for variable in variables: + env.prepend_path(variable, expected) + # PKGCONFIG + for expected in (join_path(prefix.lib, 'pkgconfig'), join_path(prefix.lib64, 'pkgconfig')): + if os.path.isdir(expected): + env.prepend_path('PKG_CONFIG_PATH', expected) + # CMake related variables + env.prepend_path('CMAKE_PREFIX_PATH', prefix) return env -- cgit v1.2.3-70-g09d2 From f0f0663d1b9ece1e2b0b0a8f720b1325eec443bb Mon Sep 17 00:00:00 2001 From: alalazo Date: Thu, 17 Mar 2016 15:11:39 +0100 Subject: package : split `environment_modifications` into `setup_environment` and `setup_dependent_environment`. package : renamed `module_modifications` to `modify_module` for consistency --- lib/spack/spack/build_environment.py | 4 +-- lib/spack/spack/modules.py | 5 ++- lib/spack/spack/package.py | 9 +++-- var/spack/repos/builtin/packages/mpich/package.py | 39 +++++++++------------- .../builtin/packages/netlib-scalapack/package.py | 2 +- .../repos/builtin/packages/openmpi/package.py | 19 ++++++----- var/spack/repos/builtin/packages/python/package.py | 27 +++++++-------- var/spack/repos/builtin/packages/qt/package.py | 4 +-- var/spack/repos/builtin/packages/ruby/package.py | 6 ++-- 9 files changed, 52 insertions(+), 63 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py index e5d256a2e0..68477145fe 100644 --- a/lib/spack/spack/build_environment.py +++ b/lib/spack/spack/build_environment.py @@ -284,8 +284,8 @@ def setup_package(pkg): # Allow dependencies to set up environment as well. for dependency_spec in pkg.spec.traverse(root=False): - dependency_spec.package.module_modifications(pkg.module, dependency_spec, pkg.spec) - env.extend(dependency_spec.package.environment_modifications(pkg.spec)) + dependency_spec.package.modify_module(pkg.module, dependency_spec, pkg.spec) + dependency_spec.package.setup_dependent_environment(env, pkg.spec) # TODO : implement validation #validate(env) env.apply_modifications() diff --git a/lib/spack/spack/modules.py b/lib/spack/spack/modules.py index 7e395736e4..09895d8c44 100644 --- a/lib/spack/spack/modules.py +++ b/lib/spack/spack/modules.py @@ -162,9 +162,8 @@ class EnvModule(object): # Environment modifications guessed by inspecting the installation prefix env = inspect_path(self.spec.prefix) # Package-specific environment modifications - # FIXME : decide how to distinguish between calls done in the installation and elsewhere - env.extend(self.spec.package.environment_modifications(None)) - # site_specific = ...` + self.spec.package.setup_environment(env) + # TODO : implement site-specific modifications and filters if not env: return diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index 042833964a..8e56dd1f97 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -977,7 +977,7 @@ class Package(object): fromlist=[self.__class__.__name__]) - def environment_modifications(self, dependent_spec): + def setup_environment(self, env): """ Called before the install() method of dependents. @@ -998,9 +998,12 @@ class Package(object): Returns: instance of environment modifications """ - return EnvironmentModifications() + pass + + def setup_dependent_environment(self, env, dependent_spec): + self.setup_environment(env) - def module_modifications(self, module, spec, dependent_spec): + def modify_module(self, module, spec, dependent_spec): """ Called before the install() method of dependents. diff --git a/var/spack/repos/builtin/packages/mpich/package.py b/var/spack/repos/builtin/packages/mpich/package.py index 4c34d0308f..5af9b585ea 100644 --- a/var/spack/repos/builtin/packages/mpich/package.py +++ b/var/spack/repos/builtin/packages/mpich/package.py @@ -47,30 +47,21 @@ class Mpich(Package): provides('mpi@:3.0', when='@3:') provides('mpi@:1.3', when='@1:') - def environment_modifications(self, dependent_spec): - env = super(Mpich, self).environment_modifications(dependent_spec) - - if dependent_spec is None: - # We are not using compiler wrappers - cc = self.compiler.cc - cxx = self.compiler.cxx - f77 = self.compiler.f77 - f90 = fc = self.compiler.fc - else: - # Spack compiler wrappers - cc = os.environ['CC'] - cxx = os.environ['CXX'] - f77 = os.environ['F77'] - f90 = fc = os.environ['FC'] - - env.set_env('MPICH_CC', cc) - env.set_env('MPICH_CXX', cxx) - env.set_env('MPICH_F77', f77) - env.set_env('MPICH_F90', f90) - env.set_env('MPICH_FC', fc) - return env - - def module_modifications(self, module, spec, dep_spec): + def setup_environment(self, env): + env.set_env('MPICH_CC', self.compiler.cc) + env.set_env('MPICH_CXX', self.compiler.cxx) + env.set_env('MPICH_F77', self.compiler.f77) + env.set_env('MPICH_F90', self.compiler.fc) + env.set_env('MPICH_FC', self.compiler.fc) + + def setup_dependent_environment(self, env, dependent_spec): + env.set_env('MPICH_CC', spack_cc) + env.set_env('MPICH_CXX', spack_cxx) + env.set_env('MPICH_F77', spack_f77) + env.set_env('MPICH_F90', spack_f90) + env.set_env('MPICH_FC', spack_fc) + + def modify_module(self, module, spec, dep_spec): """For dependencies, make mpicc's use spack wrapper.""" # FIXME : is this necessary ? Shouldn't this be part of a contract with MPI providers? module.mpicc = join_path(self.prefix.bin, 'mpicc') diff --git a/var/spack/repos/builtin/packages/netlib-scalapack/package.py b/var/spack/repos/builtin/packages/netlib-scalapack/package.py index ecdea46442..7e7e5b2e2e 100644 --- a/var/spack/repos/builtin/packages/netlib-scalapack/package.py +++ b/var/spack/repos/builtin/packages/netlib-scalapack/package.py @@ -40,7 +40,7 @@ class NetlibScalapack(Package): make() make("install") - def module_modifications(self, module, spec, dependent_spec): + def modify_module(self, module, spec, dependent_spec): # TODO treat OS that are not Linux... lib_suffix = '.so' if '+shared' in spec['scalapack'] else '.a' diff --git a/var/spack/repos/builtin/packages/openmpi/package.py b/var/spack/repos/builtin/packages/openmpi/package.py index 3a14170457..7783ca8766 100644 --- a/var/spack/repos/builtin/packages/openmpi/package.py +++ b/var/spack/repos/builtin/packages/openmpi/package.py @@ -41,14 +41,17 @@ class Openmpi(Package): def url_for_version(self, version): return "http://www.open-mpi.org/software/ompi/v%s/downloads/openmpi-%s.tar.bz2" % (version.up_to(2), version) - def environment_modifications(self, dependent_spec): - env = super(Openmpi, self).environment_modifications(dependent_spec) - # FIXME : the compilers should point to the current wrappers, not to generic cc etc. - env.set_env('OMPI_CC', 'cc') - env.set_env('OMPI_CXX', 'c++') - env.set_env('OMPI_FC', 'f90') - env.set_env('OMPI_F77', 'f77') - return env + def setup_environment(self, env): + env.set_env('OMPI_CC', self.compiler.cc) + env.set_env('OMPI_CXX', self.compiler.cxx) + env.set_env('OMPI_FC', self.compiler.fc) + env.set_env('OMPI_F77', self.compiler.f77) + + def setup_dependent_environment(self, env, dependent_spec): + env.set_env('OMPI_CC', spack_cc) + env.set_env('OMPI_CXX', spack_cxx) + env.set_env('OMPI_FC', spack_fc) + env.set_env('OMPI_F77', spack_f77) def install(self, spec, prefix): config_args = ["--prefix=%s" % prefix, diff --git a/var/spack/repos/builtin/packages/python/package.py b/var/spack/repos/builtin/packages/python/package.py index acb3651726..d47c1d1b2f 100644 --- a/var/spack/repos/builtin/packages/python/package.py +++ b/var/spack/repos/builtin/packages/python/package.py @@ -89,24 +89,21 @@ class Python(Package): def site_packages_dir(self): return os.path.join(self.python_lib_dir, 'site-packages') - def environment_modifications(self, extension_spec): - env = super(Python, self).environment_modifications(extension_spec) - if extension_spec is not None: - # Set PYTHONPATH to include site-packages dir for the - # extension and any other python extensions it depends on. - python_paths = [] - for d in extension_spec.traverse(): - if d.package.extends(self.spec): - python_paths.append(os.path.join(d.prefix, self.site_packages_dir)) - env.set_env['PYTHONPATH'] = ':'.join(python_paths) - return env - - def module_modifications(self, module, spec, ext_spec): - """Called before python modules' install() methods. + def setup_dependent_environment(self, env, extension_spec): + # Set PYTHONPATH to include site-packages dir for the extension and any other python extensions it depends on. + python_paths = [] + for d in extension_spec.traverse(): + if d.package.extends(self.spec): + python_paths.append(os.path.join(d.prefix, self.site_packages_dir)) + env.set_env['PYTHONPATH'] = ':'.join(python_paths) + + def modify_module(self, module, spec, ext_spec): + """ + Called before python modules' install() methods. In most cases, extensions will only need to have one line:: - python('setup.py', 'install', '--prefix=%s' % prefix) + python('setup.py', 'install', '--prefix=%s' % prefix) """ # Python extension builds can have a global python executable function if self.version >= Version("3.0.0") and self.version < Version("4.0.0"): diff --git a/var/spack/repos/builtin/packages/qt/package.py b/var/spack/repos/builtin/packages/qt/package.py index 0adf352be2..35b9d68462 100644 --- a/var/spack/repos/builtin/packages/qt/package.py +++ b/var/spack/repos/builtin/packages/qt/package.py @@ -55,10 +55,8 @@ class Qt(Package): depends_on("mesa", when='@4:+mesa') depends_on("libxcb") - def environment_modifications(self, dependent_spec): - env = super(Qt, self).environment_modifications(dependent_spec) + def setup_environment(self, env): env.set_env['QTDIR'] = self.prefix - return env def patch(self): if self.spec.satisfies('@4'): diff --git a/var/spack/repos/builtin/packages/ruby/package.py b/var/spack/repos/builtin/packages/ruby/package.py index 9caea30ef4..2d1da8c9af 100644 --- a/var/spack/repos/builtin/packages/ruby/package.py +++ b/var/spack/repos/builtin/packages/ruby/package.py @@ -17,8 +17,7 @@ class Ruby(Package): make() make("install") - def environment_modifications(self, extension_spec): - env = super(Ruby, self).environment_modifications(extension_spec) + def setup_dependent_environment(self, env, extension_spec): # Set GEM_PATH to include dependent gem directories ruby_paths = [] for d in extension_spec.traverse(): @@ -27,9 +26,8 @@ class Ruby(Package): env.set_env('GEM_PATH', concatenate_paths(ruby_paths)) # The actual installation path for this gem env.set_env('GEM_HOME', extension_spec.prefix) - return env - def module_modifications(self, module, spec, ext_spec): + def modify_module(self, module, spec, ext_spec): """Called before ruby modules' install() methods. Sets GEM_HOME and GEM_PATH to values appropriate for the package being built. -- cgit v1.2.3-70-g09d2 From 3da4d6664bbee38fde6faeffb39f889698ea320c Mon Sep 17 00:00:00 2001 From: alalazo Date: Thu, 17 Mar 2016 15:38:08 +0100 Subject: environment : simplified hierarchy according to comments in review --- lib/spack/spack/environment.py | 53 ++++++++++++------------------------- lib/spack/spack/modules.py | 10 +++---- lib/spack/spack/package.py | 1 + lib/spack/spack/test/environment.py | 2 +- lib/spack/spack/util/environment.py | 2 -- 5 files changed, 24 insertions(+), 44 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/environment.py b/lib/spack/spack/environment.py index b557bf0bbc..3ee917fcec 100644 --- a/lib/spack/spack/environment.py +++ b/lib/spack/spack/environment.py @@ -3,73 +3,54 @@ import os.path import collections -class AttributeHolder(object): - """ - Policy that permits to store any kind of attribute on self. The attributes must be passed as key/value pairs - during the initialization of the instance. - """ - def __init__(self, **kwargs): - for key, value in kwargs.items(): - setattr(self, key, value) +class NameModifier(object): + def __init__(self, name, **kwargs): + self.name = name + self.args = {'name': name} + self.args.update(kwargs) -class SetEnv(AttributeHolder): +class NameValueModifier(object): def __init__(self, name, value, **kwargs): - super(SetEnv, self).__init__(**kwargs) self.name = name self.value = value + self.args = {'name': name, 'value': value} + self.args.update(kwargs) + +class SetEnv(NameValueModifier): def execute(self): os.environ[self.name] = str(self.value) -class UnsetEnv(AttributeHolder): - def __init__(self, name, **kwargs): - super(UnsetEnv, self).__init__(**kwargs) - self.name = name - +class UnsetEnv(NameModifier): def execute(self): os.environ.pop(self.name, None) # Avoid throwing if the variable was not set -class AppendPath(AttributeHolder): - def __init__(self, name, path, **kwargs): - super(AppendPath, self).__init__(**kwargs) - self.name = name - self.path = path - +class AppendPath(NameValueModifier): def execute(self): environment_value = os.environ.get(self.name, '') directories = environment_value.split(':') if environment_value else [] # TODO : Check if this is a valid directory name - directories.append(os.path.normpath(self.path)) + directories.append(os.path.normpath(self.value)) os.environ[self.name] = ':'.join(directories) -class PrependPath(AttributeHolder): - def __init__(self, name, path, **kwargs): - super(PrependPath, self).__init__(**kwargs) - self.name = name - self.path = path - +class PrependPath(NameValueModifier): def execute(self): environment_value = os.environ.get(self.name, '') directories = environment_value.split(':') if environment_value else [] # TODO : Check if this is a valid directory name - directories = [os.path.normpath(self.path)] + directories + directories = [os.path.normpath(self.value)] + directories os.environ[self.name] = ':'.join(directories) -class RemovePath(AttributeHolder): - def __init__(self, name, path, **kwargs): - super(RemovePath, self).__init__(**kwargs) - self.name = name - self.path = path - +class RemovePath(NameValueModifier): def execute(self): environment_value = os.environ.get(self.name, '') directories = environment_value.split(':') if environment_value else [] - directories = [os.path.normpath(x) for x in directories if x != os.path.normpath(self.path)] + directories = [os.path.normpath(x) for x in directories if x != os.path.normpath(self.value)] os.environ[self.name] = ':'.join(directories) diff --git a/lib/spack/spack/modules.py b/lib/spack/spack/modules.py index 09895d8c44..0f826c7363 100644 --- a/lib/spack/spack/modules.py +++ b/lib/spack/spack/modules.py @@ -178,7 +178,7 @@ class EnvModule(object): def process_environment_command(self, env): for command in env: # FIXME : how should we handle errors here? - yield self.formats[type(command)].format(command) + yield self.formats[type(command)].format(**command.args) @property def file_name(self): @@ -203,8 +203,8 @@ class Dotkit(EnvModule): path = join_path(spack.share_path, "dotkit") formats = { - PrependPath: 'dk_alter {0.name} {0.path}\n', - SetEnv: 'dk_setenv {0.name} {0.value}\n' + PrependPath: 'dk_alter {name} {value}\n', + SetEnv: 'dk_setenv {name} {value}\n' } @property @@ -238,8 +238,8 @@ class TclModule(EnvModule): path = join_path(spack.share_path, "modules") formats = { - PrependPath: 'prepend-path {0.name} \"{0.path}\"\n', - SetEnv: 'setenv {0.name} \"{0.value}\"\n' + PrependPath: 'prepend-path {name} \"{value}\"\n', + SetEnv: 'setenv {name} \"{value}\"\n' } @property diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index 8e56dd1f97..680b26d69a 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -979,6 +979,7 @@ class Package(object): def setup_environment(self, env): """ + Called before the install() method of dependents. Return the list of environment modifications needed by dependents (or extensions). Default implementation does diff --git a/lib/spack/spack/test/environment.py b/lib/spack/spack/test/environment.py index d0b093b054..3e03760c01 100644 --- a/lib/spack/spack/test/environment.py +++ b/lib/spack/spack/test/environment.py @@ -53,7 +53,7 @@ class EnvironmentTest(unittest.TestCase): env = EnvironmentModifications() env.set_env('A', 'dummy value', who='Pkg1') for x in env: - assert hasattr(x, 'who') + assert 'who' in x.args env.apply_modifications() self.assertEqual('dummy value', os.environ['A']) diff --git a/lib/spack/spack/util/environment.py b/lib/spack/spack/util/environment.py index 1485992b0f..55e653fd2f 100644 --- a/lib/spack/spack/util/environment.py +++ b/lib/spack/spack/util/environment.py @@ -40,13 +40,11 @@ def env_flag(name): return False -# FIXME : remove this function ? def path_set(var_name, directories): path_str = ":".join(str(dir) for dir in directories) os.environ[var_name] = path_str -# FIXME : remove this function ? def path_put_first(var_name, directories): """Puts the provided directories first in the path, adding them if they're not already there. -- cgit v1.2.3-70-g09d2 From 38c3c84969c25aaee8f643ff9770759c7e6d9c35 Mon Sep 17 00:00:00 2001 From: alalazo Date: Thu, 17 Mar 2016 17:37:33 +0100 Subject: environment : added caller information --- lib/spack/spack/environment.py | 27 +++++++++++++++++++++++++-- lib/spack/spack/modules.py | 8 ++++++-- 2 files changed, 31 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/environment.py b/lib/spack/spack/environment.py index 3ee917fcec..6d214595a3 100644 --- a/lib/spack/spack/environment.py +++ b/lib/spack/spack/environment.py @@ -1,6 +1,7 @@ import os import os.path import collections +import inspect class NameModifier(object): @@ -32,7 +33,6 @@ class AppendPath(NameValueModifier): def execute(self): environment_value = os.environ.get(self.name, '') directories = environment_value.split(':') if environment_value else [] - # TODO : Check if this is a valid directory name directories.append(os.path.normpath(self.value)) os.environ[self.name] = ':'.join(directories) @@ -41,7 +41,6 @@ class PrependPath(NameValueModifier): def execute(self): environment_value = os.environ.get(self.name, '') directories = environment_value.split(':') if environment_value else [] - # TODO : Check if this is a valid directory name directories = [os.path.normpath(self.value)] + directories os.environ[self.name] = ':'.join(directories) @@ -57,6 +56,11 @@ class RemovePath(NameValueModifier): class EnvironmentModifications(object): """ Keeps track of requests to modify the current environment. + + Each call to a method to modify the environment stores the extra information on the caller in the request: + - 'filename' : filename of the module where the caller is defined + - 'lineno': line number where the request occurred + - 'context' : line of code that issued the request that failed """ def __init__(self, other=None): @@ -85,6 +89,20 @@ class EnvironmentModifications(object): if not isinstance(other, EnvironmentModifications): raise TypeError('other must be an instance of EnvironmentModifications') + def _get_outside_caller_attributes(self): + stack = inspect.stack() + try: + _, filename, lineno, _, context, index = stack[2] + context = context[index].strip() + except Exception: + filename, lineno, context = 'unknown file', 'unknown line', 'unknown context' + args = { + 'filename': filename, + 'lineno': lineno, + 'context': context + } + return args + def set_env(self, name, value, **kwargs): """ Stores in the current object a request to set an environment variable @@ -93,6 +111,7 @@ class EnvironmentModifications(object): name: name of the environment variable to be set value: value of the environment variable """ + kwargs.update(self._get_outside_caller_attributes()) item = SetEnv(name, value, **kwargs) self.env_modifications.append(item) @@ -103,6 +122,7 @@ class EnvironmentModifications(object): Args: name: name of the environment variable to be set """ + kwargs.update(self._get_outside_caller_attributes()) item = UnsetEnv(name, **kwargs) self.env_modifications.append(item) @@ -114,6 +134,7 @@ class EnvironmentModifications(object): name: name of the path list in the environment path: path to be appended """ + kwargs.update(self._get_outside_caller_attributes()) item = AppendPath(name, path, **kwargs) self.env_modifications.append(item) @@ -125,6 +146,7 @@ class EnvironmentModifications(object): name: name of the path list in the environment path: path to be pre-pended """ + kwargs.update(self._get_outside_caller_attributes()) item = PrependPath(name, path, **kwargs) self.env_modifications.append(item) @@ -136,6 +158,7 @@ class EnvironmentModifications(object): name: name of the path list in the environment path: path to be removed """ + kwargs.update(self._get_outside_caller_attributes()) item = RemovePath(name, path, **kwargs) self.env_modifications.append(item) diff --git a/lib/spack/spack/modules.py b/lib/spack/spack/modules.py index 0f826c7363..d192bbe004 100644 --- a/lib/spack/spack/modules.py +++ b/lib/spack/spack/modules.py @@ -177,8 +177,12 @@ class EnvModule(object): def process_environment_command(self, env): for command in env: - # FIXME : how should we handle errors here? - yield self.formats[type(command)].format(**command.args) + try: + yield self.formats[type(command)].format(**command.args) + except KeyError: + tty.warn('Cannot handle command of type {command} : skipping request'.format(command=type(command))) + tty.warn('{context} at {filename}:{lineno}'.format(**command.args)) + @property def file_name(self): -- cgit v1.2.3-70-g09d2 From e673127263a03e63d6a64840d1071a788f0c099e Mon Sep 17 00:00:00 2001 From: alalazo Date: Thu, 17 Mar 2016 18:11:23 +0100 Subject: package : added documentation --- lib/spack/spack/package.py | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index 680b26d69a..d0b94dbbeb 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -976,32 +976,41 @@ class Package(object): return __import__(self.__class__.__module__, fromlist=[self.__class__.__name__]) - def setup_environment(self, env): """ + Appends in `env` the list of environment modifications needed to use this package outside of spack. + + Default implementation does nothing, but this can be overridden if the package needs a particular environment. + + Example : + + 1. A lot of Qt extensions need `QTDIR` set. This can be used to do that. + + Args: + env: list of environment modifications to be updated + """ + pass + def setup_dependent_environment(self, env, dependent_spec): + """ Called before the install() method of dependents. - Return the list of environment modifications needed by dependents (or extensions). Default implementation does - nothing, but this can be overridden by an extendable package to set up the install environment for its - extensions. This is useful if there are some common steps to installing all extensions for a certain package. + Appends in `env` the list of environment modifications needed by dependents (or extensions) during the + installation of a package. The default implementation delegates to `setup_environment`, but can be overridden + if the modifications to the environment happen to be different from the one needed to use the package outside + of spack. + + This is useful if there are some common steps to installing all extensions for a certain package. Example : 1. Installing python modules generally requires `PYTHONPATH` to point to the lib/pythonX.Y/site-packages directory in the module's install prefix. This could set that variable. - 2. A lot of Qt extensions need `QTDIR` set. This can be used to do that. - Args: + env: list of environment modifications to be updated dependent_spec: dependent (or extension) of this spec - - Returns: - instance of environment modifications """ - pass - - def setup_dependent_environment(self, env, dependent_spec): self.setup_environment(env) def modify_module(self, module, spec, dependent_spec): @@ -1020,12 +1029,10 @@ class Package(object): """ pass - def install(self, spec, prefix): """Package implementations override this with their own build configuration.""" raise InstallError("Package %s provides no install method!" % self.name) - def do_uninstall(self, force=False): if not self.installed: raise InstallError(str(self.spec) + " is not installed.") -- cgit v1.2.3-70-g09d2 From ac394718ec0aa67c468a8529b930eaade0bcbed1 Mon Sep 17 00:00:00 2001 From: alalazo Date: Thu, 17 Mar 2016 18:22:07 +0100 Subject: python : implemented possible solution --- lib/spack/spack/package.py | 11 ++++++++++- var/spack/repos/builtin/packages/py-nose/package.py | 3 ++- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index d0b94dbbeb..a7ab20137e 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -37,6 +37,7 @@ import os import re import textwrap import time +import glob import llnl.util.tty as tty import spack @@ -55,7 +56,6 @@ from llnl.util.filesystem import * from llnl.util.lang import * from llnl.util.link_tree import LinkTree from llnl.util.tty.log import log_output -from spack.environment import EnvironmentModifications from spack.stage import Stage, ResourceStage, StageComposite from spack.util.compression import allowed_archive from spack.util.environment import dump_environment @@ -1236,6 +1236,15 @@ class Package(object): return " ".join("-Wl,-rpath,%s" % p for p in self.rpath) +class PythonExtension(Package): + def setup_dependent_environment(self, env, dependent_spec): + pass + + def setup_environment(self, env): + site_packages = glob.glob(join_path(self.spec.prefix.lib, "python*/site-packages")) + if site_packages: + env.prepend_path('PYTHONPATH', site_packages[0]) + def validate_package_url(url_string): """Determine whether spack can handle a particular URL or not.""" url = urlparse(url_string) diff --git a/var/spack/repos/builtin/packages/py-nose/package.py b/var/spack/repos/builtin/packages/py-nose/package.py index e7c6cf0264..e817b8eb51 100644 --- a/var/spack/repos/builtin/packages/py-nose/package.py +++ b/var/spack/repos/builtin/packages/py-nose/package.py @@ -1,6 +1,7 @@ from spack import * +from spack.package import PythonExtension -class PyNose(Package): +class PyNose(PythonExtension): """nose extends the test loading and running features of unittest, making it easier to write, find and run tests.""" -- cgit v1.2.3-70-g09d2 From f3ea0420f80f418a0f3e628479c782f197e6a43e Mon Sep 17 00:00:00 2001 From: Erik Schnetter Date: Thu, 17 Mar 2016 21:53:13 -0400 Subject: Import recent changes --- lib/spack/env/cc | 185 +++++++++++++++++++------------------------------------ 1 file changed, 65 insertions(+), 120 deletions(-) (limited to 'lib') diff --git a/lib/spack/env/cc b/lib/spack/env/cc index df6795c264..c6a09724e9 100755 --- a/lib/spack/env/cc +++ b/lib/spack/env/cc @@ -65,7 +65,7 @@ function die { } for param in $parameters; do - if [ -z "${!param}" ]; then + if [[ -z ${!param} ]]; then die "Spack compiler must be run from spack! Input $param was missing!" fi done @@ -78,10 +78,11 @@ done # 'command' is set based on the input command to $SPACK_[CC|CXX|F77|F90] # # 'mode' is set to one of: +# cpp preprocess # cc compile +# as assemble # ld link # ccld compile & link -# cpp preprocessor # vcheck version check # command=$(basename "$0") @@ -131,6 +132,9 @@ if [ -z "$mode" ]; then if [ "$arg" = -E ]; then mode=cpp break + elif [ "$arg" = -S ]; then + mode=as + break elif [ "$arg" = -c ]; then mode=cc break @@ -146,22 +150,25 @@ fi # Check that at least one of the real commands was actually selected, # otherwise we don't know what to execute. -if [ -z "$command" ]; then +if [[ -z $command ]]; then die "ERROR: Compiler '$SPACK_COMPILER_SPEC' does not support compiling $language programs." fi +if [ "$mode" == vcheck ] ; then + exec ${command} "$@" +fi + # Save original command for debug logging input_command="$@" args=("$@") -<<<<<<< HEAD # Dump parsed values for unit testing if asked for if [[ -n $SPACK_TEST_COMMAND ]]; then # # Now do real parsing of the command line args, trying hard to keep - # non-rpath linker arguments in the proper order w.r.t. other command - # line arguments. This is important for things like groups. + # non-rpath linker arguments in the proper order w.r.t. other command line + # arguments. This is important for things like groups. # includes=() libraries=() @@ -188,32 +195,44 @@ if [[ -n $SPACK_TEST_COMMAND ]]; then ;; -Wl,*) arg="${1#-Wl,}" - if [ -z "$arg" ]; then shift; arg="$1"; fi - if [[ "$arg" = -rpath=* ]]; then - rpaths+=("${arg#-rpath=}") - elif [[ "$arg" = -rpath ]]; then + # TODO: Handle multiple -Wl, continuations of -Wl,-rpath + if [[ $arg == -rpath=* ]]; then + arg="${arg#-rpath=}" + for rpath in ${arg//,/ }; do + rpaths+=("$rpath") + done + elif [[ $arg == -rpath,* ]]; then + arg="${arg#-rpath,}" + for rpath in ${arg//,/ }; do + rpaths+=("$rpath") + done + elif [[ $arg == -rpath ]]; then shift; arg="$1" - if [[ "$arg" != -Wl,* ]]; then + if [[ $arg != '-Wl,'* ]]; then die "-Wl,-rpath was not followed by -Wl,*" fi - rpaths+=("${arg#-Wl,}") + arg="${arg#-Wl,}" + for rpath in ${arg//,/ }; do + rpaths+=("$rpath") + done else other_args+=("-Wl,$arg") fi ;; - -Xlinker,*) - arg="${1#-Xlinker,}" - if [ -z "$arg" ]; then shift; arg="$1"; fi - if [[ "$arg" = -rpath=* ]]; then + -Xlinker) + shift; arg="$1"; + if [[ $arg = -rpath=* ]]; then rpaths+=("${arg#-rpath=}") - elif [[ "$arg" = -rpath ]]; then + elif [[ $arg = -rpath ]]; then shift; arg="$1" - if [[ "$arg" != -Xlinker,* ]]; then - die "-Xlinker,-rpath was not followed by -Xlinker,*" + if [[ $arg != -Xlinker ]]; then + die "-Xlinker -rpath was not followed by -Xlinker " fi - rpaths+=("${arg#-Xlinker,}") + shift; arg="$1" + rpaths+=("$arg") else - other_args+=("-Xlinker,$arg") + other_args+=("-Xlinker") + other_args+=("$arg") fi ;; *) @@ -222,88 +241,6 @@ if [[ -n $SPACK_TEST_COMMAND ]]; then esac shift done -======= -if [ "$mode" == vcheck ] ; then - exec ${command} "$@" -fi - -# -# Now do real parsing of the command line args, trying hard to keep -# non-rpath linker arguments in the proper order w.r.t. other command -# line arguments. This is important for things like groups. -# -includes=() -libraries=() -libs=() -rpaths=() -other_args=() - -while [ -n "$1" ]; do - case "$1" in - -I*) - arg="${1#-I}" - if [ -z "$arg" ]; then shift; arg="$1"; fi - includes+=("$arg") - ;; - -L*) - arg="${1#-L}" - if [ -z "$arg" ]; then shift; arg="$1"; fi - libraries+=("$arg") - ;; - -l*) - arg="${1#-l}" - if [ -z "$arg" ]; then shift; arg="$1"; fi - libs+=("$arg") - ;; - -Wl,*) - arg="${1#-Wl,}" - # TODO: Handle multiple -Wl, continuations of -Wl,-rpath - if [[ $arg == -rpath=* ]]; then - arg="${arg#-rpath=}" - for rpath in ${arg//,/ }; do - rpaths+=("$rpath") - done - elif [[ $arg == -rpath,* ]]; then - arg="${arg#-rpath,}" - for rpath in ${arg//,/ }; do - rpaths+=("$rpath") - done - elif [[ $arg == -rpath ]]; then - shift; arg="$1" - if [[ $arg != '-Wl,'* ]]; then - die "-Wl,-rpath was not followed by -Wl,*" - fi - arg="${arg#-Wl,}" - for rpath in ${arg//,/ }; do - rpaths+=("$rpath") - done - else - other_args+=("-Wl,$arg") - fi - ;; - -Xlinker) - shift; arg="$1"; - if [[ $arg = -rpath=* ]]; then - rpaths+=("${arg#-rpath=}") - elif [[ $arg = -rpath ]]; then - shift; arg="$1" - if [[ $arg != -Xlinker ]]; then - die "-Xlinker -rpath was not followed by -Xlinker " - fi - shift; arg="$1" - rpaths+=("$arg") - else - other_args+=("-Xlinker") - other_args+=("$arg") - fi - ;; - *) - other_args+=("$1") - ;; - esac - shift -done ->>>>>>> develop IFS=$'\n' case "$SPACK_TEST_COMMAND" in @@ -329,8 +266,8 @@ done echo "${other_args[*]}" ;; *) - echo "ERROR: Unknown test command" - exit 1 ;; + die "ERROR: Unknown test command" + ;; esac exit fi @@ -338,11 +275,14 @@ fi # Read spack dependencies from the path environment variable IFS=':' read -ra deps <<< "$SPACK_DEPENDENCIES" for dep in "${deps[@]}"; do - if [ -d "$dep/include" ]; then - args=("-I$dep/include" "${args[@]}") + if [[ -d $dep/include ]]; then + if [[ $mode = cpp || $mode = cc || $mode = as || $mode = ccld ]]; then + args=("-I$dep/include" "${args[@]}") + fi fi - if [ -d "$dep/lib" ]; then + if [[ -d $dep/lib ]]; then + # libraries+=("$dep/lib") if [[ $mode = ccld ]]; then args=("-L$dep/lib" "-Wl,-rpath,$dep/lib" "${args[@]}") elif [[ $mode = ld ]]; then @@ -350,7 +290,7 @@ for dep in "${deps[@]}"; do fi fi - if [ -d "$dep/lib64" ]; then + if [[ -d $dep/lib64 ]]; then # libraries+=("$dep/lib64") if [[ $mode = ccld ]]; then args=("-L$dep/lib" "-Wl,-rpath,$dep/lib" "${args[@]}") @@ -362,8 +302,18 @@ done # Include all -L's and prefix/whatever dirs in rpath if [[ $mode = ccld ]]; then + # for dir in "${libraries[@]}"; do + # if [[ dir = $SPACK_INSTALL* ]]; then + # args=("-Wl,-rpath,$dir" "${args[@]}") + # fi + # done args=("-Wl,-rpath,$SPACK_PREFIX/lib" "-Wl,-rpath,$SPACK_PREFIX/lib64" "${args[@]}") elif [[ $mode = ld ]]; then + # for dir in "${libraries[@]}"; do + # if [[ dir = $SPACK_INSTALL* ]]; then + # args=("-rpath" "$dir" "${args[@]}") + # fi + # done args=("-rpath" "$SPACK_PREFIX/lib" "-rpath" "$SPACK_PREFIX/lib64" "${args[@]}") fi @@ -385,28 +335,23 @@ PATH="" for dir in "${env_path[@]}"; do remove="" for rm_dir in "${spack_env_dirs[@]}"; do - if [ "$dir" = "$rm_dir" ]; then remove=True; fi + if [[ $dir = $rm_dir ]]; then remove=True; fi done - if [ -z "$remove" ]; then - if [ -z "$PATH" ]; then - PATH="$dir" - else - PATH="$PATH:$dir" - fi + if [[ -z $remove ]]; then + PATH="${PATH:+$PATH:}$dir" fi done export PATH -full_command=("$command") -full_command+=("${args[@]}") +full_command=("$command" "${args[@]}") # # Write the input and output commands to debug logs if it's asked for. # -if [ "$SPACK_DEBUG" = "TRUE" ]; then +if [[ $SPACK_DEBUG = TRUE ]]; then input_log="$SPACK_DEBUG_LOG_DIR/spack-cc-$SPACK_SHORT_SPEC.in.log" output_log="$SPACK_DEBUG_LOG_DIR/spack-cc-$SPACK_SHORT_SPEC.out.log" - echo "$input_command" >> $input_log + echo "$input_command" >> $input_log echo "$mode ${full_command[@]}" >> $output_log fi -- cgit v1.2.3-70-g09d2 From ec8cc2b52839007f0825815c8cfdee8f9a8629a6 Mon Sep 17 00:00:00 2001 From: alalazo Date: Fri, 18 Mar 2016 14:40:53 +0100 Subject: PYTHONPATH : python patches methods for its extensions --- lib/spack/spack/build_environment.py | 4 ++- lib/spack/spack/cmd/uninstall.py | 12 ++++---- lib/spack/spack/directory_layout.py | 2 +- lib/spack/spack/modules.py | 12 ++++++-- lib/spack/spack/package.py | 10 ------- .../repos/builtin/packages/py-nose/package.py | 6 ++-- var/spack/repos/builtin/packages/python/package.py | 34 ++++++++++++++++++++-- 7 files changed, 53 insertions(+), 27 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py index 68477145fe..c51fa58477 100644 --- a/lib/spack/spack/build_environment.py +++ b/lib/spack/spack/build_environment.py @@ -282,9 +282,11 @@ def setup_package(pkg): for mod in modules: set_module_variables_for_package(pkg, mod) - # Allow dependencies to set up environment as well. + # Allow dependencies to modify the module for dependency_spec in pkg.spec.traverse(root=False): dependency_spec.package.modify_module(pkg.module, dependency_spec, pkg.spec) + # Allow dependencies to set up environment as well + for dependency_spec in pkg.spec.traverse(root=False): dependency_spec.package.setup_dependent_environment(env, pkg.spec) # TODO : implement validation #validate(env) diff --git a/lib/spack/spack/cmd/uninstall.py b/lib/spack/spack/cmd/uninstall.py index d01aa2136b..2fab8f6f2a 100644 --- a/lib/spack/spack/cmd/uninstall.py +++ b/lib/spack/spack/cmd/uninstall.py @@ -79,7 +79,7 @@ def uninstall(parser, args): try: # should work if package is known to spack pkgs.append(s.package) - except spack.repository.UnknownPackageError, e: + except spack.repository.UnknownPackageError as e: # The package.py file has gone away -- but still # want to uninstall. spack.Package(s).do_uninstall(force=True) @@ -94,11 +94,11 @@ def uninstall(parser, args): for pkg in pkgs: try: pkg.do_uninstall(force=args.force) - except PackageStillNeededError, e: + except PackageStillNeededError as e: tty.error("Will not uninstall %s" % e.spec.format("$_$@$%@$#", color=True)) - print - print "The following packages depend on it:" + print() + print("The following packages depend on it:") display_specs(e.dependents, long=True) - print - print "You can use spack uninstall -f to force this action." + print() + print("You can use spack uninstall -f to force this action.") sys.exit(1) diff --git a/lib/spack/spack/directory_layout.py b/lib/spack/spack/directory_layout.py index 39ee4e203d..da8f1aa1bc 100644 --- a/lib/spack/spack/directory_layout.py +++ b/lib/spack/spack/directory_layout.py @@ -150,7 +150,7 @@ class DirectoryLayout(object): if os.path.exists(path): try: shutil.rmtree(path) - except exceptions.OSError, e: + except exceptions.OSError as e: raise RemoveFailedError(spec, path, e) path = os.path.dirname(path) diff --git a/lib/spack/spack/modules.py b/lib/spack/spack/modules.py index d192bbe004..7303844229 100644 --- a/lib/spack/spack/modules.py +++ b/lib/spack/spack/modules.py @@ -119,13 +119,13 @@ class EnvModule(object): module_types[cls.name] = cls def __init__(self, spec=None): + self.spec = spec + self.pkg = spec.package # Just stored for convenience + # category in the modules system # TODO: come up with smarter category names. self.category = "spack" - self.spec = spec - self.pkg = spec.package # Just stored for convenience - # short description default is just the package + version # packages can provide this optional attribute self.short_description = spec.format("$_ $@") @@ -161,6 +161,12 @@ class EnvModule(object): # Environment modifications guessed by inspecting the installation prefix env = inspect_path(self.spec.prefix) + + # Let the extendee modify their extensions before asking for package-specific modifications + for extendee in self.pkg.extendees: + extendee_spec = self.spec[extendee] + extendee_spec.package.modify_module(self.pkg, extendee_spec, self.spec) + # Package-specific environment modifications self.spec.package.setup_environment(env) # TODO : implement site-specific modifications and filters diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index 185e3ad2ee..72c84ec624 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -1261,16 +1261,6 @@ class Package(object): """Get the rpath args as a string, with -Wl,-rpath, for each element.""" return " ".join("-Wl,-rpath,%s" % p for p in self.rpath) - -class PythonExtension(Package): - def setup_dependent_environment(self, env, dependent_spec): - pass - - def setup_environment(self, env): - site_packages = glob.glob(join_path(self.spec.prefix.lib, "python*/site-packages")) - if site_packages: - env.prepend_path('PYTHONPATH', site_packages[0]) - def validate_package_url(url_string): """Determine whether spack can handle a particular URL or not.""" url = urlparse(url_string) diff --git a/var/spack/repos/builtin/packages/py-nose/package.py b/var/spack/repos/builtin/packages/py-nose/package.py index e817b8eb51..4fee99098e 100644 --- a/var/spack/repos/builtin/packages/py-nose/package.py +++ b/var/spack/repos/builtin/packages/py-nose/package.py @@ -1,12 +1,12 @@ from spack import * -from spack.package import PythonExtension -class PyNose(PythonExtension): + +class PyNose(Package): """nose extends the test loading and running features of unittest, making it easier to write, find and run tests.""" homepage = "https://pypi.python.org/pypi/nose" - url = "https://pypi.python.org/packages/source/n/nose/nose-1.3.4.tar.gz" + url = "https://pypi.python.org/packages/source/n/nose/nose-1.3.4.tar.gz" version('1.3.4', '6ed7169887580ddc9a8e16048d38274d') version('1.3.6', '0ca546d81ca8309080fc80cb389e7a16') diff --git a/var/spack/repos/builtin/packages/python/package.py b/var/spack/repos/builtin/packages/python/package.py index d46e1068b6..c445d26369 100644 --- a/var/spack/repos/builtin/packages/python/package.py +++ b/var/spack/repos/builtin/packages/python/package.py @@ -1,11 +1,14 @@ +import functools +import glob +import inspect import os import re from contextlib import closing -from llnl.util.lang import match_predicate -from spack.util.environment import * -from spack import * import spack +from llnl.util.lang import match_predicate +from spack import * +from spack.util.environment import * class Python(Package): @@ -111,6 +114,31 @@ class Python(Package): else: module.python = Executable(join_path(spec.prefix.bin, 'python')) + # The code below patches the any python extension to have good defaults for `setup_dependent_environment` and + # `setup_environment` only if the extension didn't override any of these functions explicitly. + def _setup_env(self, env): + site_packages = glob.glob(join_path(self.spec.prefix.lib, "python*/site-packages")) + if site_packages: + env.prepend_path('PYTHONPATH', site_packages[0]) + + def _setup_denv(self, env, extension_spec): + pass + + pkg_cls = type(ext_spec.package) # Retrieve the type we may want to patch + if 'python' in pkg_cls.extendees: + # List of overrides we are interested in + interesting_overrides = ['setup_environment', 'setup_dependent_environment'] + overrides_found = [ + (name, defining_cls) for name, _, defining_cls, _, in inspect.classify_class_attrs(pkg_cls) + if + name in interesting_overrides and # The attribute has the right name + issubclass(defining_cls, Package) and defining_cls is not Package # and is an actual override + ] + if not overrides_found: + # If no override were found go on patching + pkg_cls.setup_environment = functools.wraps(Package.setup_environment)(_setup_env) + pkg_cls.setup_dependent_environment = functools.wraps(Package.setup_dependent_environment)(_setup_denv) + # Add variables for lib/pythonX.Y and lib/pythonX.Y/site-packages dirs. module.python_lib_dir = os.path.join(ext_spec.prefix, self.python_lib_dir) module.python_include_dir = os.path.join(ext_spec.prefix, self.python_include_dir) -- cgit v1.2.3-70-g09d2 From 67ca2c704b9c367b41ce29342a06427e156a30e9 Mon Sep 17 00:00:00 2001 From: alalazo Date: Fri, 18 Mar 2016 15:18:26 +0100 Subject: modules : fixed bug in `modify_module` arguments --- lib/spack/spack/modules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/spack/spack/modules.py b/lib/spack/spack/modules.py index 7303844229..f5bf213845 100644 --- a/lib/spack/spack/modules.py +++ b/lib/spack/spack/modules.py @@ -165,7 +165,7 @@ class EnvModule(object): # Let the extendee modify their extensions before asking for package-specific modifications for extendee in self.pkg.extendees: extendee_spec = self.spec[extendee] - extendee_spec.package.modify_module(self.pkg, extendee_spec, self.spec) + extendee_spec.package.modify_module(self.pkg.module, extendee_spec, self.spec) # Package-specific environment modifications self.spec.package.setup_environment(env) -- cgit v1.2.3-70-g09d2 From ccd90df62ffd69b5c3b4e1f8dbaf82146721a52a Mon Sep 17 00:00:00 2001 From: alalazo Date: Fri, 18 Mar 2016 15:41:14 +0100 Subject: modules : turned category into a property (logic can be extended later) --- lib/spack/spack/modules.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/modules.py b/lib/spack/spack/modules.py index f5bf213845..bb1a444e5a 100644 --- a/lib/spack/spack/modules.py +++ b/lib/spack/spack/modules.py @@ -122,10 +122,6 @@ class EnvModule(object): self.spec = spec self.pkg = spec.package # Just stored for convenience - # category in the modules system - # TODO: come up with smarter category names. - self.category = "spack" - # short description default is just the package + version # packages can provide this optional attribute self.short_description = spec.format("$_ $@") @@ -137,6 +133,17 @@ class EnvModule(object): if self.spec.package.__doc__: self.long_description = re.sub(r'\s+', ' ', self.spec.package.__doc__) + @property + def category(self): + # Anything defined at the package level takes precedence + if hasattr(self.pkg, 'category'): + return self.pkg.category + # Extensions + for extendee in self.pkg.extendees: + return '{extendee} extension'.format(extendee=extendee) + # Not very descriptive fallback + return 'spack installed package' + # @property # def paths(self): # # Add python path unless it's an actual python installation -- cgit v1.2.3-70-g09d2 From 1e468c55414822365b4ba7f7c52fbfdb5f30d3b2 Mon Sep 17 00:00:00 2001 From: alalazo Date: Fri, 18 Mar 2016 16:02:44 +0100 Subject: modules : added formats mapping --- lib/spack/spack/modules.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/spack/spack/modules.py b/lib/spack/spack/modules.py index bb1a444e5a..0378110c8c 100644 --- a/lib/spack/spack/modules.py +++ b/lib/spack/spack/modules.py @@ -256,7 +256,10 @@ class TclModule(EnvModule): formats = { PrependPath: 'prepend-path {name} \"{value}\"\n', - SetEnv: 'setenv {name} \"{value}\"\n' + AppendPath: 'append-path {name} \"{value}\"\n', + RemovePath: 'remove-path {name} \"{value}\"\n', + SetEnv: 'setenv {name} \"{value}\"\n', + UnsetEnv: 'unsetenv {name}\n' } @property -- cgit v1.2.3-70-g09d2 From 491babd5cd435fc307b6e977b850e4e64d2b0ccf Mon Sep 17 00:00:00 2001 From: alalazo Date: Fri, 18 Mar 2016 17:09:20 +0100 Subject: env modifications : added a validation rule --- lib/spack/spack/build_environment.py | 6 +++--- lib/spack/spack/environment.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py index c51fa58477..59b234624c 100644 --- a/lib/spack/spack/build_environment.py +++ b/lib/spack/spack/build_environment.py @@ -34,8 +34,9 @@ import shutil import sys import spack +import llnl.util.tty as tty from llnl.util.filesystem import * -from spack.environment import EnvironmentModifications, concatenate_paths +from spack.environment import EnvironmentModifications, concatenate_paths, validate from spack.util.environment import * from spack.util.executable import Executable, which @@ -288,8 +289,7 @@ def setup_package(pkg): # Allow dependencies to set up environment as well for dependency_spec in pkg.spec.traverse(root=False): dependency_spec.package.setup_dependent_environment(env, pkg.spec) - # TODO : implement validation - #validate(env) + validate(env, tty.warn) env.apply_modifications() diff --git a/lib/spack/spack/environment.py b/lib/spack/spack/environment.py index 6d214595a3..74aef57fe8 100644 --- a/lib/spack/spack/environment.py +++ b/lib/spack/spack/environment.py @@ -202,3 +202,33 @@ def concatenate_paths(paths): string """ return ':'.join(str(item) for item in paths) + + +def set_or_unset_not_first(variable, changes, errstream): + """ + Check if we are going to set or unset something after other modifications have already been requested + """ + indexes = [ii for ii, item in enumerate(changes) if ii != 0 and type(item) in [SetEnv, UnsetEnv]] + if indexes: + good = '\t \t{context} at {filename}:{lineno}' + nogood = '\t--->\t{context} at {filename}:{lineno}' + errstream('Suspicious requests to set or unset the variable \'{var}\' found'.format(var=variable)) + for ii, item in enumerate(changes): + print_format = nogood if ii in indexes else good + errstream(print_format.format(**item.args)) + + +def validate(env, errstream): + """ + Validates the environment modifications to check for the presence of suspicious patterns. Prompts a warning for + everything that was found + + Current checks: + - set or unset variables after other changes on the same variable + + Args: + env: list of environment modifications + """ + modifications = env.group_by_name() + for variable, list_of_changes in sorted(modifications.items()): + set_or_unset_not_first(variable, list_of_changes, errstream) -- cgit v1.2.3-70-g09d2 From 23f3f1adfe01f7b1301959e7e54584724679c7b3 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Fri, 18 Mar 2016 13:32:37 -0700 Subject: Make InstallError and ExternalPackageError visiible in packages. --- lib/spack/spack/__init__.py | 8 ++++++-- lib/spack/spack/package.py | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/__init__.py b/lib/spack/spack/__init__.py index 0ba42bbbfc..aee11f061f 100644 --- a/lib/spack/spack/__init__.py +++ b/lib/spack/spack/__init__.py @@ -189,5 +189,9 @@ import spack.util.executable from spack.util.executable import * __all__ += spack.util.executable.__all__ -from spack.package import install_dependency_symlinks, flatten_dependencies, DependencyConflictError -__all__ += ['install_dependency_symlinks', 'flatten_dependencies', 'DependencyConflictError'] +from spack.package import \ + install_dependency_symlinks, flatten_dependencies, DependencyConflictError, \ + InstallError, ExternalPackageError +__all__ += [ + 'install_dependency_symlinks', 'flatten_dependencies', 'DependencyConflictError', + 'InstallError', 'ExternalPackageError'] diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index b488e4c49d..dafad0b184 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -1351,6 +1351,10 @@ class InstallError(spack.error.SpackError): super(InstallError, self).__init__(message, long_msg) +class ExternalPackageError(InstallError): + """Raised by install() when a package is only for external use.""" + + class PackageStillNeededError(InstallError): """Raised when package is still needed by another on uninstall.""" def __init__(self, spec, dependents): -- cgit v1.2.3-70-g09d2 From e9126baaabbfaa5e12641b3d44a5c5fd49e43ca3 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Fri, 18 Mar 2016 13:42:45 -0700 Subject: Add docs for InstallError. --- lib/spack/docs/packaging_guide.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'lib') diff --git a/lib/spack/docs/packaging_guide.rst b/lib/spack/docs/packaging_guide.rst index c1077e4497..519c0da232 100644 --- a/lib/spack/docs/packaging_guide.rst +++ b/lib/spack/docs/packaging_guide.rst @@ -1844,6 +1844,20 @@ dedicated process. .. _prefix-objects: + +Failing the build +---------------------- + +Sometimes you don't want a package to successfully install unless some +condition is true. You can explicitly cause the build to fail from +``install()`` by raising an ``InstallError``, for example: + +.. code-block:: python + + if spec.architecture.startswith('darwin'): + raise InstallError('This package does not build on Mac OS X!') + + Prefix objects ---------------------- -- cgit v1.2.3-70-g09d2 From aef6d50b08daf893174046ba14c09a7019fe1212 Mon Sep 17 00:00:00 2001 From: alalazo Date: Mon, 21 Mar 2016 09:23:25 +0100 Subject: uninstall : fixed typo (print statement vs. print function) --- lib/spack/spack/cmd/uninstall.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/cmd/uninstall.py b/lib/spack/spack/cmd/uninstall.py index 2fab8f6f2a..1ece838612 100644 --- a/lib/spack/spack/cmd/uninstall.py +++ b/lib/spack/spack/cmd/uninstall.py @@ -96,9 +96,9 @@ def uninstall(parser, args): pkg.do_uninstall(force=args.force) except PackageStillNeededError as e: tty.error("Will not uninstall %s" % e.spec.format("$_$@$%@$#", color=True)) - print() + print('') print("The following packages depend on it:") display_specs(e.dependents, long=True) - print() + print('') print("You can use spack uninstall -f to force this action.") sys.exit(1) -- cgit v1.2.3-70-g09d2 From b79fce76cb4d412cf718b48b05d549470e4c55ab Mon Sep 17 00:00:00 2001 From: Matthew LeGendre Date: Mon, 21 Mar 2016 14:28:07 -0700 Subject: Fix issue 573 where Spack was ignoring user's compiler preference in concretization --- lib/spack/spack/concretize.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/concretize.py b/lib/spack/spack/concretize.py index 8083f91982..2e576743ec 100644 --- a/lib/spack/spack/concretize.py +++ b/lib/spack/spack/concretize.py @@ -241,7 +241,7 @@ class DefaultConcretizer(object): return False #Find the another spec that has a compiler, or the root if none do - other_spec = find_spec(spec, lambda(x) : x.compiler) + other_spec = spec if spec.compiler else find_spec(spec, lambda(x) : x.compiler) if not other_spec: other_spec = spec.root other_compiler = other_spec.compiler @@ -288,7 +288,7 @@ def find_spec(spec, condition): if condition(spec): return spec - return None # Nohting matched the condition. + return None # Nothing matched the condition. def cmp_specs(lhs, rhs): -- cgit v1.2.3-70-g09d2 From 5d06daeb5eed28b4b91ba62a8f99165d87b5ef86 Mon Sep 17 00:00:00 2001 From: Matthew LeGendre Date: Mon, 21 Mar 2016 14:28:34 -0700 Subject: Add test for issue 573, child with compiler not respected in concretization --- lib/spack/spack/test/concretize.py | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'lib') diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py index f264faf17a..08cce09674 100644 --- a/lib/spack/spack/test/concretize.py +++ b/lib/spack/spack/test/concretize.py @@ -309,3 +309,10 @@ class ConcretizeTest(MockPackagesTest): Spec('d')), Spec('e')) self.assertEqual(None, find_spec(s['b'], lambda s: '+foo' in s)) + + + def test_compiler_child(self): + s = Spec('mpileaks%clang ^dyninst%gcc') + s.concretize() + self.assertTrue(s['mpileaks'].satisfies('%clang')) + self.assertTrue(s['dyninst'].satisfies('%gcc')) -- cgit v1.2.3-70-g09d2 From 48b35bb495bc154c64d23d1ad364506c4572b913 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Mon, 21 Mar 2016 00:11:18 -0700 Subject: Fix print function in uninstall.py --- lib/spack/spack/cmd/uninstall.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/cmd/uninstall.py b/lib/spack/spack/cmd/uninstall.py index 1ece838612..350ef372cb 100644 --- a/lib/spack/spack/cmd/uninstall.py +++ b/lib/spack/spack/cmd/uninstall.py @@ -22,6 +22,7 @@ # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ############################################################################## +from __future__ import print_function import sys import argparse @@ -63,12 +64,12 @@ def uninstall(parser, args): matching_specs = spack.installed_db.query(spec) if not args.all and len(matching_specs) > 1: tty.error("%s matches multiple packages:" % spec) - print + print() display_specs(matching_specs, long=True) - print - print "You can either:" - print " a) Use a more specific spec, or" - print " b) use spack uninstall -a to uninstall ALL matching specs." + print() + print("You can either:") + print(" a) Use a more specific spec, or") + print(" b) use spack uninstall -a to uninstall ALL matching specs.") sys.exit(1) if len(matching_specs) == 0: -- cgit v1.2.3-70-g09d2 From e88df95b42fdcaa49552811853f8ca4ecc52cf9f Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Mon, 21 Mar 2016 00:35:13 -0700 Subject: Remove unused code from modules.py --- lib/spack/spack/modules.py | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/modules.py b/lib/spack/spack/modules.py index 0378110c8c..4e98d50001 100644 --- a/lib/spack/spack/modules.py +++ b/lib/spack/spack/modules.py @@ -133,6 +133,7 @@ class EnvModule(object): if self.spec.package.__doc__: self.long_description = re.sub(r'\s+', ' ', self.spec.package.__doc__) + @property def category(self): # Anything defined at the package level takes precedence @@ -144,21 +145,6 @@ class EnvModule(object): # Not very descriptive fallback return 'spack installed package' - # @property - # def paths(self): - # # Add python path unless it's an actual python installation - # # TODO : is there a better way to do this? - # # FIXME : add PYTHONPATH to every python package - # if self.spec.name != 'python': - # site_packages = glob(join_path(self.spec.prefix.lib, "python*/site-packages")) - # if site_packages: - # add_path('PYTHONPATH', site_packages[0]) - # - # # FIXME : Same for GEM_PATH - # if self.spec.package.extends(spack.spec.Spec('ruby')): - # add_path('GEM_PATH', self.spec.prefix) - # - # return self._paths def write(self): """Write out a module file for this object.""" @@ -166,16 +152,20 @@ class EnvModule(object): if not os.path.exists(module_dir): mkdirp(module_dir) - # Environment modifications guessed by inspecting the installation prefix + # Environment modifications guessed by inspecting the + # installation prefix env = inspect_path(self.spec.prefix) - # Let the extendee modify their extensions before asking for package-specific modifications + # Let the extendee modify their extensions before asking for + # package-specific modifications for extendee in self.pkg.extendees: extendee_spec = self.spec[extendee] - extendee_spec.package.modify_module(self.pkg.module, extendee_spec, self.spec) + extendee_spec.package.modify_module( + self.pkg.module, extendee_spec, self.spec) # Package-specific environment modifications self.spec.package.setup_environment(env) + # TODO : implement site-specific modifications and filters if not env: return @@ -232,7 +222,7 @@ class Dotkit(EnvModule): def use_name(self): return "%s-%s-%s-%s-%s" % (self.spec.name, self.spec.version, self.spec.compiler.name, - self.spec.compiler.version, + self.spec.compiler.version, self.spec.dag_hash()) def write_header(self, dk_file): @@ -270,7 +260,7 @@ class TclModule(EnvModule): def use_name(self): return "%s-%s-%s-%s-%s" % (self.spec.name, self.spec.version, self.spec.compiler.name, - self.spec.compiler.version, + self.spec.compiler.version, self.spec.dag_hash()) def write_header(self, module_file): -- cgit v1.2.3-70-g09d2 From 439d47b4e45c674ab9aa4ebd0c2bfaf6911ade60 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Mon, 21 Mar 2016 01:48:18 -0700 Subject: Refactor environment setup. - Gave setup_environment and setup_dependent_environment more similar signatures. They now allows editing the Spack env and the runtime env for *this* package and dependents, respectively. - modify_module renamed to setup_dependent_python_module for symmetry with setup_dependent_environment and to avoid confusion with environment modules. - removed need for patching Package objects at runtime. - adjust packages to reflect these changes. --- lib/spack/spack/build_environment.py | 35 +++--- lib/spack/spack/modules.py | 3 +- lib/spack/spack/package.py | 120 ++++++++++++++++----- var/spack/repos/builtin/packages/mpich/package.py | 9 +- .../builtin/packages/netlib-scalapack/package.py | 2 +- .../repos/builtin/packages/openmpi/package.py | 18 ++-- var/spack/repos/builtin/packages/python/package.py | 39 ++----- var/spack/repos/builtin/packages/qt/package.py | 10 +- var/spack/repos/builtin/packages/ruby/package.py | 12 +-- 9 files changed, 151 insertions(+), 97 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py index 59b234624c..5688d47e2d 100644 --- a/lib/spack/spack/build_environment.py +++ b/lib/spack/spack/build_environment.py @@ -84,7 +84,7 @@ class MakeExecutable(Executable): return super(MakeExecutable, self).__call__(*args, **kwargs) -def set_compiler_environment_variables(pkg): +def set_compiler_environment_variables(pkg, env): assert pkg.spec.concrete # Set compiler variables used by CMake and autotools assert all(key in pkg.compiler.link_paths for key in ('cc', 'cxx', 'f77', 'fc')) @@ -92,7 +92,6 @@ def set_compiler_environment_variables(pkg): # Populate an object with the list of environment modifications # and return it # TODO : add additional kwargs for better diagnostics, like requestor, ttyout, ttyerr, etc. - env = EnvironmentModifications() link_dir = spack.build_env_path env.set_env('CC', join_path(link_dir, pkg.compiler.link_paths['cc'])) env.set_env('CXX', join_path(link_dir, pkg.compiler.link_paths['cxx'])) @@ -113,7 +112,7 @@ def set_compiler_environment_variables(pkg): return env -def set_build_environment_variables(pkg): +def set_build_environment_variables(pkg, env): """ This ensures a clean install environment when we build packages """ @@ -134,7 +133,6 @@ def set_build_environment_variables(pkg): if os.path.isdir(ci): env_paths.append(ci) - env = EnvironmentModifications() for item in reversed(env_paths): env.prepend_path('PATH', item) env.set_env(SPACK_ENV_PATH, concatenate_paths(env_paths)) @@ -180,7 +178,7 @@ def set_build_environment_variables(pkg): return env -def set_module_variables_for_package(pkg, m): +def set_module_variables_for_package(pkg, module): """Populate the module scope of install() with some useful functions. This makes things easier for package writers. """ @@ -190,6 +188,8 @@ def set_module_variables_for_package(pkg, m): jobs = 1 elif pkg.make_jobs: jobs = pkg.make_jobs + + m = module m.make_jobs = jobs # TODO: make these build deps that can be installed if not found. @@ -271,9 +271,12 @@ def parent_class_modules(cls): def setup_package(pkg): """Execute all environment setup routines.""" - env = EnvironmentModifications() - env.extend(set_compiler_environment_variables(pkg)) - env.extend(set_build_environment_variables(pkg)) + spack_env = EnvironmentModifications() + run_env = EnvironmentModifications() + + set_compiler_environment_variables(pkg, spack_env) + set_build_environment_variables(pkg, spack_env) + # If a user makes their own package repo, e.g. # spack.repos.mystuff.libelf.Libelf, and they inherit from # an existing class like spack.repos.original.libelf.Libelf, @@ -285,12 +288,20 @@ def setup_package(pkg): # Allow dependencies to modify the module for dependency_spec in pkg.spec.traverse(root=False): - dependency_spec.package.modify_module(pkg.module, dependency_spec, pkg.spec) + dpkg = dependency_spec.package + dpkg.setup_dependent_python_module(pkg.module, pkg.spec) + # Allow dependencies to set up environment as well for dependency_spec in pkg.spec.traverse(root=False): - dependency_spec.package.setup_dependent_environment(env, pkg.spec) - validate(env, tty.warn) - env.apply_modifications() + dpkg = dependency_spec.package + dpkg.setup_dependent_environment(spack_env, run_env, pkg.spec) + + # Allow the package to apply some settings. + pkg.setup_environment(spack_env, run_env) + + # Make sure nothing's strange about the Spack environment. + validate(spack_env, tty.warn) + spack_env.apply_modifications() def fork(pkg, function): diff --git a/lib/spack/spack/modules.py b/lib/spack/spack/modules.py index 4e98d50001..05c93cd3e6 100644 --- a/lib/spack/spack/modules.py +++ b/lib/spack/spack/modules.py @@ -164,7 +164,8 @@ class EnvModule(object): self.pkg.module, extendee_spec, self.spec) # Package-specific environment modifications - self.spec.package.setup_environment(env) + spack_env = EnvironmentModifications() + self.spec.package.setup_environment(spack_env, env) # TODO : implement site-specific modifications and filters if not env: diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index acad5a28f6..9d8ac87bd7 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -1002,56 +1002,120 @@ class Package(object): return __import__(self.__class__.__module__, fromlist=[self.__class__.__name__]) - def setup_environment(self, env): - """ - Appends in `env` the list of environment modifications needed to use this package outside of spack. + def setup_environment(self, spack_env, run_env): + """Set up the compile and runtime environemnts for a package. - Default implementation does nothing, but this can be overridden if the package needs a particular environment. + `spack_env` and `run_env` are `EnvironmentModifications` + objects. Package authors can call methods on them to alter + the environment within Spack and at runtime. - Example : + Both `spack_env` and `run_env` are applied within the build + process, before this package's `install()` method is called. + + Modifications in `run_env` will *also* be added to the + generated environment modules for this package. + + Default implementation does nothing, but this can be + overridden if the package needs a particular environment. - 1. A lot of Qt extensions need `QTDIR` set. This can be used to do that. + Examples: + + 1. Qt extensions need `QTDIR` set. Args: - env: list of environment modifications to be updated + spack_env (EnvironmentModifications): list of + modifications to be applied when this package is built + within Spack. + + run_env (EnvironmentModifications): list of environment + changes to be applied when this package is run outside + of Spack. + """ pass - def setup_dependent_environment(self, env, dependent_spec): - """ - Called before the install() method of dependents. - Appends in `env` the list of environment modifications needed by dependents (or extensions) during the - installation of a package. The default implementation delegates to `setup_environment`, but can be overridden - if the modifications to the environment happen to be different from the one needed to use the package outside - of spack. + def setup_dependent_environment(self, spack_env, run_env, dependent_spec): + """Set up the environment of packages that depend on this one. + + This is similar to `setup_environment`, but it is used to + modify the compile and runtime environments of packages that + *depend* on this one. This gives packages like Python and + others that follow the extension model a way to implement + common environment or compile-time settings for dependencies. - This is useful if there are some common steps to installing all extensions for a certain package. + By default, this delegates to self.setup_environment() Example : - 1. Installing python modules generally requires `PYTHONPATH` to point to the lib/pythonX.Y/site-packages - directory in the module's install prefix. This could set that variable. + 1. Installing python modules generally requires + `PYTHONPATH` to point to the lib/pythonX.Y/site-packages + directory in the module's install prefix. This could + set that variable. Args: - env: list of environment modifications to be updated - dependent_spec: dependent (or extension) of this spec - """ - self.setup_environment(env) - def modify_module(self, module, spec, dependent_spec): + spack_env (EnvironmentModifications): list of + modifications to be applied when the dependent package + is bulit within Spack. + + run_env (EnvironmentModifications): list of environment + changes to be applied when the dependent package is + run outside of Spack. + + dependent_spec (Spec): The spec of the dependent package + about to be built. This allows the extendee (self) to + query the dependent's state. Note that *this* + package's spec is available as `self.spec`. + + This is useful if there are some common steps to installing + all extensions for a certain package. + """ + self.setup_environment(spack_env, run_env) + + + def setup_dependent_python_module(self, module, dependent_spec): + """Set up Python module-scope variables for dependent packages. + Called before the install() method of dependents. - Default implementation does nothing, but this can be overridden by an extendable package to set up the module of - its extensions. This is useful if there are some common steps to installing all extensions for a - certain package. + Default implementation does nothing, but this can be + overridden by an extendable package to set up the module of + its extensions. This is useful if there are some common steps + to installing all extensions for a certain package. Example : - 1. Extensions often need to invoke the 'python' interpreter from the Python installation being extended. - This routine can put a 'python' Executable object in the module scope for the extension package to simplify - extension installs. + 1. Extensions often need to invoke the `python` + interpreter from the Python installation being + extended. This routine can put a 'python' Executable + object in the module scope for the extension package to + simplify extension installs. + + 2. MPI compilers could set some variables in the + dependent's scope that point to `mpicc`, `mpicxx`, + etc., allowing them to be called by common names + regardless of which MPI is used. + + 3. BLAS/LAPACK implementations can set some variables + indicating the path to their libraries, since these + paths differ by BLAS/LAPACK implementation. + + Args: + + module (module): The Python `module` object of the + dependent package. Packages can use this to set + module-scope variables for the dependent to use. + + dependent_spec (Spec): The spec of the dependent package + about to be built. This allows the extendee (self) to + query the dependent's state. Note that *this* + package's spec is available as `self.spec`. + + This is useful if there are some common steps to installing + all extensions for a certain package. + """ pass diff --git a/var/spack/repos/builtin/packages/mpich/package.py b/var/spack/repos/builtin/packages/mpich/package.py index 5af9b585ea..90b5d42eab 100644 --- a/var/spack/repos/builtin/packages/mpich/package.py +++ b/var/spack/repos/builtin/packages/mpich/package.py @@ -47,13 +47,6 @@ class Mpich(Package): provides('mpi@:3.0', when='@3:') provides('mpi@:1.3', when='@1:') - def setup_environment(self, env): - env.set_env('MPICH_CC', self.compiler.cc) - env.set_env('MPICH_CXX', self.compiler.cxx) - env.set_env('MPICH_F77', self.compiler.f77) - env.set_env('MPICH_F90', self.compiler.fc) - env.set_env('MPICH_FC', self.compiler.fc) - def setup_dependent_environment(self, env, dependent_spec): env.set_env('MPICH_CC', spack_cc) env.set_env('MPICH_CXX', spack_cxx) @@ -61,7 +54,7 @@ class Mpich(Package): env.set_env('MPICH_F90', spack_f90) env.set_env('MPICH_FC', spack_fc) - def modify_module(self, module, spec, dep_spec): + def setup_dependent_python_module(self, module, spec, dep_spec): """For dependencies, make mpicc's use spack wrapper.""" # FIXME : is this necessary ? Shouldn't this be part of a contract with MPI providers? module.mpicc = join_path(self.prefix.bin, 'mpicc') diff --git a/var/spack/repos/builtin/packages/netlib-scalapack/package.py b/var/spack/repos/builtin/packages/netlib-scalapack/package.py index 36f506f7cd..62abfcc48e 100644 --- a/var/spack/repos/builtin/packages/netlib-scalapack/package.py +++ b/var/spack/repos/builtin/packages/netlib-scalapack/package.py @@ -40,7 +40,7 @@ class NetlibScalapack(Package): make() make("install") - def modify_module(self, module, spec, dependent_spec): + def setup_dependent_python_module(self, module, spec, dependent_spec): lib_dsuffix = '.dylib' if sys.platform == 'darwin' else '.so' lib_suffix = lib_dsuffix if '+shared' in spec['scalapack'] else '.a' diff --git a/var/spack/repos/builtin/packages/openmpi/package.py b/var/spack/repos/builtin/packages/openmpi/package.py index 7783ca8766..c91a13e376 100644 --- a/var/spack/repos/builtin/packages/openmpi/package.py +++ b/var/spack/repos/builtin/packages/openmpi/package.py @@ -41,17 +41,13 @@ class Openmpi(Package): def url_for_version(self, version): return "http://www.open-mpi.org/software/ompi/v%s/downloads/openmpi-%s.tar.bz2" % (version.up_to(2), version) - def setup_environment(self, env): - env.set_env('OMPI_CC', self.compiler.cc) - env.set_env('OMPI_CXX', self.compiler.cxx) - env.set_env('OMPI_FC', self.compiler.fc) - env.set_env('OMPI_F77', self.compiler.f77) - - def setup_dependent_environment(self, env, dependent_spec): - env.set_env('OMPI_CC', spack_cc) - env.set_env('OMPI_CXX', spack_cxx) - env.set_env('OMPI_FC', spack_fc) - env.set_env('OMPI_F77', spack_f77) + + def setup_dependent_environment(self, spack_env, run_env, dependent_spec): + spack_env.set_env('OMPI_CC', spack_cc) + spack_env.set_env('OMPI_CXX', spack_cxx) + spack_env.set_env('OMPI_FC', spack_fc) + spack_env.set_env('OMPI_F77', spack_f77) + def install(self, spec, prefix): config_args = ["--prefix=%s" % prefix, diff --git a/var/spack/repos/builtin/packages/python/package.py b/var/spack/repos/builtin/packages/python/package.py index c445d26369..593a27708c 100644 --- a/var/spack/repos/builtin/packages/python/package.py +++ b/var/spack/repos/builtin/packages/python/package.py @@ -92,13 +92,21 @@ class Python(Package): def site_packages_dir(self): return os.path.join(self.python_lib_dir, 'site-packages') - def setup_dependent_environment(self, env, extension_spec): - # Set PYTHONPATH to include site-packages dir for the extension and any other python extensions it depends on. + + def setup_dependent_environment(self, spack_env, run_env, extension_spec): + # TODO: do this only for actual extensions. + + # Set PYTHONPATH to include site-packages dir for the + # extension and any other python extensions it depends on. python_paths = [] for d in extension_spec.traverse(): if d.package.extends(self.spec): python_paths.append(os.path.join(d.prefix, self.site_packages_dir)) - env.set_env('PYTHONPATH', ':'.join(python_paths)) + + pythonpath = ':'.join(python_paths) + spack_env.set_env('PYTHONPATH', pythonpath) + run_env.set_env('PYTHONPATH', pythonpath) + def modify_module(self, module, spec, ext_spec): """ @@ -114,31 +122,6 @@ class Python(Package): else: module.python = Executable(join_path(spec.prefix.bin, 'python')) - # The code below patches the any python extension to have good defaults for `setup_dependent_environment` and - # `setup_environment` only if the extension didn't override any of these functions explicitly. - def _setup_env(self, env): - site_packages = glob.glob(join_path(self.spec.prefix.lib, "python*/site-packages")) - if site_packages: - env.prepend_path('PYTHONPATH', site_packages[0]) - - def _setup_denv(self, env, extension_spec): - pass - - pkg_cls = type(ext_spec.package) # Retrieve the type we may want to patch - if 'python' in pkg_cls.extendees: - # List of overrides we are interested in - interesting_overrides = ['setup_environment', 'setup_dependent_environment'] - overrides_found = [ - (name, defining_cls) for name, _, defining_cls, _, in inspect.classify_class_attrs(pkg_cls) - if - name in interesting_overrides and # The attribute has the right name - issubclass(defining_cls, Package) and defining_cls is not Package # and is an actual override - ] - if not overrides_found: - # If no override were found go on patching - pkg_cls.setup_environment = functools.wraps(Package.setup_environment)(_setup_env) - pkg_cls.setup_dependent_environment = functools.wraps(Package.setup_dependent_environment)(_setup_denv) - # Add variables for lib/pythonX.Y and lib/pythonX.Y/site-packages dirs. module.python_lib_dir = os.path.join(ext_spec.prefix, self.python_lib_dir) module.python_include_dir = os.path.join(ext_spec.prefix, self.python_include_dir) diff --git a/var/spack/repos/builtin/packages/qt/package.py b/var/spack/repos/builtin/packages/qt/package.py index 35b9d68462..039aeb3c31 100644 --- a/var/spack/repos/builtin/packages/qt/package.py +++ b/var/spack/repos/builtin/packages/qt/package.py @@ -55,8 +55,14 @@ class Qt(Package): depends_on("mesa", when='@4:+mesa') depends_on("libxcb") - def setup_environment(self, env): - env.set_env['QTDIR'] = self.prefix + + def setup_environment(self, spack_env, env): + env.set_env('QTDIR', self.prefix) + + + def setup_dependent_environment(self, spack_env, run_env, dspec): + spack_env.set_env('QTDIR', self.prefix) + def patch(self): if self.spec.satisfies('@4'): diff --git a/var/spack/repos/builtin/packages/ruby/package.py b/var/spack/repos/builtin/packages/ruby/package.py index 2d1da8c9af..39f65f51d2 100644 --- a/var/spack/repos/builtin/packages/ruby/package.py +++ b/var/spack/repos/builtin/packages/ruby/package.py @@ -2,7 +2,7 @@ from spack import * class Ruby(Package): - """A dynamic, open source programming language with a focus on + """A dynamic, open source programming language with a focus on simplicity and productivity.""" homepage = "https://www.ruby-lang.org/" @@ -17,15 +17,17 @@ class Ruby(Package): make() make("install") - def setup_dependent_environment(self, env, extension_spec): + def setup_dependent_environment(self, spack_env, run_env, extension_spec): + # TODO: do this only for actual extensions. # Set GEM_PATH to include dependent gem directories ruby_paths = [] for d in extension_spec.traverse(): if d.package.extends(self.spec): ruby_paths.append(d.prefix) - env.set_env('GEM_PATH', concatenate_paths(ruby_paths)) + + spack_env.set_env('GEM_PATH', concatenate_paths(ruby_paths)) # The actual installation path for this gem - env.set_env('GEM_HOME', extension_spec.prefix) + spack_env.set_env('GEM_HOME', extension_spec.prefix) def modify_module(self, module, spec, ext_spec): """Called before ruby modules' install() methods. Sets GEM_HOME @@ -38,5 +40,3 @@ class Ruby(Package): # Ruby extension builds have global ruby and gem functions module.ruby = Executable(join_path(spec.prefix.bin, 'ruby')) module.gem = Executable(join_path(spec.prefix.bin, 'gem')) - - -- cgit v1.2.3-70-g09d2 From b1516f64eb75c108eded1e9ee7e0480a4552236a Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Mon, 21 Mar 2016 02:21:31 -0700 Subject: Rename some environment methods to be less repetitive, add set_path. --- lib/spack/spack/build_environment.py | 45 +++++++++++----------- lib/spack/spack/environment.py | 22 ++++++++++- lib/spack/spack/test/environment.py | 22 +++++++---- var/spack/repos/builtin/packages/mpich/package.py | 10 ++--- .../repos/builtin/packages/openmpi/package.py | 8 ++-- var/spack/repos/builtin/packages/python/package.py | 4 +- var/spack/repos/builtin/packages/qt/package.py | 4 +- var/spack/repos/builtin/packages/ruby/package.py | 5 ++- 8 files changed, 73 insertions(+), 47 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py index 5688d47e2d..fc5b7d6207 100644 --- a/lib/spack/spack/build_environment.py +++ b/lib/spack/spack/build_environment.py @@ -36,7 +36,7 @@ import sys import spack import llnl.util.tty as tty from llnl.util.filesystem import * -from spack.environment import EnvironmentModifications, concatenate_paths, validate +from spack.environment import EnvironmentModifications, validate from spack.util.environment import * from spack.util.executable import Executable, which @@ -93,22 +93,23 @@ def set_compiler_environment_variables(pkg, env): # and return it # TODO : add additional kwargs for better diagnostics, like requestor, ttyout, ttyerr, etc. link_dir = spack.build_env_path - env.set_env('CC', join_path(link_dir, pkg.compiler.link_paths['cc'])) - env.set_env('CXX', join_path(link_dir, pkg.compiler.link_paths['cxx'])) - env.set_env('F77', join_path(link_dir, pkg.compiler.link_paths['f77'])) - env.set_env('FC', join_path(link_dir, pkg.compiler.link_paths['fc'])) + env.set('CC', join_path(link_dir, pkg.compiler.link_paths['cc'])) + env.set('CXX', join_path(link_dir, pkg.compiler.link_paths['cxx'])) + env.set('F77', join_path(link_dir, pkg.compiler.link_paths['f77'])) + env.set('FC', join_path(link_dir, pkg.compiler.link_paths['fc'])) + # Set SPACK compiler variables so that our wrapper knows what to call compiler = pkg.compiler if compiler.cc: - env.set_env('SPACK_CC', compiler.cc) + env.set('SPACK_CC', compiler.cc) if compiler.cxx: - env.set_env('SPACK_CXX', compiler.cxx) + env.set('SPACK_CXX', compiler.cxx) if compiler.f77: - env.set_env('SPACK_F77', compiler.f77) + env.set('SPACK_F77', compiler.f77) if compiler.fc: - env.set_env('SPACK_FC', compiler.fc) + env.set('SPACK_FC', compiler.fc) - env.set_env('SPACK_COMPILER_SPEC', str(pkg.spec.compiler)) + env.set('SPACK_COMPILER_SPEC', str(pkg.spec.compiler)) return env @@ -135,25 +136,25 @@ def set_build_environment_variables(pkg, env): for item in reversed(env_paths): env.prepend_path('PATH', item) - env.set_env(SPACK_ENV_PATH, concatenate_paths(env_paths)) + env.set_path(SPACK_ENV_PATH, env_paths) # Prefixes of all of the package's dependencies go in SPACK_DEPENDENCIES dep_prefixes = [d.prefix for d in pkg.spec.traverse(root=False)] - env.set_env(SPACK_DEPENDENCIES, concatenate_paths(dep_prefixes)) - env.set_env('CMAKE_PREFIX_PATH', concatenate_paths(dep_prefixes)) # Add dependencies to CMAKE_PREFIX_PATH + env.set_path(SPACK_DEPENDENCIES, dep_prefixes) + env.set_path('CMAKE_PREFIX_PATH', dep_prefixes) # Add dependencies to CMAKE_PREFIX_PATH # Install prefix - env.set_env(SPACK_PREFIX, pkg.prefix) + env.set(SPACK_PREFIX, pkg.prefix) # Install root prefix - env.set_env(SPACK_INSTALL, spack.install_path) + env.set(SPACK_INSTALL, spack.install_path) # Remove these vars from the environment during build because they # can affect how some packages find libraries. We want to make # sure that builds never pull in unintended external dependencies. - env.unset_env('LD_LIBRARY_PATH') - env.unset_env('LD_RUN_PATH') - env.unset_env('DYLD_LIBRARY_PATH') + env.unset('LD_LIBRARY_PATH') + env.unset('LD_RUN_PATH') + env.unset('DYLD_LIBRARY_PATH') # Add bin directories from dependencies to the PATH for the build. bin_dirs = reversed(filter(os.path.isdir, ['%s/bin' % prefix for prefix in dep_prefixes])) @@ -162,9 +163,9 @@ def set_build_environment_variables(pkg, env): # Working directory for the spack command itself, for debug logs. if spack.debug: - env.set_env(SPACK_DEBUG, 'TRUE') - env.set_env(SPACK_SHORT_SPEC, pkg.spec.short_spec) - env.set_env(SPACK_DEBUG_LOG_DIR, spack.spack_working_dir) + env.set(SPACK_DEBUG, 'TRUE') + env.set(SPACK_SHORT_SPEC, pkg.spec.short_spec) + env.set(SPACK_DEBUG_LOG_DIR, spack.spack_working_dir) # Add any pkgconfig directories to PKG_CONFIG_PATH pkg_config_dirs = [] @@ -173,7 +174,7 @@ def set_build_environment_variables(pkg, env): pcdir = join_path(p, libdir, 'pkgconfig') if os.path.isdir(pcdir): pkg_config_dirs.append(pcdir) - env.set_env('PKG_CONFIG_PATH', concatenate_paths(pkg_config_dirs)) + env.set_path('PKG_CONFIG_PATH', pkg_config_dirs) return env diff --git a/lib/spack/spack/environment.py b/lib/spack/spack/environment.py index 74aef57fe8..72aafa4e2d 100644 --- a/lib/spack/spack/environment.py +++ b/lib/spack/spack/environment.py @@ -29,6 +29,12 @@ class UnsetEnv(NameModifier): os.environ.pop(self.name, None) # Avoid throwing if the variable was not set +class SetPath(NameValueModifier): + def execute(self): + string_path = concatenate_paths(self.value) + os.environ[self.name] = string_path + + class AppendPath(NameValueModifier): def execute(self): environment_value = os.environ.get(self.name, '') @@ -103,7 +109,7 @@ class EnvironmentModifications(object): } return args - def set_env(self, name, value, **kwargs): + def set(self, name, value, **kwargs): """ Stores in the current object a request to set an environment variable @@ -115,7 +121,7 @@ class EnvironmentModifications(object): item = SetEnv(name, value, **kwargs) self.env_modifications.append(item) - def unset_env(self, name, **kwargs): + def unset(self, name, **kwargs): """ Stores in the current object a request to unset an environment variable @@ -126,6 +132,18 @@ class EnvironmentModifications(object): item = UnsetEnv(name, **kwargs) self.env_modifications.append(item) + def set_path(self, name, elts, **kwargs): + """ + Stores a request to set a path generated from a list. + + Args: + name: name o the environment variable to be set. + elts: elements of the path to set. + """ + kwargs.update(self._get_outside_caller_attributes()) + item = SetPath(name, elts, **kwargs) + self.env_modifications.append(item) + def append_path(self, name, path, **kwargs): """ Stores in the current object a request to append a path to a path list diff --git a/lib/spack/spack/test/environment.py b/lib/spack/spack/test/environment.py index 3e03760c01..6c8f5ea43c 100644 --- a/lib/spack/spack/test/environment.py +++ b/lib/spack/spack/test/environment.py @@ -11,21 +11,27 @@ class EnvironmentTest(unittest.TestCase): os.environ['PATH_LIST'] = '/path/second:/path/third' os.environ['REMOVE_PATH_LIST'] = '/a/b:/duplicate:/a/c:/remove/this:/a/d:/duplicate/:/f/g' - def test_set_env(self): + def test_set(self): env = EnvironmentModifications() - env.set_env('A', 'dummy value') - env.set_env('B', 3) + env.set('A', 'dummy value') + env.set('B', 3) env.apply_modifications() self.assertEqual('dummy value', os.environ['A']) self.assertEqual(str(3), os.environ['B']) - def test_unset_env(self): + def test_unset(self): env = EnvironmentModifications() self.assertEqual('foo', os.environ['UNSET_ME']) - env.unset_env('UNSET_ME') + env.unset('UNSET_ME') env.apply_modifications() self.assertRaises(KeyError, os.environ.__getitem__, 'UNSET_ME') + def test_set_path(self): + env = EnvironmentModifications() + env.set_path('A', ['foo', 'bar', 'baz']) + env.apply_modifications() + self.assertEqual('foo:bar:baz', os.environ['A']) + def test_path_manipulation(self): env = EnvironmentModifications() @@ -51,7 +57,7 @@ class EnvironmentTest(unittest.TestCase): def test_extra_arguments(self): env = EnvironmentModifications() - env.set_env('A', 'dummy value', who='Pkg1') + env.set('A', 'dummy value', who='Pkg1') for x in env: assert 'who' in x.args env.apply_modifications() @@ -59,8 +65,8 @@ class EnvironmentTest(unittest.TestCase): def test_extend(self): env = EnvironmentModifications() - env.set_env('A', 'dummy value') - env.set_env('B', 3) + env.set('A', 'dummy value') + env.set('B', 3) copy_construct = EnvironmentModifications(env) self.assertEqual(len(copy_construct), 2) for x, y in zip(env, copy_construct): diff --git a/var/spack/repos/builtin/packages/mpich/package.py b/var/spack/repos/builtin/packages/mpich/package.py index 90b5d42eab..c4d9940bb7 100644 --- a/var/spack/repos/builtin/packages/mpich/package.py +++ b/var/spack/repos/builtin/packages/mpich/package.py @@ -48,11 +48,11 @@ class Mpich(Package): provides('mpi@:1.3', when='@1:') def setup_dependent_environment(self, env, dependent_spec): - env.set_env('MPICH_CC', spack_cc) - env.set_env('MPICH_CXX', spack_cxx) - env.set_env('MPICH_F77', spack_f77) - env.set_env('MPICH_F90', spack_f90) - env.set_env('MPICH_FC', spack_fc) + env.set('MPICH_CC', spack_cc) + env.set('MPICH_CXX', spack_cxx) + env.set('MPICH_F77', spack_f77) + env.set('MPICH_F90', spack_f90) + env.set('MPICH_FC', spack_fc) def setup_dependent_python_module(self, module, spec, dep_spec): """For dependencies, make mpicc's use spack wrapper.""" diff --git a/var/spack/repos/builtin/packages/openmpi/package.py b/var/spack/repos/builtin/packages/openmpi/package.py index c91a13e376..9a127f1812 100644 --- a/var/spack/repos/builtin/packages/openmpi/package.py +++ b/var/spack/repos/builtin/packages/openmpi/package.py @@ -43,10 +43,10 @@ class Openmpi(Package): def setup_dependent_environment(self, spack_env, run_env, dependent_spec): - spack_env.set_env('OMPI_CC', spack_cc) - spack_env.set_env('OMPI_CXX', spack_cxx) - spack_env.set_env('OMPI_FC', spack_fc) - spack_env.set_env('OMPI_F77', spack_f77) + spack_env.set('OMPI_CC', spack_cc) + spack_env.set('OMPI_CXX', spack_cxx) + spack_env.set('OMPI_FC', spack_fc) + spack_env.set('OMPI_F77', spack_f77) def install(self, spec, prefix): diff --git a/var/spack/repos/builtin/packages/python/package.py b/var/spack/repos/builtin/packages/python/package.py index 593a27708c..4f55bc803e 100644 --- a/var/spack/repos/builtin/packages/python/package.py +++ b/var/spack/repos/builtin/packages/python/package.py @@ -104,8 +104,8 @@ class Python(Package): python_paths.append(os.path.join(d.prefix, self.site_packages_dir)) pythonpath = ':'.join(python_paths) - spack_env.set_env('PYTHONPATH', pythonpath) - run_env.set_env('PYTHONPATH', pythonpath) + spack_env.set('PYTHONPATH', pythonpath) + run_env.set('PYTHONPATH', pythonpath) def modify_module(self, module, spec, ext_spec): diff --git a/var/spack/repos/builtin/packages/qt/package.py b/var/spack/repos/builtin/packages/qt/package.py index 039aeb3c31..d08e8e81e1 100644 --- a/var/spack/repos/builtin/packages/qt/package.py +++ b/var/spack/repos/builtin/packages/qt/package.py @@ -57,11 +57,11 @@ class Qt(Package): def setup_environment(self, spack_env, env): - env.set_env('QTDIR', self.prefix) + env.set('QTDIR', self.prefix) def setup_dependent_environment(self, spack_env, run_env, dspec): - spack_env.set_env('QTDIR', self.prefix) + spack_env.set('QTDIR', self.prefix) def patch(self): diff --git a/var/spack/repos/builtin/packages/ruby/package.py b/var/spack/repos/builtin/packages/ruby/package.py index 39f65f51d2..7ff1898ce9 100644 --- a/var/spack/repos/builtin/packages/ruby/package.py +++ b/var/spack/repos/builtin/packages/ruby/package.py @@ -25,9 +25,10 @@ class Ruby(Package): if d.package.extends(self.spec): ruby_paths.append(d.prefix) - spack_env.set_env('GEM_PATH', concatenate_paths(ruby_paths)) + spack_env.set_path('GEM_PATH', ruby_paths) + # The actual installation path for this gem - spack_env.set_env('GEM_HOME', extension_spec.prefix) + spack_env.set('GEM_HOME', extension_spec.prefix) def modify_module(self, module, spec, ext_spec): """Called before ruby modules' install() methods. Sets GEM_HOME -- cgit v1.2.3-70-g09d2 From a26992ef55fed958c15b45b989fc0a4d57f02251 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Tue, 22 Mar 2016 01:56:16 -0700 Subject: Change from PR #552: rename setup_dependent_python_module -> setup_dependent_package - Fixed in package.py - Fixed wrong prototypes in packages that use it. - Fixed build_environment to set module variables properly - added hacky fix to ensure spec/package consistency in build processes. - Need to think about defensive spec copy done by `Repo.get`. May be time to think about an immutable spec implementation. --- lib/spack/spack/build_environment.py | 52 ++++++++++++++++------ lib/spack/spack/package.py | 2 +- var/spack/repos/builtin/packages/mpich/package.py | 2 +- .../builtin/packages/netlib-scalapack/package.py | 22 ++++----- 4 files changed, 52 insertions(+), 26 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py index fc5b7d6207..119a255a34 100644 --- a/lib/spack/spack/build_environment.py +++ b/lib/spack/spack/build_environment.py @@ -225,7 +225,7 @@ def set_module_variables_for_package(pkg, module): m.spack_cc = join_path(link_dir, pkg.compiler.link_paths['cc']) m.spack_cxx = join_path(link_dir, pkg.compiler.link_paths['cxx']) m.spack_f77 = join_path(link_dir, pkg.compiler.link_paths['f77']) - m.spack_f90 = join_path(link_dir, pkg.compiler.link_paths['fc']) + m.spack_fc = join_path(link_dir, pkg.compiler.link_paths['fc']) # Emulate some shell commands for convenience m.pwd = os.getcwd @@ -270,32 +270,56 @@ def parent_class_modules(cls): return result +def setup_module_variables_for_dag(pkg): + """Set module-scope variables for all packages in the DAG.""" + for spec in pkg.spec.traverse(order='post'): + # If a user makes their own package repo, e.g. + # spack.repos.mystuff.libelf.Libelf, and they inherit from + # an existing class like spack.repos.original.libelf.Libelf, + # then set the module variables for both classes so the + # parent class can still use them if it gets called. + spkg = spec.package + modules = parent_class_modules(spkg.__class__) + for mod in modules: + set_module_variables_for_package(spkg, mod) + set_module_variables_for_package(spkg, spkg.module) + + def setup_package(pkg): """Execute all environment setup routines.""" spack_env = EnvironmentModifications() run_env = EnvironmentModifications() + # Before proceeding, ensure that specs and packages are consistent + # + # This is a confusing behavior due to how packages are + # constructed. `setup_dependent_package` may set attributes on + # specs in the DAG for use by other packages' install + # method. However, spec.package will look up a package via + # spack.repo, which defensively copies specs into packages. This + # code ensures that all packages in the DAG have pieces of the + # same spec object at build time. + # + # This is safe for the build process, b/c the build process is a + # throwaway environment, but it is kind of dirty. + # + # TODO: Think about how to avoid this fix and do something cleaner. + for s in pkg.spec.traverse(): s.package.spec = s + set_compiler_environment_variables(pkg, spack_env) set_build_environment_variables(pkg, spack_env) - - # If a user makes their own package repo, e.g. - # spack.repos.mystuff.libelf.Libelf, and they inherit from - # an existing class like spack.repos.original.libelf.Libelf, - # then set the module variables for both classes so the - # parent class can still use them if it gets called. - modules = parent_class_modules(pkg.__class__) - for mod in modules: - set_module_variables_for_package(pkg, mod) + setup_module_variables_for_dag(pkg) # Allow dependencies to modify the module - for dependency_spec in pkg.spec.traverse(root=False): + spec = pkg.spec + for dependency_spec in spec.traverse(root=False): dpkg = dependency_spec.package - dpkg.setup_dependent_python_module(pkg.module, pkg.spec) + dpkg.setup_dependent_package(pkg.module, spec) # Allow dependencies to set up environment as well - for dependency_spec in pkg.spec.traverse(root=False): + for dependency_spec in spec.traverse(root=False): dpkg = dependency_spec.package - dpkg.setup_dependent_environment(spack_env, run_env, pkg.spec) + dpkg.setup_dependent_environment(spack_env, run_env, spec) # Allow the package to apply some settings. pkg.setup_environment(spack_env, run_env) diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index 9d8ac87bd7..9af3221837 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -1075,7 +1075,7 @@ class Package(object): self.setup_environment(spack_env, run_env) - def setup_dependent_python_module(self, module, dependent_spec): + def setup_dependent_package(self, module, dependent_spec): """Set up Python module-scope variables for dependent packages. Called before the install() method of dependents. diff --git a/var/spack/repos/builtin/packages/mpich/package.py b/var/spack/repos/builtin/packages/mpich/package.py index c4d9940bb7..b20dc8dd60 100644 --- a/var/spack/repos/builtin/packages/mpich/package.py +++ b/var/spack/repos/builtin/packages/mpich/package.py @@ -54,7 +54,7 @@ class Mpich(Package): env.set('MPICH_F90', spack_f90) env.set('MPICH_FC', spack_fc) - def setup_dependent_python_module(self, module, spec, dep_spec): + def setup_dependent_package(self, module, dep_spec): """For dependencies, make mpicc's use spack wrapper.""" # FIXME : is this necessary ? Shouldn't this be part of a contract with MPI providers? module.mpicc = join_path(self.prefix.bin, 'mpicc') diff --git a/var/spack/repos/builtin/packages/netlib-scalapack/package.py b/var/spack/repos/builtin/packages/netlib-scalapack/package.py index 62abfcc48e..c3e6822cdf 100644 --- a/var/spack/repos/builtin/packages/netlib-scalapack/package.py +++ b/var/spack/repos/builtin/packages/netlib-scalapack/package.py @@ -1,4 +1,5 @@ from spack import * +import sys class NetlibScalapack(Package): """ScaLAPACK is a library of high-performance linear algebra routines for parallel distributed memory machines""" @@ -11,16 +12,16 @@ class NetlibScalapack(Package): version('2.0.0', '9e76ae7b291be27faaad47cfc256cbfe') # versions before 2.0.0 are not using cmake and requires blacs as # a separated package - + variant('shared', default=True, description='Build the shared library version') variant('fpic', default=False, description="Build with -fpic compiler option") - + provides('scalapack') - + depends_on('mpi') depends_on('lapack') - - def install(self, spec, prefix): + + def install(self, spec, prefix): options = [ "-DBUILD_SHARED_LIBS:BOOL=%s" % ('ON' if '+shared' in spec else 'OFF'), "-DBUILD_STATIC_LIBS:BOOL=%s" % ('OFF' if '+shared' in spec else 'ON'), @@ -40,10 +41,11 @@ class NetlibScalapack(Package): make() make("install") - def setup_dependent_python_module(self, module, spec, dependent_spec): + def setup_dependent_package(self, module, dependent_spec): + spec = self.spec lib_dsuffix = '.dylib' if sys.platform == 'darwin' else '.so' - lib_suffix = lib_dsuffix if '+shared' in spec['scalapack'] else '.a' + lib_suffix = lib_dsuffix if '+shared' in spec else '.a' - spec['scalapack'].fc_link = '-L%s -lscalapack' % spec['scalapack'].prefix.lib - spec['scalapack'].cc_link = spec['scalapack'].fc_link - spec['scalapack'].libraries = [join_path(spec['scalapack'].prefix.lib, 'libscalapack%s' % lib_suffix)] + spec.fc_link = '-L%s -lscalapack' % spec.prefix.lib + spec.cc_link = spec.fc_link + spec.libraries = [join_path(spec.prefix.lib, 'libscalapack%s' % lib_suffix)] -- cgit v1.2.3-70-g09d2 From c4134ee71e43a6a2a38822e25cc72ca73efdcfea Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Wed, 23 Mar 2016 00:36:32 -0700 Subject: Fix #608: broken numpy build. - Failed to catch all instances of modify_module when it was renamed to setup_dependent_package. - Refactored remaining modify_module calls. - Also modified Python's setup_dependent_package slightly: only creates empty site-packages directory for Python extensions now, not for all dependents. --- lib/spack/spack/modules.py | 4 ++-- lib/spack/spack/preferred_packages.py | 4 +++- var/spack/repos/builtin/packages/python/package.py | 11 ++++++----- var/spack/repos/builtin/packages/ruby/package.py | 6 +++--- 4 files changed, 14 insertions(+), 11 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/modules.py b/lib/spack/spack/modules.py index 05c93cd3e6..8ed98e5d38 100644 --- a/lib/spack/spack/modules.py +++ b/lib/spack/spack/modules.py @@ -160,8 +160,8 @@ class EnvModule(object): # package-specific modifications for extendee in self.pkg.extendees: extendee_spec = self.spec[extendee] - extendee_spec.package.modify_module( - self.pkg.module, extendee_spec, self.spec) + extendee_spec.package.setup_dependent_package( + self.pkg.module, self.spec) # Package-specific environment modifications spack_env = EnvironmentModifications() diff --git a/lib/spack/spack/preferred_packages.py b/lib/spack/spack/preferred_packages.py index 4d8526c75f..f0a5382dc9 100644 --- a/lib/spack/spack/preferred_packages.py +++ b/lib/spack/spack/preferred_packages.py @@ -150,7 +150,9 @@ class PreferredPackages(object): def version_compare(self, pkgname, a, b): """Return less-than-0, 0, or greater than 0 if version a of pkgname is respecively less-than, equal-to, or greater-than version b of pkgname. - One version is less-than another if it is preferred over the other.""" + Versions marked 'preferred=True' in package.py take precedence over any + versions not marked preferred. + """ return self._spec_compare(pkgname, 'version', a, b, True, None) diff --git a/var/spack/repos/builtin/packages/python/package.py b/var/spack/repos/builtin/packages/python/package.py index 4f55bc803e..6d9030805b 100644 --- a/var/spack/repos/builtin/packages/python/package.py +++ b/var/spack/repos/builtin/packages/python/package.py @@ -108,7 +108,7 @@ class Python(Package): run_env.set('PYTHONPATH', pythonpath) - def modify_module(self, module, spec, ext_spec): + def setup_dependent_package(self, module, ext_spec): """ Called before python modules' install() methods. @@ -118,17 +118,18 @@ class Python(Package): """ # Python extension builds can have a global python executable function if self.version >= Version("3.0.0") and self.version < Version("4.0.0"): - module.python = Executable(join_path(spec.prefix.bin, 'python3')) + module.python = Executable(join_path(self.spec.prefix.bin, 'python3')) else: - module.python = Executable(join_path(spec.prefix.bin, 'python')) + module.python = Executable(join_path(self.spec.prefix.bin, 'python')) # Add variables for lib/pythonX.Y and lib/pythonX.Y/site-packages dirs. module.python_lib_dir = os.path.join(ext_spec.prefix, self.python_lib_dir) module.python_include_dir = os.path.join(ext_spec.prefix, self.python_include_dir) module.site_packages_dir = os.path.join(ext_spec.prefix, self.site_packages_dir) - # Make the site packages directory if it does not exist already. - mkdirp(module.site_packages_dir) + # Make the site packages directory for extensions, if it does not exist already. + if ext_spec.package.is_extension: + mkdirp(module.site_packages_dir) # ======================================================================== # Handle specifics of activating and deactivating python modules. diff --git a/var/spack/repos/builtin/packages/ruby/package.py b/var/spack/repos/builtin/packages/ruby/package.py index 7ff1898ce9..e13677e4d2 100644 --- a/var/spack/repos/builtin/packages/ruby/package.py +++ b/var/spack/repos/builtin/packages/ruby/package.py @@ -30,7 +30,7 @@ class Ruby(Package): # The actual installation path for this gem spack_env.set('GEM_HOME', extension_spec.prefix) - def modify_module(self, module, spec, ext_spec): + def setup_dependent_package(self, module, ext_spec): """Called before ruby modules' install() methods. Sets GEM_HOME and GEM_PATH to values appropriate for the package being built. @@ -39,5 +39,5 @@ class Ruby(Package): gem('install', '.gem') """ # Ruby extension builds have global ruby and gem functions - module.ruby = Executable(join_path(spec.prefix.bin, 'ruby')) - module.gem = Executable(join_path(spec.prefix.bin, 'gem')) + module.ruby = Executable(join_path(self.spec.prefix.bin, 'ruby')) + module.gem = Executable(join_path(self.spec.prefix.bin, 'gem')) -- cgit v1.2.3-70-g09d2 From 38350ae33d29e108803cebdf13b90b6898947328 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Wed, 23 Mar 2016 01:32:54 -0700 Subject: resurrect preferred=True option for packages lost in merge of externals support. - Pyton 2.7.11 is preferred again. --- lib/spack/spack/concretize.py | 4 ++++ lib/spack/spack/preferred_packages.py | 4 +--- lib/spack/spack/test/concretize.py | 9 +++++++++ 3 files changed, 14 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/concretize.py b/lib/spack/spack/concretize.py index 2e576743ec..ed9bf79868 100644 --- a/lib/spack/spack/concretize.py +++ b/lib/spack/spack/concretize.py @@ -159,6 +159,10 @@ class DefaultConcretizer(object): if any(v.satisfies(sv) for sv in spec.versions)], cmp=cmp_versions) + def prefer_key(v): + return pkg.versions.get(Version(v)).get('preferred', False) + valid_versions.sort(key=prefer_key, reverse=True) + if valid_versions: spec.versions = ver([valid_versions[0]]) else: diff --git a/lib/spack/spack/preferred_packages.py b/lib/spack/spack/preferred_packages.py index f0a5382dc9..4d8526c75f 100644 --- a/lib/spack/spack/preferred_packages.py +++ b/lib/spack/spack/preferred_packages.py @@ -150,9 +150,7 @@ class PreferredPackages(object): def version_compare(self, pkgname, a, b): """Return less-than-0, 0, or greater than 0 if version a of pkgname is respecively less-than, equal-to, or greater-than version b of pkgname. - Versions marked 'preferred=True' in package.py take precedence over any - versions not marked preferred. - """ + One version is less-than another if it is preferred over the other.""" return self._spec_compare(pkgname, 'version', a, b, True, None) diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py index 08cce09674..9cd8c969ae 100644 --- a/lib/spack/spack/test/concretize.py +++ b/lib/spack/spack/test/concretize.py @@ -24,6 +24,7 @@ ############################################################################## import spack from spack.spec import Spec, CompilerSpec +from spack.version import ver from spack.concretize import find_spec from spack.test.mock_packages_test import * @@ -77,6 +78,14 @@ class ConcretizeTest(MockPackagesTest): self.check_concretize('mpich') + def test_concretize_preferred_version(self): + spec = self.check_concretize('python') + self.assertEqual(spec.versions, ver('2.7.11')) + + spec = self.check_concretize('python@3.5.1') + self.assertEqual(spec.versions, ver('3.5.1')) + + def test_concretize_with_virtual(self): self.check_concretize('mpileaks ^mpi') self.check_concretize('mpileaks ^mpi@:1.1') -- cgit v1.2.3-70-g09d2 From 0fbdb3f65d234d6ed8f77d3732c134962ad47b35 Mon Sep 17 00:00:00 2001 From: alalazo Date: Wed, 23 Mar 2016 15:43:16 +0100 Subject: modules : added configuration file with disable keyword --- lib/spack/spack/config.py | 28 +++++++++++++++++++++++++--- lib/spack/spack/modules.py | 12 ++++++++++-- 2 files changed, 35 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/config.py b/lib/spack/spack/config.py index 6afd69b3ac..6ef79c70b1 100644 --- a/lib/spack/spack/config.py +++ b/lib/spack/spack/config.py @@ -237,7 +237,29 @@ section_schemas = { 'type' : 'object', 'default' : {}, } - },},},},},} + },},},},},}, + 'modules': { + '$schema': 'http://json-schema.org/schema#', + 'title': 'Spack module file configuration file schema', + 'type': 'object', + 'additionalProperties': False, + 'patternProperties': { + r'modules:?': { + 'type': 'object', + 'default': {}, + 'additionalProperties': False, + 'properties': { + 'disable': { + 'type': 'array', + 'default': [], + 'items': { + 'type': 'string' + } + } + } + }, + }, + }, } """OrderedDict of config scopes keyed by name. @@ -405,11 +427,11 @@ def _read_config_file(filename, schema): validate_section(data, schema) return data - except MarkedYAMLError, e: + except MarkedYAMLError as e: raise ConfigFileError( "Error parsing yaml%s: %s" % (str(e.context_mark), e.problem)) - except IOError, e: + except IOError as e: raise ConfigFileError( "Error reading configuration file %s: %s" % (filename, str(e))) diff --git a/lib/spack/spack/modules.py b/lib/spack/spack/modules.py index 8ed98e5d38..639f1101b8 100644 --- a/lib/spack/spack/modules.py +++ b/lib/spack/spack/modules.py @@ -48,6 +48,7 @@ import textwrap import llnl.util.tty as tty import spack +import spack.config from llnl.util.filesystem import join_path, mkdirp from spack.environment import * @@ -57,6 +58,13 @@ __all__ = ['EnvModule', 'Dotkit', 'TclModule'] module_types = {} +def read_configuration_file(): + f = spack.config.get_config('modules') + f.setdefault('disable', []) # Default : disable nothing + return f + +CONFIGURATION = read_configuration_file() + def print_help(): """For use by commands to tell user how to activate shell support.""" @@ -115,8 +123,8 @@ class EnvModule(object): class __metaclass__(type): def __init__(cls, name, bases, dict): type.__init__(cls, name, bases, dict) - if cls.name != 'env_module': - module_types[cls.name] = cls + if cls.name != 'env_module' and cls.name not in CONFIGURATION['disable']: + module_types[cls.name] = cls def __init__(self, spec=None): self.spec = spec -- cgit v1.2.3-70-g09d2 From d93f2b335d5a5198b943cc6293a1d24d614c979b Mon Sep 17 00:00:00 2001 From: alalazo Date: Wed, 23 Mar 2016 16:04:36 +0100 Subject: modules : fixed annoying indent --- lib/spack/spack/modules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/spack/spack/modules.py b/lib/spack/spack/modules.py index 639f1101b8..d354c8bb71 100644 --- a/lib/spack/spack/modules.py +++ b/lib/spack/spack/modules.py @@ -124,7 +124,7 @@ class EnvModule(object): def __init__(cls, name, bases, dict): type.__init__(cls, name, bases, dict) if cls.name != 'env_module' and cls.name not in CONFIGURATION['disable']: - module_types[cls.name] = cls + module_types[cls.name] = cls def __init__(self, spec=None): self.spec = spec -- cgit v1.2.3-70-g09d2 From f095e619b985a9271ff96cd469086d4654edf489 Mon Sep 17 00:00:00 2001 From: alalazo Date: Thu, 24 Mar 2016 09:31:28 +0100 Subject: module files configuration : enable/disable logic is now positive --- lib/spack/spack/config.py | 2 +- lib/spack/spack/modules.py | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/config.py b/lib/spack/spack/config.py index 6ef79c70b1..14e5aaf4fb 100644 --- a/lib/spack/spack/config.py +++ b/lib/spack/spack/config.py @@ -249,7 +249,7 @@ section_schemas = { 'default': {}, 'additionalProperties': False, 'properties': { - 'disable': { + 'enable': { 'type': 'array', 'default': [], 'items': { diff --git a/lib/spack/spack/modules.py b/lib/spack/spack/modules.py index d354c8bb71..6c32937c3c 100644 --- a/lib/spack/spack/modules.py +++ b/lib/spack/spack/modules.py @@ -57,13 +57,8 @@ __all__ = ['EnvModule', 'Dotkit', 'TclModule'] # Registry of all types of modules. Entries created by EnvModule's metaclass module_types = {} +CONFIGURATION = spack.config.get_config('modules') -def read_configuration_file(): - f = spack.config.get_config('modules') - f.setdefault('disable', []) # Default : disable nothing - return f - -CONFIGURATION = read_configuration_file() def print_help(): """For use by commands to tell user how to activate shell support.""" @@ -123,7 +118,7 @@ class EnvModule(object): class __metaclass__(type): def __init__(cls, name, bases, dict): type.__init__(cls, name, bases, dict) - if cls.name != 'env_module' and cls.name not in CONFIGURATION['disable']: + if cls.name != 'env_module' and cls.name in CONFIGURATION['enable']: module_types[cls.name] = cls def __init__(self, spec=None): -- cgit v1.2.3-70-g09d2 From 758a9c9096bd6c306f2dba0e40b46544dcec1992 Mon Sep 17 00:00:00 2001 From: alalazo Date: Wed, 23 Mar 2016 11:18:11 +0100 Subject: python extensions : create PYTHONPATH in module files --- lib/spack/spack/modules.py | 10 +++++----- var/spack/repos/builtin/packages/python/package.py | 5 ++++- 2 files changed, 9 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/modules.py b/lib/spack/spack/modules.py index 6c32937c3c..d45fdde703 100644 --- a/lib/spack/spack/modules.py +++ b/lib/spack/spack/modules.py @@ -161,13 +161,13 @@ class EnvModule(object): # Let the extendee modify their extensions before asking for # package-specific modifications - for extendee in self.pkg.extendees: - extendee_spec = self.spec[extendee] - extendee_spec.package.setup_dependent_package( - self.pkg.module, self.spec) + spack_env = EnvironmentModifications() + for item in self.pkg.extendees: + package = self.spec[item].package + package.setup_dependent_package(self.pkg.module, self.spec) + package.setup_dependent_environment(spack_env, env, self.spec) # Package-specific environment modifications - spack_env = EnvironmentModifications() self.spec.package.setup_environment(spack_env, env) # TODO : implement site-specific modifications and filters diff --git a/var/spack/repos/builtin/packages/python/package.py b/var/spack/repos/builtin/packages/python/package.py index 6d9030805b..f5237c3b57 100644 --- a/var/spack/repos/builtin/packages/python/package.py +++ b/var/spack/repos/builtin/packages/python/package.py @@ -105,7 +105,10 @@ class Python(Package): pythonpath = ':'.join(python_paths) spack_env.set('PYTHONPATH', pythonpath) - run_env.set('PYTHONPATH', pythonpath) + + # For run time environment set only the path for extension_spec and prepend it to PYTHONPATH + if extension_spec.package.extends(self.spec): + run_env.prepend_path('PYTHONPATH', os.path.join(extension_spec.prefix, self.site_packages_dir)) def setup_dependent_package(self, module, ext_spec): -- cgit v1.2.3-70-g09d2 From 9985816642bad10008f45583a7d715761a6ae03d Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Thu, 24 Mar 2016 14:49:41 -0500 Subject: Fix spack info indentation --- lib/spack/spack/cmd/info.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/cmd/info.py b/lib/spack/spack/cmd/info.py index e7abe7f4a5..c93db55c63 100644 --- a/lib/spack/spack/cmd/info.py +++ b/lib/spack/spack/cmd/info.py @@ -52,7 +52,7 @@ def print_text_info(pkg): print "Safe versions: " if not pkg.versions: - print("None") + print(" None") else: pad = padder(pkg.versions, 4) for v in reversed(sorted(pkg.versions)): @@ -62,7 +62,7 @@ def print_text_info(pkg): print print "Variants:" if not pkg.variants: - print "None" + print " None" else: pad = padder(pkg.variants, 4) -- cgit v1.2.3-70-g09d2 From b0b882cbb3d903a85413acb0439a02d6ac9e26fc Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Sat, 26 Mar 2016 00:56:19 -0700 Subject: Speed up directives by skipping debug info in stack traversal. - `caller_locals()` doesn't need debug info, only frame locals. - `get_calling_module()` doesn't either. - Changed calls to `inspect.stack()` -> `inspect.stack(0)` --- lib/spack/llnl/util/lang.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/spack/llnl/util/lang.py b/lib/spack/llnl/util/lang.py index 13d301f84e..3b4e2c8352 100644 --- a/lib/spack/llnl/util/lang.py +++ b/lib/spack/llnl/util/lang.py @@ -117,7 +117,8 @@ def caller_locals(): scope. Yes, this is some black magic, and yes it's useful for implementing things like depends_on and provides. """ - stack = inspect.stack() + # Passing zero here skips line context for speed. + stack = inspect.stack(0) try: return stack[2][0].f_locals finally: @@ -128,7 +129,8 @@ def get_calling_module_name(): """Make sure that the caller is a class definition, and return the enclosing module's name. """ - stack = inspect.stack() + # Passing zero here skips line context for speed. + stack = inspect.stack(0) try: # Make sure locals contain __module__ caller_locals = stack[2][0].f_locals -- cgit v1.2.3-70-g09d2 From dce590fb21af844230727b283f6c8bf759ea805c Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Sat, 26 Mar 2016 19:59:02 -0700 Subject: Add a dso_suffix variable to build_environment - Consolidate this in one place so that we don't have to do it in every build. - Will update further once better OS support is committed. Shoudl really be an attribute of the forthcoming `Platform` class. --- lib/spack/spack/build_environment.py | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'lib') diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py index 119a255a34..640db0c1d1 100644 --- a/lib/spack/spack/build_environment.py +++ b/lib/spack/spack/build_environment.py @@ -59,6 +59,11 @@ SPACK_SHORT_SPEC = 'SPACK_SHORT_SPEC' SPACK_DEBUG_LOG_DIR = 'SPACK_DEBUG_LOG_DIR' +# Platform-specific library suffix. +dso_suffix = 'dylib' if sys.platform == 'darwin' else 'so' + + + class MakeExecutable(Executable): """Special callable executable object for make so the user can specify parallel or not on a per-invocation basis. Using @@ -246,6 +251,9 @@ def set_module_variables_for_package(pkg, module): # a Prefix object. m.prefix = pkg.prefix + # Platform-specific library suffix. + m.dso_suffix = dso_suffix + def get_rpaths(pkg): """Get a list of all the rpaths for a package.""" -- cgit v1.2.3-70-g09d2 From cde33205827edbed988ec4548c983ff93e9445c6 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Sat, 26 Mar 2016 20:00:28 -0700 Subject: Add a method to find the containing directory of a library. --- lib/spack/llnl/util/filesystem.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/spack/llnl/util/filesystem.py b/lib/spack/llnl/util/filesystem.py index c4665c284c..92f9ca2983 100644 --- a/lib/spack/llnl/util/filesystem.py +++ b/lib/spack/llnl/util/filesystem.py @@ -27,7 +27,7 @@ __all__ = ['set_install_permissions', 'install', 'install_tree', 'traverse_tree' 'force_remove', 'join_path', 'ancestor', 'can_access', 'filter_file', 'FileFilter', 'change_sed_delimiter', 'is_exe', 'force_symlink', 'set_executable', 'copy_mode', 'unset_executable_mode', - 'remove_dead_links', 'remove_linked_tree'] + 'remove_dead_links', 'remove_linked_tree', 'find_library_path'] import os import sys @@ -392,3 +392,18 @@ def remove_linked_tree(path): os.unlink(path) else: shutil.rmtree(path, True) + + +def find_library_path(libname, *paths): + """Searches for a file called in each path. + + Return: + directory where the library was found, if found. None otherwise. + + """ + for path in paths: + library = join_path(path, libname) + if os.path.exists(library): + return path + return None + -- cgit v1.2.3-70-g09d2 From e049fc2840ba81cdff2ca7edd798c5e961ae94e9 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Sun, 27 Mar 2016 11:47:20 -0700 Subject: Run post-install hoooks before build stage is removed. - Build will properly fail when post-install hoooks fail. - Post-install hooks have a proper working directory set now. --- lib/spack/spack/package.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index 9af3221837..c17bec4a14 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -926,6 +926,9 @@ class Package(object): install(env_path, env_install_path) dump_packages(self.spec, packages_dir) + # Run post install hooks before build stage is removed. + spack.hooks.post_install(self) + # Stop timer. self._total_time = time.time() - start_time build_time = self._total_time - self._fetch_time @@ -954,9 +957,6 @@ class Package(object): # the database, so that we don't need to re-read from file. spack.installed_db.add(self.spec, self.prefix) - # Once everything else is done, run post install hooks - spack.hooks.post_install(self) - def sanity_check_prefix(self): """This function checks whether install succeeded.""" -- cgit v1.2.3-70-g09d2 From 5695e4c03d6c98fc187ec405923cd1dcf2fbdff6 Mon Sep 17 00:00:00 2001 From: Glenn Johnson Date: Sun, 27 Mar 2016 15:37:52 -0500 Subject: Wrap the long description of an environment module so it is more readable. --- lib/spack/spack/modules.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/modules.py b/lib/spack/spack/modules.py index d45fdde703..f6a11c92e3 100644 --- a/lib/spack/spack/modules.py +++ b/lib/spack/spack/modules.py @@ -278,6 +278,6 @@ class TclModule(EnvModule): # Long description if self.long_description: module_file.write('proc ModulesHelp { } {\n') - doc = re.sub(r'"', '\"', self.long_description) - module_file.write("puts stderr \"%s\"\n" % doc) + for line in textwrap.wrap(self.long_description, 72): + module_file.write("puts stderr \"%s\"\n" % line) module_file.write('}\n\n') -- cgit v1.2.3-70-g09d2 From 7eca1284c81c3efc5a87b8a174a0974811656b3e Mon Sep 17 00:00:00 2001 From: Denis Davydov Date: Sun, 27 Mar 2016 08:59:25 +0200 Subject: metis/parmetis/boost/oce/scalapack: correct install_name on Darwin via a global function. --- lib/spack/llnl/util/filesystem.py | 30 ++++++++++++- var/spack/repos/builtin/packages/boost/package.py | 50 ++++++++++++---------- var/spack/repos/builtin/packages/metis/package.py | 6 ++- .../builtin/packages/netlib-scalapack/package.py | 5 +++ var/spack/repos/builtin/packages/oce/package.py | 6 ++- .../repos/builtin/packages/parmetis/package.py | 6 ++- 6 files changed, 76 insertions(+), 27 deletions(-) (limited to 'lib') diff --git a/lib/spack/llnl/util/filesystem.py b/lib/spack/llnl/util/filesystem.py index c4665c284c..46ca03bec4 100644 --- a/lib/spack/llnl/util/filesystem.py +++ b/lib/spack/llnl/util/filesystem.py @@ -27,9 +27,10 @@ __all__ = ['set_install_permissions', 'install', 'install_tree', 'traverse_tree' 'force_remove', 'join_path', 'ancestor', 'can_access', 'filter_file', 'FileFilter', 'change_sed_delimiter', 'is_exe', 'force_symlink', 'set_executable', 'copy_mode', 'unset_executable_mode', - 'remove_dead_links', 'remove_linked_tree'] + 'remove_dead_links', 'remove_linked_tree', 'fix_darwin_install_name'] import os +import glob import sys import re import shutil @@ -38,6 +39,7 @@ import errno import getpass from contextlib import contextmanager, closing from tempfile import NamedTemporaryFile +import subprocess import llnl.util.tty as tty from spack.util.compression import ALLOWED_ARCHIVE_TYPES @@ -392,3 +394,29 @@ def remove_linked_tree(path): os.unlink(path) else: shutil.rmtree(path, True) + +def fix_darwin_install_name(path): + """ + Fix install name of dynamic libraries on Darwin to have full path. + There are two parts of this task: + (i) use install_name('-id',...) to change install name of a single lib; + (ii) use install_name('-change',...) to change the cross linking between libs. + The function assumes that all libraries are in one folder and currently won't + follow subfolders. + + Args: + path: directory in which .dylib files are alocated + + """ + libs = glob.glob(join_path(path,"*.dylib")) + for lib in libs: + # fix install name first: + subprocess.Popen(["install_name_tool", "-id",lib,lib], stdout=subprocess.PIPE).communicate()[0] + long_deps = subprocess.Popen(["otool", "-L",lib], stdout=subprocess.PIPE).communicate()[0].split('\n') + deps = [dep.partition(' ')[0][1::] for dep in long_deps[2:-1]] + # fix all dependencies: + for dep in deps: + for loc in libs: + if dep == os.path.basename(loc): + subprocess.Popen(["install_name_tool", "-change",dep,loc,lib], stdout=subprocess.PIPE).communicate()[0] + break diff --git a/var/spack/repos/builtin/packages/boost/package.py b/var/spack/repos/builtin/packages/boost/package.py index fb1f5daee7..82ce6fbb74 100644 --- a/var/spack/repos/builtin/packages/boost/package.py +++ b/var/spack/repos/builtin/packages/boost/package.py @@ -1,5 +1,6 @@ from spack import * import spack +import sys class Boost(Package): """Boost provides free peer-reviewed portable C++ source @@ -45,34 +46,34 @@ class Boost(Package): version('1.34.1', '2d938467e8a448a2c9763e0a9f8ca7e5') version('1.34.0', 'ed5b9291ffad776f8757a916e1726ad0') - default_install_libs = set(['atomic', - 'chrono', - 'date_time', - 'filesystem', + default_install_libs = set(['atomic', + 'chrono', + 'date_time', + 'filesystem', 'graph', 'iostreams', 'locale', 'log', - 'math', + 'math', 'program_options', - 'random', - 'regex', - 'serialization', - 'signals', - 'system', - 'test', - 'thread', + 'random', + 'regex', + 'serialization', + 'signals', + 'system', + 'test', + 'thread', 'wave']) - # mpi/python are not installed by default because they pull in many - # dependencies and/or because there is a great deal of customization + # mpi/python are not installed by default because they pull in many + # dependencies and/or because there is a great deal of customization # possible (and it would be difficult to choose sensible defaults) default_noinstall_libs = set(['mpi', 'python']) all_libs = default_install_libs | default_noinstall_libs for lib in all_libs: - variant(lib, default=(lib not in default_noinstall_libs), + variant(lib, default=(lib not in default_noinstall_libs), description="Compile with {0} library".format(lib)) variant('debug', default=False, description='Switch to the debug version of Boost') @@ -124,9 +125,9 @@ class Boost(Package): with open('user-config.jam', 'w') as f: compiler_wrapper = join_path(spack.build_env_path, 'c++') - f.write("using {0} : : {1} ;\n".format(boostToolsetId, + f.write("using {0} : : {1} ;\n".format(boostToolsetId, compiler_wrapper)) - + if '+mpi' in spec: f.write('using mpi : %s ;\n' % join_path(spec['mpi'].prefix.bin, 'mpicxx')) @@ -155,7 +156,7 @@ class Boost(Package): linkTypes = ['static'] if '+shared' in spec: linkTypes.append('shared') - + threadingOpts = [] if '+multithreaded' in spec: threadingOpts.append('multi') @@ -163,12 +164,12 @@ class Boost(Package): threadingOpts.append('single') if not threadingOpts: raise RuntimeError("At least one of {singlethreaded, multithreaded} must be enabled") - + options.extend([ 'toolset=%s' % self.determine_toolset(spec), 'link=%s' % ','.join(linkTypes), '--layout=tagged']) - + return threadingOpts def install(self, spec, prefix): @@ -177,14 +178,14 @@ class Boost(Package): if "+{0}".format(lib) in spec: withLibs.append(lib) if not withLibs: - # if no libraries are specified for compilation, then you dont have + # if no libraries are specified for compilation, then you dont have # to configure/build anything, just copy over to the prefix directory. src = join_path(self.stage.source_path, 'boost') mkdirp(join_path(prefix, 'include')) dst = join_path(prefix, 'include', 'boost') install_tree(src, dst) return - + # to make Boost find the user-config.jam env['BOOST_BUILD_PATH'] = './' @@ -207,4 +208,7 @@ class Boost(Package): # Boost.MPI if the threading options are not separated. for threadingOpt in threadingOpts: b2('install', 'threading=%s' % threadingOpt, *b2_options) - + + # The shared libraries are not installed correctly on Darwin; correct this + if (sys.platform == 'darwin') and ('+shared' in spec): + fix_darwin_install_name(prefix.lib) diff --git a/var/spack/repos/builtin/packages/metis/package.py b/var/spack/repos/builtin/packages/metis/package.py index 68b9f6fd30..9301135f9f 100644 --- a/var/spack/repos/builtin/packages/metis/package.py +++ b/var/spack/repos/builtin/packages/metis/package.py @@ -24,7 +24,7 @@ ############################################################################## from spack import * -import glob +import glob,sys class Metis(Package): """ @@ -90,3 +90,7 @@ class Metis(Package): fs = glob.glob(join_path(source_directory,'GKlib',"*.h")) for f in fs: install(f, GKlib_dist) + + # The shared library is not installed correctly on Darwin; correct this + if (sys.platform == 'darwin') and ('+shared' in spec): + fix_darwin_install_name(prefix.lib) diff --git a/var/spack/repos/builtin/packages/netlib-scalapack/package.py b/var/spack/repos/builtin/packages/netlib-scalapack/package.py index c3e6822cdf..d59f8e41fe 100644 --- a/var/spack/repos/builtin/packages/netlib-scalapack/package.py +++ b/var/spack/repos/builtin/packages/netlib-scalapack/package.py @@ -41,6 +41,11 @@ class NetlibScalapack(Package): make() make("install") + # The shared libraries are not installed correctly on Darwin; correct this + if (sys.platform == 'darwin') and ('+shared' in spec): + fix_darwin_install_name(prefix.lib) + + def setup_dependent_package(self, module, dependent_spec): spec = self.spec lib_dsuffix = '.dylib' if sys.platform == 'darwin' else '.so' diff --git a/var/spack/repos/builtin/packages/oce/package.py b/var/spack/repos/builtin/packages/oce/package.py index 06acb96736..4d5081ac9d 100644 --- a/var/spack/repos/builtin/packages/oce/package.py +++ b/var/spack/repos/builtin/packages/oce/package.py @@ -1,5 +1,5 @@ from spack import * -import platform +import platform, sys class Oce(Package): """ @@ -45,3 +45,7 @@ class Oce(Package): cmake('.', *options) make("install/strip") + + # The shared libraries are not installed correctly on Darwin; correct this + if (sys.platform == 'darwin'): + fix_darwin_install_name(prefix.lib) diff --git a/var/spack/repos/builtin/packages/parmetis/package.py b/var/spack/repos/builtin/packages/parmetis/package.py index f5b8b6de91..ff4370aa4b 100644 --- a/var/spack/repos/builtin/packages/parmetis/package.py +++ b/var/spack/repos/builtin/packages/parmetis/package.py @@ -24,7 +24,7 @@ ############################################################################## from spack import * - +import sys class Parmetis(Package): """ @@ -83,3 +83,7 @@ class Parmetis(Package): cmake(source_directory, *options) make() make("install") + + # The shared library is not installed correctly on Darwin; correct this + if (sys.platform == 'darwin') and ('+shared' in spec): + fix_darwin_install_name(prefix.lib) -- cgit v1.2.3-70-g09d2 From f3dd889d4462d14c9f0233540bccbf6a9720bcf0 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Mon, 28 Mar 2016 03:51:05 -0700 Subject: Fix bug with lib64 RPATH setting in cc. --- lib/spack/env/cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/spack/env/cc b/lib/spack/env/cc index c6a09724e9..17740250d1 100755 --- a/lib/spack/env/cc +++ b/lib/spack/env/cc @@ -293,9 +293,9 @@ for dep in "${deps[@]}"; do if [[ -d $dep/lib64 ]]; then # libraries+=("$dep/lib64") if [[ $mode = ccld ]]; then - args=("-L$dep/lib" "-Wl,-rpath,$dep/lib" "${args[@]}") + args=("-L$dep/lib64" "-Wl,-rpath,$dep/lib64" "${args[@]}") elif [[ $mode = ld ]]; then - args=("-L$dep/lib" "-rpath" "$dep/lib" "${args[@]}") + args=("-L$dep/lib64" "-rpath" "$dep/lib64" "${args[@]}") fi fi done -- cgit v1.2.3-70-g09d2 From d8579a5b80efd8b09e5332a922dee533f2a0a55e Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Mon, 28 Mar 2016 03:51:41 -0700 Subject: Simplify cc: Remove old logic and add better tests. - removed a lot of old logic that was only still needed for tests. - Added better unit tests for dependency RPATH, -L, and -I args - tests now check whether the compiler omits -I args in link mode. --- lib/spack/env/cc | 138 +++++---------------------------------------- lib/spack/spack/test/cc.py | 127 +++++++++++++++++++++++++++++++++++------ 2 files changed, 123 insertions(+), 142 deletions(-) (limited to 'lib') diff --git a/lib/spack/env/cc b/lib/spack/env/cc index 17740250d1..4217159a25 100755 --- a/lib/spack/env/cc +++ b/lib/spack/env/cc @@ -114,7 +114,9 @@ case "$command" in ;; esac -# If any of the arguments below is present then the mode is vcheck. In vcheck mode nothing is added in terms of extra search paths or libraries +# If any of the arguments below is present then the mode is vcheck. In +# vcheck mode nothing is added in terms of extra search paths or +# libraries if [ -z "$mode" ]; then for arg in "$@"; do if [ "$arg" = -v -o "$arg" = -V -o "$arg" = --version -o "$arg" = -dumpversion ]; then @@ -125,7 +127,6 @@ if [ -z "$mode" ]; then fi # Finish setting up the mode. - if [ -z "$mode" ]; then mode=ccld for arg in "$@"; do @@ -162,127 +163,18 @@ fi input_command="$@" args=("$@") -# Dump parsed values for unit testing if asked for -if [[ -n $SPACK_TEST_COMMAND ]]; then - - # - # Now do real parsing of the command line args, trying hard to keep - # non-rpath linker arguments in the proper order w.r.t. other command line - # arguments. This is important for things like groups. - # - includes=() - libraries=() - libs=() - rpaths=() - other_args=() - - while [ -n "$1" ]; do - case "$1" in - -I*) - arg="${1#-I}" - if [ -z "$arg" ]; then shift; arg="$1"; fi - includes+=("$arg") - ;; - -L*) - arg="${1#-L}" - if [ -z "$arg" ]; then shift; arg="$1"; fi - libraries+=("$arg") - ;; - -l*) - arg="${1#-l}" - if [ -z "$arg" ]; then shift; arg="$1"; fi - libs+=("$arg") - ;; - -Wl,*) - arg="${1#-Wl,}" - # TODO: Handle multiple -Wl, continuations of -Wl,-rpath - if [[ $arg == -rpath=* ]]; then - arg="${arg#-rpath=}" - for rpath in ${arg//,/ }; do - rpaths+=("$rpath") - done - elif [[ $arg == -rpath,* ]]; then - arg="${arg#-rpath,}" - for rpath in ${arg//,/ }; do - rpaths+=("$rpath") - done - elif [[ $arg == -rpath ]]; then - shift; arg="$1" - if [[ $arg != '-Wl,'* ]]; then - die "-Wl,-rpath was not followed by -Wl,*" - fi - arg="${arg#-Wl,}" - for rpath in ${arg//,/ }; do - rpaths+=("$rpath") - done - else - other_args+=("-Wl,$arg") - fi - ;; - -Xlinker) - shift; arg="$1"; - if [[ $arg = -rpath=* ]]; then - rpaths+=("${arg#-rpath=}") - elif [[ $arg = -rpath ]]; then - shift; arg="$1" - if [[ $arg != -Xlinker ]]; then - die "-Xlinker -rpath was not followed by -Xlinker " - fi - shift; arg="$1" - rpaths+=("$arg") - else - other_args+=("-Xlinker") - other_args+=("$arg") - fi - ;; - *) - other_args+=("$1") - ;; - esac - shift - done - - IFS=$'\n' - case "$SPACK_TEST_COMMAND" in - dump-includes) echo "${includes[*]}";; - dump-libraries) echo "${libraries[*]}";; - dump-libs) echo "${libs[*]}";; - dump-rpaths) echo "${rpaths[*]}";; - dump-other-args) echo "${other_args[*]}";; - dump-all) - echo "INCLUDES:" - echo "${includes[*]}" - echo - echo "LIBRARIES:" - echo "${libraries[*]}" - echo - echo "LIBS:" - echo "${libs[*]}" - echo - echo "RPATHS:" - echo "${rpaths[*]}" - echo - echo "ARGS:" - echo "${other_args[*]}" - ;; - *) - die "ERROR: Unknown test command" - ;; - esac - exit -fi - # Read spack dependencies from the path environment variable IFS=':' read -ra deps <<< "$SPACK_DEPENDENCIES" for dep in "${deps[@]}"; do + # Prepend include directories if [[ -d $dep/include ]]; then if [[ $mode = cpp || $mode = cc || $mode = as || $mode = ccld ]]; then args=("-I$dep/include" "${args[@]}") fi fi + # Prepend lib and RPATH directories if [[ -d $dep/lib ]]; then - # libraries+=("$dep/lib") if [[ $mode = ccld ]]; then args=("-L$dep/lib" "-Wl,-rpath,$dep/lib" "${args[@]}") elif [[ $mode = ld ]]; then @@ -290,8 +182,8 @@ for dep in "${deps[@]}"; do fi fi + # Prepend lib64 and RPATH directories if [[ -d $dep/lib64 ]]; then - # libraries+=("$dep/lib64") if [[ $mode = ccld ]]; then args=("-L$dep/lib64" "-Wl,-rpath,$dep/lib64" "${args[@]}") elif [[ $mode = ld ]]; then @@ -302,18 +194,8 @@ done # Include all -L's and prefix/whatever dirs in rpath if [[ $mode = ccld ]]; then - # for dir in "${libraries[@]}"; do - # if [[ dir = $SPACK_INSTALL* ]]; then - # args=("-Wl,-rpath,$dir" "${args[@]}") - # fi - # done args=("-Wl,-rpath,$SPACK_PREFIX/lib" "-Wl,-rpath,$SPACK_PREFIX/lib64" "${args[@]}") elif [[ $mode = ld ]]; then - # for dir in "${libraries[@]}"; do - # if [[ dir = $SPACK_INSTALL* ]]; then - # args=("-rpath" "$dir" "${args[@]}") - # fi - # done args=("-rpath" "$SPACK_PREFIX/lib" "-rpath" "$SPACK_PREFIX/lib64" "${args[@]}") fi @@ -345,6 +227,14 @@ export PATH full_command=("$command" "${args[@]}") +# In test command mode, write out full command for Spack tests. +if [[ $SPACK_TEST_COMMAND = dump-args ]]; then + echo "${full_command[@]}" + exit +elif [[ -n $SPACK_TEST_COMMAND ]]; then + die "ERROR: Unknown test command" +fi + # # Write the input and output commands to debug logs if it's asked for. # diff --git a/lib/spack/spack/test/cc.py b/lib/spack/spack/test/cc.py index f3f6d4a22e..0b1aeb2a8f 100644 --- a/lib/spack/spack/test/cc.py +++ b/lib/spack/spack/test/cc.py @@ -28,6 +28,8 @@ arguments correctly. """ import os import unittest +import tempfile +import shutil from llnl.util.filesystem import * import spack @@ -55,13 +57,40 @@ class CompilerTest(unittest.TestCase): self.ld = Executable(join_path(spack.build_env_path, "ld")) self.cpp = Executable(join_path(spack.build_env_path, "cpp")) - os.environ['SPACK_CC'] = "/bin/mycc" - os.environ['SPACK_PREFIX'] = "/usr" + self.realcc = "/bin/mycc" + self.prefix = "/spack-test-prefix" + + os.environ['SPACK_CC'] = self.realcc + os.environ['SPACK_PREFIX'] = self.prefix os.environ['SPACK_ENV_PATH']="test" os.environ['SPACK_DEBUG_LOG_DIR'] = "." os.environ['SPACK_COMPILER_SPEC'] = "gcc@4.4.7" os.environ['SPACK_SHORT_SPEC'] = "foo@1.2" + # Make some fake dependencies + self.tmp_deps = tempfile.mkdtemp() + self.dep1 = join_path(self.tmp_deps, 'dep1') + self.dep2 = join_path(self.tmp_deps, 'dep2') + self.dep3 = join_path(self.tmp_deps, 'dep3') + self.dep4 = join_path(self.tmp_deps, 'dep4') + + mkdirp(join_path(self.dep1, 'include')) + mkdirp(join_path(self.dep1, 'lib')) + + mkdirp(join_path(self.dep2, 'lib64')) + + mkdirp(join_path(self.dep3, 'include')) + mkdirp(join_path(self.dep3, 'lib64')) + + mkdirp(join_path(self.dep4, 'include')) + + if 'SPACK_DEPENDENCIES' in os.environ: + del os.environ['SPACK_DEPENDENCIES'] + + + def tearDown(self): + shutil.rmtree(self.tmp_deps, True) + def check_cc(self, command, args, expected): os.environ['SPACK_TEST_COMMAND'] = command @@ -92,6 +121,10 @@ class CompilerTest(unittest.TestCase): self.check_cpp('dump-mode', [], "cpp") + def test_as_mode(self): + self.check_cc('dump-mode', ['-S'], "as") + + def test_ccld_mode(self): self.check_cc('dump-mode', [], "ccld") self.check_cc('dump-mode', ['foo.c', '-o', 'foo'], "ccld") @@ -104,27 +137,85 @@ class CompilerTest(unittest.TestCase): self.check_ld('dump-mode', ['foo.o', 'bar.o', 'baz.o', '-o', 'foo', '-Wl,-rpath,foo'], "ld") - def test_includes(self): - self.check_cc('dump-includes', test_command, - "\n".join(["/test/include", "/other/include"])) + def test_dep_rpath(self): + """Ensure RPATHs for root package are added.""" + self.check_cc('dump-args', test_command, + self.realcc + ' ' + + '-Wl,-rpath,' + self.prefix + '/lib ' + + '-Wl,-rpath,' + self.prefix + '/lib64 ' + + ' '.join(test_command)) + + + def test_dep_include(self): + """Ensure a single dependency include directory is added.""" + os.environ['SPACK_DEPENDENCIES'] = self.dep4 + self.check_cc('dump-args', test_command, + self.realcc + ' ' + + '-Wl,-rpath,' + self.prefix + '/lib ' + + '-Wl,-rpath,' + self.prefix + '/lib64 ' + + '-I' + self.dep4 + '/include ' + + ' '.join(test_command)) + + + def test_dep_lib(self): + """Ensure a single dependency RPATH is added.""" + os.environ['SPACK_DEPENDENCIES'] = self.dep2 + self.check_cc('dump-args', test_command, + self.realcc + ' ' + + '-Wl,-rpath,' + self.prefix + '/lib ' + + '-Wl,-rpath,' + self.prefix + '/lib64 ' + + '-L' + self.dep2 + '/lib64 ' + + '-Wl,-rpath,' + self.dep2 + '/lib64 ' + + ' '.join(test_command)) + + + def test_all_deps(self): + """Ensure includes and RPATHs for all deps are added. """ + os.environ['SPACK_DEPENDENCIES'] = ':'.join([ + self.dep1, self.dep2, self.dep3, self.dep4]) + + # This is probably more constrained than it needs to be; it + # checks order within prepended args and doesn't strictly have + # to. We could loosen that if it becomes necessary + self.check_cc('dump-args', test_command, + self.realcc + ' ' + + '-Wl,-rpath,' + self.prefix + '/lib ' + + '-Wl,-rpath,' + self.prefix + '/lib64 ' + + + '-I' + self.dep4 + '/include ' + + + '-L' + self.dep3 + '/lib64 ' + + '-Wl,-rpath,' + self.dep3 + '/lib64 ' + + '-I' + self.dep3 + '/include ' + + + '-L' + self.dep2 + '/lib64 ' + + '-Wl,-rpath,' + self.dep2 + '/lib64 ' + + + '-L' + self.dep1 + '/lib ' + + '-Wl,-rpath,' + self.dep1 + '/lib ' + + '-I' + self.dep1 + '/include ' + + + ' '.join(test_command)) - def test_libraries(self): - self.check_cc('dump-libraries', test_command, - "\n".join(["/test/lib", "/other/lib"])) + def test_ld_deps(self): + """Ensure no (extra) -I args or -Wl, are passed in ld mode.""" + os.environ['SPACK_DEPENDENCIES'] = ':'.join([ + self.dep1, self.dep2, self.dep3, self.dep4]) + self.check_ld('dump-args', test_command, + 'ld ' + + '-rpath ' + self.prefix + '/lib ' + + '-rpath ' + self.prefix + '/lib64 ' + - def test_libs(self): - self.check_cc('dump-libs', test_command, - "\n".join(["lib1", "lib2", "lib3", "lib4"])) + '-L' + self.dep3 + '/lib64 ' + + '-rpath ' + self.dep3 + '/lib64 ' + + '-L' + self.dep2 + '/lib64 ' + + '-rpath ' + self.dep2 + '/lib64 ' + - def test_rpaths(self): - self.check_cc('dump-rpaths', test_command, - "\n".join(["/first/rpath", "/second/rpath", "/third/rpath", "/fourth/rpath"])) + '-L' + self.dep1 + '/lib ' + + '-rpath ' + self.dep1 + '/lib ' + + ' '.join(test_command)) - def test_other_args(self): - self.check_cc('dump-other-args', test_command, - "\n".join(["arg1", "-Wl,--start-group", "arg2", "arg3", "arg4", - "-Wl,--end-group", "arg5", "arg6"])) -- cgit v1.2.3-70-g09d2 From a14527ec0619151d6defc909a46aefd2a9378cb7 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Mon, 28 Mar 2016 15:34:25 -0700 Subject: Add command to compiler input log. --- lib/spack/env/cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/spack/env/cc b/lib/spack/env/cc index 4217159a25..68cd8514f4 100755 --- a/lib/spack/env/cc +++ b/lib/spack/env/cc @@ -241,7 +241,7 @@ fi if [[ $SPACK_DEBUG = TRUE ]]; then input_log="$SPACK_DEBUG_LOG_DIR/spack-cc-$SPACK_SHORT_SPEC.in.log" output_log="$SPACK_DEBUG_LOG_DIR/spack-cc-$SPACK_SHORT_SPEC.out.log" - echo "$input_command" >> $input_log + echo "$command $input_command" >> $input_log echo "$mode ${full_command[@]}" >> $output_log fi -- cgit v1.2.3-70-g09d2 From f80e839ff48809a5ba8b7343d2378133a3fbce82 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Tue, 29 Mar 2016 02:58:05 -0700 Subject: Handle Darwin's ld -r option properly - ld -r doesn't work with RPATH on OS X. - for GNU ld, the -r option only means 'relocatable', and doesn't affect RPATH. - This adds special handling to omit RPATHs for ld -r on OS X --- lib/spack/env/cc | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/spack/env/cc b/lib/spack/env/cc index 68cd8514f4..2eb6f46afe 100755 --- a/lib/spack/env/cc +++ b/lib/spack/env/cc @@ -85,6 +85,10 @@ done # ccld compile & link # vcheck version check # +# Depending on the mode, we may or may not add extra rpaths. +# This variable controls whether they are added. +add_rpaths=true + command=$(basename "$0") case "$command" in cc|c89|c99|gcc|clang|icc|pgcc|xlc) @@ -108,6 +112,17 @@ case "$command" in ;; ld) mode=ld + + # Darwin's linker has a -r argument that merges object files + # together. It doesn't work with -rpath. + if [[ $OSTYPE = darwin* ]]; then + for arg in "$@"; do + if [ "$arg" = -r ]; then + add_rpaths=false + break + fi + done + fi ;; *) die "Unkown compiler: $command" @@ -176,27 +191,31 @@ for dep in "${deps[@]}"; do # Prepend lib and RPATH directories if [[ -d $dep/lib ]]; then if [[ $mode = ccld ]]; then - args=("-L$dep/lib" "-Wl,-rpath,$dep/lib" "${args[@]}") + $add_rpaths && args=("-Wl,-rpath,$dep/lib" "${args[@]}") + args=("-L$dep/lib" "${args[@]}") elif [[ $mode = ld ]]; then - args=("-L$dep/lib" "-rpath" "$dep/lib" "${args[@]}") + $add_rpaths && args=("-rpath" "$dep/lib" "${args[@]}") + args=("-L$dep/lib" "${args[@]}") fi fi # Prepend lib64 and RPATH directories if [[ -d $dep/lib64 ]]; then if [[ $mode = ccld ]]; then - args=("-L$dep/lib64" "-Wl,-rpath,$dep/lib64" "${args[@]}") + $add_rpaths && args=("-Wl,-rpath,$dep/lib64" "${args[@]}") + args=("-L$dep/lib64" "${args[@]}") elif [[ $mode = ld ]]; then - args=("-L$dep/lib64" "-rpath" "$dep/lib64" "${args[@]}") + $add_rpaths && args=("-rpath" "$dep/lib64" "${args[@]}") + args=("-L$dep/lib64" "${args[@]}") fi fi done # Include all -L's and prefix/whatever dirs in rpath if [[ $mode = ccld ]]; then - args=("-Wl,-rpath,$SPACK_PREFIX/lib" "-Wl,-rpath,$SPACK_PREFIX/lib64" "${args[@]}") + $add_rpaths && args=("-Wl,-rpath,$SPACK_PREFIX/lib" "-Wl,-rpath,$SPACK_PREFIX/lib64" "${args[@]}") elif [[ $mode = ld ]]; then - args=("-rpath" "$SPACK_PREFIX/lib" "-rpath" "$SPACK_PREFIX/lib64" "${args[@]}") + $add_rpaths && args=("-rpath" "$SPACK_PREFIX/lib" "-rpath" "$SPACK_PREFIX/lib64" "${args[@]}") fi # @@ -241,8 +260,8 @@ fi if [[ $SPACK_DEBUG = TRUE ]]; then input_log="$SPACK_DEBUG_LOG_DIR/spack-cc-$SPACK_SHORT_SPEC.in.log" output_log="$SPACK_DEBUG_LOG_DIR/spack-cc-$SPACK_SHORT_SPEC.out.log" - echo "$command $input_command" >> $input_log - echo "$mode ${full_command[@]}" >> $output_log + echo "[$mode] $command $input_command" >> $input_log + echo "[$mode] ${full_command[@]}" >> $output_log fi exec "${full_command[@]}" -- cgit v1.2.3-70-g09d2 From dfc5cf288c1017ef62390489cb534848aef5a9a6 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Tue, 29 Mar 2016 04:35:41 -0700 Subject: Fix bug in restage - Restage previously only removed the source directory from the stage. - Now removes any other directories in stage as well. --- lib/spack/spack/fetch_strategy.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/fetch_strategy.py b/lib/spack/spack/fetch_strategy.py index 0d0a7db8a9..4ea87bea7e 100644 --- a/lib/spack/spack/fetch_strategy.py +++ b/lib/spack/spack/fetch_strategy.py @@ -289,8 +289,14 @@ class URLFetchStrategy(FetchStrategy): if not self.archive_file: raise NoArchiveFileError("Tried to reset URLFetchStrategy before fetching", "Failed on reset() for URL %s" % self.url) - if self.stage.source_path: - shutil.rmtree(self.stage.source_path, ignore_errors=True) + + # Remove everythigng but the archive from the stage + for filename in os.listdir(self.stage.path): + abspath = os.path.join(self.stage.path, filename) + if abspath != self.archive_file: + shutil.rmtree(abspath, ignore_errors=True) + + # Expand the archive again self.expand() def __repr__(self): -- cgit v1.2.3-70-g09d2 From 63f824b218af9fcea4c13d7bef8b1d8ff31d09b2 Mon Sep 17 00:00:00 2001 From: Tom Scogland Date: Wed, 30 Dec 2015 11:53:27 -0800 Subject: add a path argument to the stage command Allow users to use spack to stage a, potentially complex, package into a given path. This is nice for packages with multiple resources that must be placed, for example LLVM with all sub-projects. --- lib/spack/spack/cmd/stage.py | 8 +++++++- lib/spack/spack/package.py | 8 ++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/cmd/stage.py b/lib/spack/spack/cmd/stage.py index 5786780efb..749fa90868 100644 --- a/lib/spack/spack/cmd/stage.py +++ b/lib/spack/spack/cmd/stage.py @@ -35,6 +35,9 @@ def setup_parser(subparser): subparser.add_argument( '-n', '--no-checksum', action='store_true', dest='no_checksum', help="Do not check downloaded packages against checksum") + subparser.add_argument( + '-p', '--path', dest='path', + help="Path to stage package, does not add to spack tree") subparser.add_argument( 'specs', nargs=argparse.REMAINDER, help="specs of packages to stage") @@ -50,4 +53,7 @@ def stage(parser, args): specs = spack.cmd.parse_specs(args.specs, concretize=True) for spec in specs: package = spack.repo.get(spec) - package.do_stage() + if args.path: + package.do_stage(path=args.path) + else: + package.do_stage() diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index 9af3221837..ce314b7b0a 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -709,14 +709,18 @@ class Package(object): if spack.do_checksum and self.version in self.versions: self.stage.check() - - def do_stage(self, mirror_only=False): + def do_stage(self, mirror_only=False, path=None): """Unpacks the fetched tarball, then changes into the expanded tarball directory.""" + if not self.spec.concrete: raise ValueError("Can only stage concrete packages.") self.do_fetch(mirror_only) + + if path is not None: + self.stage.path = path + self.stage.expand_archive() self.stage.chdir_to_source() -- cgit v1.2.3-70-g09d2 From 5d2151ed645f853a083cd445ae8631f9ed987559 Mon Sep 17 00:00:00 2001 From: Tom Scogland Date: Thu, 31 Mar 2016 10:20:55 -0700 Subject: reworked to deal with stage.path as property This version actually pulls the path through the package to deliver it to each stage on creation when passed through the command. This is necessary due to the new StageComposite class that makes setting the path directly on the stage impractical, it also takes the logic out of package for the most part, which seems like an improvement. --- lib/spack/spack/cmd/stage.py | 5 ++--- lib/spack/spack/package.py | 15 +++++++-------- lib/spack/spack/stage.py | 7 +++++-- 3 files changed, 14 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/cmd/stage.py b/lib/spack/spack/cmd/stage.py index 749fa90868..975bb54ef7 100644 --- a/lib/spack/spack/cmd/stage.py +++ b/lib/spack/spack/cmd/stage.py @@ -54,6 +54,5 @@ def stage(parser, args): for spec in specs: package = spack.repo.get(spec) if args.path: - package.do_stage(path=args.path) - else: - package.do_stage() + package.path = args.path + package.do_stage() diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index ce314b7b0a..9dcfbee661 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -335,6 +335,9 @@ class Package(object): if '.' in self.name: self.name = self.name[self.name.rindex('.') + 1:] + # Allow custom staging paths for packages + self.path=None + # Sanity check attributes required by Spack directives. spack.directives.ensure_dicts(type(self)) @@ -445,7 +448,8 @@ class Package(object): resource_stage_folder = self._resource_stage(resource) resource_mirror = join_path(self.name, os.path.basename(fetcher.url)) stage = ResourceStage(resource.fetcher, root=root_stage, resource=resource, - name=resource_stage_folder, mirror_path=resource_mirror) + name=resource_stage_folder, mirror_path=resource_mirror, + path=self.path) return stage def _make_root_stage(self, fetcher): @@ -455,7 +459,7 @@ class Package(object): s = self.spec stage_name = "%s-%s-%s" % (s.name, s.version, s.dag_hash()) # Build the composite stage - stage = Stage(fetcher, mirror_path=mp, name=stage_name) + stage = Stage(fetcher, mirror_path=mp, name=stage_name, path=self.path) return stage def _make_stage(self): @@ -709,18 +713,13 @@ class Package(object): if spack.do_checksum and self.version in self.versions: self.stage.check() - def do_stage(self, mirror_only=False, path=None): + def do_stage(self, mirror_only=False): """Unpacks the fetched tarball, then changes into the expanded tarball directory.""" - if not self.spec.concrete: raise ValueError("Can only stage concrete packages.") self.do_fetch(mirror_only) - - if path is not None: - self.stage.path = path - self.stage.expand_archive() self.stage.chdir_to_source() diff --git a/lib/spack/spack/stage.py b/lib/spack/spack/stage.py index f88f82fc2d..d711752c20 100644 --- a/lib/spack/spack/stage.py +++ b/lib/spack/spack/stage.py @@ -89,7 +89,7 @@ class Stage(object): """ def __init__(self, url_or_fetch_strategy, - name=None, mirror_path=None, keep=False): + name=None, mirror_path=None, keep=False, path=None): """Create a stage object. Parameters: url_or_fetch_strategy @@ -135,7 +135,10 @@ class Stage(object): # Try to construct here a temporary name for the stage directory # If this is a named stage, then construct a named path. - self.path = join_path(spack.stage_path, self.name) + if path is not None: + self.path = path + else: + self.path = join_path(spack.stage_path, self.name) # Flag to decide whether to delete the stage folder on exit or not self.keep = keep -- cgit v1.2.3-70-g09d2 From a670408617b76777d35185aa554eeaf3892e0188 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Thu, 31 Mar 2016 11:34:00 -0700 Subject: Quick fix for pkg diff. --- lib/spack/spack/cmd/pkg.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/spack/spack/cmd/pkg.py b/lib/spack/spack/cmd/pkg.py index cf478d3763..20a3fc5fc2 100644 --- a/lib/spack/spack/cmd/pkg.py +++ b/lib/spack/spack/cmd/pkg.py @@ -77,7 +77,8 @@ def get_git(): def list_packages(rev): git = get_git() - relpath = spack.packages_path[len(spack.prefix + os.path.sep):] + os.path.sep + pkgpath = os.path.join(spack.packages_path, 'packages') + relpath = pkgpath[len(spack.prefix + os.path.sep):] + os.path.sep output = git('ls-tree', '--full-tree', '--name-only', rev, relpath, output=str) return sorted(line[len(relpath):] for line in output.split('\n') if line) -- cgit v1.2.3-70-g09d2