Add CEF 147, Python 3.10–3.14, Linux/macOS ARM64/Windows support with modern build system#691
Open
linesight wants to merge 159 commits intocztomczak:masterfrom
Open
Add CEF 147, Python 3.10–3.14, Linux/macOS ARM64/Windows support with modern build system#691linesight wants to merge 159 commits intocztomczak:masterfrom
linesight wants to merge 159 commits intocztomczak:masterfrom
Conversation
Fixes: cztomczak#546 Had to include harfbuzz manually as newer Pango change this. See: eiskaltdcpp/eiskaltdcpp#413 https://gitlab.gnome.org/GNOME/pango/-/issues/387 Also had to add `-Wno-deprecated-declarations` to get this to compile because of the following errors that didn't seem to be coming from this code directly: warning: ‘GTimeVal’ is deprecated: Use 'GDateTime' instead warning: ‘GTypeDebugFlags’ is deprecated
…k#484). These callbacks were never called previously. Rename --no-run-examples flag to --unittests in build scripts.
… code at frame.pyx
…nd CanSaveCookie; restore network_cookies.py and make slight tweak to use CanSendCookie and CanSaveCookie
…ailures
Chrome 130+ MachPortRendezvousServerMac validates the signature of each
connecting subprocess via process_requirement.cc. Without a valid code
signature the server rejects the connection, bootstrap_look_up returns
BOOTSTRAP_UNKNOWN_SERVICE (1102), and shared_memory_switch.cc kills the
subprocess ("No rendezvous client, terminating process").
The browser process also fails its own process_requirement check (-67030)
when it has loaded the unsigned cefpython_py*.so extension, because macOS
marks the process code signature as invalid when an unsigned library is
dlopen'd into a signed process.
Ad-hoc signing both the subprocess binary and the Python extension gives
them a valid (self-signed) code identity that process_requirement.cc
accepts, restoring normal MachPortRendezvousClient operation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ous lookup CEF 130+ builds the MachPortRendezvousClient service name as: CFBundleIdentifier + ".MachPortRendezvousServer." + parent_pid The browser process injects CFBundleIdentifier = "org.cefpython" via MacInitialize() in util_mac.mm before CefInitialize(), so it registers: "org.cefpython.MachPortRendezvousServer.<pid>" The subprocess binary is a flat binary (not in an app bundle), so CFBundleGetMainBundle() returns no CFBundleIdentifier and the client looks up ".MachPortRendezvousServer.<parent_pid>" — a name starting with "." that bootstrap_look_up can never find (BOOTSTRAP_UNKNOWN_SERVICE 1102). This caused every spawned subprocess to terminate immediately with "No rendezvous client, terminating process (parent died?)". Fix: add main_mac.mm (compiled only on Apple) which injects the same "org.cefpython" bundle identifier into the subprocess's main bundle dict before CefExecuteProcess runs, matching what the parent registered. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
extern "C" linkage specification must be at namespace (file) scope in C++, not inside a function body. Move the SubprocessMacInit() forward declaration out of main() into file scope, guarded by OS_MAC. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
main_mac.mm uses CFBundleGetMainBundle, CFBundleGetIdentifier, etc. Add -framework CoreFoundation so the linker resolves those symbols. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the broken SubprocessMacInit() runtime injection approach with a reliable compile-time solution: embed Info.plist in the subprocess Mach-O binary using the -sectcreate __TEXT __info_plist linker flag. CoreFoundation reads the __TEXT,__info_plist section automatically, so CFBundleGetMainBundle() returns CFBundleIdentifier = "org.cefpython" without any runtime code. This matches the service name the browser process registers with MachPortRendezvousServer, fixing bootstrap_look_up. The previous approach (CFDictionarySetValue on the info dict) was broken because CFBundleGetInfoDictionary() returns an immutable CFDictionaryRef for flat binaries; the set operation silently did nothing. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tion Without an ad-hoc signature on the Python binary (the browser process), process_requirement.cc fails with errSecCSUnsigned (-67030). Chrome responds by launching subprocesses with a restricted bootstrap namespace that cannot see Mach services registered by the parent. This causes bootstrap_look_up for MachPortRendezvousServer to return 1102 regardless of whether the service name is correct. Signing the Python binary (in addition to subprocess and .so files) prevents the namespace restriction and allows subprocesses to find the registered service. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
--in-process-renderer was removed from Chrome 130+. The flag no longer appears in content_switches.cc so passing it was a no-op, leaving the renderer as a full subprocess. That subprocess calls MachPortRendezvousClientMac::AcquirePorts() -> bootstrap_look_up, which returns 1102 (BOOTSTRAP_UNKNOWN_SERVICE) on unsigned CI runners because Chrome gives them a restricted bootstrap namespace. Without a working renderer, g_js_code_completed is never set and the tests fail. Switch to --single-process, which runs the renderer in the browser process and eliminates the renderer's bootstrap_look_up call entirely. Also drop the Python-interpreter codesigning step: ad-hoc signing never fixed the -67030 (errSecCSUnsigned) error from process_requirement.cc, and may have broken any valid Developer ID signature that python.org Python already carried. Our own compiled binaries (subprocess, cefpython_py*.so) still need ad-hoc signing since they ship unsigned from the build. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
--single-process runs the renderer's V8 in the browser process, which requires a large contiguous virtual memory reservation for JIT code (CodeRange). On older macOS-14 CI runner images this reservation fails: V8 process OOM (Failed to reserve virtual memory for CodeRange) --jitless disables all V8 JIT compilers (Sparkplug, Maglev, Turbofan), eliminating the CodeRange requirement entirely. Unit test JS is simple enough that interpreted execution is sufficient. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Restore LF line endings (linux branch base) and keep only the functional macOS additions: - build.py: MAC/LINUX flags, CEF framework detection, _codesign_macos(), symlinks=True in copytree - main_test.py / osr_test.py: if MAC: switch block (no-sandbox, single-process, jitless, NetworkServiceInProcess2); also update Linux block: no-zygote, NetworkServiceInProcess2 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Delete cef_version_mac.h (CEF 66 x86_64 header, never updated for 146). CMakeLists.txt, common.py, and build_distrib.py all now unconditionally use cef_version_macarm64.h and the cef*_macarm64 CEF directory on macOS. The -mmacosx-version-min is hardcoded to 11.0 (ARM64 minimum). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- screenshot.py: add macOS switches matching osr_test.py; remove dead switches (enable-begin-frame-scheduling, disable-surfaces not present anywhere in CEF 146 source) from the macOS path - osr_test.py: drop --no-sandbox (cefpython.pyx already sets no_sandbox=1 at the C level) and --in-process-gpu (macos-14-arm64 CI has real Apple Silicon GPU; subprocess is ad-hoc signed in the test setup step); update comments to cite actual mechanism (restricted bootstrap namespace for ad-hoc-only signed processes) verified against CEF source - ci-macos.yml wheel job: ad-hoc codesign subprocess and .so before packaging so installed wheels don't ship unsigned binaries; unsigned subprocess binary is the root cause of GPU_DEAD_ON_ARRIVAL (exit code 1003) on macOS 14+ Gatekeeper Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
ZipFile.write() does not preserve Unix file mode bits, so the subprocess binary inside the wheel lost its +x permission. pip extracts it as a non-executable file, and CEF cannot launch the renderer process, leaving browser windows blank. Use ZipInfo.from_file() which stores the real file mode in the zip entry's external_attr field. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…LTO on Linux GCC's alias analysis loses track of object sizes when small ref-counted classes are inlined across translation units during LTO, triggering spurious -Wstringop-overflow warnings on the atomic ref_count_ write. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
cp -r does not preserve permissions, so subprocess lost its +x bit before build_distrib zipped it into the wheel. The ZipInfo.from_file() fix in a68d6b1 preserves whatever mode is on disk — but by the time the wheel job copies files into cefpython3/, the permission was already gone. Add chmod +x to match what the test job already does. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Merge compile/test/wheel into a single matrix job per Python version so that each version's pipeline is fully independent — a 3.11 failure no longer delays the 3.10 wheel. Extract CEF download into a dedicated job to avoid 5 concurrent downloads of the same 600 MB archive from Spotify's CDN. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
GCC's lto-wrapper re-compiles combined IR during linking and doesn't propagate -Wno-* flags from the compile phase, so the false-positive -Wstringop-overflow warnings resurfaced at link time. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
qt.py: override QT_QPA_PLATFORM=xcb unconditionally on Linux for all Qt bindings (PyQt5/PyQt6/PySide6). Wayland desktops such as KDE Plasma on Kubuntu often pre-set QT_QPA_PLATFORM=wayland in the session environment; setdefault was insufficient to override it, causing CEF to open a detached top-level window instead of embedding into the Qt widget. window_info.pyx: add a warnings.warn() in SetAsChild when parentWindowHandle is 0 and WAYLAND_DISPLAY is set. This catches the same misconfiguration for any toolkit (Qt, GTK, SDL2) and points the developer to the correct per-toolkit env var fix. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…Linux qt.py: force QT_QPA_PLATFORM=xcb on Linux for all Qt bindings before QApplication is created. On Wayland desktops (e.g. KDE Plasma on Kubuntu) the session environment often pre-sets QT_QPA_PLATFORM=wayland; setdefault was insufficient to override it, causing CEF to receive a non-X11 window handle and open a detached top-level window instead of embedding into the Qt widget. qt.py: add CefWidget._phys() and apply it to the initial embed rect and all SetBounds calls on Linux for PyQt6/PySide6. Qt6 enables AA_EnableHighDpiScaling by default so width()/height() return logical pixels; CEF expects physical pixels. Without this fix, a display at 125-200% DPI causes the browser to fill only the top-left fraction of the window and resizing does not correct it. PyQt5 is unaffected as it uses the hidden_window/XReparentWindow path where X11 geometry drives browser sizing independently of SetBounds. window_info.pyx: warn when SetAsChild receives parentWindowHandle=0 on Linux in a Wayland session (WAYLAND_DISPLAY set). Fires at the caller site via stacklevel=2 and lists the per-toolkit env var fix for Qt, GTK, and SDL2. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Matches the pattern already used in ci-linux.yml and ci-windows.yml: a dedicated download-cef job saves the cache, and each compile matrix job restores from it rather than downloading independently. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Matches the pattern already used in ci-linux.yml and ci-windows.yml: a dedicated download-cef job saves the cache, and each compile matrix job restores from it rather than downloading independently. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…pi.h The #else branch with hardcoded version-specific include paths was only reachable by the old root-level build.py which no longer exists; all builds now go through CMake which always defines CEFPYTHON_API_H_FILE. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removes the third-party `packaging` dependency from all example scripts. The upstream master branch has no such requirement, and the version checks only need simple numeric comparisons that a split+tuple handles cleanly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…itions CefFrame::GetBrowser() can return a null CefRefPtr while a frame is being created or destroyed during rapid navigation (e.g. heavy pages with many iframes). The naked .get().GetIdentifier() chain in GetPyFrame() was a latent SIGSEGV; all handler entry points that call GetPyFrame() or dereference the frame's browser pointer now return their safe defaults when the browser pointer is NULL. Affected files: - src/frame.pyx: store GetBrowser() result, check .get() before chaining - src/handlers/load_handler.pyx: OnLoadStart / OnLoadEnd / OnLoadError - src/handlers/display_handler.pyx: OnAddressChange - src/handlers/v8context_handler.pyx: OnContextCreated - src/handlers/request_handler.pyx: OnBeforeBrowse, OnBeforeResourceLoad, GetResourceHandler, OnResourceRedirect, GetAuthCredentials - src/handlers/cookie_access_filter.pyx: CanSendCookie, CanSaveCookie - src/handlers/lifespan_handler.pyx: OnBeforePopup Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…t variance Move onclick from <h1> to <body> and click at viewport center (400,300) instead of hardcoded h1 coordinates (200,43). selectText() now selects the h1 via querySelector rather than ev.target, so any click on the page reliably triggers OnTextSelectionChanged regardless of font metrics or rendering differences in CI environments. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Owner
|
Hi, thank you for the PR. If this is continuation of changes started in cepfython123 branch - then I have created branch cefpython147, please send the PR against that branch. It will make reviewing easier. Changes in cefpython123 were already reviewed and were good. Regarding #686 GPU process crashes 3 times when running unit tests - was this an issue with upstream CEF 123 or was this a problem with cefpython? "CI publishes wheel artifacts for all 15 combinations (3 platforms × 5 Python versions)" - sounds awesome! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
This PR modernizes cefpython from CEF 66 (2018) to CEF 147, adds full support
for Linux and macOS Apple Silicon, and replaces the legacy build toolchain with
a pip-installable wheel workflow. It also incorporates all work from the
cefpython123branch (PR #679) which was never merged to master.What's new
CEF & Python versions
Platform support
Build system
setup.pywith scikit-build-core + CMakebuild_distrib.pyproduces installable wheels per platform/Python versionCI (GitHub Actions)
from cache rather than downloading independently
Linux
macOS
Qt
API changes
OnPluginCrashed;SendFocusEventkeptas no-op stub for compatibility
CanSendCookie/CanSaveCookiehandler signatures revisedOpen issues addressed
Definitely fixed
Likely fixed