From 541b538cf7e58de21907252103b0ccbdc5e79793 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Sat, 9 May 2026 08:38:57 +0300 Subject: [PATCH] docs: troubleshoot "Failed to create CEF browser" on Linux Simulator (#4882) Documents the UnsatisfiedLinkError some Linux users hit when the Simulator loads the bundled CEF, along with the JAVA_HOME / LD_LIBRARY_PATH IDE-launcher workaround. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../The-Components-Of-Codename-One.asciidoc | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/docs/developer-guide/The-Components-Of-Codename-One.asciidoc b/docs/developer-guide/The-Components-Of-Codename-One.asciidoc index 5518267690..778834c3ef 100644 --- a/docs/developer-guide/The-Components-Of-Codename-One.asciidoc +++ b/docs/developer-guide/The-Components-Of-Codename-One.asciidoc @@ -2900,6 +2900,35 @@ wb.setURL("jar:///Page.html"); IMPORTANT: On Android a native indicator might show up when the web page is loading. This can be disabled using the `Display.getInstance().setProperty("WebLoadingHidden", "true");` call. You need to invoke this once. +==== Troubleshooting "Failed to create CEF browser" on Linux + +In the Simulator, `BrowserComponent` is rendered by the bundled https://bitbucket.org/chromiumembedded/java-cef[CEF] (Chromium Embedded Framework) port. On Linux, `BrowserComponent.isNativeBrowserSupported()` may return `true` and yet creating the component throws `RuntimeException: Failed to create CEF browser`, with a root cause similar to: + +[source] +---- +java.lang.UnsatisfiedLinkError: .../codenameone-cef-*-linux64.zip-extracted/lib/linux64/libjcef.so: + .../lib/linux64/libjawt.so: version `SUNWprivate_1.1' not found + (required by .../lib/linux64/libjcef.so) +---- + +The native CEF library (`libjcef.so`) is loaded with a sibling `libjawt.so` shipped inside the CEF archive. That copy of `libjawt.so` expects symbols (`SUNWprivate_1.1`) provided by the JDK's own `libjawt.so` and the matching `libjvm.so`. When the JVM running the Simulator does not expose those symbols at load time -- typically because the dynamic linker does not have the JDK's native library directories on its search path -- the load fails before any browser is created. This is purely a Simulator/desktop concern; the same code runs unchanged on Android and iOS. + +The fix is to launch the IDE (and therefore the Simulator JVM) with `JAVA_HOME` and `LD_LIBRARY_PATH` pointing at a supported JDK. For example, on Linux Mint / Ubuntu wrap the IDE startup script: + +[source,bash] +---- +#!/bin/bash +export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 +export LD_LIBRARY_PATH=$JAVA_HOME/lib:$JAVA_HOME/lib/server${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} +exec /path/to/your/ide "$@" +---- + +After relaunching the IDE through this wrapper, `BrowserComponent` instantiation succeeds in the Simulator. Any JDK from 11 through 25 that is supported for running the Simulator works -- the important part is that `LD_LIBRARY_PATH` resolves to that JDK's `lib` and `lib/server` directories so the bundled `libjcef.so` finds a compatible `libjawt`/`libjvm` pair. + +TIP: If `BrowserComponent` instantiation fails on Linux, log the environment with `CN.getProperty("java.home", "")`, `CN.getProperty("JAVA_HOME", "")` and `CN.getProperty("LD_LIBRARY_PATH", "")`. An `` value for `LD_LIBRARY_PATH` while the IDE was launched from a desktop shortcut is the typical fingerprint of this problem -- desktop launchers do not source your shell profile. + +NOTE: This issue does not affect packaged native applications, only the desktop Simulator running on Linux. + ==== BrowserComponent hierarchy When Codename One packages applications into native apps it hides a lot of details to make the process simpler. One of the things hidden is the fact that you aren't dealing with a JAR anymore, so