29908646ea
Introduce a macOS Cocoa-based UI and CEF helper subprocess support. CMake: enable OBJCXX on Apple, treat mac sources as .mm, set -fobjc-arc, link Cocoa frameworks, and generate helper app targets using a mac Info.plist template; keep libcef logical target off macOS. Implementation: add Objective-C++ implementations for browser_host and nebula_window, convert startup to ObjC++ (prepare NSApplication), add process_helper_mac (CEF helper entry) and load CEF library from main/main_bigpicture on mac. Tooling/docs: add .clangd fallback flags, compile_commands symlink helper, update cross-platform docs for mac status. Misc: add menu-popup UI page, define UNREFERENCED_PARAMETER in platform/types.h, small code cleanups (use (void)layout, include platform/types.h) and update .gitignore.
216 lines
8.5 KiB
Markdown
216 lines
8.5 KiB
Markdown
# Cross-platform build guide
|
||
|
||
Nebula Browser uses a **single codebase** and **one git branch** for Windows, macOS, and Linux. You do not maintain separate platform branches. Instead, each machine unpacks the correct [CEF](https://bitbucket.org/chromiumembedded/cef) binary distribution into `thirdparty/cef/` and builds with CMake.
|
||
|
||
## Overview
|
||
|
||
| Layer | Location | Platform-specific? |
|
||
|-------|----------|-------------------|
|
||
| CEF binaries | `thirdparty/cef/` (gitignored) | Yes — one distribution per OS |
|
||
| CMake / deploy | `CMakeLists.txt` | Yes — uses CEF’s `COPY_FILES`, `COPY_MAC_FRAMEWORK`, etc. |
|
||
| App entry & CEF init | `src/app/run.cpp`, `src/platform/*/startup_*.cpp` | Partly |
|
||
| Native window shell | `src/platform/win\|mac\|linux/` | Yes |
|
||
| Browser embedding | `src/platform/*/browser_host_*.cpp` | Partly |
|
||
| Tabs, URLs, UI routing | `src/browser/`, `src/ui/`, `src/cef/` | No (shared) |
|
||
|
||
**Windows** has a full native shell (custom frame, DWM, embedded CEF views).
|
||
|
||
**macOS** has a Cocoa native shell (`NSWindow` / `NSView`) with CEF child-view embedding.
|
||
|
||
**Linux** compiles and links today, but `NebulaWindow::Create()` is still a stub that returns `false` until a real X11 (or GTK) host is implemented.
|
||
|
||
## Directory layout
|
||
|
||
```
|
||
thirdparty/cef/ # CEF standard distribution for your OS (not in git)
|
||
|
||
src/platform/
|
||
types.h # Rect, BrowserLayout, NativeWindow, AppStartup
|
||
startup.h # PrepareApp, single-instance, CefMainArgs, CefSettings paths
|
||
browser_host.h # CefWindowInfo helpers, resize/show/destroy browser HWNDs
|
||
paths_platform.h # ExecutableDirectory, DefaultUserDataRoot, PathToUtf8
|
||
|
||
win/ # Windows implementation
|
||
mac/ # macOS Cocoa implementation
|
||
linux/ # Linux stubs + partial CEF glue
|
||
|
||
src/window/
|
||
nebula_window.h # Platform-agnostic window API (PIMPL)
|
||
|
||
src/app/ # Shared controller and run loop
|
||
src/browser/ # Shared tab/session logic
|
||
src/cef/ # Shared CEF app and browser client
|
||
src/ui/ # Shared nebula:// URLs and path helpers
|
||
ui/ # HTML/JS UI (copied next to the binary at build time)
|
||
```
|
||
|
||
## Prerequisites
|
||
|
||
- **CMake** 3.21+
|
||
- **C++20** compiler
|
||
- Windows: Visual Studio 2022
|
||
- macOS: Xcode 16+ (Clang)
|
||
- Linux: GCC 10+ or Clang, plus development packages for X11 (CEF’s CMake runs `pkg-config` for X11 on Linux)
|
||
- **CEF standard binary distribution** for your OS and CPU architecture from the [CEF builds](https://cef-builds.spotifycdn.com/index.html) page (or your usual CEF source)
|
||
|
||
## CEF setup
|
||
|
||
1. Download the **standard distribution** for your platform (e.g. `cef_binary_*_windows64`, `*_macos*`, `*_linux64`).
|
||
2. Extract so that this path exists:
|
||
|
||
```
|
||
thirdparty/cef/cmake/FindCEF.cmake
|
||
```
|
||
|
||
3. The rest of the distribution (`Release/`, `Resources/`, `libcef_dll/`, etc.) should sit directly under `thirdparty/cef/` as shipped by CEF.
|
||
|
||
`thirdparty/cef/` is listed in `.gitignore` so binaries are never committed. Each developer and CI machine supplies its own copy.
|
||
|
||
## IDE / clangd setup
|
||
|
||
Without CEF headers, clangd will show many errors (unknown types like `CefWindowInfo`, `CefMainArgs`, etc.). To get full IDE support:
|
||
|
||
1. Unpack CEF into `thirdparty/cef/` as described above
|
||
2. Generate `compile_commands.json`:
|
||
```bash
|
||
cmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
|
||
```
|
||
3. Symlink it to the project root:
|
||
```bash
|
||
ln -s build/compile_commands.json .
|
||
```
|
||
|
||
The included `.clangd` file provides fallback flags, but full diagnostics require the compile database.
|
||
|
||
Optional: override the location at configure time:
|
||
|
||
```bash
|
||
cmake -B build -DCEF_ROOT=/path/to/cef_binary
|
||
```
|
||
|
||
## Building
|
||
|
||
### Windows
|
||
|
||
```powershell
|
||
cmake -B build
|
||
cmake --build build --config Release
|
||
```
|
||
|
||
Output: `build/Release/NebulaBrowser.exe` (plus CEF DLLs and `ui/` copied beside it).
|
||
|
||
### macOS
|
||
|
||
```bash
|
||
cmake -B build -DPROJECT_ARCH=x86_64 # or arm64 on Apple Silicon
|
||
cmake --build build --config Release
|
||
```
|
||
|
||
CMake builds a `NebulaBrowser.app` bundle and copies the Chromium Embedded Framework into `Contents/Frameworks`. The macOS port includes a Cocoa `NSWindow` / `NSView` host and child-view embedding for CEF browsers.
|
||
|
||
CEF **helper app** subprocess targets may still need to be added if the selected CEF distribution does not provide a compatible default subprocess layout. Use CEF’s `cefsimple` sample as the reference for the complete Mac bundle layout.
|
||
|
||
### Linux
|
||
|
||
```bash
|
||
cmake -B build
|
||
cmake --build build
|
||
```
|
||
|
||
Output: `build/NebulaBrowser` (or `build/<Config>/NebulaBrowser` depending on generator). CEF `.so` files and resources are copied next to the executable.
|
||
|
||
You may need to set **SUID** on `chrome-sandbox` as printed by CMake post-build (CEF documents this in its Linux README).
|
||
|
||
Until a Linux host window exists, the binary will not show a UI for the same reason as macOS.
|
||
|
||
## How CMake picks a platform
|
||
|
||
`find_package(CEF)` loads CEF’s `cef_variables.cmake`, which sets:
|
||
|
||
- `OS_WINDOWS`
|
||
- `OS_MACOSX`
|
||
- `OS_LINUX`
|
||
|
||
`CMakeLists.txt` then:
|
||
|
||
1. Adds the matching `src/platform/{win,mac,linux}/*.cpp` sources
|
||
2. Sets the executable type (`WIN32`, `MACOSX_BUNDLE`, or plain executable)
|
||
3. Links `libcef_dll_wrapper`, `libcef_lib`, and `${CEF_STANDARD_LIBS}`
|
||
4. Runs CEF’s copy macros so runtime files land beside the app
|
||
|
||
Shared sources are always compiled; only the `src/platform/...` tree changes per OS.
|
||
|
||
## Application flow
|
||
|
||
```
|
||
main (app/main.cpp)
|
||
└─ RunNebula(AppStartup) src/app/run.cpp
|
||
├─ platform::PrepareApp()
|
||
├─ CefExecuteProcess() (subprocesses)
|
||
├─ platform::TryAcquireSingleInstance()
|
||
├─ CefInitialize()
|
||
├─ NebulaController::Create()
|
||
│ └─ NebulaWindow::Create() platform-specific
|
||
└─ CefRunMessageLoop()
|
||
```
|
||
|
||
`AppStartup` carries platform entry data:
|
||
|
||
- **Windows:** `HINSTANCE` + show command (`wWinMain`)
|
||
- **macOS / Linux:** `argc` / `argv` (`main`)
|
||
|
||
## User data and profile paths
|
||
|
||
Shared logic in `src/ui/paths.cpp` writes under:
|
||
|
||
| OS | Default root |
|
||
|----|----------------|
|
||
| Windows | `%LOCALAPPDATA%\Nebula\User Data` (falls back to exe directory) |
|
||
| macOS | `~/Library/Application Support/Nebula/User Data` |
|
||
| Linux | `$XDG_DATA_HOME/Nebula/User Data` or `~/.local/share/Nebula/User Data` |
|
||
|
||
Platform-specific discovery lives in `src/platform/*/paths_*.cpp`.
|
||
|
||
## GPU / Chromium flags
|
||
|
||
`src/cef/nebula_app.cpp` applies shared switches (`no-sandbox`, `ignore-gpu-blocklist`, etc.) and platform graphics backends:
|
||
|
||
| OS | Backend |
|
||
|----|---------|
|
||
| Windows | ANGLE + D3D11 |
|
||
| macOS | ANGLE + Metal |
|
||
| Linux | EGL |
|
||
|
||
## Adding or changing platform code
|
||
|
||
1. **Shared behavior** (tabs, `nebula://` URLs, CEF clients) → edit under `src/browser/`, `src/ui/`, `src/cef/`, `src/app/` only if it is truly cross-platform.
|
||
2. **Native window or OS API** → edit `src/platform/<os>/` and keep `src/window/nebula_window.h` free of `#include <windows.h>` (or Cocoa/X11 headers).
|
||
3. **CEF child window embedding** → `src/platform/<os>/browser_host_*.cpp` (`MakeChildWindowInfo`, resize, visibility).
|
||
4. **Startup / paths** → `startup_*.cpp` and `paths_*.cpp` in the same folder.
|
||
5. **New OS** → add `src/platform/<os>/`, extend the `if(OS_...)` blocks in `CMakeLists.txt`, and document CEF distribution layout here.
|
||
|
||
## Porting checklist (macOS / Linux)
|
||
|
||
- [x] macOS: implement `NebulaWindow` in `nebula_window_mac.mm`
|
||
- [x] macOS: wire `browser_host_mac.mm` resize/show/raise to Cocoa views
|
||
- [ ] Linux: implement `NebulaWindow` in `nebula_window_linux.cpp`
|
||
- [ ] Linux: wire `browser_host_linux.cpp` resize/show/raise to the real toolkit
|
||
- [ ] macOS: add CEF helper app targets and bundle layout (copy from `cefsimple`)
|
||
- [ ] Linux: confirm X11 (or chosen toolkit) parent handle for `CefWindowInfo::SetAsChild`
|
||
- [ ] Test GPU diagnostics page and hardware acceleration on target hardware
|
||
- [ ] Package or script runtime layout (`ui/`, CEF frameworks/libs, ICU locales, etc.)
|
||
|
||
## FAQ
|
||
|
||
**Do I need a separate git branch per OS?**
|
||
No. Use one branch; swap `thirdparty/cef` and rebuild on each machine.
|
||
|
||
**Can I commit CEF into the repo?**
|
||
Not recommended (size, licensing, per-arch binaries). Keeping `thirdparty/cef/` gitignored is intentional.
|
||
|
||
**Why does Linux build but not run?**
|
||
The Linux window stub intentionally returns `false` from `Create()` until a native shell exists. Shared CEF and browser code are ready; the missing piece is the host window.
|
||
|
||
**Where is the Windows UI code?**
|
||
`src/platform/win/nebula_window_win.cpp` — custom chrome, hit-testing, fullscreen, and child browser placement.
|