Linux Stand Alone Executable Generation

Linux stand alone executable generation

Some choices:

  1. Learn C or C++. How hard could it be? It might be fun.
  2. Use gcj. This is the gnu java compiler.
  3. Use RubyScript2Exe

How can I make a Python script standalone executable to run without ANY dependency?

You can use py2exe as already answered and use Cython to convert your key .py files in .pyc, C compiled files, like .dll in Windows and .so on Linux.

It is much harder to revert than common .pyo and .pyc files (and also gain in performance!).

Cython standalone executable on ubuntu

I guess you have to compile the .c file you have obtained.

Assuming you are using python 3.5 and don't have to link to other libraries than python you can do this with a simple gcc command like :

gcc -I /usr/include/python3.5m -o your_program your_file.c -lpython3.5m

(you might need to remove the m following the version number)

As you expect it will use the if __name__ == "__main__": statement as entry-point of the program.

Having difficulties creating a stand alone compiler

I'll try to paint you a picture.

You're creating a new language L. For that language you wrote a compiler, CL in (for instance) Java that compiles from L to x86 and creates an ELF executable file (i.e. Linux executable). You need to use the JVM in order to use CL (well, technically there are tool-chains that will compile Java to native, but lets ignore that).

Say you don't want to be JVM bound, and instead prefer to run natively on Linux. Well, no problem. You just wrote a compiler that compiles from L to native Linux executable. You just need to use that compiler, CL, to write a new compiler C2L. C2L does the same thing as CL only it's written in L instead of Java and so you can compile it to native with CL (running CL on the JVM). Once you've compiled C2L, you no longer need the JVM to run or compile anything because C2L runs natively and compiles to native executables.

Now, if you want to create another compiler that runs on Windows, you'll need to create a third compiler, C3L, that compiles L to native EXE (or whatever Windows-compatible format you'll choose) - that compiler will be compiled with CL or C2L. Once you've compiled C3L you can take that executable over to a Windows machine and you're done.

How do I compile a PyQt script (.py) to a single standalone executable file for windows (.exe) and/or linux?

if you want completelly create one stand alone executable, you can try PyInstaller . i feel it's better to create one stand alone executable than cx_freeze or py2exe (in my experience). and easy to use (full documentation available in the site).

It supports Python 3.6 or newer.

Pass the --onefile argument if you want to create completely standalone .exe. in example :

pyinstaller.exe --onefile --windowed app.py

How to create a standalone .exe in Java (that runs without an installer and a JRE)

Solution

Use warp-packer to create a exe out of the image and app launcher created by jlink.

First:

  1. Copy warp-packer from this download link.
  2. Generate an image for your application using jlink.

Then, create a single file application executable. This can be done with one command (running it on a single line and using your values instead of the %% variables):

 %WARP_DIR%\warp-packer 
--arch windows-x64
--input_dir %APP_JLINK_IMAGE_DIR%
--exec %APP_JLINK_LAUNCHER_BAT_FILE%
--output %APP_SINGLE_EXECUTABLE_FILE_NAME%

The command could be run from the command line manually or automatically via an appropriate build tool plugin.

jlink can be invoked using whichever means works best for your build environment; e.g. any one of: maven plugin, gradle plugin, command line utility, jpackage utility or jpackage build tool plugin, etc.

Related Answer

This idea is not mine, it was proposed here:

  • How do I bundle a JRE into an EXE for a Java Application?

Tutorial

A full tutorial example follows if more information is required.

Solution Description

This answer is long because it seeks to provide a complete example with additional contextual advice. It could be more concise. It's style is closer to a tutorial or blog post style post than to a StackOverflow answer. Hopefully the length is not intimidating and it is easy to replicate the outcome.

I was curious about this so I thought I would try it. Surprisingly to me, I was able to get it to work. So I have documented how to replicate that here.

The key is the suggestion in comments by "OH GOD SPIDERS", to use the the "warp" tool for packaging, in conjunction with other comments suggesting interfacing with jlink.

I tried to do as much as possible using the Maven build tool, so this solution is oriented towards that. You could adapt the solution to another tool chain if you prefer.

The solution example builds a JavaFX application with FXML. The example could be simpler and much smaller if it did not include FXML, but I thought it was important to show how resources work with this solution, which is why FXML is included.

Limitations

  • This is, by design, a Windows only build solution which must be run on a Windows machine, both at build time and at deployment and run time.

  • It will only work for applications that rely on Java modules that have module-info.java definitions. For example, it won't work for a Spring or SpringBoot application unless it is fully modular. This is, until Spring 6 or SpringBoot 3 with full Java Platform module support is released.

