Javatrans: Java byte-code to C++ translator
Chris Greenhalgh, 2006-03-29; last updated 2006-05-05
Contents
- Introduction
- Building_and_testing
- Usage
- Output_files
- Compiling_output
- Known_Issues
- Change_Log
See also:
1. Introduction
Javatrans is a general-purpose Java to C++ translator, that has been
developed to allow the (Java-based) EQUIP2 system to be automatically
ported to C++, and in particular to C++ for Windows, Linux and the
Symbian OS used on many
mobile phones (partial).
Javatrans itself is written in Java, the main javatrans application
being javatrans.GenerateCPP.
I have not attempted to translate any of the built-in Java packages
or classes, since Javatrans cannot do anything to translate native
methods and also because these constitutes reverse engineering and may
be in breach of license(s) for Java. However I have provided partial
from scratch C++ implementations of the core classes and methods used
(so far) by the code which I have translated. This includes quite a few
java.lang classes and a
small number of java.io
and java.util classes
(see ../src.cpp/).
Javatrans is used to translate groups of related classes into a C++
DLL, library or application.
2. Building and testing
2.1. Getting Javatrans
At present Javatrans is in CVS accessible as:
CVSROOT :pserver:anonymous@dumas.mrl.nott.ac.uk:/mrl/src/cvsroot
/Equator/javatrans
This is likely to move, e.g. to sourceforge, before too long. Before
then the copyright boilerplates will be added, probably (so called)
modified BSD.
Building Javatrans
There is an Apache ANT build.xml
file for Javatrans. Current build targets include:
- jar - compile and
jar the javatrans application.
- clean - delete
built and generated files.
- test - translate some test applications- Java test classes in ../src/example/,
producing output in ../generated/.
The C++ support library and generated code is currently built using
batch files (windows) or symbian projects. The top-level targets/ directory has target platform specific
subdirectories with build scripts:
- targets/win32/ for Windows,
including:
- buildlib-win32.bat
-
build the support library, dist/win32/javasupport.dll
& .lib.
- buildexample-win32.bat
- build the test code in generated/
(after ant test) to make dist/win32/example.exe.
- targets/unix/ for Posix unix,
including GNU/Linux (gcc)
- targets/symbian/ for Symbian.
This is just a placeholder; out of date symbian project files are under
the top-level symbian/ directory.
Windows
So
a basic test for Windows would be (starting in the top-level javatrans directory):
> ant jar
> ant test
[now with a visual studio shell...]
> cd targets\win32
> buildlib-win32.bat
> buildexample-win32.bat
If successful this will compile all of the generated and
hand-crafted support files as described above, and leave a single
executable, dist/win32/example.exe,
and supporting dll dist/win32/javasupport.dll,
which can be used
more or less equivalently to the java
command (both must be in the shell path).
Unix
Equivalently for Unix (you might need to set execute permissions on
the batch files):
> ant jar
> ant test
> cd targets\unix
> buildlib.sh
> buildexample.sh
If successful this will compile all of the generated and
hand-crafted support files as described above, and leave a single
executable, dist/unix/example,
and supporting (currently static) library dist/unix/libjavasupport.a,
which can be used
more or less equivalently to the java
command (both must be in the shell path).
Testing Javatrans
Running generated/example.exe
with no arguments will list the
available classes that can be run with it; for example, for the
examples the output would be:
> dist/win32/example.exe [or dist/unix/example]
Usage: <classname> ...
Known classes:
example.ArrayTest
example.ClassesTest
example.ConstTest
example.ForTest
example.HashtableTest
example.Print
example.SwitchTest
example.SyncTest
example.ThreadSyncTest
example.UnicodeTest
example.VectorTest
For example:
> dist/win32/example.exe example.Print
Hello world!
0 = 0
3. Usage
Command-line usage of the translator is:
java javatrans.GenerateCPP [-m(ain)] [-d <dependencies-directory>] [-l <library-name>]
[-L <dependent-library-name>]* <output-directory> <input-classfile1> ...
Where the options are:
- -m - generate a main
file with entry point (not symbian), which can be used to run
translated java applications much like the java command.
- -d
<dependencies-directory> - generate skeleton header and
body files for dependencies found in translation (untranslated classes
and their referenced fields and methods).
- -l <library-name>
- specify the name of the library to be generated (default 'library');
it is important that translated libraries that are to be used together
(from the same application) have distinct library names specified.
- -L
<dependent-library-name> - only required with -m option - specify a dependent
library, which therefore needs to be initialised before being used in
the generated main.
- Classfiles can be specified as path to .class file, as a
directory path ending in '/' for all .class files in that directory, or
a directory path ending in '//' for all .class file in that directory
and sub-directories (recursively).
Because of the supporting files generated (see below) it is
currently best to convert all class files in one invocation of
javatrans.
If the input class files were compiling with debugging information
then this will be used to determine the names of method arguments and
local variables, otherwise default names will be used (e.g. "arg1",
...).
3.1. Output files
This application reads the specified java .class files (i.e. Java
bytecode files) and generates a corresponding set of C++ header (.h) and body (.cpp) files. The C++ file name
is (usually - see below) the same as the name of the generated C++
class, which is derived from the package-qualified Java class name,
except that:
- '.' becomes '_'
- '$' becomes '_'
For example, the java input class example.PrintTest will be
converted to the C++ class example_PrintTest,
declared in the C++ header file example_PrintTest.h
and defined in the C++ body/implementation file example_PrintTest.cpp. The
exception referred to above is that Symbian and/or the tool chain for
ARM development has a relatively limited maximum path name, so
currently filenames longer than 40 characters are shortened to 40
characters. The current heuristic used is to preserve the last word of
the filename - usually the class name - and to truncate the package
name, inserting an integer to avoid clashes with other converted files
(during the same conversion run).
Javatrans will only translate specifically identified class files.
However, where these class files include references to other classes or
their methods or fields it will optionally generate stub C++ headers
and body
files for which implenentations must be provided if the translated code
is to compile; this option is enabled by the '-d <directory>' option.
It also generates some additional files containing common
functions/fields for all processed files:
- LIBRARY.h and LIBRARY.cpp - library-specific
files containing library initialisation/entry point(s) (currently the
function 'void LIBRARY_init()'
which must be called before a library is used from another
application), class registration
functions (used by to support Java's java.lang.Class.forName(String)
capability), static class variables and supporting compile-time
definitions. LIBRARY is
specified by '-l
<library-name>' option; defaults to 'library'.
- main.cpp - only for
Windows OS (not Symbian), allows the various public static void main(String[])
application methods in the processed classes to be called from a single
C++ main function. Generated when '-m'
option is specified.
3.2. Compiling output
Output files should be compiled in the usual way for the target OS. The
only non-standard requirement is that the target OS must be defined by
setting a compiler definition, currently one of:
- TARGET_WIN32 - for a
build for Windows native OS
- TARGET_UNIX - for
POSIX C++, e.g. GNU/Linux (Gcc)
- TARGET_SYMBIAN - for
a build for Symbian OS, either emulator or actual device.
In addition, javatrans presumes that (like Java) unicode will be
supported rather than a single-byte character set; on windows and
symbian this requires the definition of:
- _UNICODE - to
specify support for Unicode (16 bit rather than 8 bit) characters.
Source-code and headers for a subset of java support classes (from
java.lang, java.io and java.util) are included in the src.cpp/ and src.cpp/include directories.
These can
be compiled to a library for each supported platform as described
above. Compiling generated files will depend on at least a subset of
these
header files, and will need to be linked with the compiled library/DLL.
4. Known Issues
- Although many Java bytecode instructions are supported, some are
not. The application will terminate immediately with an error message
if you attempt to translate a class file containing an unsupport byte
code instruction.
- Only a limited subset of java.lang/io/util classes and methods
have currently been implemented. EQUIP2 is a J2ME/J2SE application to I
have only been targetting their intersection.
- Windows does not cope properly with '\u0000' in a string, even
with the new unicode support (e.g. in a string constant it will be
taken as the end of the string).
- The global variables and other 'global' (on Symbian,
thread-local) state is not currently freed at any point.
- I have had trouble on Symbian with defining my own additional
java-like classes outside the main DLL with the core/translated classes
in (error during DLL loading). Really not sure what this is about :-(
- Exceptions are not currently supported, and will probably cause
an ABORT (Windows) or thread Panic (Symbian).
Change Log
2007-05-30
- updated target info, including Unix
2006-05-05
2006-05-04
- documentation of support library and test build now as separate
DLL/executable, and further revision of usage/file generation to match
this new structure.
2006-05-03
- modified usage. Removed equip-specific stuff (to equip2)
2006-03-29