Linux/Mac: Fix discovery of icudtl.dat

Issue #109 new
Former user created an issue

Original issue 109 created by christophe.cornu on 2014-08-15T18:35:40.000Z:

Congrats on the work for revision 99 with the adoption of CEF 3.1916.1749 and the Mac fix for visibility. For the first time we can have multiple tabs working on the Mac :-) I did notice a regression affecting those that launch their app through the java command line. Details below.

What steps will reproduce the problem?
1. Get and build latest JCEF r99 on Mac
2. Double click on jcef_app.app. All works fine.
3. Start a Java program that uses jcef, from the command line (using e.g. /Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/bin/java)

What is the expected output? What do you see instead?

When starting the program from the command line with the java executable, Java_org_cef_CefApp_N_1Initialize fails with the following msg.

[0815/140948:FATAL:content_main_runner.cc(751)] Check failed: base::i18n::InitializeICU().

A bad workaround is to copy icudtl.dat from jcef_app.app/Contents/Frameworks/Resources/ to /Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/bin/java (or wherever your java executable is installed).

What do you recommend to have util_mac::CefInitializeOnMainThread find icudtl.dat in the right location instead of getting it from the main executable's path? pathToJavaDLL points to jcef_app.app/Contents/Java, we can build the full path pointing to jcef_app.app/Contents/Frameworks/Resources/. How can we tell CEF to use that location?

These 2 links are interesting.
http://www.magpcss.org/ceforum/viewtopic.php?f=6&t=11459https://code.google.com/p/chromiumembedded/issues/detail?id=1198

This was not a pb with former revisions (r90) when icudtl.dll was loaded as a dll directly.

