Как я могу определить, какая версия Scala была скомпилирована .class файлом?
Как я могу определить, с какими Scala версиями был скомпилирован файл .class?
Ответ 1
Вы можете увидеть версию Scala Major/Minor в файле класса, если вы используете javap
с расширенной опцией. Например, показано следующее для файла, скомпилированного с помощью Scala 2.8.0 final:
javap -private -verbose T
Compiled from "SomeTest.scala"
public interface T
SourceFile: "SomeTest.scala"
ScalaSig: length = 0x3
05 00 00
RuntimeVisibleAnnotations: length = 0xB
00 01 00 06 00 01 00 07 73 00 08
minor version: 0
major version: 49
Constant pool:
const #1 = Asciz SourceFile;
const #2 = Asciz SomeTest.scala;
const #3 = Asciz s;
const #4 = Asciz ()Ljava/lang/String;;
const #5 = Asciz ScalaSig;
//etc etc...
в то время как следующий результат - это файл, скомпилированный с помощью Scala 2.7.7:
javap -verbose T2
Compiled from "SomeTest2.scala"
public interface T2
SourceFile: "SomeTest2.scala"
ScalaSig: length = 0x87
04 01 1B 06 08 01 02 FFFFFF84 FFFFFF90 FFFFFF80 FFFFFF91 00 05 02 02 54
32 0A 01 03 01 07 3C 65 6D 70 74 79 3E 03 00 13
02 00 06 10 02 07 0C 0D 01 08 0A 02 09 0A 01 04
6C 61 6E 67 0A 01 0B 01 04 6A 61 76 61 09 02 0D
08 02 06 4F 62 6A 65 63 74 08 05 0F 00 FFFFFF86 00 10
01 01 73 15 01 11 10 02 12 18 0E 02 13 16 0D 01
14 0A 01 15 01 05 73 63 61 6C 61 09 02 17 14 01
06 50 72 65 64 65 66 09 02 19 1A 02 06 53 74 72
69 6E 67 0A 02 17 14
minor version: 0
major version: 49
Constant pool:
const #1 = Asciz SourceFile;
const #2 = Asciz SomeTest2.scala;
//etc etc...
Первые два байта константной записи ScalaSig должны представлять Scala версию Major/Minor, я полагаю, которые определены в PickleFormat. Версия 2.7.7 версии PickleFormat можно найти здесь и показывает, что основная/младшая версия отличается от версии 2.8.0.
Ответ 2
Я полагаю, что информация хранится в "маринованной" части файла .class
, в соответствии с 2008 "Отражение Scala" rapport, от Йоханна Коппеля, под руководством профессора Мартина Одерского.
В процессе компиляции (представлен на рисунке 2) компилятор Scala генерирует два типа данных.
- Первый - это классический байт-код Java, который можно читать и выполнять стандартной виртуальной машиной Java.
- Второй - это то, что называется "Рассыпчатые данные", и представляет основную структуру исходного исходного файла.
Эта информация содержится в файле.class
.
Спецификация байт-кода Java позволяет компилятору "определять и выпускать файлы классов, содержащие новые атрибуты в таблицах атрибутов структур файлов классов". Эти атрибуты молча игнорируются JVM, если они не распознают их.
Компилятор Scala генерирует маринованные данные для любой структуры данных в программе Scala, называемой символами в контексте pickler.
Символы сохраняются линейно в формате, показанном на рисунке 3.
- Тег представляет тип хранимых данных,
- тогда длина дает длину следующего блока данных.
- Блок данных может содержать несколько информации, например, имя символа.
ScalaSig = "ScalaSig" Version Symtab
Version = Major_Nat Minor_Nat <====
Symtab = numberOfEntries_Nat {Entry}
Определение атрибута ScalaSig.
Более полное определение можно найти в исходном файле(теперьscala.tools.nsc.symtab.PickleFormat
scala.reflect.internal.pickling.PickleFormat
).
Вы также можете увидеть, как читать данные Масленицы в scala.tools.nsc.util.ShowPickled
.
Эта страница показывает script (не тестируется), в котором будут отображены маринованные данные:
#!/bin/sh
#
# Shows the pickled scala data in a classfile.
if [ $# == 0 ] ; then
echo "Usage: $0 [--bare] [-cp classpath] <class*>"
exit 1
fi
TOOLSDIR=`dirname $0`
CPOF="$TOOLSDIR/cpof"
PACK="$TOOLSDIR/../build/pack/lib"
QUICK="$TOOLSDIR/../build/quick/classes"
STARR="$TOOLSDIR/../lib"
CP=""
if [ -f "${PACK}/scala-library.jar" ] ; then
CP=`${TOOLSDIR}/packcp`
elif [ -d "${QUICK}/library" ] ; then
CP=`${TOOLSDIR}/quickcp`
else
CP=`${TOOLSDIR}/starrcp`
fi
if [ "$1" == "-cp" ] ; then
shift
CP="${1}:${CP}"
shift
fi
java -cp "$CP" scala.tools.nsc.util.ShowPickled $*
Ответ 3
Скорее всего, вы можете проанализировать файл .class и прочитать версию из атрибута, прикрепленного к компилятору scala, в файл класса.
Чтобы узнать больше о существовании такого атрибута, вы можете начать с источников компилятора scala (http://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala).
Чтобы узнать, как разбирать файл .class, вы можете прочитать в спецификации (http://jcp.org/aboutJava/communityprocess/final/jsr202/index.html).
Пример кода, который я разместил здесь (Модификаторы класса Java Illegal Код исключения 0x209), также может помочь в реализации.
Ответ 4
FWIW, Здесь версия VonC script, которая устанавливает путь к классу scala -library.jar и scala -compiler.jar
Протестировано под cygwin и linux, с scala 2.11.8 и 2.12.1, Должен работать под OSX. Кажется, вам не нравится - простой аргумент.
(требуется scala для вашего PATH.)
#!/bin/bash
# Shows the pickled scala data in a classfile.
if [ $# == 0 ] ; then
echo "Usage: $0 [--bare] [-cp classpath] <class*>"
exit 1
fi
unset JAVA_TOOL_OPTIONS
[ -z "$SCALA_HOME" ] && SCALA_HOME=$(which scala | sed -e 's#/bin/scala##')
export OSTYPE=$(uname | tr '[A-Z]' '[a-z]' | sed -e 's#[_0-9].*##')
case $OSTYPE in
cygwin) SEP=";" ;;
*) SEP=":" ;;
esac
CP="${SCALA_HOME}/lib/scala-library.jar${SEP}${SCALA_HOME}/lib/scala-compiler.jar${SEP}${SCALA_HOME}/lib/scala-reflect.jar"
if [ "$1" == "-cp" ] ; then
shift
CP="${1}${SEP}${CP}"
shift
fi
java -cp "$CP" scala.tools.nsc.util.ShowPickled $*