High Level Steps

  1. Build the application as a Java platform modular application.

    • The application MUST have no automatic dependencies (the application itself and all transitive dependencies it relies on must be defined as Java modules with properly defined module-info.java files).
  2. Link the application to create a runtime image with a launch script.

    • I used the openjfx JavaFX Maven plugin to do the linking.
  3. Turn the runtime image with the launch script into an exe.

    • This step uses the warp-packer tool, which can be executed via the maven exec plugin.

Procedure

  1. Install JDK 17 (does not require a version which includes JavaFX).
  2. Install Maven.
  3. Create the project files shown below.
  4. Install warp to tools\warp-packer.exe.
  5. Build and package the project (mvn package).
  6. Run the application exe (target/hellowarp.exe) to test it.
  7. Give the application exe to friends with Windows machines.
  8. Friends will be able to run the exe from the command line or via a double-click on the exe.

No installation of your application is required, no extraction or unzipping of any archives, no Java runtime installation and no other additional installations are required. All that is needed is to copy the exe file to a windows machine (e.g. click on a download link on the web or copy the exe out of a mail attachment), then double click on the exe it to instantly run your application.

File tree


C:\dev\hellowarp>tree /a /f .
Folder PATH listing for volume Local Disk
Volume serial number is 00000086 C034:A84E
C:\DEV\HELLOWARP
| pom.xml
|
+---src
| \---main
| +---java
| | | module-info.java
| | |
| | \---com
| | \---example
| | \---hellowarp
| | HelloController.java
| | HelloWarp.java
| |
| \---resources
| \---com
| \---example
| \---hellowarp
| hello-view.fxml
|
\---tools
warp-packer.exe

Obtaining and installing warp

Create a new directory, \tools, in the root of your project.

Download Warp from:

  • https://github.com/dgiagio/warp/releases/download/v0.3.0/windows-x64.warp-packer.exe

And copy the warp executable (renaming it) to the following location:

\tools\warp-packer.exe

Files

pom.xml

Maven project.

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.example</groupId>
<artifactId>hellowarp</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>17</java.version>
<javafx.version>17.0.1</javafx.version>
</properties>

<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>${javafx.version}</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>${javafx.version}</version>
</dependency>
</dependencies>

<build>
<plugins>
<!--compile-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<!--create linked image-->
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.8</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jlink</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>com.example.hellowarp/com.example.hellowarp.HelloWarp</mainClass>
<compress>2</compress>
<noManPages>true</noManPages>
<noHeaderFiles>true</noHeaderFiles>
<stripDebug>true</stripDebug>
<launcher>${project.artifactId}</launcher>
</configuration>
</plugin>
<!--package image as an exe-->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- obtain warp-packer.exe from: "https://github.com/dgiagio/warp/releases/download/v0.3.0/windows-x64.warp-packer.exe" -->
<executable>${project.basedir}\tools\warp-packer.exe</executable>
<arguments>
<argument>--arch</argument>
<argument>windows-x64</argument>

<argument>--input_dir</argument>
<argument>${project.build.directory}\image</argument>

<argument>--exec</argument>
<argument>bin\${project.artifactId}.bat</argument>

<argument>--output</argument>
<argument>${project.build.directory}\${project.artifactId}.exe</argument>
</arguments>
</configuration>
</plugin>
</plugins>
</build>
</project>

module-info.java

Java platform module definition for the application.

module com.example.hellowarp {
requires javafx.controls;
requires javafx.fxml;

opens com.example.hellowarp to javafx.fxml;
exports com.example.hellowarp;
}

HelloWarp.java

JavaFX application.

package com.example.hellowarp;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.io.IOException;

public class HelloWarp extends Application {
@Override
public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(
HelloWarp.class.getResource(
"hello-view.fxml"
)
);

Scene scene = new Scene(fxmlLoader.load());

stage.setTitle("Hello!");
stage.setScene(scene);
stage.show();
}

public static void main(String[] args) {
launch();
}
}

HelloController.java

JavaFX FXML controller class.

package com.example.hellowarp;

import javafx.fxml.FXML;
import javafx.scene.control.Label;

public class HelloController {
@FXML
private Label welcomeText;

@FXML
protected void onHelloButtonClick() {
welcomeText.setText("Welcome to my JavaFX Application!");
}
}

hello-view.fxml

UI view definition file.

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>

