简体   繁体   中英

How To Create An Executable Out Of A Executable Jar File Using Gradle?

I'm using gradle for my application (a python compiler). I already wrote one before in C++, but I'm thinking of doing another better on in java as I have more knowledge in Java. I'm using gradle to build. So far, here is what my project looks like:

.
├── build.gradle
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
    ├── main
    │   ├── java
    │   │   └── compiler
    │   │       ├── Lexer.java
    │   │       ├── Main.java
    │   │       └── TableEntry.java
    │   └── resources
    └── test
        ├── java
        │   └── compiler
        │       └── MainTest.java
        └── resources

The Lexer and TableEntry files are not important. Here is what my build.gradle file looks like:

repositories {
    mavenCentral()
}

apply plugin: 'java'

version '0.1.0'

sourceCompatibility = '1.8'
targetCompatibility = '1.8'

jar {
    manifest {
        attributes 'Implementation-Title': 'python',
        'Implementation-Version': version, 
        'Main-Class': 'compiler.Main'
    }
}

dependencies {
    implementation 'com.google.guava:guava:29.0-jre'

    testImplementation 'junit:junit:4.13'
}

task deleteBin(type: Delete) {
    doLast {
        new File('bin').deleteDir()
    }
}

tasks.clean.dependsOn(tasks.deleteBin)

tasks.jar.doLast {
    copy {
        from 'build/libs'
        into 'bin'
    }
}

What this is supposed to do is build the Main.java file into an executable jar and copy it into a directory called bin . Which it does do. After I call ./gradlew build , this is what the tree looks like:

.
├── bin
│   └── python-0.1.0.jar
├── build
│   ├── classes
│   │   └── java
│   │       ├── main
│   │       │   └── compiler
│   │       │       ├── Lexer.class
│   │       │       ├── Main.class
│   │       │       └── TableEntry.class
│   │       └── test
│   │           └── compiler
│   │               └── MainTest.class
│   ├── generated
│   │   └── sources
│   │       ├── annotationProcessor
│   │       │   └── java
│   │       │       ├── main
│   │       │       └── test
│   │       └── headers
│   │           └── java
│   │               ├── main
│   │               └── test
│   ├── libs
│   │   └── python-0.1.0.jar
│   ├── reports
│   │   └── tests
│   │       └── test
│   │           ├── css
│   │           │   ├── base-style.css
│   │           │   └── style.css
│   │           ├── index.html
│   │           └── js
│   │               └── report.js
│   ├── test-results
│   │   └── test
│   │       └── binary
│   │           ├── output.bin
│   │           ├── output.bin.idx
│   │           └── results.bin
│   └── tmp
│       ├── compileJava
│       │   └── source-classes-mapping.txt
│       ├── compileTestJava
│       │   └── source-classes-mapping.txt
│       └── jar
│           └── MANIFEST.MF
├── build.gradle
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
    ├── main
    │   ├── java
    │   │   └── compiler
    │   │       ├── Lexer.java
    │   │       ├── Main.java
    │   │       └── TableEntry.java
    │   └── resources
    └── test
        ├── java
        │   └── compiler
        │       └── MainTest.java
        └── resources

But I was thinking that people who use my compiler will need java installed to actually use it. In C++, it already compiles it into an executable, which is convenient. With a little research, I found a plugin called launch4j , but I couldn't seem to get it to work. What other options do I have to covert my jar file into an executable?

Sorry for not explaining why launch4j doesn't work. So I went to the github repository where it said to add this plugin:

'edu.sc.seis.launch4j'

I added that, and gradle didn't recognize it. The line I put:

apply plugin: 'edu.sc.seis.launch4j'

The output:

Plugin with id 'edu.sc.seis.launch4j' not found.

So then I went to the maven central repository search, and found it again as a dependency over here . It got added fine when I added this line to my dependencies section:

implementation 'edu.sc.seis.gradle:launch4j:1.0.6'

However, when I tried editing the launch4j task like this:

launch4j {
}

It said that it could not find that task.

Could not find method launch4j() for arguments [build_c92xwmoykapsewu0cy351y5ww$_run_closure4@5635a004] on root project 'python' of type org.gradle.api.Project.

launch4j is fine. It's a bit odd that you found a tool that describes precisely what you want, and all you have to say about it is: "... it doesn't work".

A few notes to help you out with launch4j:

  • This is, of course, solely for windows.
  • You still need to ship an entire VM. It's never going to be a single executable; java is not that kind of tool.
  • You'd need an installer that places the exe (made by launch4j) + a VM + all your deps in a single location.

You'd end up with something like:

C:\Program Files\MyApp\myapp.exe
C:\Program Files\MyApp\jvm\(a bunch of files here; an entire JRE/JDK installation)
C:\Program Files\MyApp\lib\dep1.jar
C:\Program Files\MyApp\lib\dep2.jar

The dependencies are of course optional and can be striped in too.

You can then tell launch4j to use that VM and not whatever's already installed (if any). This also has the convenient side-effect of being compatible with the current 'model' of running java apps on desktops (which is that you, the app vendor, are responsible for VM distribution and not oracle+the end user, which was how it more or less worked until java8, which is outdated), and also that you know precisely which version you're running on.

Starting with java 11 you can use jlink to make 'treeshaken' custom VMs: These contain juuust the bits of the VM you actually end up using. You do need to switch to a modular build (which involves making a module-info.java file - plenty of tutorials to be found if you really want to go this route).

I have no idea if you can make such treeshaken VMs work together with launch4j, but you should be able to.

I am not aware of any solutions for linux and mac.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM