BibleGet-I-O / bibleget-openoffice

BibleGet I/O Project plugin for Open Office
Apache License 2.0
2 stars 1 forks source link

figure out how to package and distribute JCEF native libraries and make available to java.library.path #16

Closed JohnRDOrazio closed 3 years ago

JohnRDOrazio commented 3 years ago

Now that the functionality for JCEF is created and tested and pretty much complete, we have to move to the next phase of figuring out how to package and distribute the JCEF native libraries and make them available to the java.library.path.

JohnRDOrazio commented 3 years ago

Started packaging the necessary files inside the project, in a JCEF folder, and implementing code that will copy all of the files to the user.home under the BibleGetPlugin directory. It was working on first test, here's the code:

    private static void setNativeLibraryDir() throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException, IOException {
        String nativelibrarypath = "";
        if(SystemUtils.IS_OS_WINDOWS){
            nativelibrarypath = "/AppData/Roaming/BibleGetOpenOfficePlugin/JCEF";
        }
        else if(SystemUtils.IS_OS_MAC_OSX){
            nativelibrarypath = "/Library/Application Support/BibleGetOpenOfficePlugin/JCEF";
        }
        else if(SystemUtils.IS_OS_LINUX){
            nativelibrarypath = "/.BibleGetOpenOfficePlugin/JCEF";
        }
        nativelibrarypath = System.getProperty("user.home") + nativelibrarypath;

        //first let's check if the JCEF directory exists in the user's home under our BibleGetOpenOfficePlugin directory
        //and if not, we create it
        Path JCEFpath = Paths.get(nativelibrarypath);
        Path JCEFlocalespath = Paths.get(nativelibrarypath, "locales");
        Path JCEFswshaderpath = Paths.get(nativelibrarypath, "swiftshader");
        if(Files.notExists(JCEFpath)){
            File jcefDirectory = new File(nativelibrarypath);
            jcefDirectory.mkdirs();
        }
        if(Files.notExists(JCEFlocalespath) ){
            File jcefLocalesDir = new File(nativelibrarypath, "locales");
            jcefLocalesDir.mkdir();
        }
        if(Files.notExists(JCEFswshaderpath) ){
            File jcefSwShaderDir = new File(nativelibrarypath, "swiftshader");
            jcefSwShaderDir.mkdir();
        }

        String[] JCEFfiles = new String[]{
            "cef.pak",
            "cef_100_percent.pak",
            "cef_200_percent.pak",
            "cef_extensions.pak",
            "chrome_elf.dll",
            "d3dcompiler_47.dll",
            "devtools_resources.pak",
            "icudtl.dat",
            "jcef.dll",
            "jcef_helper.exe",
            "libEGL.dll",
            "libGLESv2.dll",
            "libcef.dll",
            "snapshot_blob.bin",
            "v8_context_snapshot.bin"
        };
        String[] JCEFlocaleFiles = new String[]{
            "am.pak",
            "ar.pak",
            "bg.pak",
            "bn.pak",
            "ca.pak",
            "cs.pak",
            "da.pak",
            "de.pak",
            "el.pak",
            "en-GB.pak",
            "en-US.pak",
            "es-419.pak",
            "es.pak",
            "et.pak",
            "fa.pak",
            "fi.pak",
            "fil.pak",
            "fr.pak",
            "gu.pak",
            "he.pak",
            "hi.pak",
            "hr.pak",
            "hu.pak",
            "id.pak",
            "it.pak",
            "ja.pak",
            "kn.pak",
            "ko.pak",
            "lt.pak",
            "lv.pak",
            "ml.pak",
            "mr.pak",
            "ms.pak",
            "nb.pak",
            "nl.pak",
            "pl.pak",
            "pt-BR.pak",
            "pt-PT.pak",
            "ro.pak",
            "ru.pak",
            "sk.pak",
            "sl.pak",
            "sr.pak",
            "sv.pak",
            "sw.pak",
            "ta.pak",
            "te.pak",
            "th.pak",
            "tr.pak",
            "uk.pak",
            "vi.pak",
            "zh-CN.pak",
            "zh-TW.pak"
        };
        String[] JCEFswiftshaderFiles = new String[]{
           "libEGL.dll",
            "libGLESv2.dll"
        };

        for(String fileName : JCEFfiles ){
            Path filePath = Paths.get(nativelibrarypath, fileName);
            if(Files.notExists(filePath) ){
                try (InputStream fileInput = new BufferedInputStream(
                    // this files is shipped with the application
                    BibleGetIO.class.getResourceAsStream("/io/bibleget/JCEF/"+fileName))) {
                    Files.copy(fileInput, filePath);
                }
            }
        }
        for(String fileName : JCEFlocaleFiles ){
            Path filePath = Paths.get(nativelibrarypath, "locales", fileName);
            if(Files.notExists(filePath) ){
                try (InputStream fileInput = new BufferedInputStream(
                    // this files is shipped with the application
                    BibleGetIO.class.getResourceAsStream("/io/bibleget/JCEF/locales/"+fileName))) {
                    Files.copy(fileInput, filePath);
                }
            }
        }
        for(String fileName : JCEFswiftshaderFiles ){
            Path filePath = Paths.get(nativelibrarypath, "swiftshader", fileName);
            if(Files.notExists(filePath) ){
                try (InputStream fileInput = new BufferedInputStream(
                    // this files is shipped with the application
                    BibleGetIO.class.getResourceAsStream("/io/bibleget/JCEF/swiftshader/"+fileName))) {
                    Files.copy(fileInput, filePath);
                }
            }
        }

        if(JAVAVERSION == 8){

            final Field usrPathsField = ClassLoader.class.getDeclaredField("usr_paths");
            usrPathsField.setAccessible(true);
            //get array of paths
            final String[] paths = (String[])usrPathsField.get(null);
            //check if the path to add is already present
            for(String path : paths) {
                if(path.equals(nativelibrarypath)) {
                    return;
                }
            }

            //add the new path
            final String[] newPaths = Arrays.copyOf(paths, paths.length + 1);
            newPaths[newPaths.length-1] = nativelibrarypath;
            usrPathsField.set(null, newPaths);
        }

    }

However when trying to push to github, I got an error because libcef.dll is slightly over 100MB which is the limit for github without resorting to git lfs. This would just make development that much more complicated.

So I'm thinking of trying another route: downloading the zip directly from the jcefbuild github releases on program initialization, and unzipping the package to the user.home under the BibleGetPluginOpenOffice directory.

JohnRDOrazio commented 3 years ago

I believe I have it working now, at least the build is successful on Windows 10 with JDK 1.8. The following commits should have implemented the solution to this issue for both Windows and Linux:

And for MacOS:

Needs testing however.

JohnRDOrazio commented 3 years ago

Haven't tested yet for MacOS, but at least for Linux x64 and Windows x86 the build is now working. For Linux there is an extra installation process / GUI the sets up the environment, and the last commit to fix this is 0657f21c99f29bfd72e7281cd3f1ec5c5e02aec9 . Still a couple things to perfect and iron out but at least the build is now working. Closing for now, MacOS can have it's own issues opened and I don't think I'm even going to bother much with Linux x86, I don't think it's worth the effort (and perhaps it's simple enough to port from the Linux x64 build).