Official response

  • Marshall Greenblatt

    macOS: Support command-line configuration of framework-dir-path (see issue #109)

    If specified via the command-line the framework-dir-path value will be used locate the "Chromium Embedded Framework" library for dynamic loading by JCEF.

    For example, create the following directory structure:

    /path/to/jcef/
      run.sh
      bin/
        *.jar
        lib/macos64/
          Chromium Embedded Framework.framework/
            Chromium Embedded Framework
            Resources/
              *.lproj, *.pak, etc.
          jcef Helper[ (GPU)| (Plugin)| (Renderer)].app/
            Contents/
              Info.plist
              MacOS/jcef Helper
          libjcef.dylib
    

    And create run.sh with the following contents:

    export LIB_PATH="/path/to/jcef/bin/lib/macos64"
    
    java -cp "./bin:./bin/*" -Djava.library.path=$LIB_PATH tests.detailed.MainFrame
      --framework-dir-path=$LIB_PATH/Chromium\ Embedded\ Framework.framework
      --main-bundle-path=$LIB_PATH/jcef\ Helper.app
      --browser-subprocess-path=$LIB_PATH/jcef\ Helper.app/Contents/MacOS/jcef\ Helper
      --disable-gpu
    

    The app bundle path passed to --main-bundle-path is used for determining an app bundle ID and locating the optional Contents/Resources/crash_reporter.cfg file. It can point to any valid app bundle.

    → <<cset cbde7f9d45d3>>

Comments (39)

  1. Marshall Greenblatt

    Comment 2. originally posted by magreenblatt on 2014-08-20T15:10:23.000Z:

    issue #110 has been merged into this issue.

  2. Former user Account Deleted

    Comment 4. originally posted by anthapu on 2014-08-29T16:38:23.000Z:

    Hi,
    How are you launching the app using Java at command line. I am not much familiar with MAC env. I have it working in Linux. But on MAC I am not able to get the app to come up using "Java" at command line. The "JCEF_app" does work.

  3. Former user Account Deleted

    Comment 5. originally posted by christophe.cornu on 2014-08-29T23:01:37.000Z:

    Anth: I'm away from the mac I use for the next few days so i can't paste you the exact command line until then. It's pretty similar to Linux except the native libs and jars are in different folders. Yes the "JCEF_app" works, the pb is for those running without their own custom bundled app such as java/javaw/javaws. Maybe someone else will reply to you before I get back to you...

  4. Former user Account Deleted

    Comment 6. originally posted by anthapu on 2014-08-31T18:33:03.000Z:

    Hi Christopher,
    That's not an issue. Please post it when you get a chance. I tried various options. Since the xcode also tries to hardcode the path to different libraries it becomes a bit contrived to get the command line working. I tried to change the PATH references of the built libraries to make it simpler also. I still couldn't get it to work.

  5. Former user Account Deleted

    Comment 7. originally posted by anthapu on 2014-09-08T12:53:07.000Z:

    Hi Christopher,
    If you have access to your MAC, can you please post the command line?

  6. Former user Account Deleted

    Comment 8. originally posted by christophe.cornu on 2014-09-09T13:11:00.000Z:

    Hi Anth: here it is. It's very similar to the command line on Windows (run.bat).

    Open console
    Go to directory that contains jcef_app.app (e.g. <...>/jcef/src/xcodebuild/Release/
    java -cp "./jcef_app.app/Contents/Java/*" -Djava.library.path=./jcef_app.app/Contents/Java tests.detailed.MainFrame

    This works fine with revision92. With revision99, this fails with the following output:

    java -cp "./jcef_app.app/Contents/Java/*" -Djava.library.path=./jcef_app.app/Contents/Java tests.detailed.MainFrame
    Offscreen rendering disabled
    Using:
    JCEF Version = 3.1916.1749.99
    CEF Version = 3.1916.1749
    Chromium Version = 35.0.1916.138
    initialize on Thread[AWT-EventQueue-0,6,main] with library path ./jcef_app.app/Contents/Java
    Added scheme search://
    Added scheme client://
    [0909/090956:FATAL:content_main_runner.cc(751)] Check failed: base::i18n::InitializeICU().
    Trace/BPT trap: 5

  7. Former user Account Deleted

    Comment 10. originally posted by christophe.cornu on 2014-09-23T15:20:40.000Z:

    Thanks. That works.
    Hi Anth... I'm suspended on your last words... Were you working on a Chromium patch to make the loading of icudtl.dat more flexible?

  8. Former user Account Deleted

    Comment 11. originally posted by anthapu on 2014-09-23T16:17:55.000Z:

    No. I was not able to get the MAC command line working. Your suggestion helped. I was trying to change the library paths using install_name_tool to change the directory structure to launch the app, as I wanted to customize the structure. But I couldn't get the Java command line working correctly.

    I had the same problem in Linux and your issue report helped to work around that issue there.

    Your suggestion helped getting it working on MAC.

    Also, icudtl.dat may be part of the CEF issue. There were some people complaining about it had to be in the directory where the binary (CEFClient.exe) is located.

    I have not found alternative yet.

  9. Dmitry Azaraev

    It is not needed to fix icu_util.cc. Instead "fixing" of random files, better if CEF will provide own customizable PathService. icu_util already capable with path service and covers any platforms.

  10. Trejkaz (pen name)

    If the issue is in Chromium, has it at least been filed with Chromium? I get a crash every time I run this thing.

    Getting it working in a full application is one thing, but unless I can use the library while working in an IDE, who is going to build the application? Because I sure as hell can't...

  11. Marcin

    any news on this issue ? This issue is also relevant for mac's CEF3 based dylib opened as a plugin by 3rd party application which forces a workaround to inject icudtl.dat into app boundle ....

  12. Dominic Eubel

    The problem comes from chromium, not jcef... You have to set working directory to jcef_app.app or create an own bundle with right structure and set working directory to it.

    You need mandatory an app-bundle with this structure: anyApp.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources and set resources_dir_path of browser settings

  13. Czarek Tomczak

    Discovery of icudtl.dat is fixable in upstream CEF on both Linux and Mac:

    1. Linux - if you can build from sources apply the CefOverridePath attached in CEF Issue #1936 or wait for CEF PR 66 to be reworked.

    2. Mac - branches 2924 and later have the CefSettings.framework_dir_path setting, see CEF Issue 1532 and this comment by Marshall

  14. Andrew Thompson

    Naïve question, but is fixing this in CefSettings.java as simple as creating a public String with the name framework_dir_path and Magic Bridging Stuff™ happens, or is it more involved?

  15. Marshall Greenblatt

    You can make this work on macOS without changes to JCEF source code. Here's an example using a JCEF build at current master (CEF version 3.2987.1597.gffc5773) and extracting the contents from a Release build of jcef_app.app:

    1. Create a directory structure like the following:

    /path/to/jcef/
      run.sh
      bin/
        *.jar
        lib/macosx64/
          Chromium Embedded Framework.framework/
            Chromium Embedded Framework
            Resources/
              *.lproj, *.pak, etc.
          jcef Helper.app/
            Contents/
              Info.plist
              MacOS/jcef Helper
          libjcef.dylib
    

    2. Fix name links for libjcef.dylib and jcef Helper:

    $ cd /path/to/jcef/bin/lib/macosx64
    $ install_name_tool -change "@rpath/Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework" "@loader_path/Chromium Embedded Framework.framework/Chromium Embedded Framework" libjcef.dylib
    $ install_name_tool -change "@executable_path/Chromium Embedded Framework.framework/Chromium Embedded Framework" "@executable_path/../../../Chromium Embedded Framework.framework/Chromium Embedded Framework" "jcef Helper.app/Contents/MacOS/jcef Helper"
    

    3. Create run.sh with the following contents:

    #!/bin/bash
    # Absolute path to the library directory.
    export LIB_PATH="/path/to/jcef/bin/lib/macosx64"
    
    java -cp "./bin:./bin/*" -Djava.library.path=$LIB_PATH tests.detailed.MainFrame --framework-dir-path=$LIB_PATH/Chromium\ Embedded\ Framework.framework --browser-subprocess-path=$LIB_PATH/jcef\ Helper.app/Contents/MacOS/jcef\ Helper --disable-gpu
    

    The --disable-gpu flag seems to be necessary at the moment to avoid silent failures when creating the child processes.

  16. Wai Wang

    I created a simple hack for icudtl.dat discovery by copying over the java binary to a temporary folder and symlinking the libs directory so the general directory structure is like this:

    tmpDirectory/fakeJvm/
        bin/
            java
            icudtl.dat
            natives_blob.bin
            snapshot_blob.bin
         lib/             <- Symlink to JRE lib directory
    

    Then the program executes itself with the new java binary, code(in Kotlin): https://gist.github.com/waicool20/10619ab01f6cf26be4919a6670f17bdd

  17. Jonathan Cremieux

    I can confirm that Marshall's setup from his post from the 29th of March 2017 works. It is very helpful, thanks!

    However, with the JCEF build at current master (CEF version 3.3029.1604.g364cd86), I had to slightly modify the 2nd call to install_name_tool:

    #!bash
    
    install_name_tool -change "@rpath/Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework" "@executable_path/../../../Chromium Embedded Framework.framework/Chromium Embedded Framework" "jcef Helper.app/Contents/MacOS/jcef Helper
    
  18. Stefan Arisona

    Are there any insights / known reasons why "--disable-gpu" is needed? I need to add it when using CEF from Java, otherwise the window remains white. If I run the same code directly from the command line, disabling the GPU is not necessary.

  19. Mark van de Korput

    @magreenblatt's solution finally shed some light in the dark of these breaking dependency references when trying to embed cef in another java host application. For reference, here is my slight modification of his patch and run commands (using also the same modification that @kremio applied). My scripts work with the unmodified jcef_app.app, no need to build the custom structure that @magreenblatt suggested;

    patch.sh

    #!sh
    install_name_tool -change "@rpath/Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework" "@loader_path/../Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework" ./jcef_app.app/Contents/Java/libjcef.dylib
    install_name_tool -change "@rpath/Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework" "@executable_path/../../../Chromium Embedded Framework.framework/Chromium Embedded Framework" "./jcef_app.app/Contents/Frameworks/jcef Helper.app/Contents/MacOS/jcef Helper"
    

    run.sh

    #!sh
    #!/bin/bash
    JAVA_PATH="./jcef_app.app/Contents/Java"
    FRAMEWORKS_PATH="./jcef_app.app/Contents/Frameworks"
    RESOURCES_DIR_PATH="$(pwd)/jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources"
    java -cp "$JAVA_PATH:$JAVA_PATH/*" -Djava.library.path=$JAVA_PATH tests.detailed.MainFrame --framework-dir-path=$FRAMEWORKS_PATH/Chromium\ Embedded\ Framework.framework --browser-subprocess-path=$FRAMEWORKS_PATH/jcef\ Helper.app/Contents/MacOS/jcef\ Helper --resources-dir-path="$RESOURCES_DIR_PATH" --disable-gpu
    

    Put these patch.sh and run.sh files in the same folder as your jcef_app.app (path/to/jcef/src/jcef_build/native/Release/ if you followed the build wiki using the cmake method) and run the patch.sh ONCE to patch the internal executable references. Then run the run.sh to run the app java test application.

    NOTE; this issue has been around for 4 years and has 14 votes, should the "minor" status be revisited? Seeing also that it basically renders jcef unusable to embedded in java host applications on the mac.

  20. Bart Adriaanse

    Do we need to wait for an update of JCEF for this fix ?

    Triggered by the security alerts last week I am building a JCEF update (with JDK 11.01) according to the instructions in the Wiki but the native dll's (win64) I get are 3.3626.* versions and on linux I still need to put these files in the jre/bin folder or the application fails hard...

  21. Marshall Greenblatt

    @adriaanse JCEF needs to be built against the correct CEF branch/version. The version is controlled in CMakeLists.txt. The Linux fix mentioned above will soon be available in 3683 branch builds.

  22. Bart Adriaanse

    Given the recent 99ee032 commit, I just rebuilt and tested this issue on both CentOS 7 and Ubuntu 14 so i can confirm that it works !

  23. Rene Schneider

    I can confirm this to be working as well. I've had a preliminary fix for this problem in my JCEF branch and dropped it for the build against CEF 3683. Application still working just fine (on CentOS 7 in my case).

  24. Frantisek Kolar

    @Mark van de Korput, I just found your comment and I wonder if its possible to share something working. When i try to follow all the instruction for simple app, I just get allot of exception type of: UnsatisfiedLinkError.

    So not sure if these steps might not be working for current version or used to work for something that was valid a year ago - or I do something completly wrong.

    Thanks for any hints.

  25. Marshall Greenblatt

    macOS: Support command-line configuration of framework-dir-path (see issue #109)

    If specified via the command-line the framework-dir-path value will be used locate the "Chromium Embedded Framework" library for dynamic loading by JCEF.

    For example, create the following directory structure:

    /path/to/jcef/
      run.sh
      bin/
        *.jar
        lib/macos64/
          Chromium Embedded Framework.framework/
            Chromium Embedded Framework
            Resources/
              *.lproj, *.pak, etc.
          jcef Helper[ (GPU)| (Plugin)| (Renderer)].app/
            Contents/
              Info.plist
              MacOS/jcef Helper
          libjcef.dylib
    

    And create run.sh with the following contents:

    export LIB_PATH="/path/to/jcef/bin/lib/macos64"
    
    java -cp "./bin:./bin/*" -Djava.library.path=$LIB_PATH tests.detailed.MainFrame
      --framework-dir-path=$LIB_PATH/Chromium\ Embedded\ Framework.framework
      --main-bundle-path=$LIB_PATH/jcef\ Helper.app
      --browser-subprocess-path=$LIB_PATH/jcef\ Helper.app/Contents/MacOS/jcef\ Helper
      --disable-gpu
    

    The app bundle path passed to --main-bundle-path is used for determining an app bundle ID and locating the optional Contents/Resources/crash_reporter.cfg file. It can point to any valid app bundle.

    → <<cset cbde7f9d45d3>>

  26. Rene Schneider

    @Marshall Greenblatt Huge thanks to you for adding that latest commit! This is super practical! I was using some similar, but more intrusive and hacky version of that on my branches in order to allow for dynamic extraction of CEF from JARs. Was able to drop that now and adopted your solution (I also didn’t know about the --main-bundle-path parameter, which is nicer than patching around in Chromium code to fix the bundle ID problem).

  27. Steve Hannah

    Can someone explain why this problem is difficult to solve? If I want to include JCEF in a Java project, without wrapping it inside an .app bundle, it seems the only solution is to add symlinks into my JDK. Otherwise we get

    [0623/092048.019986:ERROR:icu_util.cc(168)] icudtl.dat not found in bundle

    [0623/092048.020215:ERROR:icu_util.cc(241)] Invalid file descriptor to ICU data received.

    Is there a way to use JCEF in a Java project without wrapping it in an .app bundle, and without modifying the JDK?

    I’m poking around the sources to see if I can find an easy way to tell it where to find icudtl.dat, but I’d appreciate any pointers to help me understand why this problem is hard to solve or where I need to look to solve it.

  28. Steve Hannah

    @Marshall Greenblatt Sorry. Didn’t notice that that was pinned and official. I had tried that first and it wasn’t working for me. Now that I know that that is the official solution, I’ll spend more time trying variations on that.

  29. Gulshan Bhatia

    HI,

    @Michael Green

    I tried whatever steps are mentioned and now I am able to run the sample examples by JCEF which is mentioned in the run.sh but when I tried to put my class files in the same folder and added that class name in run.sh the. it give me a class not found error.

  30. Gulshan Bhatia

    Hi Guys,

    With the above hack, provided by the @Mark van de Korput by creating patch.sh and run.sh sample application is tests.detailed.MainFrame working completely fine.

    But can someone tell me how can I run my java jcef app? where can I put my java file to compile .class file and where can I put my class file to run from run.sh?

    Also @Mark van de Korput can you please let me know from where sample app ests.detailed.MainFrame is executed?

  31. Log in to comment