<?import javafx.scene.control.Button?>
<VBox alignment="CENTER" spacing="20.0" prefWidth="250" xmlns:fx="http://javafx.com/fxml"
fx:controller="com.example.hellowarp.HelloController">
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0"/>
</padding>

<Label fx:id="welcomeText"/>
<Button text="Hello!" onAction="#onHelloButtonClick"/>
</VBox>

Screenshot of the running hellowarp.exe application

hello-screenshot

FAQ

There FAQ section just provides contextual information. You can ignore this section if you already know this info, or if you don't need it.

Is this an alternative distribution method to a "fat jar"?

Yes, I think so.

What would this be appropriate for?

A small-scale application distributed in an environment where you know the users are running Windows.

Can I also package my app as an MSI installer?

Yes. I did that using the akman jpackage-maven-plugin, it worked well. To limit size and scope I will not document that in this answer.

Would it be better to use a "git repo", "fat jar", a exe, a packaged installer or "zipped" image?

It depends on what you are doing.

If your target is other developers, set up an account on github, put your project there and provide a maven or gradle build file for the developers to build the app from source in their environment. Just packaging the application as a standard jar file (no fat jar), would be fine. Any jar you create could be deployed to maven central. Use a module-info.java for the jar so that it can be linked via jlink into packaged applications.

If it is a school project. It depends on the acceptance preference for the school. Perhaps they just want the code source in git, and that is all you need. Or maybe you can create a (thin) jar file (or a zip with the jar and its dependencies) which you provide, knowing that the standard school systems have all the relevant Java/JavaFX software already installed on them.

Or maybe it is a known OS environment, e.g. Windows, Mac or Linux, and you can use jpackage to build an installable package for one (or two) of those environments.

Or, if it is windows only, this solution of packaging as an "exe" for distribution might work well.

A "fat jar" configuration is not supported for JavaFX development. I do not recommend it. You can get it to work (currently) and it can be convenient sometimes, but you will need to decide if the trade-offs involved to do that are worth it.

If you are building a commercial or popular open source desktop product, create packaged installers, using a tool like jpackage (or one of the commercial or open source alternatives) in the appropriate format for your target platforms (e.g. msi or exe for windows, rpm and deb for linux, dmg for mac). You may choose to deploy those packaged formats to Windows or Mac app stores or Linux yum/apt repositories.

If it is a mobile deployment, use gluon mobile.

Can I use the Apache jlink Maven plugin instead of the OpenJFX Maven plugin.

The OpenJFX JavaFX Maven plugin or the akman jpackage-maven-plugin will produce the correct images at this time.

The Apache jlink Maven plugin will, currently, fail (with JavaFX 17.0.1 and Apache jlink plugin 3.1.0).

When I tried using the Apache jlink Maven plugin, it got confused by the JavaFX platform module definitions. The Apache jlink plugin started working with weird phantom module names like javafx.graphicsEmpty that it treated as automatic modules and passed to jlink, so jlink refused to link them. I could not find a way around that issue.

When I double click on the exe, there is blank window with the name of the exe in the title bar in addition to my application window.

Yes. Depending on the application that could either be a minor annoyance or a show stopper.

The display of the black screen on double-click is just the way this solution, as presented here, works.

There may be a way to circumvent this, but I haven't done a lot of investigation into it. You could look at the information supplied here (which discusses various ways to hide or minimize app launcher windows in MS Windows) and see if it helps you:

  • https://www.robvanderwoude.com/battech_hideconsole.php
  • https://stackoverflow.com/a/55662615/1155209

If, instead of double-clicking on the app, you are running the app by typing the exe name in a command console, there is no additional screen as there is already an existing console that you were typing in.

Can I use this technique to create single file executables for other operating systems?

Yes, I believe so.

At this time, I have not tried to use this solution for anything but Windows executables.

warp-packer is, capable of generating executables for a variety of OS systems.

To package for a non-windows machine, you would need to input the appropriate jlink image output for the target operating system to warp-packer and then run the appropriate warp-packer utility (I believe on the target OS) to generate the single executable for execution on that target OS.

If interested, see the warp-packer and jlink documentation.

What is the size of the generated executable?

For the sample application, my generated application executable was 34 megabytes in size.

What is the startup time?

I didn't measure it, but time to startup (time to display the application GUI window after double clicking the exe) appeared to be about a second.

Could I create an exe for a non-modular Java project.

Yes probably, but that is outside the scope of what I am prepared to discuss here, and the method would be different from that described here.

C++ Executable distribution strategy

You might give this technique a try.



Related Topics



Leave a reply



Submit