Meta: Add option to select GUI Framework to ladybird.py

This commit is contained in:
Andrew Kaster 2026-04-17 18:52:15 -06:00 committed by Tim Flynn
parent c16d5ebe0e
commit f7c932f50e
4 changed files with 61 additions and 12 deletions

View file

@ -255,12 +255,14 @@ Ladybird will be built with one of the following browser frontends, depending on
* [GTK 4](https://docs.gtk.org/gtk4/) - An alternative UI on Linux (experimental).
* [Android UI](https://developer.android.com/develop/ui) - The native UI on Android.
The Qt and GTK UIs are available on Linux. You can pick the UI using the `LADYBIRD_GUI_FRAMEWORK` option:
You can pick the UI using the `LADYBIRD_GUI_FRAMEWORK` option, or the `--gui` argument to ladybird.py.
For example, to force building with the Qt UI:
```bash
# From /path/to/ladybird
cmake --preset Release -DLADYBIRD_GUI_FRAMEWORK=Qt
cmake --preset Release -DLADYBIRD_GUI_FRAMEWORK=Gtk
# Or
./Meta/ladybird.py run --gui=Qt
```
#### Additional prerequisites for the GTK UI

View file

@ -1,3 +1,4 @@
# Keep the lists here in sync with Meta/host_platform.py
if (ANDROID OR VCPKG_TARGET_ANDROID)
set(_possible_guis "Android")
set(_default_gui "Android")

View file

@ -22,6 +22,14 @@ class HostSystem(enum.IntEnum):
BSD = enum.auto()
class GUIFramework(enum.StrEnum):
# enum.auto() will tolower the values
Qt = "Qt"
AppKit = "AppKit"
Gtk = "Gtk"
Android = "Android"
class Platform:
def __init__(self):
self.system = platform.system()
@ -76,3 +84,19 @@ class Platform:
libc, _ = platform.libc_ver()
return libc
def valid_gui_frameworks(self) -> list[GUIFramework]:
"""
List of valid GUI frameworks based on target platform.
Keep in sync with Meta/CMake/gui_framework.cmake
"""
if self.host_system == HostSystem.macOS:
return [GUIFramework.Qt, GUIFramework.AppKit]
if self.host_system in (HostSystem.Linux, HostSystem.BSD):
return [GUIFramework.Qt, GUIFramework.Gtk]
return [GUIFramework.Qt]
def default_gui_framework(self) -> GUIFramework:
if self.host_system == HostSystem.macOS:
return GUIFramework.AppKit
return GUIFramework.Qt

View file

@ -19,6 +19,7 @@ sys.path.append(str(Path(__file__).resolve().parent.parent))
from Meta.build_vcpkg import build_vcpkg
from Meta.find_compiler import pick_host_compiler
from Meta.host_platform import GUIFramework
from Meta.host_platform import HostArchitecture
from Meta.host_platform import HostSystem
from Meta.host_platform import Platform
@ -43,6 +44,7 @@ def main():
compiler_parser.add_argument("--cc", required=False, default=default_cc)
compiler_parser.add_argument("--cxx", required=False, default=default_cxx)
compiler_parser.add_argument("--jobs", "-j", required=False)
compiler_parser.add_argument("--gui", required=False, choices=platform.valid_gui_frameworks())
target_parser = argparse.ArgumentParser(add_help=False)
target_parser.add_argument("target", nargs=argparse.OPTIONAL)
@ -139,10 +141,10 @@ def main():
args.target = "ladybird" if platform.host_system == HostSystem.Windows else "Ladybird"
if args.command == "build":
build_dir = configure_main(platform, args.preset, args.cc, args.cxx)
build_dir = configure_main(platform, args.preset, args.cc, args.cxx, args.gui)
build_main(build_dir, args.jobs, args.target, args.args)
elif args.command == "test":
build_dir = configure_main(platform, args.preset, args.cc, args.cxx)
build_dir = configure_main(platform, args.preset, args.cc, args.cxx, args.gui)
build_main(build_dir, args.jobs)
test_main(build_dir, args.preset, args.pattern)
elif args.command == "run":
@ -156,19 +158,19 @@ def main():
os.environ["UBSAN_OPTIONS"] = os.environ.get(
"UBSAN_OPTIONS", "print_stacktrace=1:print_summary=1:halt_on_error=1"
)
build_dir = configure_main(platform, args.preset, args.cc, args.cxx)
build_dir = configure_main(platform, args.preset, args.cc, args.cxx, args.gui)
build_main(build_dir, args.jobs, args.target)
run_main(platform.host_system, build_dir, args.target, args.args)
elif args.command == "debug":
build_dir = configure_main(platform, args.preset, args.cc, args.cxx)
build_dir = configure_main(platform, args.preset, args.cc, args.cxx, args.gui)
build_main(build_dir, args.jobs, args.target, args.args)
debug_main(platform.host_system, build_dir, args.target, args.debugger, args.cmd)
elif args.command == "profile":
build_dir = configure_main(platform, args.preset, args.cc, args.cxx)
build_dir = configure_main(platform, args.preset, args.cc, args.cxx, args.gui)
build_main(build_dir, args.jobs, args.target)
profile_main(platform.host_system, build_dir, args.target, args.args)
elif args.command == "install":
build_dir = configure_main(platform, args.preset, args.cc, args.cxx)
build_dir = configure_main(platform, args.preset, args.cc, args.cxx, args.gui)
build_main(build_dir, args.jobs, args.target, args.args)
build_main(build_dir, args.jobs, "install", args.args)
elif args.command == "vcpkg":
@ -178,20 +180,24 @@ def main():
clean_main(platform, args.preset)
elif args.command == "rebuild":
clean_main(platform, args.preset)
build_dir = configure_main(platform, args.preset, args.cc, args.cxx)
build_dir = configure_main(platform, args.preset, args.cc, args.cxx, args.gui)
build_main(build_dir, args.jobs, args.target, args.args)
elif args.command == "addr2line":
build_dir = configure_main(platform, args.preset, args.cc, args.cxx)
build_dir = configure_main(platform, args.preset, args.cc, args.cxx, args.gui)
build_main(build_dir, args.jobs, args.target)
addr2line_main(build_dir, args.target, args.program, args.addresses)
def configure_main(platform: Platform, preset: str, cc: str, cxx: str) -> Path:
def configure_main(platform: Platform, preset: str, cc: str, cxx: str, gui: Optional[GUIFramework]) -> Path:
ladybird_source_dir, build_preset_dir = configure_build_env(platform, preset)
build_vcpkg()
if build_preset_dir.joinpath("build.ninja").exists() or build_preset_dir.joinpath("ladybird.sln").exists():
return build_preset_dir
if not gui or gui == gui_for_build_dir(build_preset_dir):
return build_preset_dir
if not gui:
gui = platform.default_gui_framework()
validate_cmake_version()
@ -207,6 +213,7 @@ def configure_main(platform: Platform, preset: str, cc: str, cxx: str) -> Path:
build_preset_dir,
f"-DCMAKE_C_COMPILER={cc}",
f"-DCMAKE_CXX_COMPILER={cxx}",
f"-DLADYBIRD_GUI_FRAMEWORK={gui}",
]
if platform.host_system == HostSystem.Linux and platform.host_architecture == HostArchitecture.AArch64:
@ -219,6 +226,21 @@ def configure_main(platform: Platform, preset: str, cc: str, cxx: str) -> Path:
return build_preset_dir
def gui_for_build_dir(build_preset_dir: Path) -> Optional[GUIFramework]:
cmake_cachefile = build_preset_dir.joinpath("CMakeCache.txt")
if not cmake_cachefile.exists():
return None
with cmake_cachefile.open("r") as f:
for line in f:
if line.startswith("LADYBIRD_GUI_FRAMEWORK:STRING="):
try:
return GUIFramework(line.strip().split("=", 1)[1])
except ValueError:
return None
return None
def configure_skia_jemalloc() -> list[str]:
# NOTE: The resource module is only available on Unix, see the "Availability" section at
# https://docs.python.org/3/library/resource.html. Given Windows never calls this function, we import locally