Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I tell what Scala version a .class file was compiled with?

Tags:

version

scala

How can I tell what Scala version a .class file was compiled with?

like image 643
Seth Tisue Avatar asked Jul 22 '10 16:07

Seth Tisue


People also ask

How do I find the compiled version of a class file?

In Java, we can use javap -verbose className to print out the Java class file information; the output includes the major version number. Or we can use the javap -verbose JavaClassName | grep major to display only the major version of the Java class file.

How do I know my Scala version?

Check Scala Version Using scala CommandWrite the scala command to your terminal and press enter. After that, it opens Scala interpreter with a welcome message and Scala version and JVM details.

How do I view a .class file?

A simple way to see what String literals are used in a ". class" file is to use the javap utility in your JDK installation to dump the file using the "-v" option. Then grep for text that looks like <String "..."> where ... is the String you are looking for.


2 Answers

I suppose the information is stored in the "pickled" part of the .class file, according to the 2008 "Reflecting Scala" rapport, from Yohann Coppel, under the supervision of Prof. Martin Odersky.

During the compilation process (represented on fig. 2), the Scala compiler generates two types of data.

  • The first one is some classic Java bytecode, which can be read and executed by a standard Java virtual machine.
  • The second one is what is called “Pickled data”, and represents the basic structure of the original source file.
    This information is enclosed in a .class file.
    The Java bytecode specification allows the compiler to “define and emit class files containing new attributes in the attributes tables of class file structures”. These attributes are silently ignored by JVMs if they do not recognize them.

Pickelr

The Scala compiler generates pickled data for about any data structure in a Scala program, called symbols in the pickler context.
Symbols are stored linearly with the format shown on Fig. 3.

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

  • The tag represents the type of data stored,
  • then the length gives the length of the following data block.
  • The data block can contain multiple information, such as the name of a symbol.
ScalaSig = "ScalaSig" Version Symtab
Version = Major_Nat Minor_Nat         <====
Symtab = numberOfEntries_Nat {Entry}

The ScalaSig attribute definition.
A more complete definition can be found in the scala.tools.nsc.symtab.PickleFormat source file (now scala.reflect.internal.pickling.PickleFormat).

You can also see how to read the Pickled data in scala.tools.nsc.util.ShowPickled.


This page shows a script (not tested) which will display the pickled data:

#!/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 $*
like image 112
VonC Avatar answered Sep 29 '22 16:09

VonC


You can see the Scala Major/Minor version in the class file if you use javap with the verbose option. For example, the following is shown for a file compiled using 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...

while the following is the output of a file compiled using 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...

The first two bytes of the ScalaSig constant entry should represent the scala Major/Minor version, I believe, which are defined in PickleFormat. The 2.7.7 version of PickleFormat can be found here, and shows that the major/minor version differs from the 2.8.0 version.

I checked the 2.7.1 version of this class as well, but here the Major/Minor version is the same as the 2.7.7 one, so you may not be able to distinguish between minor scala versions by using this method.

like image 44
Arjan Blokzijl Avatar answered Sep 29 '22 15:09

Arjan Blokzijl