Как узнать, с какой версией Scala был скомпилирован файл .class?

Как узнать, с какой версией Scala был скомпилирован файл .class?


person Seth Tisue    schedule 22.07.2010    source источник
comment
Вывод: javap -verbose YouClass дает (используя пример classfile) ScalaSig: length = 0x3 05 00 00 возможно, это полезно?   -  person Don Mackenzie    schedule 22.07.2010
comment
Вы пробовали класс ShowPickeld, о котором я упоминаю в своем ответе? Он имеет метод main(), где вы можете ввести путь к файлу .class. Я только что добавил скрипт для вызова этого класса утилиты.   -  person VonC    schedule 23.07.2010


Ответы (4)


Вы можете увидеть версию 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. Версию PickleFormat 2.7.7 можно найти 7_7_final/src/compiler/scala/tools/nsc/symtab/classfile. /PickleFormat.scala" rel="noreferrer">здесь и показывает, что основная/дополнительная версия отличается от версии 2.8.0.

Я проверил версию 2.7.1 7javapfinal/src/compiler/scala/tools/nsc/symtab/classfile/PickleFormat. .scala" rel="noreferrer">этот класс, но здесь версия Major/Minor такая же, как и версия 2.7.7, поэтому вы не сможете отличить второстепенные версии scala, используя этот метод.

person Arjan Blokzijl    schedule 24.07.2010
comment
Интересный. +1. Вы пробовали использовать класс ShowPickled, о котором я упоминал в своем ответе? - person VonC; 24.07.2010
comment
@VonC: я быстро попробовал это из командной строки, но он напечатал только это: Версия -1345413376.0 Должно быть, я сделал что-то не так, но пока не понял, что это такое. - person Arjan Blokzijl; 25.07.2010

Я предполагаю, что информация хранится в "маринованной" части файла .class в соответствии с Взаимопонимание «Отражение Scala», 2008 г., от Йоханна Коппеля, под руководством профессора Мартина Одерски.

В процессе компиляции (представлен на рис. 2) компилятор Scala генерирует два типа данных.

  • Первый — это классический байт-код Java, который может быть прочитан и выполнен стандартной виртуальной машиной Java.
  • Второй файл называется «Pickled data» и представляет собой базовую структуру исходного файла.
    Эта информация заключена в файл .class.
    Спецификация байт-кода Java позволяет компилятору «определять и выдавать файлы классов, содержащие новые атрибуты в таблицах атрибутов структур файлов классов». Эти атрибуты молча игнорируются JVM, если они их не распознают.

Пикельр

Компилятор Scala генерирует обработанные данные для любой структуры данных в программе Scala, которые в контексте сборщика называются символами.
Символы хранятся линейно в формате, показанном на рис. 3.

http://img27.i_mageshack.us/img27/4042/scalapickledformat.png

  • Тег представляет тип хранимых данных,
  • тогда длина дает длину следующего блока данных.
  • Блок данных может содержать различную информацию, например имя символа.
ScalaSig = "ScalaSig" Version Symtab
Version = Major_Nat Minor_Nat         <====
Symtab = numberOfEntries_Nat {Entry}

Определение атрибута ScalaSig.
Более полное определение можно найти в исходном файле scala.tools.nsc.symtab.PickleFormat (теперь scala.reflect.internal.pickling.PickleFormat).

Вы также можете увидеть, как читать данные Pickled, в scala.tools.nsc.util.ShowPickled.


На этой странице показан скрипт (не тестировался), который будет отображать маринованные данные:

#!/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 $*
person VonC    schedule 22.07.2010
comment
Из плюсов я предполагаю, что сценарий Bash работал для людей. Я получил эти ошибки при запуске скрипта из Cygwin - ShowPickled.sh: line 4: $'\r': command not found ShowPickled.sh: line 20: syntax error near unexpected token elif' ShowPickled.sh: строка 20: elif [ -d "${QUICK}/library" ] ; then. Также - первая ссылка PDF 404 - lamp.epfl.ch/teaching/projects/ архив/coppel_report.pdf - person Kevin Meredith; 23.01.2014
comment
@KevinMeredith Я восстановил ссылку в формате PDF. Я понятия не имею, может ли этот скрипт трехлетней давности работать в оболочке cygwin. - person VonC; 23.01.2014
comment
благодарю вас. Извините, я не искал PDF, прежде чем комментировать. - person Kevin Meredith; 23.01.2014
comment
См. также github.com/scala/scala/commit/ - person VonC; 27.12.2016

Скорее всего, вы могли бы проанализировать файл .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 Недопустимые модификаторы класса Код исключения 0x209 ) также может помочь в реализации.

person Arne Deutsch    schedule 22.07.2010

FWIW, вот версия сценария VonC, которая устанавливает путь к классам в scala-library.jar и scala-compiler.jar.

Протестировано под cygwin и linux, со scala 2.11.8 и 2.12.1, должно работать под OSX. Однако, похоже, аргумент --bare не нравится.

(требуется, чтобы 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 $*
person philwalk    schedule 03.02.2017
comment
Интересная версия. +1 - person VonC; 04.02.2017
comment
Я сгенерировал эту версию после того, как заметил, что scala.tools.nsc.util.ShowPickled находится в scala-compiler.jar, но я не уверен, что она сравнима с версией VonC, не играя с ней. Версия ShowPickled scala 2.12.1 не любит аргумент '--bare'... - person philwalk; 04.02.2017