javamacosuniversal-binary

How to create a mac universal binary with bundled JRE?


I am creating a JAVA desktop app for Mac computers, using jpackage to bundle the desired JRE into the app and finally shipping a .app to the customers.

With the new m1 apple arm silicon computers I do not want to create different apps for each processor architecture with the right JRE (intel & arm) but create one single universal binary app that launches the Intel JRE on Intel computers and the Arm JRE on Arm computers. I know this is possible somehow.

I tried to create two .apps and use the lipo tool from the mac command line, but this doesn't really work.

Any suggestions how to proceed?


Solution

  • So I followed this very detailed tutorial:

    https://incenp.org/notes/2023/universal-java-app-on-macos.html

    After some minor little changes it works perfectly on Intel (with Mac OS 11) and Apple chip (with Mac OS 14). I tried all three options but will use the last one with 2 threads.

    I compiled the file on the machine with the older operating system.

    Two small remarks: The function get_application_directory needs to be fixed a little bit:

    static char * get_application_directory(char *buffer, uint32_t len)
    {
        char *last_slash = NULL;
        int n = 2;
    
        if ( ! _NSGetExecutablePath(buffer, &len) ) {
            while ( n-- > 0 ) {
                if ( (last_slash = strrchr(buffer, '/')) )
                    *last_slash = '\0';
            }
    
        }
    
        return last_slash ? buffer : NULL;
    }
    

    and the reference of the jars on the classpath only work when I put every single jar file on the classpath and not use any wildcard *.

    To debug you can always call this method that will print any exception the JVM is throwing:

    void check_and_print_exception(JNIEnv *env) {
        if ((*env)->ExceptionCheck(env)) {
            (*env)->ExceptionDescribe(env);
            (*env)->ExceptionClear(env);
        }
    }