342 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			342 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
| #!/bin/bash
 | |
| ##############################################################################
 | |
| # Copyright (c) 2013, Lawrence Livermore National Security, LLC.
 | |
| # Produced at the Lawrence Livermore National Laboratory.
 | |
| #
 | |
| # This file is part of Spack.
 | |
| # Written by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
 | |
| # LLNL-CODE-647188
 | |
| #
 | |
| # For details, see https://github.com/llnl/spack
 | |
| # Please also see the LICENSE file for our notice and the LGPL.
 | |
| #
 | |
| # This program is free software; you can redistribute it and/or modify
 | |
| # it under the terms of the GNU General Public License (as published by
 | |
| # the Free Software Foundation) version 2.1 dated February 1999.
 | |
| #
 | |
| # This program is distributed in the hope that it will be useful, but
 | |
| # WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
 | |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
 | |
| # conditions of the GNU General Public License for more details.
 | |
| #
 | |
| # You should have received a copy of the GNU Lesser General Public License
 | |
| # along with this program; if not, write to the Free Software Foundation,
 | |
| # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 | |
| ##############################################################################
 | |
| #
 | |
| # Spack compiler wrapper script.
 | |
| #
 | |
| # Compiler commands go through this compiler wrapper in Spack builds.
 | |
| # The compiler wrapper is a thin layer around the standard compilers.
 | |
| # It enables several key pieces of functionality:
 | |
| #
 | |
| # 1. It allows Spack to swap compilers into and out of builds easily.
 | |
| # 2. It adds several options to the compile line so that spack
 | |
| #    packages can find their dependencies at build time and run time:
 | |
| #      -I           arguments for dependency /include directories.
 | |
| #      -L           arguments for dependency /lib directories.
 | |
| #      -Wl,-rpath   arguments for dependency /lib directories.
 | |
| #
 | |
| 
 | |
| # This is the list of environment variables that need to be set before
 | |
| # the script runs.  They are set by routines in spack.build_environment
 | |
| # as part of spack.package.Package.do_install().
 | |
| parameters="
 | |
| SPACK_PREFIX
 | |
| SPACK_ENV_PATH
 | |
| SPACK_DEBUG_LOG_DIR
 | |
| SPACK_COMPILER_SPEC
 | |
| SPACK_SHORT_SPEC"
 | |
| 
 | |
| # The compiler input variables are checked for sanity later:
 | |
| #   SPACK_CC, SPACK_CXX, SPACK_F77, SPACK_FC
 | |
| # Debug flag is optional; set to true for debug logging:
 | |
| #   SPACK_DEBUG
 | |
| # Test command is used to unit test the compiler script.
 | |
| #   SPACK_TEST_COMMAND
 | |
| # Dependencies can be empty for pkgs with no deps:
 | |
| #   SPACK_DEPENDENCIES
 | |
| 
 | |
| # die()
 | |
| # Prints a message and exits with error 1.
 | |
| function die {
 | |
|     echo "$@"
 | |
|     exit 1
 | |
| }
 | |
| 
 | |
| for param in $parameters; do
 | |
|     if [[ -z ${!param} ]]; then
 | |
|         die "Spack compiler must be run from spack!  Input $param was missing!"
 | |
|     fi
 | |
| done
 | |
| 
 | |
| #
 | |
| # Figure out the type of compiler, the language, and the mode so that
 | |
| # the compiler script knows what to do.
 | |
| #
 | |
| # Possible languages are C, C++, Fortran 77, and Fortran 90.
 | |
| # 'command' is set based on the input command to $SPACK_[CC|CXX|F77|F90]
 | |
| #
 | |
| # 'mode' is set to one of:
 | |
| #    cc      compile
 | |
| #    ld      link
 | |
| #    ccld    compile & link
 | |
| #    cpp     preprocessor
 | |
| #    vcheck  version check
 | |
| #
 | |
| command=$(basename "$0")
 | |
| case "$command" in
 | |
|     cc|c89|c99|gcc|clang|icc|pgcc|xlc)
 | |
|         command="$SPACK_CC"
 | |
|         language="C"
 | |
|         ;;
 | |
|     c++|CC|g++|clang++|icpc|pgCC|xlc++)
 | |
|         command="$SPACK_CXX"
 | |
|         language="C++"
 | |
|         ;;
 | |
|     f90|fc|f95|gfortran|ifort|pgf90|xlf90)
 | |
|         command="$SPACK_FC"
 | |
|         language="Fortran 90"
 | |
|         ;;
 | |
|     f77|gfortran|ifort|pgf77|xlf)
 | |
|         command="$SPACK_F77"
 | |
|         language="Fortran 77"
 | |
|         ;;
 | |
|     cpp)
 | |
|         mode=cpp
 | |
|         ;;
 | |
|     ld)
 | |
|         mode=ld
 | |
|         ;;
 | |
|     *)
 | |
|         die "Unkown compiler: $command"
 | |
|         ;;
 | |
| esac
 | |
| 
 | |
| # Finish setting up the mode.
 | |
| 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
 | |
|     done
 | |
| fi
 | |
| 
 | |
| # Dump the version and exist if we're in testing mode.
 | |
| 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
 | |
|     die "ERROR: Compiler '$SPACK_COMPILER_SPEC' does not support compiling $language programs."
 | |
| fi
 | |
| 
 | |
| # Save original command for debug logging
 | |
| 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,}"
 | |
|                 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
 | |
|                 ;;
 | |
|             -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
 | |
|                 ;;
 | |
|             *)
 | |
|                 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
 | |
|     if [[ -d $dep/include ]]; then
 | |
|         args=("-I$dep/include" "${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")
 | |
|         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
 | |
| 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
 | |
| 
 | |
| #
 | |
| # Unset pesky environment variables that could affect build sanity.
 | |
| #
 | |
| unset LD_LIBRARY_PATH
 | |
| unset LD_RUN_PATH
 | |
| unset DYLD_LIBRARY_PATH
 | |
| 
 | |
| #
 | |
| # Filter '.' and Spack environment directories out of PATH so that
 | |
| # this script doesn't just call itself
 | |
| #
 | |
| IFS=':' read -ra env_path <<< "$PATH"
 | |
| IFS=':' read -ra spack_env_dirs <<< "$SPACK_ENV_PATH"
 | |
| 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
 | |
|     done
 | |
|     if [[ -z $remove ]]; then
 | |
|         PATH="${PATH:+$PATH:}$dir"
 | |
|     fi
 | |
| done
 | |
| export PATH
 | |
| 
 | |
| 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
 | |
|     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 "$mode       ${full_command[@]}" >> $output_log
 | |
| fi
 | |
| 
 | |
| exec "${full_command[@]}"
 | 
