Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/ReadyTalk/avian

[INACTIVE] Avian is a lightweight virtual machine and class library designed to provide a useful subset of Java's features, suitable for building self-contained applications.
https://github.com/ReadyTalk/avian

java jit-compiler jvm openjdk portable

Last synced: about 2 months ago
JSON representation

[INACTIVE] Avian is a lightweight virtual machine and class library designed to provide a useful subset of Java's features, suitable for building self-contained applications.

Awesome Lists containing this project

README

        

Avian - A lightweight Java Virtual Machine (JVM)
================================================

**PLEASE NOTE: This project is not currently being developed, maintained, or supported. Feel free to use and/or fork it, but any issues filed here will probably be ignored.**

[![Build Status](https://travis-ci.org/ReadyTalk/avian.png?branch=master)](https://travis-ci.org/ReadyTalk/avian)

Quick Start
-----------

These are examples of building Avian on various operating systems for
the x86_64 architecture. You may need to modify JAVA_HOME according
to where the JDK is installed on your system. In all cases, be sure
to use forward slashes in the path.

#### on Linux:
$ export JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64
$ make
$ build/linux-x86_64/avian -cp build/linux-x86_64/test Hello

#### on Mac OS X:
$ export JAVA_HOME=$(/usr/libexec/java_home)
$ make
$ build/macosx-x86_64/avian -cp build/macosx-x86_64/test Hello

#### on Windows (Cygwin):
$ git clone [email protected]:ReadyTalk/win64.git ../win64
$ export JAVA_HOME="/cygdrive/c/Program Files/Java/jdk1.7.0_45"
$ make
$ build/windows-x86_64/avian -cp build/windows-x86_64/test Hello

#### on FreeBSD:
$ export JAVA_HOME=/usr/local/openjdk7
$ gmake
$ build/freebsd-x86_64/avian -cp build/freebsd-x86_64/test Hello

Introduction
------------

Avian is a lightweight virtual machine and class library designed to
provide a useful subset of Java's features, suitable for building
self-contained applications.

Supported Platforms
-------------------

Avian can currently target the following platforms:

* Linux (i386, x86_64, ARM, and ARM64)
* Windows (i386 and x86_64)
* Mac OS X (i386 and x86_64)
* Apple iOS (i386, x86_64, ARM, and ARM64)
* FreeBSD (i386, x86_64)

Building
--------

Build requirements include:

* GNU make 3.80 or later
* GCC 4.6 or later
or LLVM Clang 3.1 or later (see use-clang option below)
* JDK 1.6 or later
* MinGW 3.4 or later (only if compiling for Windows)
* zlib 1.2.3 or later

Earlier versions of some of these packages may also work but have not
been tested.

The build is directed by a single makefile and may be influenced via
certain flags described below, all of which are optional.

$ make \
platform={linux,windows,macosx,ios,freebsd} \
arch={i386,x86_64,arm,arm64} \
process={compile,interpret} \
mode={debug,debug-fast,fast,small} \
lzma= \
bootimage={true,false} \
tails={true,false} \
continuations={true,false} \
use-clang={true,false} \
openjdk= \
openjdk-src= \
android= \
ios-version=

* `platform` - the target platform
* _default:_ output of $(uname -s | tr [:upper:] [:lower:]),
normalized in some cases (e.g. CYGWIN_NT-5.1 -> windows)

* `arch` - the target architecture
* _default:_ output of $(uname -m), normalized in some cases
(e.g. i686 -> i386)

* `process` - choice between pure interpreter or JIT compiler
* _default:_ compile

* `mode` - which set of compilation flags to use to determine
optimization level, debug symbols, and whether to enable
assertions
* _default:_ fast

* `lzma` - if set, support use of LZMA to compress embedded JARs and
boot images. The value of this option should be a directory
containing a recent LZMA SDK (available [here](http://www.7-zip.org/sdk.html)). Currently, only version 9.20 of
the SDK has been tested, but other versions might work.
* _default:_ not set

* `armv6` - if true, don't use any instructions newer than armv6. By
default, we assume the target is armv7 or later, and thus requires explicit
memory barrier instructions to ensure cache coherency

* `bootimage` - if true, create a boot image containing the pre-parsed
class library and ahead-of-time compiled methods. This option is
only valid for process=compile builds. Note that you may need to
specify both build-arch=x86_64 and arch=x86_64 on 64-bit systems
where "uname -m" prints "i386".
* _default:_ false

* `tails` - if true, optimize each tail call by replacing the caller's
stack frame with the callee's. This convention ensures proper
tail recursion, suitable for languages such as Scheme. This
option is only valid for process=compile builds.
* _default:_ false

* `continuations` - if true, support continuations via the
avian.Continuations methods callWithCurrentContinuation and
dynamicWind. See Continuations.java for details. This option is
only valid for process=compile builds.
* _default:_ false

* `use-clang` - if true, use LLVM's clang instead of GCC to build.
Note that this does not currently affect cross compiles, only
native builds.
* _default:_ false

* `openjdk` - if set, use the OpenJDK class library instead of the
default Avian class library. See "Building with the OpenJDK Class
Library" below for details.
* _default:_ not set

* `openjdk-src` - if this and the openjdk option above are both set,
build an embeddable VM using the OpenJDK class library. The JNI
components of the OpenJDK class library will be built from the
sources found under the specified directory. See "Building with
the OpenJDK Class Library" below for details.
* _default:_ not set

* `android` - if set, use the Android class library instead of the
default Avian class library. See "Building with the Android Class
Library" below for details.
* _default:_ not set

* `ios-version` - the minimum iOS SDK version which will be used
when compiling for ios target. Do not use a value 11.0 or larger,
if you want to support 32 bit version. This option is only valid
for platform=ios .
* _default:_ 8.0

These flags determine the name of the directory used for the build.
The name always starts with _${platform}-${arch}_, and each non-default
build option is appended to the name. For example, a debug build with
bootimage enabled on Linux/x86_64 would be built in
_build/linux-x86_64-debug-bootimage_. This allows you to build with
several different sets of options independently and even
simultaneously without doing a clean build each time.

Note that not all combinations of these flags are valid. For instance,
non-jailbroken iOS devices do not allow JIT compilation, so only
process=interpret or bootimage=true builds will run on such
devices. See [here](https://github.com/ReadyTalk/hello-ios) for an
example of an Xcode project for iOS which uses Avian.

If you are compiling for Windows, you may either cross-compile using
MinGW or build natively on Windows under Cygwin.

#### Installing Cygwin:

__1.__ Download and run setup.exe from [cygwin's website](http://www.cygwin.com), installing the base
system and these packages: make, gcc-mingw-g++,
mingw64-i686-gcc-g++, mingw64-x86_64-gcc-g++, and (optionally) git.

You may also find our win32 repository useful: (run this from the
directory containing the avian directory)

$ git clone [email protected]:ReadyTalk/win32.git

This gives you the Windows JNI headers, zlib headers and library, and
a few other useful libraries like OpenSSL, libjpeg, and libpng.
There's also a win64 repository for 64-bit builds:

$ git clone [email protected]:ReadyTalk/win64.git

Building with the Microsoft Visual C++ Compiler
-----------------------------------------------

You can also build using the MSVC compiler, which makes debugging with
tools like WinDbg and Visual Studio much easier. Note that you will
still need to have GCC installed - MSVC is only used to compile the
C++ portions of the VM, while the assembly code and helper tools are
built using GCC.

*Note that the MSVC build isn't tested regularly, so is fairly likely to be broken.*

Avian targets MSVC 11 and above (it uses c++ features not available in older versions).

To build with MSVC, install Cygwin as described above and set the
following environment variables:

$ export PATH="/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:/cygdrive/c/Program Files/Microsoft Visual Studio 11.0/Common7/IDE:/cygdrive/c/Program Files/Microsoft Visual Studio 11.0/VC/BIN:/cygdrive/c/Program Files/Microsoft Visual Studio 11.0/Common7/Tools:/cygdrive/c/WINDOWS/Microsoft.NET/Framework/v3.5:/cygdrive/c/WINDOWS/Microsoft.NET/Framework/v2.0.50727:/cygdrive/c/Program Files/Microsoft Visual Studio 11.0/VC/VCPackages:/cygdrive/c/Program Files/Microsoft SDKs/Windows/v6.0A/bin:/cygdrive/c/WINDOWS/system32:/cygdrive/c/WINDOWS:/cygdrive/c/WINDOWS/System32/Wbem"
$ export LIBPATH="C:\WINDOWS\Microsoft.NET\Framework\v3.5;C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727;C:\Program Files\Microsoft Visual Studio 11.0\VC\LIB;"
$ export VCINSTALLDIR="C:\Program Files\Microsoft Visual Studio 11.0\VC"
$ export LIB="C:\Program Files\Microsoft Visual Studio 11.0\VC\LIB;C:\Program Files\Microsoft SDKs\Windows\v6.0A\lib;"
$ export INCLUDE="C:\Program Files\Microsoft Visual Studio 11.0\VC\INCLUDE;C:\Program Files\Microsoft SDKs\Windows\v6.0A\include;"

Adjust these definitions as necessary according to your MSVC
installation.

Finally, build with the msvc flag set to the MSVC tool directory:

$ make msvc="/cygdrive/c/Program Files/Microsoft Visual Studio 11.0/VC"

Building with the OpenJDK Class Library
---------------------------------------

By default, Avian uses its own lightweight class library. However,
that library only contains a relatively small subset of the classes
and methods included in the JRE. If your application requires
features beyond that subset, you may want to tell Avian to use
OpenJDK's class library instead. To do so, specify the directory
where OpenJDK is installed, e.g.:

$ make openjdk=/usr/lib/jvm/java-7-openjdk

This will build Avian as a conventional JVM (e.g. libjvm.so) which
loads its boot class library and native libraries (e.g. libjava.so)
from _/usr/lib/jvm/java-7-openjdk/jre_ at runtime. Note that you must
use an absolute path here, or else the result will not work when run
from other directories. In this configuration, OpenJDK needs to
remain installed for Avian to work, and you can run applications like
this:

$ build/linux-x86_64-openjdk/avian-dynamic -cp /path/to/my/application \
com.example.MyApplication

Alternatively, you can enable a stand-alone build using OpenJDK by
specifying the location of the OpenJDK source code, e.g.:

$ make openjdk=$(pwd)/../jdk7/build/linux-amd64/j2sdk-image \
openjdk-src=$(pwd)/../jdk7/jdk/src

You must ensure that the path specified for openjdk-src does not have
any spaces in it; make gets confused when dependency paths include
spaces, and we haven't found away around that except to avoid paths
with spaces entirely.

The result of such a build is a self-contained binary which does not
depend on external libraries, jars, or other files. In this case, the
specified paths are used only at build time; anything needed at
runtime is embedded in the binary. Thus, the process of running an
application is simplified:

$ build/linux-x86_64-openjdk-src/avian -cp /path/to/my/application \
com.example.MyApplication

Note that the resulting binary will be very large due to the size of
OpenJDK's class library. This can be mitigated using UPX, preferably
an LZMA-enabled version:

$ upx --lzma --best build/linux-x86_64-openjdk-src/avian

You can reduce the size futher for embedded builds by using ProGuard
and the supplied openjdk.pro configuration file (see "Embedding with
ProGuard and a Boot Image" below). Note that you'll still need to use
vm.pro in that case -- openjdk.pro just adds additional constraints
specific to the OpenJDK port. Also see
[app.mk](https://github.com/ReadyTalk/avian-swt-examples/blob/master/app.mk)
in the _avian-swt-examples_ project for an example of using Avian,
OpenJDK, ProGuard, and UPX in concert.

Here are some examples of how to install OpenJDK and build Avian with
it on various OSes:

#### Debian-based Linux:
_Conventional build:_

$ apt-get install openjdk-7-jdk
$ make openjdk=/usr/lib/jvm/java-7-openjdk test

_Stand-alone build:_

$ apt-get install openjdk-7-jdk
$ apt-get source openjdk-7-jdk
$ apt-get build-dep openjdk-7-jdk
$ (cd openjdk-7-7~b147-2.0 && dpkg-buildpackage)
$ make openjdk=/usr/lib/jvm/java-7-openjdk \
openjdk-src=$(pwd)/openjdk-7-7~b147-2.0/build/openjdk/jdk/src \
test

#### Mac OS X:
_Prerequisite:_ Build OpenJDK 7 according to [this site](https://wikis.oracle.com/display/OpenJDK/Mac+OS+X+Port).

_Conventional build:_

$ make openjdk=$(pwd)/../jdk7u-dev/build/macosx-amd64/j2sdk-image test

_Stand-alone build:_

$ make openjdk=$(pwd)/../jdk7u-dev/build/macosx-amd64/j2sdk-image \
openjdk-src=$(pwd)/../p/jdk7u-dev/jdk/src test

#### Windows (Cygwin):
_Prerequisite:_ Build OpenJDK 7 according to [this site](http://weblogs.java.net/blog/simonis/archive/2011/10/28/yaojowbi-yet-another-openjdk-windows-build-instruction). Alternatively, use https://github.com/alexkasko/openjdk-unofficial-builds.

_Conventional build:_

$ make openjdk=$(pwd)/../jdk7u-dev/build/windows-i586/j2sdk-image test

_Stand-alone build:_

$ make openjdk=$(pwd)/../jdk7u-dev/build/windows-i586/j2sdk-image \
openjdk-src=$(pwd)/../p/jdk7u-dev/jdk/src test

Currently, only OpenJDK 7 is supported. Later versions might work,
but have not yet been tested.

Building with the Android Class Library
---------------------------------------
As an alternative to both the Avian and OpenJDK class libaries, you
can also build with the Android class library. Now it should work on Linux, OS X and Windows.

The simpliest way to build Avian with Android classpath is to use `avian-pack` project: https://github.com/bigfatbrowncat/avian-pack

Avian-pack consists of Avian itself with some Android components (such as libcore and icu4c).

Note that we use the upstream OpenSSL repository and apply the
Android patches to it. This is because it is not clear how to build
the Android fork of OpenSSL directly without checking out and building
the entire platform. As of this writing, the patches apply cleanly
against OpenSSL 1.0.1h, so that's the tag we check out, but this may
change in the future when the Android fork rebases against a new
OpenSSL version.

Installing
----------

Installing Avian is as simple as copying the executable to the desired
directory:

$ cp build/${platform}-${arch}/avian ~/bin/

Embedding
---------

The following series of commands illustrates how to produce a
stand-alone executable out of a Java application using Avian.

Note: if you are building on Cygwin, prepend "x86_64-w64-mingw32-" or
"i686-w64-mingw32-" to the ar, g++, gcc, strip, and dlltool commands
below (e.g. x86_64-w64-mingw32-gcc).

__1.__ Build Avian, create a new directory, and populate it with the
VM object files and bootstrap classpath jar.

$ make
$ mkdir hello
$ cd hello
$ ar x ../build/${platform}-${arch}/libavian.a
$ cp ../build/${platform}-${arch}/classpath.jar boot.jar

__2.__ Build the Java code and add it to the jar.

$ cat >Hello.java <embedded-jar-main.cpp <("-Xbootclasspath:[bootJar]");

JavaVM* vm;
void* env;
JNI_CreateJavaVM(&vm, &env, &vmArgs);
JNIEnv* e = static_cast(env);

jclass c = e->FindClass("Hello");
if (not e->ExceptionCheck()) {
jmethodID m = e->GetStaticMethodID(c, "main", "([Ljava/lang/String;)V");
if (not e->ExceptionCheck()) {
jclass stringClass = e->FindClass("java/lang/String");
if (not e->ExceptionCheck()) {
jobjectArray a = e->NewObjectArray(ac-1, stringClass, 0);
if (not e->ExceptionCheck()) {
for (int i = 1; i < ac; ++i) {
e->SetObjectArrayElement(a, i-1, e->NewStringUTF(av[i]));
}

e->CallStaticVoidMethod(c, m, a);
}
}
}
}

int exitCode = 0;
if (e->ExceptionCheck()) {
exitCode = -1;
e->ExceptionDescribe();
}

vm->DestroyJavaVM();

return exitCode;
}
EOF

__on Linux:__

$ g++ -I$JAVA_HOME/include -I$JAVA_HOME/include/linux \
-D_JNI_IMPLEMENTATION_ -c embedded-jar-main.cpp -o main.o

__on Mac OS X:__

$ g++ -I$JAVA_HOME/include -I$JAVA_HOME/include/darwin \
-D_JNI_IMPLEMENTATION_ -c embedded-jar-main.cpp -o main.o

__on Windows:__

$ g++ -fno-exceptions -fno-rtti -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/win32" \
-D_JNI_IMPLEMENTATION_ -c embedded-jar-main.cpp -o main.o

__5.__ Link the objects produced above to produce the final
executable, and optionally strip its symbols.

__on Linux:__

$ g++ -rdynamic *.o -ldl -lpthread -lz -o hello
$ strip --strip-all hello

__on Mac OS X:__

$ g++ -rdynamic *.o -ldl -lpthread -lz -o hello -framework CoreFoundation
$ strip -S -x hello

__on Windows:__

$ dlltool -z hello.def *.o
$ dlltool -d hello.def -e hello.exp
$ gcc hello.exp *.o -L../../win32/lib -lmingwthrd -lm -lz -lws2_32 \
-lIphlpapi -mwindows -mconsole -o hello.exe
$ strip --strip-all hello.exe

Embedding with ProGuard and a Boot Image
----------------------------------------

The following illustrates how to embed an application as above, except
this time we preprocess the code using ProGuard and build a boot image
from it for quicker startup. The pros and cons of using ProGuard are
as follow:

* Pros: ProGuard will eliminate unused code, optimize the rest, and
obfuscate it as well for maximum space savings

* Cons: increased build time, especially for large applications, and
extra effort needed to configure it for applications which rely
heavily on reflection and/or calls to Java from native code

For boot image builds:

* Pros: the boot image build pre-parses all the classes and compiles
all the methods, obviating the need for JIT compilation at runtime.
This also makes garbage collection faster, since the pre-parsed
classes are never visited.

* Cons: the pre-parsed classes and AOT-compiled methods take up more
space in the executable than the equivalent class files. In
practice, this can make the executable 30-50% larger. Also, AOT
compilation does not yet yield significantly faster or smaller code
than JIT compilation. Finally, floating point code may be slower
on 32-bit x86 since the compiler cannot assume SSE2 support will be
available at runtime, and the x87 FPU is not supported except via
out-of-line helper functions.

Note you can use ProGuard without using a boot image and vice-versa,
as desired.

The following instructions assume we are building for Linux/x86_64.
Please refer to the previous example for guidance on other platforms.

__1.__ Build Avian, create a new directory, and populate it with the
VM object files.

$ make bootimage=true
$ mkdir hello
$ cd hello
$ ar x ../build/linux-x86_64-bootimage/libavian.a

__2.__ Create a stage1 directory and extract the contents of the
class library jar into it.

$ mkdir stage1
$ (cd stage1 && jar xf ../../build/linux-x86_64-bootimage/classpath.jar)

__3.__ Build the Java code and add it to stage1.

$ cat >Hello.java <hello.pro <bootimage-main.cpp <("-Davian.bootimage=bootimageBin");

options[1].optionString
= const_cast("-Davian.codeimage=codeimageBin");

JavaVM* vm;
void* env;
JNI_CreateJavaVM(&vm, &env, &vmArgs);
JNIEnv* e = static_cast(env);

jclass c = e->FindClass("Hello");
if (not e->ExceptionCheck()) {
jmethodID m = e->GetStaticMethodID(c, "main", "([Ljava/lang/String;)V");
if (not e->ExceptionCheck()) {
jclass stringClass = e->FindClass("java/lang/String");
if (not e->ExceptionCheck()) {
jobjectArray a = e->NewObjectArray(ac-1, stringClass, 0);
if (not e->ExceptionCheck()) {
for (int i = 1; i < ac; ++i) {
e->SetObjectArrayElement(a, i-1, e->NewStringUTF(av[i]));
}

e->CallStaticVoidMethod(c, m, a);
}
}
}
}

int exitCode = 0;
if (e->ExceptionCheck()) {
exitCode = -1;
e->ExceptionDescribe();
}

vm->DestroyJavaVM();

return exitCode;
}
EOF

$ g++ -I$JAVA_HOME/include -I$JAVA_HOME/include/linux \
-D_JNI_IMPLEMENTATION_ -c bootimage-main.cpp -o main.o

__8.__ Link the objects produced above to produce the final
executable, and optionally strip its symbols.

$ g++ -rdynamic *.o -ldl -lpthread -lz -o hello
$ strip --strip-all hello

Trademarks
----------

Oracle and Java are registered trademarks of Oracle and/or its
affiliates. Other names may be trademarks of their respective owners.

The Avian project is not affiliated with Oracle.