avian轻巧的Java虚拟机(JVM)
请注意:此项目目前尚未得到开发,维护或支持。随时使用和/或分叉,但是这里提出的任何问题都可能会被忽略。
快速开始
这些是在X86_64体系结构的各种操作系统上构建avian的示例。您可能需要根据系统上安装JDK的位置来修改Java_home。在所有情况下,请确保在路径中使用前向斜线。
在Linux上:
avian –cp build/linux-x86_64/test Hello\”>
$ export JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64
$ make
$ build/linux-x86_64/ avian -cp build/linux-x86_64/test Hello
在Mac OS X上:
avian -cp build/macosx-x86_64/test Hello\”>
$ export JAVA_HOME=$(/usr/libexec/java_home)
$ make
$ build/macosx-x86_64/ avian -cp build/macosx-x86_64/test Hello
在Windows上(Cygwin):
avian -cp build/windows-x86_64/test Hello\”>
$ git clone git@github.com: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
在FreeBSD上:
avian -cp build/freebsd-x86_64/test Hello\”>
$ export JAVA_HOME=/usr/local/openjdk7
$ gmake
$ build/freebsd-x86_64/ avian -cp build/freebsd-x86_64/test Hello
介绍
avian是一款轻巧的虚拟机和类库,旨在提供Java功能的有用子集,适合构建独立应用。
支持的平台
avian目前可以针对以下平台:
- Linux(I386,X86_64,ARM和ARM64)
- Windows(i386和x86_64)
- Mac OS X(I386和X86_64)
- 苹果iOS(i386,x86_64,ARM和ARM64)
- freebsd(i386,x86_64)
建筑
构建要求包括:
- GNU使3.80或更高版本
- GCC 4.6或更高版本或LLVM Clang 3.1或更高版本(请参阅下面的用途选项)
- JDK 1.6或更高版本
- mingw 3.4或更高版本(仅当Windows编译时)
- Zlib 1.2.3或更高版本
其中一些软件包的较早版本也可能起作用,但尚未进行测试。
该构建由单个makefile指向,可能会通过下面描述的某些标志来影响,所有这些标志都是可选的。
$ make \\
platform={linux,windows,macosx,ios,freebsd} \\
arch={i386,x86_64,arm,arm64} \\
process={compile,interpret} \\
mode={debug,debug-fast,fast,small} \\
lzma=<lzma source directory> \\
bootimage={true,false} \\
tails={true,false} \\
continuations={true,false} \\
use-clang={true,false} \\
openjdk=<openjdk installation directory> \\
openjdk-src=<openjdk source directory> \\
android=<android source directory> \\
ios-version=<iOS minimum version>
-
platform– 目标平台- 默认值: $(UNAME -S | TR [:UPPER:] [:LOWER:])的输出,在某些情况下对(例如Cygwin_nt -5.1-> Windows)进行了归一化
-
arch– 目标体系结构- 默认值: $(UNAME -M)的输出,在某些情况下对(例如i686-> i386)进行标准化
-
process– 纯解释器或JIT编译器之间的选择- 默认值:编译
-
mode– 用于确定优化级别,调试符号以及是否启用断言的哪一组汇编标志- 默认值:快速
-
lzma如果设置,则支持使用LZMA压缩嵌入式罐子和引导图像。此选项的值应该是包含最近LZMA SDK的目录(可在此处找到)。目前,仅测试了SDK的9.20版本,但其他版本可能起作用。- 默认值:未设置
-
armv6如果是真的,请不要使用比ARMV6更新的任何说明。默认情况下,我们假设目标是ARMV7或更高版本,因此需要明确的内存屏障说明以确保缓存相干性 -
bootimage如果为true,请创建一个启动图像,其中包含预先放置的类库和提前编译的方法。此选项仅适用于Process =编译构建。请注意,您可能需要在64位系统上指定Build-Arch = X86_64和Arch = X86_64,其中“ UNAME -M”打印“ I386”。- 默认值: false
-
tails– 如果是真的,请用Callee替换呼叫者的堆栈框架来优化每个尾巴调用。该公约可确保适当的尾部递归,适用于诸如方案之类的语言。此选项仅适用于Process =编译构建。- 默认值: false
-
continuations– 如果为真,则通过avian连续。结合方法callwithCurrentContinatun和DynamicWind。有关详细信息,请参见Continuations.java。此选项仅适用于Process =编译构建。- 默认值: false
-
use-clang– 如果为true,请使用LLVM的clang而不是GCC来构建。请注意,目前不影响交叉编译,仅影响本机制造。- 默认值: false
-
openjdk如果设置,请使用OpenJDK类库,而不是默认的avian类库。有关详细信息,请参见下面的“使用OpenJDK类库的构建”。- 默认值:未设置
-
openjdk-src如果设置了此功能和上面的OpenJDK选项,请使用OpenJDK类库来构建可嵌入的VM。 OpenJDK类库的JNI组件将是根据指定目录下的来源构建的。有关详细信息,请参见下面的“使用OpenJDK类库的构建”。- 默认值:未设置
-
android如果设置,请使用Android类库,而不是默认的avian类库。有关详细信息,请参见下面的“使用Android类库构建”。- 默认值:未设置
-
ios-version为iOS目标编译时将使用最小iOS SDK版本。如果要支持32位版本,请勿使用值11.0或更大的值。此选项仅适用于平台= ios。- 默认值: 8.0
这些标志确定用于构建的目录的名称。该名称总是以$ {Platform} – $ {Arch}开头,每个非默认构建选项都附加到名称上。例如,将在build/linux-x86_64-debug-bootimage中构建具有bootImage的调试构建。这使您可以独立甚至同时使用几组不同的选项来构建,而无需每次进行干净的构建。
请注意,这些标志的所有组合并非所有组合都是有效的。例如,非盖式iOS设备不允许使用JIT编译,因此仅处理= drigens = drigens = botimage = true builds将在此类设备上运行。请参阅此处,以获取使用avian iOS XCode项目的示例。
如果您要为Windows编译,则可以使用MingW进行交叉编译,也可以在Cygwin下的Windows上固定。
安装Cygwin:
1。从Cygwin的网站下载和运行设置。EXE,安装基本系统和这些软件包:Make,GCC-MingW-G ++,MingW64-I686-GCC-G ++,Mingw64-X86_64-GCC-GCC-G ++,以及(选项)GIT。
您可能还会发现我们的Win32存储库很有用:(从包含avian目录的目录运行)
$ git clone git@github.com:ReadyTalk/win32.git
这为您提供了Windows JNI标题,Zlib标头和库,以及其他一些有用的库,例如OpenSSL,Libjpeg和Libpng。还有一个可容纳64位版本的Win64存储库:
$ git clone git@github.com:ReadyTalk/win64.git
使用Microsoft Visual C ++编译器构建
您还可以使用MSVC编译器构建,这使使用WindBG和Visual Studio等工具进行调试变得更加容易。请注意,您仍然需要安装GCC -MSVC仅用于编译VM的C ++部分,而使用GCC构建了组装代码和辅助工具。
请注意,MSVC构建未定期测试,因此很可能会被打破。
avian目标是MSVC 11及更高版本(它使用旧版本中不可用的C ++功能)。
要使用MSVC构建,请如上所述安装Cygwin并设置以下环境变量:
$ 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;\"
根据您的MSVC安装,根据需要调整这些定义。
最后,将MSVC标志设置为MSVC工具目录:
$ make msvc=\"/cygdrive/c/Program Files/Microsoft Visual Studio 11.0/VC\"
使用OpenJDK类库建造
默认情况下, avian使用自己的轻量级类库。但是,该库仅包含JRE中包含的类和方法的相对较小的子集。如果您的应用程序需要该子集之外的功能,则可能需要告诉avian改用OpenJDK的类库。为此,请指定安装OpenJDK的目录,例如:
$ make openjdk=/usr/lib/jvm/java-7-openjdk
这将构建avian作为常规JVM(例如Libjvm.so),该JVM从/usr/usr/lib/jvm/java-7-openjdk/jre加载其引导类库和本机库(例如libjava.so)。请注意,您必须在此处使用绝对路径,否则从其他目录运行时结果将不起作用。在此配置中,OpenJDK需要保持安装才能使avian工作,并且您可以运行这样的应用程序:
avian-dynamic -cp /path/to/my/application \\
com.example.MyApplication\”>
$ build/linux-x86_64-openjdk/ avian -dynamic -cp /path/to/my/application \\
com.example.MyApplication
另外,您可以通过指定OpenJDK源代码的位置,例如:
$ make openjdk=$(pwd)/../jdk7/build/linux-amd64/j2sdk-image \\
openjdk-src=$(pwd)/../jdk7/jdk/src
您必须确保为OpenJDK-SRC指定的路径中没有任何空间;当依赖性路径包括空间时,变得混乱了,我们还没有发现它,除非避免完全带有空间的路径。
这种构建的结果是一个独立的二进制文件,不取决于外部库,罐子或其他文件。在这种情况下,指定的路径仅在构建时间使用;运行时需要的任何东西都嵌入了二进制中。因此,简化了运行应用程序的过程:
avian -cp /path/to/my/application \\
com.example.MyApplication\”>
$ build/linux-x86_64-openjdk-src/ avian -cp /path/to/my/application \\
com.example.MyApplication
请注意,由于OpenJDK的类库的大小,所得的二进制文件将非常大。可以使用UPX来缓解这一点,最好是启用LZMA的版本:
$ upx --lzma --best build/linux-x86_64-openjdk-src/ avian
您可以使用Proguard和提供的OpenJDK.pro配置文件来减少嵌入式构建的尺寸futher(请参阅下面的“嵌入使用Proguard和启动图像”)。请注意,在这种情况下,您仍然需要使用vm.pro -OpenJDK.PRO只是添加了OpenJDK端口的其他约束。另请参阅avian -SWT -餐馆项目中的App.mk,以示例使用avian ,OpenJDK,Proguard和UPX音乐会。
以下是如何在各种OS上安装OpenJDK并用它来构建avian的一些示例:
基于Debian的Linux:
常规构建:
$ apt-get install openjdk-7-jdk
$ make openjdk=/usr/lib/jvm/java-7-openjdk test
独立构建:
$ 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:
先决条件:根据本网站构建OpenJDK 7。
常规构建:
$ make openjdk=$(pwd)/../jdk7u-dev/build/macosx-amd64/j2sdk-image test
独立构建:
$ make openjdk=$(pwd)/../jdk7u-dev/build/macosx-amd64/j2sdk-image \\
openjdk-src=$(pwd)/../p/jdk7u-dev/jdk/src test
Windows(Cygwin):
先决条件:根据本网站构建OpenJDK 7。或者,使用https://github.com/alexkasko/openjdk-unofficial-builds。
常规构建:
$ make openjdk=$(pwd)/../jdk7u-dev/build/windows-i586/j2sdk-image test
独立构建:
$ make openjdk=$(pwd)/../jdk7u-dev/build/windows-i586/j2sdk-image \\
openjdk-src=$(pwd)/../p/jdk7u-dev/jdk/src test
目前,仅支持OpenJDK 7。以后的版本可能会起作用,但尚未进行测试。
使用Android班级图书馆建造
作为avian和OpenJDK类诽谤的替代方案,您也可以使用Android类库来构建。现在,它应该在Linux,OS X和Windows上使用。
使用Android Class Path构建avian最简单方法是使用avian -pack项目:https://github.com/bigfatbrowncat/avian-pack
avian袋由avian本身与一些Android组件(例如Libcore和ICU4C)组成。
请注意,我们使用上游OpenSSL存储库,并将Android补丁应用于它。这是因为尚不清楚如何直接构建OpenSSL的Android叉,而无需检查并构建整个平台。在撰写本文时,这些补丁可与OpenSSL 1.0.1H进行干净的应用,因此这就是我们签出的标签,但是当Android Fork反对新的OpenSSL版本时,这可能会在将来发生变化。
安装
安装avian就像将可执行文件复制到所需目录一样简单:
$ cp build/${platform}-${arch}/ avian ~/bin/
嵌入
以下一系列命令说明了如何使用avian从Java应用程序中产生独立的可执行文件。
注意:如果您要在Cygwin上构建,请在下面的AR,G ++,GCC,Strip和dllTool命令中预处“ X86_64-W64-MINGW32-”或“ I686-W64-MINGW32-”(例如
1。构建avian ,创建一个新的目录,并使用VM对象文件和Bootstrap class Path Jar填充它。
avian.a
$ cp ../build/${platform}-${arch}/classpath.jar boot.jar\”>
$ make
$ mkdir hello
$ cd hello
$ ar x ../build/${platform}-${arch}/lib avian .a
$ cp ../build/${platform}-${arch}/classpath.jar boot.jar
2。构建Java代码并将其添加到JAR中。
$ cat >Hello.java <<EOF
public class Hello {
public static void main(String[] args) {
System.out.println(\"hello, world!\");
}
}
EOF
$ javac -bootclasspath boot.jar Hello.java
$ jar u0f boot.jar Hello.class
3。将对象文件从罐子中取出。
$ ../build/${platform}-${arch}/binaryToObject/binaryToObject boot.jar \\
boot-jar.o _binary_boot_jar_start _binary_boot_jar_end ${platform} ${arch}
如果您使用lzma选项构建了avian ,则可以选择在生成对象之前压缩JAR:
../build/$(platform}-${arch}-lzma/lzma/lzma encode boot.jar boot.jar.lzma
&& ../build/${platform}-${arch}-lzma/binaryToObject/binaryToObject \\
boot.jar.lzma boot-jar.o _binary_boot_jar_start _binary_boot_jar_end \\
${platform} ${arch}
请注意,您需要在下一步中指定“ -xbootClasspath:[lzma.bootjar]”,而不是“ -xbootclasspath:[bootjar]”,如果您使用LZMA来压缩JAR。
4。写一个启动VM并运行所需的主方法的驱动程序。注意bootjar函数,该功能将由VM调用以获取嵌入式jar的句柄。我们通过将boot Class路径设置为“ [bootjar]”来告诉VM有关此罐子的信息。
$ cat >embedded-jar-main.cpp <<EOF
#include \"stdint.h\"
#include \"jni.h\"
#include \"stdlib.h\"
#if (defined __MINGW32__) || (defined _MSC_VER)
# define EXPORT __declspec(dllexport)
#else
# define EXPORT __attribute__ ((visibility(\"default\"))) \\
__attribute__ ((used))
#endif
#if (! defined __x86_64__) && ((defined __MINGW32__) || (defined _MSC_VER))
# define SYMBOL(x) binary_boot_jar_##x
#else
# define SYMBOL(x) _binary_boot_jar_##x
#endif
extern \"C\" {
extern const uint8_t SYMBOL(start)[];
extern const uint8_t SYMBOL(end)[];
EXPORT const uint8_t*
bootJar(size_t* size)
{
*size = SYMBOL(end) - SYMBOL(start);
return SYMBOL(start);
}
} // extern \"C\"
extern \"C\" void __cxa_pure_virtual(void) { abort(); }
int
main(int ac, const char** av)
{
JavaVMInitArgs vmArgs;
vmArgs.version = JNI_VERSION_1_2;
vmArgs.nOptions = 1;
vmArgs.ignoreUnrecognized = JNI_TRUE;
JavaVMOption options[vmArgs.nOptions];
vmArgs.options = options;
options[0].optionString = const_cast<char*>(\"-Xbootclasspath:[bootJar]\");
JavaVM* vm;
void* env;
JNI_CreateJavaVM(&vm, &env, &vmArgs);
JNIEnv* e = static_cast<JNIEnv*>(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
在Linux上:
$ g++ -I$JAVA_HOME/include -I$JAVA_HOME/include/linux \\
-D_JNI_IMPLEMENTATION_ -c embedded-jar-main.cpp -o main.o
在Mac OS X上:
$ g++ -I$JAVA_HOME/include -I$JAVA_HOME/include/darwin \\
-D_JNI_IMPLEMENTATION_ -c embedded-jar-main.cpp -o main.o
在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。链接上面产生的对象以产生最终可执行文件,并可选地剥离其符号。
在Linux上:
$ g++ -rdynamic *.o -ldl -lpthread -lz -o hello
$ strip --strip-all hello
在Mac OS X上:
$ g++ -rdynamic *.o -ldl -lpthread -lz -o hello -framework CoreFoundation
$ strip -S -x hello
在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
嵌入Proguard和引导图像
以上说明了如何嵌入应用程序,除了这次,我们使用Proguard预处理代码,并从中构建启动图像以较快启动。使用Proguard的优缺点如下:
-
优点:Proguard将消除未使用的代码,优化其余的代码,并将其混淆,以最大程度地节省空间
-
缺点:增加构建时间,尤其是对于大型应用程序,以及将其配置为严重依赖反射和/或从本机代码调用Java的应用所需的额外精力
启动图像构建:
-
优点:启动图像构建了所有类并编译所有方法,从而避免了运行时汇编的需求。这也使垃圾收集更快,因为从未参观过预先放置的课程。
-
缺点:与等效类文件相比,预先放置的类和AOT编译的方法在可执行文件中占用更多的空间。实际上,这可以使可执行文件更大30-50%。同样,AOT汇编尚未比JIT汇编更快或更小的代码得出。最后,在32位X86上的浮点代码可能会较慢,因为编译器不能假设在运行时可以使用SSE2支持,并且除非通过离线辅助辅助功能,否则不支持X87 FPU。
请注意,您可以根据需要使用Proguard而无需使用启动图像和反之亦然。
以下说明假设我们正在为Linux/X86_64构建。请参阅上一个示例以获取其他平台的指南。
1。构建avian ,创建一个新的目录,然后用VM对象文件填充它。
avian.a\”>
$ make bootimage=true
$ mkdir hello
$ cd hello
$ ar x ../build/linux-x86_64-bootimage/lib avian .a
2。创建一个stage1目录,然后将类库罐的内容提取到其中。
$ mkdir stage1
$ (cd stage1 && jar xf ../../build/linux-x86_64-bootimage/classpath.jar)
3。构建Java代码并将其添加到stage1。
$ cat >Hello.java <<EOF
public class Hello {
public static void main(String[] args) {
System.out.println(\"hello, world!\");
}
}
EOF
$ javac -bootclasspath stage1 -d stage1 Hello.java
4。创建一个proguard配置文件,指定hello.main作为入口点。
$ cat >hello.pro <<EOF
-keep class Hello {
public static void main(java.lang.String[]);
}
EOF
5。以stage1为输入和阶段2作为输出运行proguard。
$ java -jar ../../proguard4.6/lib/proguard.jar \\
-dontusemixedcaseclassnames -injars stage1 -outjars stage2 \\
@../vm.pro @hello.pro
(note: The -dontusemixedcaseclassnames option is only needed when building on systems with case-insensitive filesystems such as Windows and OS X. Also, you\’ll need to add -ignorewarnings if you use the OpenJDK class library since the openjdk-src build does not include all the JARs from OpenJDK, and thus ProGuard will not be able to resolve all referenced classes. If you actually plan to use such classes at runtime, you\’ll在运行proguard之前,需要将它们添加到stage1。
6。构建启动和代码图像。
$ ../build/linux-x86_64-bootimage/bootimage-generator \\
-cp stage2 \\
-bootimage bootimage-bin.o \\
-codeimage codeimage-bin.o \\
-hostvm ../build/linux-x86_64-interpret/libjvm.so
请注意,您可以通过通过:
-bootimage-symbols my_bootimage_start:my_bootimage_end \\
-codeimage-symbols my_codeimage_start:my_codeimage_end
7。写一个启动VM并运行所需主方法的驱动程序。请注意,bootimagebin函数将由VM调用以获取嵌入式引导图像的句柄。我们通过“ avian .bootimage”属性告诉VM有关此功能的信息。
还请注意,此示例除了类文件以外没有资源。如果我们的应用程序通过ClassLoader加载了图像和属性文件等资源,我们还需要嵌入包含它们的JAR文件。有关说明,请参见上一个示例。
avian.bootimage=bootimageBin\”);
options[1].optionString
= const_cast<char*>(\”-D avian .codeimage=codeimageBin\”);
JavaVM* vm;
void* env;
JNI_CreateJavaVM(&vm, &env, &vmArgs);
JNIEnv* e = static_cast<JNIEnv*>(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\”>
$ cat >bootimage-main.cpp <<EOF
#include \"stdint.h\"
#include \"jni.h\"
#if (defined __MINGW32__) || (defined _MSC_VER)
# define EXPORT __declspec(dllexport)
#else
# define EXPORT __attribute__ ((visibility(\"default\")))
#endif
#if (! defined __x86_64__) && ((defined __MINGW32__) || (defined _MSC_VER))
# define BOOTIMAGE_BIN(x) binary_bootimage_bin_##x
# define CODEIMAGE_BIN(x) binary_codeimage_bin_##x
#else
# define BOOTIMAGE_BIN(x) _binary_bootimage_bin_##x
# define CODEIMAGE_BIN(x) _binary_codeimage_bin_##x
#endif
extern \"C\" {
extern const uint8_t BOOTIMAGE_BIN(start)[];
extern const uint8_t BOOTIMAGE_BIN(end)[];
EXPORT const uint8_t*
bootimageBin(size_t* size)
{
*size = BOOTIMAGE_BIN(end) - BOOTIMAGE_BIN(start);
return BOOTIMAGE_BIN(start);
}
extern const uint8_t CODEIMAGE_BIN(start)[];
extern const uint8_t CODEIMAGE_BIN(end)[];
EXPORT const uint8_t*
codeimageBin(size_t* size)
{
*size = CODEIMAGE_BIN(end) - CODEIMAGE_BIN(start);
return CODEIMAGE_BIN(start);
}
} // extern \"C\"
int
main(int ac, const char** av)
{
JavaVMInitArgs vmArgs;
vmArgs.version = JNI_VERSION_1_2;
vmArgs.nOptions = 2;
vmArgs.ignoreUnrecognized = JNI_TRUE;
JavaVMOption options[vmArgs.nOptions];
vmArgs.options = options;
options[0].optionString
= const_cast<char*>(\"-D avian .bootimage=bootimageBin\");
options[1].optionString
= const_cast<char*>(\"-D avian .codeimage=codeimageBin\");
JavaVM* vm;
void* env;
JNI_CreateJavaVM(&vm, &env, &vmArgs);
JNIEnv* e = static_cast<JNIEnv*>(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。链接上面产生的对象以产生最终可执行文件,并可选地剥离其符号。
$ g++ -rdynamic *.o -ldl -lpthread -lz -o hello
$ strip --strip-all hello
商标
Oracle和Java是Oracle和/或其分支机构的注册商标。其他名称可能是其各自所有者的商标。
avian项目与Oracle没有关联。
