#!/bin/bash # This script is used for running compiler standalone(outside of sbt) # it's based on miniboxing script and paulp's launcher script # Try to autodetect real location of the script DOTTY_ROOT="$(readlink "$0")" # relative, symbolic links resolved if [[ "$DOTTY_ROOT" == "" ]]; then DOTTY_ROOT="$0" fi DOTTY_ROOT="$(dirname "$DOTTY_ROOT")" DOTTY_ROOT="$( cd "$DOTTY_ROOT" >& /dev/null && pwd )/.." # absolute # Finds in dotty build file a line containing PATTERN # returns last "" escaped string in this line function getLastStringOnLineWith { PATTERN="$1" grep "$PATTERN" "$DOTTY_ROOT/project/Build.scala"|sed -n 's/.*\"\(.*\)\".*/\1/'p } # Configuration SCALA_VERSION=$(getLastStringOnLineWith "scalaVersion in") SCALA_BINARY_VERSION=2.11 SCALA_COMPILER_VERSION=$(getLastStringOnLineWith "scala-compiler") JLINE_VERSION=$(getLastStringOnLineWith "jline") SBT_VERSION=$(grep "sbt.version=" "$DOTTY_ROOT/project/build.properties" | sed 's/sbt.version=//') bootcp=true bootstrapped=false default_java_opts="-Xmx768m -Xms768m" programName=$(basename "$0") # uncomment next line to enable debug output #debug=true declare -a java_args scala_args residual_args unset verbose quiet cygwin toolcp colors saved_stty CDPATH function build_jar { # Usage: # build_jar package path/to/jar/dir ['/some/sed/command'] # # Last arg is optional cd $DOTTY_ROOT >& /dev/null local build_output=$(sbt "$1") local jar=$(echo $build_output | sed -n 's/.*Packaging //g; s/ \.\.\..*//g; /^\/.*/p') local sedjar="$3" if [ "$sedjar" == "" ]; then sedjar="/.*\.jar/p" fi if [ "$jar" == "" ]; then # Didn't build a jar - could've run sbt by oneself, get latest jar in target: jar="$DOTTY_ROOT/$2/$(ls -1t "$2" | sed -n "$sedjar" | awk 'NR==1')" fi cd - >& /dev/null echo $jar } function update_packages { echo "$INTERFACES_JAR" > $DOTTY_ROOT/.packages echo "$MAIN_JAR" >> $DOTTY_ROOT/.packages echo "$TEST_JAR" >> $DOTTY_ROOT/.packages } function build_all { echo "The script is going to build the required jar files" printf "Building dotty-interfaces..." INTERFACES_JAR=$(build_jar dotty-interfaces/package interfaces/target) printf "done\n" printf "Building dotty..." MAIN_JAR=$(build_jar package target/scala-2.11) printf "done\n" printf "Building tests..." TEST_JAR=$(build_jar test:package target/scala-2.11 '/dotty.*-tests\.jar/p') printf "done\n" update_packages } # Check if .packages file does not exist - if so assume old build and rebuild all if [ ! -f "$DOTTY_ROOT/.packages" ]; then build_all else IFS=$'\r\n' GLOBIGNORE='*' command eval 'JARS=($(cat $DOTTY_ROOT/.packages))' if [ "${#JARS[@]}" == "3" ]; then INTERFACES_JAR="${JARS[0]}" MAIN_JAR="${JARS[1]}" TEST_JAR="${JARS[2]}" else echo "Corrupted .packages file" build_all fi fi ################# After this point, jar variables will be set ################# function check_jar { # Usage: # check_jar "name" "path/to/package.jar" "sources/dir" 'lambda to exec on failure' local new_files="$(find "$3" \( -iname "*.scala" -o -iname "*.java" \) -newer "$2")" if [ ! -z "$new_files" ]; then printf "New files detected in $1, rebuilding..." eval "$4" printf "done\n" update_packages fi } check_jar "dotty-interfaces" $INTERFACES_JAR "interfaces" 'INTERFACES_JAR=$(build_jar dotty-interfaces/package interfaces/target)' check_jar "dotty" $MAIN_JAR "src" 'MAIN_JAR=$(build_jar package target/scala-2.11)' check_jar "dotty-tests" $TEST_JAR "test" 'TEST_JAR=$(build_jar test:package target/scala-2.11 /dotty.*-tests\.jar/p)' # dotc.build test places bootstrapped jar here DOTTY_JAR=$DOTTY_ROOT/dotty.jar CompilerMain=dotty.tools.dotc.Main FromTasty=dotty.tools.dotc.FromTasty ReplMain=dotty.tools.dotc.repl.Main # Autodetecting the scala-library location, in case it wasn't provided by an environment variable if [ "$SCALA_LIBRARY_JAR" == "" ] then SCALA_LIBRARY_JAR=$HOME/.ivy2/cache/org.scala-lang/scala-library/jars/scala-library-$SCALA_VERSION.jar # this is location where sbt stores it in ivy cache fi # save as for scala-library now for scala-reflect if [ "$SCALA_REFLECT_JAR" == "" ] then SCALA_REFLECT_JAR=$HOME/.ivy2/cache/org.scala-lang/scala-reflect/jars/scala-reflect-$SCALA_VERSION.jar fi if [ "$SCALA_COMPILER_JAR" == "" ] then SCALA_COMPILER_JAR=$HOME/.ivy2/cache/me.d-d/scala-compiler/jars/scala-compiler-$SCALA_COMPILER_VERSION.jar fi if [ "$JLINE_JAR" == "" ] then JLINE_JAR=$HOME/.ivy2/cache/jline/jline/jars/jline-$JLINE_VERSION.jar fi if [ "$SBT_INTERFACE_JAR" == "" ] then SBT_INTERFACE_JAR=$HOME/.ivy2/cache/org.scala-sbt/interface/jars/interface-$SBT_VERSION.jar fi if [ ! -f "$SCALA_LIBRARY_JAR" -o ! -f "$SCALA_REFLECT_JAR" -o ! -f "$SCALA_COMPILER_JAR" -o ! -f "$JLINE_JAR" -o ! -f "$SBT_INTERFACE_JAR" ] then echo To use this script please set echo SCALA_LIBRARY_JAR to point to scala-library-$SCALA_VERSION.jar "(currently $SCALA_LIBRARY_JAR)" echo SCALA_REFLECT_JAR to point to scala-reflect-$SCALA_VERSION.jar "(currently $SCALA_REFLECT_JAR)" echo SCALA_COMPILER_JAR to point to scala-compiler-$SCALA_VERSION.jar with bcode patches "(currently $SCALA_COMPILER_JAR)" echo JLINE_JAR to point to jline-$JLINE_VERSION.jar "(currently $JLINE_JAR)" echo SBT_INTERFACE_JAR to point to interface-$SBT_VERSION.jar "(currently $SBT_INTERFACE_JAR)" fi ifdebug () { [[ -n $debug ]] && eval "$@" } echoErr () { echo >&2 "$@" } dlog () { [[ -n $debug ]] && echoErr "$@" } die() { echo "Aborting: $@" exit 1 } echoArgs () { echoErr "" for arg; do echoErr "$arg" done echoErr "" } execCommand () { ifdebug echoArgs "$@" ignore="$(cat "$HOME/.scala_ignore_crashes" 2>/dev/null)" if [[ $ignore == "true" ]]; then "$@" 2>&1 | scala-crash-filter else $@ fi } # restore stty settings (echo in particular) restoreSttySettings () { dlog "" && dlog "[restore stty] $saved_stty" stty $saved_stty && saved_stty="" } onExit () { [[ -n $saved_stty ]] && restoreSttySettings exit $scala_exit_status } # Get debug set early for arg in "$@"; do [[ $arg == "-debug" ]] && debug=true done # to reenable echo if we are interrupted before completing. trap onExit INT # save terminal settings saved_stty="$(stty -g 2>/dev/null)" # clear on error so we don't later try to restore them [[ $? ]] || saved_stty="" dlog "[save stty] $saved_stty" if uname | grep -q ^CYGWIN; then cygwin="$(uname)" fi addJava () { dlog "[addJava] arg = '$1'" java_args+=("$1") } addScala () { dlog "[addScala] arg = '$1'" scala_args+=("$1") } addResidual () { dlog "[residual] arg = '$1'" residual_args+=("$1") } onExit() { [[ -n $saved_stty ]] && restoreSttySettings exit $scala_exit_status } # to reenable echo if we are interrupted before completing. trap onExit INT # If using the boot classpath, also pass an empty classpath # to java to suppress "." from materializing. classpathArgs () { if [[ "true" == $bootstrapped ]]; then check_jar "dotty-bootstrapped" $DOTTY_JAR "target" 'build_jar "test:runMain dotc.build" target' &> /dev/null toolchain="$DOTTY_JAR:$SCALA_LIBRARY_JAR:$SCALA_REFLECT_JAR:$SCALA_COMPILER_JAR:$JLINE_JAR:$SBT_INTERFACE_JAR" else toolchain="$SCALA_LIBRARY_JAR:$SCALA_REFLECT_JAR:$SCALA_COMPILER_JAR:$JLINE_JAR:$SBT_INTERFACE_JAR" fi bcpJars="$INTERFACES_JAR:$MAIN_JAR" cpJars="$INTERFACES_JAR:$MAIN_JAR:$TEST_JAR" if [[ -n "$cygwin" ]]; then if [[ "$OS" = "Windows_NT" ]] && cygpath -m .>/dev/null 2>/dev/null ; then format=mixed else format=windows fi if [[ -n $bootcp ]]; then boot_classpath="$(cygpath --path --$format "$toolchain:$bcpJars")" classpath="$(cygpath --path --$format "$cpJars")" cpArgs="-Xbootclasspath/a:$boot_classpath -classpath $classpath" else classpath="$(cygpath --path --$format "$toolchain:$cpJars")" cpArgs="-classpath $classpath" fi else if [[ -n $bootcp ]]; then cpArgs="-Xbootclasspath/a:$toolchain:$bcpJars -classpath $cpJars" else cpArgs="-classpath $toolchain:$cpJars" fi fi echo ${cpArgs} } # e.g. path -java-home /path/to/java_home require_arg () { local type="$1" local opt="$2" local arg="$3" if [[ -z "$arg" ]] || [[ "${arg:0:1}" == "-" ]]; then die "$opt requires <$type> argument" fi } main_class=$CompilerMain while [[ $# -gt 0 ]]; do case "$1" in --) shift; for arg; do addResidual "$arg"; done; set -- ;; -h|-help) help=true && shift ;; -bootstrapped) bootstrapped=true && shift ;; -v|-verbose) verbose=true && shift ;; -debug) debug=true && shift ;; -q|-quiet) quiet=true && shift ;; # Optimize for short-running applications, see https://github.com/lampepfl/dotty/issues/222 -Oshort) addJava "-XX:+TieredCompilation -XX:TieredStopAtLevel=1" && shift ;; -repl) main_class=$ReplMain && shift ;; -tasty) main_class=$FromTasty && shift ;; -compile) main_class=$CompilerMain && shift ;; -run) main_class=$ReplMain && shift ;; -fsc) main_class=$FscMain && shift ;; -bootcp) bootcp=true && shift ;; -nobootcp) unset bootcp && shift ;; -colors) colors=true && shift ;; -no-colors) unset colors && shift ;; -jrebel) jrebel=true && shift ;; -no-jrebel) unset jrebel && shift ;; -toolcp) require_arg classpath "$1" "$2" && toolcp="$2" && shift 2 ;; -java-home) require_arg path "$1" "$2" && java_cmd="$2/bin/java" && shift 2 ;; # break out -D and -J options and add them to JAVA_OPTS as well # so they reach the JVM in time to do some good. The -D options # will be available as system properties. -D*) addJava "$1" && addScala "$1" && shift ;; -J*) addJava "${1:2}" && addScala "$1" && shift ;; *) addResidual "$1" && shift ;; esac done [[ -z $java_cmd ]] && prefix=${java_home:+$java_home/bin/} && java_cmd="${prefix}java" # note that variables which may intentionally be empty must not # be quoted: otherwise an empty string will appear as a command line # argument, and java will think that is the program to run. execCommand \ "$java_cmd" \ ${JAVA_OPTS:-$default_java_opts} \ "${java_args[@]}" \ "$(classpathArgs)" \ -Dscala.usejavacp=true \ "${main_class}" \ "${scala_args[@]}" \ "${residual_args[@]}" # record the exit status lest it be overwritten: # then reenable echo and propagate the code. scala_exit_status=$? onExit #echo java -cp $MAIN_JAR: -Dscala.usejavacp=true dotty.tools.dotc.Main $@