文章目录
- 1、下载
- 2、graalvm安装
- 3、native-image工具安装
- 3.1 安装native-image
- 3.2 安装C++编译工具
- 4、java编译成二进制exe
- 4.1、普通的java命令行应用
- 4.2、Swing应用编译
- 4.3、使用maven插件静态编译
- 4.4、javafx应用编译
1、下载
文件下载:https://www.graalvm.org/downloads/
安装教程:https://www.graalvm.org/22.3/docs/getting-started/
下载下边两个文件
graalvm-ce-java17-windows-amd64-22.3.0.zip # 包含openjdk的作用
native-image-installable-svm-java17-windows-amd64-22.3.0.jar # 把java编译成二进制工具
2、graalvm安装
graalvm-ce-java17-windows-amd64-22.3.0.zip解压即可用
3、native-image工具安装
3.1 安装native-image
native-image支持本地安装(native-image-installable-svm-java17-windows-amd64-22.3.0.jar)和在线安装。
本地安装
gu -L ../../install native-image-installable-svm-java17-windows-amd64-22.3.0.jar
在线安装命令
gu install native-image
安装完成后,C:\Program Files\Java\graalvm\graalvm-ce-java17-22.3.0\bin目录会有相关native-image的命令和文件
native-image查看版本
native-image --version
设置环境变量
GRAALVM_HOME=C:\Program Files\Java\graalvm\graalvm-ce-java17-22.3.0
# 把GRAALVM_HOME加到PATH变量后边
PATH=........;%GRAALVM_HOME%\bin
3.2 安装C++编译工具
native-image编译java为二进制,需要依赖C++编译工具,安装 vs2019, 选中 “使用 C++ 的桌面开发”,可选组件中选择 “VS 2019 C++ x64/x86” 生成工具和 “Windows 10 SDK”
配置VC环境变量1
MSVC=C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133
PATH=.........;%MSVC%\bin\HostX64\x64
如果不配置,可能会出现下边错误
# 出错1
Error: Default native-compiler executable 'cl.exe' not found via environment variable PATH
Error: To prevent native-toolchain checking provide command-line option -H:-CheckToolchain
Error: Use -H:+ReportExceptionStackTraces to print stacktrace of underlying exception
配置VC环境变量2
WK10_INCLUDE=C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0
WK10_LIB=C:\Program Files (x86)\Windows Kits\10\Lib\10.0.19041.0
INCLUDE=%WK10_INCLUDE%\ucrt;%WK10_INCLUDE%\um;%WK10_INCLUDE%\shared;%MSVC%\include;
LIB=%WK10_LIB%\um\x64;%WK10_LIB%\ucrt\x64;%MSVC%\lib\x64;
# 出错2
Error: Error compiling query code (in C:\Users\penngo\AppData\Local\Temp\SVM-1701580662269299485\AMD64LibCHelperDirectives.c). Compiler command ''C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\cl.exe' /WX /W4 /wd4244 /wd4245 /wd4800 /wd4804 /wd4214 '/FeC:\Users\penngo\AppData\Local\Temp\SVM-1701580662269299485\AMD64LibCHelperDirectives.exe' 'C:\Users\penngo\AppData\Local\Temp\SVM-1701580662269299485\AMD64LibCHelperDirectives.c'' output included error: [AMD64LibCHelperDirectives.c, C:\Users\penngo\AppData\Local\Temp\SVM-1701580662269299485\AMD64LibCHelperDirectives.c(1): fatal error C1034: stdio.h: 不包括路径集]
如果不使用上边的环境变量配置,也可以在构建前使用vs2019的命令来设置环境变量,可以在命令行执行下边的命令来初始化变量
call "D:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"
4、java编译成二进制exe
4.1、普通的java命令行应用
Main.java
package com.penngo.gralvm;
public class Main {
public static void main(String[] args) {
System.out.println("Hello world!");
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>graalvm_test</artifactId>
<groupId>com.penngo.gralvm</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>console</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
</project>
native_build.bat
SET class_path=target/console-1.0.jar;
native-image -classpath %class_path% com.penngo.gralvm.Main
编译结果
运行exe
4.2、Swing应用编译
MainSwing.java
package com.penngo.gralvm;
import javax.swing.*;
public class MainSwing {
public static void main(String[] args) {
JFrame jFrame = new JFrame("title");
JButton button = new JButton("Test button");
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.add(button);//把button添加到JFrame中
jFrame.setSize(300,300);//设置JFrame大小
jFrame.setVisible(true);//设置可见,不然的话看不到
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>graalvm_test</artifactId>
<groupId>com.penngo.gralvm</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>swing</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
</dependencies>
</project>
直接用上边4.1的方式来编译二进制也是成功的,但是运行会报错
Exception in thread "main" java.lang.NoSuchMethodError: java.awt.Toolkit.getDefaultToolkit()Ljava/awt/Toolkit;
at org.graalvm.nativeimage.builder/com.oracle.svm.core.jni.functions.JNIFunctions$Support.getMethodID(JNIFunctions.java:1259)
at org.graalvm.nativeimage.builder/com.oracle.svm.core.jni.functions.JNIFunctions$Support.getMethodID(JNIFunctions.java:1244)
at org.graalvm.nativeimage.builder/com.oracle.svm.core.jni.functions.JNIFunctions.GetStaticMethodID(JNIFunctions.java:413)
at java.desktop@17.0.5/java.awt.Toolkit.initIDs(Toolkit.java)
at java.desktop@17.0.5/java.awt.Toolkit.initStatic(Toolkit.java:1425)
at java.desktop@17.0.5/java.awt.Toolkit.<clinit>(Toolkit.java:1397)
at java.desktop@17.0.5/java.awt.Component.<clinit>(Component.java:624)
at java.base@17.0.5/java.lang.Class.ensureInitialized(DynamicHub.java:528)
at java.base@17.0.5/java.lang.Class.ensureInitialized(DynamicHub.java:528)
at java.base@17.0.5/java.lang.Class.ensureInitialized(DynamicHub.java:528)
at java.base@17.0.5/java.lang.Class.ensureInitialized(DynamicHub.java:528)
at com.penngo.gralvm.MainSwing.main(MainSwing.java:14)
主要是因为Swing运行时一些jni对象和反射类没有被加载造成的。graalvm提供native-image-agent工具来收集这些运行库信息,并保存到 reflect-config.json、jni-config.json、resource-config.json、proxy-config.json、serialization-config.json 和 predefined-classes-config.json 这 6 个 json 格式的配置文件这几个配置文件。当然,如果你熟悉需要用到的库或类,也可以手动编写这几个文件。
native_agnet_build.bat
set GRAALVM_HOME=C:\Progra~1\Java\graalvm\graalvm-ce-java17-22.3.0
SET class_path=target/swing-1.0.jar;
%GRAALVM_HOME%/bin/java -classpath %class_path% -agentlib:native-image-agent=config-output-dir=META-INF/native-image com.penngo.gralvm.MainSwing
运行native_agnet_build.bat,需要把所有功能执行一次,这样才能收集完整的运行库信息。
native_build.bat
SET class_path=target/swing-1.0.jar;
native-image --no-fallback -classpath %class_path% com.penngo.gralvm.MainSwing
新建 conf\fonts 目录,复制 graalvm-ce-java17-22.3.0\lib\fontconfig.bfc 文件到 swing\conf\fonts目录
执行完native_build.bat后,输入下边命令运行swing应用
com.penngo.gralvm.mainswing.exe -Djava.home=.
注意需要加参数“-Djava.home=.”,不然会报下边类似的错误
Exception in thread "AWT-EventQueue-0" java.lang.InternalError: java.lang.reflect.InvocationTargetException
at java.desktop@17.0.5/sun.font.FontManagerFactory$1.run(FontManagerFactory.java:87)
at java.base@17.0.5/java.security.AccessController.executePrivileged(AccessController.java:168)
at java.base@17.0.5/java.security.AccessController.doPrivileged(AccessController.java:318)
at java.desktop@17.0.5/sun.font.FontManagerFactory.getInstance(FontManagerFactory.java:75)
......
Caused by: java.lang.reflect.InvocationTargetException
at java.base@17.0.5/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
at java.base@17.0.5/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
at java.desktop@17.0.5/sun.font.FontManagerFactory$1.run(FontManagerFactory.java:85)
... 55 more
Caused by: java.lang.Error: java.home property not set
at java.desktop@17.0.5/sun.awt.FontConfiguration.findFontConfigFile(FontConfiguration.java:181)
at java.desktop@17.0.5/sun.awt.FontConfiguration.<init>(FontConfiguration.java:98)
at java.desktop@17.0.5/sun.awt.windows.WFontConfiguration.<init>(WFontConfiguration.java:41)
.......
4.3、使用maven插件静态编译
使用4.2的swing源码,
native_agnet_build.bat收集的运行库信息META-INF/native-image需要放进resource目录中,代码目录结构如下:
MainSwing.java
package com.penngo.gralvm;
import javax.swing.*;
public class MainSwing {
static {
// 设置java.home,运行时不再需要指定目录
System.setProperty("java.home", ".");
}
public static void main(String[] args) {
JFrame jFrame = new JFrame("title");
JButton button = new JButton("Test button");
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.add(button);
jFrame.setSize(300,300);
jFrame.setVisible(true);
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>graalvm_test</artifactId>
<groupId>com.penngo.gralvm</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>swing_plugin</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<graalvm.version>22.3.0</graalvm.version>
</properties>
<dependencies>
<dependency>
<groupId>org.graalvm.sdk</groupId>
<artifactId>graal-sdk</artifactId>
<version>${graalvm.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<configuration>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.graalvm.nativeimage</groupId>
<artifactId>native-image-maven-plugin</artifactId>
<version>21.2.0</version>
<executions>
<execution>
<goals>
<goal>native-image</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
<configuration>
<skip>false</skip>
<imageName>MainSwing</imageName>
<mainClass>com.penngo.gralvm.MainSwing</mainClass>
<!-- -no-fallback -H:-DeleteLocalSymbols -->
<buildArgs>
</buildArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.source}</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>
命令行输入mvn package编译
编译后target目录
可以在命令输入MainSwing.exe,或双击运行,但是上边编译的exe还是会带黑窗体。
4.4、javafx应用编译
Desktop.java
package com.penngo.gralvm;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.text.Text;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import java.io.File;
public class Desktop extends Application {
private TextField createField;
public void start(Stage stage){
stage.setTitle("JavaFX测试");
GridPane grid = new GridPane();
grid.setAlignment(Pos.CENTER);
grid.setHgap(10);
grid.setVgap(10);
grid.setPadding(new Insets(25, 25, 25, 25));
ColumnConstraints cc0 = new ColumnConstraints();
cc0.setMinWidth(GridPane.USE_PREF_SIZE);
System.out.println(grid.getColumnConstraints().size());
grid.getColumnConstraints().add(cc0);//.add(cc);
ColumnConstraints cc1 = new ColumnConstraints();
cc1.setMinWidth(GridPane.USE_PREF_SIZE);
cc1.setHgrow(Priority.ALWAYS);
grid.getColumnConstraints().add(cc1);//.add(cc);
Text scenetitle = new Text("");
grid.add(scenetitle, 0, 0, 2, 1);
Label userName = new Label("文件名:");
grid.add(userName, 0, 1);
TextField selectField = new TextField();
grid.add(selectField, 1, 1);
Button buttonLoad = new Button("选择文件");
buttonLoad.setOnAction(arg0 -> {
FileChooser fileChooser = new FileChooser();
fileChooser.setInitialDirectory(new File("."));
FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("TXT files (*.pdf)", "*.pdf");
fileChooser.getExtensionFilters().add(extFilter);
File file = fileChooser.showOpenDialog(stage);
if(file != null){
selectField.setText(file.getAbsolutePath());
}
});
grid.add(buttonLoad, 2, 1);
Label pw = new Label("生成文件:");
grid.add(pw, 0, 2);
createField = new TextField();
grid.add(createField, 1, 2);
ProgressIndicator pi = new ProgressIndicator();
pi.setVisible(false);
grid.add(pi, 0, 4);
Button btn = new Button("解析文件");
HBox hbBtn = new HBox(10);
hbBtn.setAlignment(Pos.BOTTOM_RIGHT);
hbBtn.getChildren().add(btn);
grid.add(hbBtn, 1, 4);
Scene scene = new Scene(grid, 500, 275);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
module-info.java
module com.penngo.gralvm.app {
requires javafx.controls;
requires javafx.fxml;
requires javafx.base;
requires javafx.graphics;
requires javafx.media;
requires javafx.swing;
requires javafx.web;
exports com.penngo.gralvm;
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>graalvm_test</artifactId>
<groupId>com.penngo.gralvm</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>javafx</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<openjfx.version>17.0.2</openjfx.version>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-base</artifactId>
<version>${openjfx.version}</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>${openjfx.version}</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-web</artifactId>
<version>${openjfx.version}</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-swing</artifactId>
<version>${openjfx.version}</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics</artifactId>
<version>${openjfx.version}</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>${openjfx.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.gluonhq</groupId>
<artifactId>gluonfx-maven-plugin</artifactId>
<version>1.0.16</version>
<configuration>
<mainClass>com.penngo.gralvm.Desktop</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.source}</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>
gluonhq插件https://docs.gluonhq.com/#_goals,可用命令:
gluonfx:run
gluonfx:runagent
gluonfx:compile
gluonfx:link
gluonfx:build
gluonfx:package
gluonfx:install
gluonfx:nativerun
gluonhq插件可用参数https://docs.gluonhq.com/#_configuration
<plugin>
<groupId>com.gluonhq</groupId>
<artifactId>gluonfx-maven-plugin</artifactId>
<version>1.0.16</version>
<configuration>
<target>host</target>
<mainClass>your.mainClass</mainClass>
<bundlesList></bundlesList>
<resourcesList></resourcesList>
<reflectionList></reflectionList>
<jniList></jniList>
<attachList></attachList>
<nativeImageArgs></nativeImageArgs>
<linkerArgs></linkerArgs>
<runtimeArgs></runtimeArgs>
<verbose>false</verbose>
<graalvmHome></graalvmHome>
<javaStaticSdkVersion>11-ea+10</javaStaticSdkVersion>
<javafxStaticSdkVersion>20-ea+7</javafxStaticSdkVersion>
<enableSWRendering>false</enableSWRendering>
<remoteHostName></remoteHostName>
<remoteDir></remoteDir>
<appIdentifier></appIdentifier>
<releaseConfiguration>
<!-- all targets -->
<packageType></packageType>
<description></description>
<vendor></vendor>
<!-- macOS -->
<macAppStore></macAppStore>
<macSigningUserName></macSigningUserName>
<macAppCategory></macAppCategory>
<!-- macOS/iOS -->
<bundleName></bundleName>
<bundleVersion>1.0</bundleVersion>
<bundleShortVersion>1.0</bundleShortVersion>
<providedSigningIdentity></providedSigningIdentity>
<providedProvisioningProfile></providedProvisioningProfile>
<skipSigning>false</skipSigning>
<!-- iOS Simulator -->
<simulatorDevice></simulatorDevice>
<!-- Android -->
<appLabel></appLabel>
<versionCode>1</versionCode>
<versionName>1.0</versionName>
<providedKeyStorePath>${android-keystore-path}</providedKeyStorePath>
<providedKeyStorePassword>${android-keystore-password}</providedKeyStorePassword>
<providedKeyAlias>${android-key-alias}</providedKeyAlias>
<providedKeyAliasPassword>${android-key-password}</providedKeyAliasPassword>
</releaseConfiguration>
</configuration>
</plugin>
编译
mvn clean gluonfx:build
target\gluonfx\x86_64-windows目录下会生成相应的exe可执行文件
运行,可以直接双击exe运行,可以使用插件命令运行
mvn gluonfx:nativerun