Servo-kirja
API-dokumentaatio · Englanninkielinen alkuperä
Servo on Rust-ohjelmointikielellä kirjoitettu selainmoottori, jota kehitetään tällä hetkellä seuraaville alustoille:
- 64-bittinen Linux
- 64-bittinen macOS
- 64-bittinen Windows
- Android
- OpenHarmony
Työtä webview-kirjastona käytettäväksi Servo jatkuvat. Tällä hetkellä suositeltu tapa ajaa Servoa selaimena on servoshell, winit- ja egui-pohjainen demoseilain. Jos haluat upottaa Servon omaan sovellukseesi, harkitse tauri-runtime-verso -ajoaikaa, mukautettua Tauri-ajoaikaa, tai servo-gtk -GTK4-pohjaista selainwidgetiä.

Tämä kirja opastaa servoshellin kääntämisessä ja ajamisessa, Servon kehittämisessä ja osallistumisessa, Servon arkkitehtuurissa sekä Servon ja sen kirjastojen käytössä.
Kirja on työn alla! Sisällysluettelossa * merkitsee lukuja, jotka on äskettäin lisätty tai tuotu vanhemmasta dokumentaatiosta ja jotka tarvitsevat vielä oikoluvun tai uudelleentyöstön.
Osallistuminen on aina tervetullutta. Ehdota muutoksia kunkin sivun oikean yläkulman kynäpainikkeella tai katso lisätietoja reposta Mikko-Huuskonen-Pro/Servo-kirja.
Tarvitsetko apua?
Liity Servo Zulipiin, jos sinulla on kysyttävää. Kaikki ovat tervetulleita!
Servoshellin hankkiminen
Servo-projekti tarjoaa pienen testiselaimen nimeltä servoshell, jonka avulla Servoa voi testata. servoshell ei ole täysiverinen selain, vaan tarkoitettu näkemään, miten Servo toimii järjestelmässäsi, ja testien ajamiseen. Voit ladata servoshellin uusimman valmiin version verkkosivumme latausosiosta. Voit ladata servoshellin myös alla olevista linkeistä:
- Windows-asennusohjelma (sha256)
- Windows ZIP (sha256)
- macOS (x86) (sha256)
- macOS (AArch64) (sha256)
- Linux (x86) (sha256)
- Android (AArch64) (sha256)
- OpenHarmony (AAarch64) (sha256)
Vanhemmat yökohtaiset julkaisut ovat saatavilla repossa servo/servo-nightly-builds.
Servoshellin käyttö
Oletetaan, että olet hakemistossa, jossa servo sijaitsee. Voit ajaa servoshellin komennolla:
$ ./servo [url] [options]
Käytä --help nähdäksesi käytettävissä olevat komentorivivalinnat:
$ ./servo --help
Kokeellisten web-alustan ominaisuuksien käyttöönotto
Servolla on käynnissä tuki monille web-alustan ominaisuuksille.
Jotkut eivät ole vielä valmiita oletuksena käyttöön, mutta voit kokeilla niitä pref-asetuksella.
Luettelo näistä ominaisuuksista ja niitä käyttöönotosta löytyy kohdasta Kokeelliset ominaisuudet.
Lisäksi voit ottaa käyttöön hyödyllisen osajoukon näistä ominaisuuksista --enable-experimental-web-platform-features -komentoriviparametrilla tai servoshellin käyttöliittymän kautta.
Pikanäppäimet
- Ctrl+
Q(⌘Q macOS:llä) sulkee servoshellin - Ctrl+
L(⌘L macOS:llä) kohdistaa osoitepalkkiin - Ctrl+
R(⌘R macOS:llä) lataa sivun uudelleen - Alt+
←(⌘← macOS:llä) siirtyy historiassa taaksepäin - Alt+
→(⌘→ macOS:llä) siirtyy historiassa eteenpäin - Ctrl+
=(⌘= macOS:llä) suurentaa sivun zoomia - Ctrl+
-(⌘- macOS:llä) pienentää sivun zoomia - Ctrl+
0(⌘0 macOS:llä) palauttaa sivun zoomin - Esc poistuu koko näytön tilasta
Vianmääritys
servoshellin pitäisi toimia useimmilla järjestelmillä ilman erillisiä riippuvuuksia. Jos olet Linuxilla ja servoshell ilmoittaa puuttuvasta jaetusta kirjastosta, varmista että seuraavat paketit on asennettu:
GStreamer≥ 1.18gst-plugins-base≥ 1.18gst-plugins-good≥ 1.18gst-plugins-bad≥ 1.18gst-plugins-ugly≥ 1.18libXcursorlibXrandrlibXilibxkbcommonvulkan-loader
Lähdekoodin hankkiminen
Jos haluat tehdä muutoksia Servoon tai kääntää servoshellin itse, kloonaa päärepo Gitillä:
$ git clone https://github.com/servo/servo.git
$ cd servo
Servon repo on melko suuri! Jos verkkoyhteys on epävakaa tai levytila rajallinen, harkitse matalaa kloonausta.
Kun olet kloonannut Servon lähdekoodin, seuraava vaihe on riippuvuuksien asentaminen ja Servon kääntäminen.
Servon kääntäminen
Tällä sivulla on tarkempaa tietoa Servon kääntämisestä. Voit hypätä suoraan ohjeisiin omalle järjestelmällesi:
mach
Servon kääntämiseen tarvitset mach-työkalun.
mach on Python-ohjelma, joka helpottaa Servon parissa työskentelyä monin tavoin: kääntäminen ja ajaminen, testien ajo ja riippuvuuksien päivitys.
Windows-käyttäjät: sinun täytyy korvata ./mach komennoissa merkkijonolla .\mach, jos käytät cmd:tä.
Käytä --help listataksesi alikomennot tai saadaksesi apua tiettyyn alikomentoon:
$ ./mach --help
$ ./mach build --help
Kun käytät machia ajamaan toista ohjelmaa, kuten servoshelliä, sillä ohjelmalla voi olla omia valintoja samoilla nimillä kuin machilla.
Voit käyttää -- (välilyönneillä ympäröitynä) kertoaksesi machille, ettei se koske myöhempiin valintoihin vaan jättää ne toiselle ohjelmalle.
$ ./mach run --help # Gets help for `mach run`.
$ ./mach run -d --help # Still gets help for `mach run`.
$ ./mach run -d -- --help # Gets help for the debug build of servoshell.
Tämä pätee myös Servon yksikkötesteihin, joissa on kolme valintakerrosta: mach-valinnat, cargo test -valinnat ja libtest-valinnat.
$ ./mach test-unit --help # Gets help for `mach test-unit`.
$ ./mach test-unit -- --help # Gets help for `cargo test`.
$ ./mach test-unit -- -- --help # Gets help for the test harness (libtest).
Työtä jatketaan, jotta Servo voidaan kääntää ilman machia. Harkitse aina, voitko käyttää natiivia Cargo-toiminnallisuutta ennen kuin lisäät uutta toiminnallisuutta machiin.
Käännösprofiilit
On kolme pääkäännösprofiilia, joita voit kääntää ja käyttää toisistaan riippumatta:
- debug-käännökset, joiden avulla voit käyttää debuggeria (lldb) (oletus, jos profiilia ei anneta)
- release-käännökset, jotka kääntyvät hitaammin mutta ovat suorituskykyisempiä
- production-käännökset, joita käytetään vain virallisissa julkaisuissa
| debug | release | production | |
|---|---|---|---|
| mach-valinta | -d |
-r |
--prod |
| optimoitu? | ei | kyllä | kyllä, enemmän kuin release |
| suurin RUST_LOG-taso | trace |
info |
info |
| debug-väitteet? | kyllä | kyllä(!) | ei |
| debug-tiedot? | kyllä | ei | ei |
| symbolit? | kyllä | ei | kyllä |
| etsii resursseja nykyisestä työhakemistosta? |
kyllä | kyllä | ei(!) |
Lisäksi on kaksi erityistä production-käännöksen varianttia suorituskykyyn liittyviin käyttötarkoituksiin:
production-stripped-käännökset sopivat Servon benchmarkkaukseen ajan myötä, kun debug-symbolit on poistettu nopeampaa käynnistystä vartenprofiling-käännökset sopivat profilointiin ja suorituskykyongelmien vianmääritykseen; ne käyttäytyvät kuin debug- tai release-käännös, mutta niiden suorituskyky on sama kuin production-käännöksellä
| production | production-stripped | profiling | |
|---|---|---|---|
mach --profile |
production |
production-stripped |
profiling |
| debug-tiedot? | ei | ei | kyllä |
| symbolit? | kyllä | ei | kyllä |
| etsii resursseja nykyisestä työhakemistosta? |
ei | ei | kyllä(!) |
Voit muuttaa näitä asetuksia servobuild-tiedostossa (katso servobuild.example) tai juuren Cargo.toml -tiedostossa.
Valinnaiset käännösasetukset
Joitakin käännösasetuksia voi ottaa käyttöön vain manuaalisesti:
- AddressSanitizer-käännökset otetaan käyttöön komennolla
./mach build --with-asan - ThreadSanitizer-käännökset otetaan käyttöön komennolla
./mach build --with-tsan - crown-linttaus on suositeltava DOM-koodia muokattaessa, ja se otetaan käyttöön komennolla
./mach build --use-crown - SpiderMonkey debug -käännökset otetaan käyttöön komennolla
./mach build --debug-mozjstai[build] debug-mozjs = trueservobuild-tiedostossasi
Täydellisen argumenttilistan näet ajamalla ./mach build --help.
Servoshellin ajaminen
Kun käännät itse, servoshell on polussa target/debug/servo tai target/release/servo.
Voit ajaa sen suoraan kuten yllä, mutta suosittelemme käyttämään machia sen sijaan.
Ajaaksesi servoshellin machilla, korvaa ./servo komennoilla ./mach run -d -- tai ./mach run -r -- riippuen käännösprofiilista, jonka haluat ajaa.
Esimerkiksi molemmat alla olevat komennot ajavat debug-käännöksen servoshelliä samoilla valinnoilla:
$ target/debug/servo https://demo.servo.org
$ ./mach run -d -- https://demo.servo.org
Kääntäminen Linuxille
- Asenna
curl:- Arch:
sudo pacman -S --needed curl - Debian, Ubuntu:
sudo apt install curl - Fedora:
sudo dnf install curl - Gentoo:
sudo emerge net-misc/curl
- Arch:
- Asenna
uv:curl -LsSf https://astral.sh/uv/install.sh | sh - Asenna
rustup:curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh - Käynnistä shell uudelleen varmistaaksesi, että
cargoon käytettävissä - Asenna muut riippuvuudet:
./mach bootstrap - Käännä servoshell:
./mach build
Tukemattomat jakelut
Jos ./mach boostrap ilmoittaa, että jakelusi ei ole tuettu, sinun täytyy asentaa riippuvuudet manuaalisesti.
Alla on ohjeita käännösriippuvuuksien asentamiseen erilaisille jakelutyypeille.
Jos jakelusi ei ole listalla, suositellaan sovittamaan lista järjestelmäsi pakettinimille.
Päivitykset tähän listaan ovat erittäin tervetulleita!
Arch ja Manjaro
-
sudo pacman -S --needed curl -
sudo pacman -S --needed base-devel git mesa cmake libxmu pkg-config ttf-fira-sans harfbuzz ccache llvm clang autoconf2.13 gstreamer gstreamer-vaapi gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly vulkan-icd-loader wireshark-cli
Debian-tyyppiset
(mukaan lukien elementary OS, KDE neon, Linux Mint, Pop!_OS, Raspbian, TUXEDO OS, Ubuntu)
sudo apt install curl
sudo apt install build-essential ca-certificates ccache clang cmake curl g++ git gperf gstreamer1.0-libav gstreamer1.0-plugins-bad gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-ugly gstreamer1.0-tools libdbus-1-dev libegl1-mesa-dev libfreetype6-dev libges-1.0-dev libgl1-mesa-dri libgles2-mesa-dev libglib2.0-dev libgstreamer-plugins-bad1.0-dev libgstreamer-plugins-base1.0-dev libgstrtspserver-1.0-dev libharfbuzz-dev liblzma-dev libudev-dev libunwind-dev libvulkan1 libx11-dev libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev libxkbcommon-x11-0 libxkbcommon0 libxmu-dev libxmu6 llvm-dev m4 xorg-dev
Huom: Ubuntu-pohjaisissa jakelussa varmista, että sisällytät myös paketin libgstreamer-plugins-good1.0-dev yllä lueteltujen pakettien lisäksi.
Fedora-tyyppiset
sudo dnf install cabextract ccache clang clang-libs cmake dbus-devel expat-devel fontconfig-devel freetype-devel gcc-c++ glib2-devel gperf gstreamer1-devel gstreamer1-plugins-bad-free-devel gstreamer1-plugins-base-devel gstreamer1-plugins-good gstreamer1-plugins-ugly-free harfbuzz-devel libjpeg-turbo libjpeg-turbo-devel libtool libunwind-devel libX11-devel libXcursor-devel libXi-devel libxkbcommon libxkbcommon-x11 libXmu-devel libXrandr-devel llvm mesa-libEGL-devel mesa-libGL-devel ncurses-devel python3-devel rpm-build ttmkfdir vulkan-loader zlib-ng
Gentoo-tyyppiset
sudo emerge net-misc/curl media-libs/freetype media-libs/mesa dev-util/gperf dev-libs/openssl media-libs/harfbuzz dev-util/ccache sys-libs/libunwind x11-libs/libXmu x11-base/xorg-server sys-devel/clang media-libs/gstreamer media-libs/gst-plugins-base media-libs/gst-plugins-good media-libs/gst-plugins-bad media-libs/gst-plugins-ugly media-libs/vulkan-loader
openSUSE
sudo zypper install libX11-devel libexpat-devel Mesa-libEGL-devel Mesa-libGL-devel cabextract cmake dbus-1-devel fontconfig-devel freetype-devel gcc-c++ git glib2-devel gperf harfbuzz-devel libXcursor-devel libXi-devel libXmu-devel libXrandr-devel libopenssl-devel rpm-build ccache llvm-clang libclang autoconf213 gstreamer-devel gstreamer-plugins-base-devel gstreamer-plugins-good gstreamer-plugins-bad-devel gstreamer-plugins-ugly vulkan-loader libvulkan1
Void Linux
sudo xbps-install bzip2-devel cabextract ccache clang cmake cmake dbus-devel expat-devel fontconfig-devel freetype-devel gcc glib-devel glu-devel gperf gst-plugins-bad1-devel gst-plugins-base1-devel gst-plugins-good1 gst-plugins-ugly1 gstreamer1-devel harfbuzz-devel libtool libunwind-devel libX11-devel libXcursor-devel libXi-devel libxkbcommon libxkbcommon-x11 libXmu-devel libXrandr-devel MesaLib-devel ncurses-devel pkg-config vulkan-loader
Vianmääritys
Katso Yleinen vianmääritys -osio, jos käännöksessä on ongelmia eikä ongelmaasi ole listattu alla.
build: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.39' not found
Tämä kiertotie soveltuu, kun käännät Servoa nix:llä muilla Linux-jakelulla kuin NixOS:lla.
Virhe tarkoittaa, että jakelun glibc-versio on vanhempi kuin nixpkgs-paketissa.
Muuta shell.nix-tiedoston loppuun rivi if ! [ -e /etc/NIXOS ]; then muotoon if false; then poistaaksesi shell.nix-tuen binääritulosteille, jotka eivät riipu nix-kaupasta.
Kääntäminen macOS:lle
- Lataa ja asenna Xcode ja
brew. - Asenna
uv:curl -LsSf https://astral.sh/uv/install.sh | sh - Asenna
rustup:curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh - Käynnistä shell uudelleen varmistaaksesi, että
cargoon käytettävissä - Asenna muut riippuvuudet:
./mach bootstrap - Käännä servoshell:
./mach build
Vianmääritys
Katso Yleinen vianmääritys -osio, jos käännöksessä on ongelmia.
Kääntäminen Windowsille
- Lataa
uv,chocojarustup- Valitse Quick install via the Visual Studio Community installer
- Varmista Visual Studio Installerissa, että seuraavat komponentit on asennettu:
- Windows 10/11 SDK (anything >= 10.0.19041.0) (
Microsoft.VisualStudio.Component.Windows{10, 11}SDK.{>=19041}) - MSVC v143 - VS 2022 C++ x64/x86 build tools (Latest) (
Microsoft.VisualStudio.Component.VC.Tools.x86.x64) - C++ ATL for latest v143 build tools (x86 & x64) (
Microsoft.VisualStudio.Component.VC.ATL)
- Windows 10/11 SDK (anything >= 10.0.19041.0) (
- Käynnistä shell uudelleen varmistaaksesi, että
cargoon käytettävissä - Asenna muut riippuvuudet:
.\mach bootstrap - Käännä servoshell:
.\mach build
Emme suosittele useamman kuin yhden Visual Studio -version asentamista. Servo yrittää etsiä oikean Visual Studio -version, mutta vain yhden version asentaminen vähentää virheiden riskiä.
Vianmääritys
Katso Yleinen vianmääritys -osio, jos käännöksessä on ongelmia eikä ongelmaasi ole listattu alla.
Cannot run mach in a path on a case-sensitive file system on Windows.
- Avaa komentokehote tai PowerShell ylläpitäjänä (Win+X, A)
- Poista kirjainkoon herkkyys Servo-repollesi:
fsutil file SetCaseSensitiveInfo X:\path\to\servo disable
Could not find DLL dependency: api-ms-win-crt-runtime-l1-1-0.dllDLL file `api-ms-win-crt-runtime-l1-1-0.dll` not found!
Etsi polku tiedostoon Redist\ucrt\DLLs\x64\api-ms-win-crt-runtime-l1-1-0.dll, esim. C:\Program Files (x86)\Windows Kits\10\Redist\ucrt\DLLs\x64\api-ms-win-crt-runtime-l1-1-0.dll.
Aseta sitten WindowsSdkDir-ympäristömuuttuja polkuun, joka sisältää Redist, esim. C:\Program Files (x86)\Windows Kits\10.
thread 'main' panicked at 'Unable to find libclang: "couldn\'t find any valid shared libraries matching: [\'clang.dll\', \'libclang.dll\'], set the `LIBCLANG_PATH` environment variable to a path where one of these files can be found (invalid: [(C:\\Program Files\\LLVM\\bin\\libclang.dll: invalid DLL (64-bit))])"', C:\Users\me\.cargo\registry\src\...
rustup on ehkä asennettu 32-bittisellä oletusisännällä 64-bittisen oletusisännän sijaan, jota Servo tarvitsee.
Tarkista oletusisäntä komennolla rustup show, aseta sitten oletusisäntä:
> rustup set default-host x86_64-pc-windows-msvc
ERROR: GetShortPathName returned a long path name: `C:/PROGRA~2/Windows Kits/10/`. Use `fsutil file setshortname' to create a short name for any components of this path that have spaces.
SpiderMonkey (mozjs) vaatii 8.3-tiedostonimet käyttöön Windowsilla (#26010).
- Avaa komentokehote tai PowerShell ylläpitäjänä (Win+X, A)
- Ota 8.3-tiedostonimien luonti käyttöön:
fsutil behavior set disable8dot3 0 - Poista ja asenna uudelleen mikä tahansa, joka sisältää epäonnistuvat polut, kuten Visual Studio tai Windows SDK — tämä on helpompaa kuin 8.3-tiedostonimien lisääminen käsin
= note: lld-link: error: undefined symbol: __std_search_1 >>> referenced by D:\a\mozjs\mozjs\mozjs-sys\mozjs\intl\components\src\NumberFormatterSkeleton.cpp:157
Tällaiset ongelmat voivat ilmetä mozjs:n päivityksen yhteydessä, koska päivitys voi riippua uudemmasta MSVC:stä (muista, että vaadimme “Latest” kohdassa set up your environment!). Ratkaise ongelma käynnistämällä Visual Studio Installer ja asentamalla kaikki saatavilla olevat päivitykset.
Kääntäminen NixOS:lle
- Asenna Nix, paketinhallinta. Helpoin tapa on käyttää asennusohjelmaa monikäyttäjä- tai yksikäyttäjäasennuksella (valintasi mukaan).
- Kerro
mach:lle Nixin käytöstä:export MACH_USE_NIX= - Kirjoita
nix-shellpäästäksesi shelliin, jossa on kaikki tarvittavat työkalut ja riippuvuudet. - Asenna muut riippuvuudet:
./mach bootstrap - Käännä servoshell:
./mach build
Vianmääritys
Katso Yleinen vianmääritys -osio, jos käännöksessä on ongelmia eikä ongelmaasi ole listattu alla.
error: getting status of /nix/var/nix/daemon-socket/socket: Permission denied
Jos saat tämän virheen ja olet asentanut Nixin järjestelmän paketinhallinnalla:
- Lisää itsesi
nix-users-ryhmään - Kirjaudu ulos ja takaisin sisään
error: file 'nixpkgs' was not found in the Nix search path (add it using $NIX_PATH or -I)
Tämä virhe on vaaraton, mutta voit korjata sen näin:
- Aja
sudo nix-channel --add https://nixos.org/channels/nixpkgs-unstable nixpkgs - Aja
sudo nix-channel --update
Kääntäminen WSL:llä
Servo voidaan kääntää WSL:llä kuten millä tahansa muulla Linux-jakelulla. Ajaaksesi ei-headless servoshelliä WSL:llä, tarvitset todennäköisesti Windows 10 Build 19044+ tai Windows 11, koska WSL v2 -pääsy tarvitaan graafiseen käyttöliittymään.
- Ota WSL v2 käyttöön. Katso Microsoftin ohjeet GUI-sovellusten käyttöön WSL:llä.
- Seuraa ohjeita Servon kääntämiseen ja ajamiseen käyttämälläsi WSL-jakelulla (esim. Ubuntu, OpenSuse jne.)
WSL v2:ssä on vastaavat sovittimet Wayland- ja X11-sovellusten näyttämiseen, vaikka se ei aina toimi suoraan Servon kanssa.
Vianmääritys
Katso Yleinen vianmääritys -osio, jos käännöksessä on ongelmia eikä ongelmaasi ole listattu alla.
Failed to create event loop
Jos kohtaat välittömän kaatumisen ajon jälkeen, joka viittaa winitiin ja sen alustatoteutukseen, WAYLAND_DISPLAY='' pysäyttää kaatumisen.
Failed to create events loop: Os(OsError { line: 81, file: "/home/astra/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/winit-0.30.9/src/platform_impl/linux/wayland/event_loop/mod.rs", error: WaylandError(Connection(NoCompositor)) }) (thread main, at ports/servoshell/desktop/cli.rs:34)
0: servoshell::backtrace::print
at /home/astra/workspace/servo/ports/servoshell/backtrace.rs:18:5
...
18: main
19: <unknown>
20: __libc_start_main
21: _start
Servo was terminated by signal 11
Joko vie muuttuja ympäristöön tai aseta se ennen ajoa:
export WAYLAND_DISPLAY=''
./mach run
# or
WAYLAND_DISPLAY='' ./mach run
# optionally save the variable long term to your .bashrc profile
echo 'export WAYLAND_DISPLAY=""' >> ~/.bashrc
Library libxkbcommon-x11.so could not be loaded
Tämä voi johtua siitä, että jakelusi ei ole asentanut vaadittua kirjastoa. Aja seuraava komento (oletetaan WSL Debian/Ubuntu, säädä muille jakelulle):
sudo apt install libxkbcommon-x11-0
error: failed to run build command...
Jos kohtaat alla olevan kaltaisen virheen ./mach build -ajossa WSL:llä, syy voi olla muistin loppuminen (OOM), koska WSL:llä ei ole tarpeeksi RAMia Servon kääntämiseen.
Sinun täytyy kasvattaa WSL:n muistirajaa ja swap-tiedostoa tai päivittää RAM.
yourusername@PC:~/servo$ ./mach build
No build type specified so assuming `--dev`.
Building `debug` build with crown disabled (no JS garbage collection linting).
...
Compiling script v0.0.1 (/home/yourusername/servo/components/script)
error: failed to run build command...
Caused by:
process didn't exit successfully: `/home/yourusername/.rustup/toolchains/1.91.0-x86_64-unknown-linux-gnu/bin/rustc --crate-name script --edition=2024 components/script/lib.rs...
...
warning: build failed, waiting for other jobs to finish...
Luo C:/user/yourusername/.wslconfig ja lisää seuraava:
[wsl2]
memory=6GB
swap=16GB
swapfile=C:\\Users\\yourusername\\swapfile.vhdx
Tallenna tiedosto ja käynnistä WSL uudelleen PowerShellissä:
wsl --shutdown
Kääntäminen Androidille
- Varmista, että seuraavat ympäristömuuttujat on asetettu:
ANDROID_SDK_ROOTANDROID_NDK_ROOT:$ANDROID_SDK_ROOT/ndk/28.2.13676358/ANDROID_SDK_ROOTvoi olla mikä tahansa hakemisto (kuten~/android-sdk). Kaikki Android-käännösriippuvuudet asennetaan sinne.
- Asenna Android command-line tools -työkalujen uusin versio hakemistoon
$ANDROID_SDK_ROOT/cmdline-tools/latest. - Asenna tarvittavat komponentit seuraavalla komennolla:
sudo $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager --install \ "build-tools;36.0.0" \ "emulator" \ "ndk;28.2.13676358" \ "platform-tools" \ "platforms;android-37" \ "system-images;android-37;google_apis;arm64-v8a" - Aja
./mach build --android
Huom: Tämä asentaa riippuvuudet ja kääntää Servon aarch64-linux-android -alustalle.
Kääntääksesi Servon muille Android-kohteille, asenna sopivat järjestelmäkuvat sdkmanager:lla ja anna mach:lle --target Rust-yhteensopivalla kohteella --android:n sijaan.
Huom: Jos et käytä Android Studioa macOS:lla, sinun täytyy asentaa JDK.
Käytä brew install opendjdk@21 asentaaksesi toimivan version; uudemmat versiot aiheuttavat java.lang.IllegalArgumentException: 25 Servon käännöksen gradle-vaiheessa.
Huom: Jos käytät Nixiä, sinun ei tarvitse asentaa työkaluja tai asettaa ANDROID_SDK_ROOT- ja ANDROID_NDK_ROOT -ympäristömuuttujia manuaalisesti.
Ota Android-käännöstuki käyttöön ajamalla:
export SERVO_ANDROID_BUILD=1
shell-istunnossa ennen ./mach-komentoja
Kääntäminen Android Studiolla
Servon kääntäminen komentoriviltä on suositeltavaa Androidille, mutta voit kääntää sen myös Android Studiolla, jos haluat käyttää Android-IDE:tä.
- Asenna Android Studio lataamalla sopiva versio viralliselta sivustolta ja seuraamalla asennusohjeita.
- Asentaaksesi lisätyökaluja, käynnistä Android Studio, mene Settings-valikkoon ja kirjoita hakupalkkiin
sdk. - Valitse SDK:
- Klikkaa Android SDK`
- Siirry kohtaan SDK Tools
- Valitse Android SDK Command-line tools (latest):

- Valitse NDK. Huomaa, että Servo vaatii NDK:n version 28.
- Osiossa SDK Tools valitse NDK (side by side)
- Klikkaa show package details:

- Valitse NDK 28:n uusin versio:

- Klikkaa Ok asentaaksesi sekä NDK:n että SDK:n.
- Etsi SDK:n polku kohdasta Languages & Frameworks sitten Android SDK Location:
.
Varmista sitten, että seuraavat ympäristömuuttujat on asetettu:
ANDROID_SDK_ROOT: Yllä löytynyt polku.ANDROID_NDK_ROOT:$ANDROID_SDK_ROOT/ndk/28.2.13676358/
- Aja
./mach build --android
Ajaminen emulaattorissa
- Luo uusi AVD-kuva Servon ajamiseen:
$ANDROID_SDK_ROOT/cmdline-tools/latest/bin/avdmanager create avd \ --name "Servo" \ --device "pixel" \ --package "system-images;android-33;google_apis;arm64-v8a" \ --tag "google_apis" \ --abi "arm64-v8a" - Ota laitteiston näppäimistö käyttöön.
Avaa
~/.android/avd/Servo.avd/config.inija muutahw.keyboard = nomuotoonhw.keyboard = yes. - Käynnistä emulaattori
$ANDROID_SDK_ROOT/emulator/emulator -avd Servo -netdelay none -no-snapshot - Asenna Servo emulaattoriin:
./mach install --android - Käynnistä Servo napauttamalla Servo-kuvaketta käynnistysohjelmassa.
Asentaminen fyysiselle laitteelle
- Valmistele laitteesi kehitystä varten.
- Käännä Servo kuten yllä, varmistaen että käännät sopivalle kohteelle laitteellesi.
- Asenna Servo laitteellesi ajamalla:
./mach install --android - Käynnistä Servo napauttamalla Servo-kuvaketta käynnistysohjelmassa tai aja:
./mach run --android https://www.servo.org/
Voit pakottaa Servon pysähtymään ajamalla:
adb shell am force-stop org.servo.servoshell/org.servo.servoshell.MainActivity
Jos yllä oleva ei toimi, kokeile tätä:
adb shell am force-stop org.servo.servoshell
Voit poistaa Servon asennuksen ajamalla:
adb uninstall org.servo.servoshell
Vianmääritys
Katso Yleinen vianmääritys -osio, jos käännöksessä on ongelmia.
Kääntäminen OpenHarmonylle
OpenHarmony-työkalujen hankkiminen
OpenHarmonylle kääntäminen vaatii seuraavat:
- OpenHarmony SDK. Tämä riittää Servon kääntämiseen jaetulla kirjastolla OpenHarmonylle.
hvigor-käännöstyökalun sovelluksen kääntämiseen sovelluspaketiksi ja allekirjoittamiseen.
OpenHarmony SDK:n asennus
OpenHarmony SDK vaaditaan sovellusten kääntämiseen OpenHarmonylle. Servon tukeman SDK:n vähimmäisversio on v6.0.0 (API-20).
Lataus DevEco Studion kautta
DevEco Studio on IDE HarmonyOS NEXT- ja OpenHarmony-sovellusten kehittämiseen. Se tukee Windowsia ja macOS:ää. Voit hallita asennettuja OpenHarmony SDK:ita valitsemalla File->Settings ja “OpenHarmony SDK”. Kun olet asettanut sopivan asennuspolun, voit valita asennettavat komponentit kullekin saatavilla olevalle API-versiolle. DevEco Studio lataa ja asentaa komponentit automaattisesti.
OpenHarmony SDK:n manuaalinen asennus (esim. Linuxilla)
- Mene OpenHarmony release notes -sivulle ja valitse versio, jolle haluat kääntää.
- Vieritä osioon “Acquiring Source Code from Mirrors” ja klikkaa latauslinkkiä “Public SDK package for the standard system” -versiolle, joka vastaa isäntäjärjestelmääsi.
- Pura arkisto sopivaan sijaintiin.
- Siirry SDK-kansioon komennolla
cd <sdk_folder>/<your_operating_system>. - Luo alikansio samalla nimellä kuin API-versio (esim. 14 SDK v5.0.2:lle) ja siirry siihen.
- Pura yksittäisten komponenttien zip-tiedostot edellisessä vaiheessa luotuun kansioon. Käytä mieluiten
unzip-komentoa komentorivillä, tai varmista manuaalisesti että puretut paketit ovat nimeltään esim.nativeeivätkänative-linux-x64-5.x.y.z.
Seuraava pätkä toimii viitteenä vaiheille 4–6:
cd ~/ohos-sdk/linux
for COMPONENT in "native toolchains ets js previewer" do
echo "Extracting component ${COMPONENT}"
unzip ${COMPONENT}-*.zip
API_VERSION=$(cat ${COMPONENT}/oh-uni-package.json | jq -r '.apiVersion')
mkdir -p ${API_VERSION}
mv ${COMPONENT} "${API_VERSION}/"
done
Windowsilla on suositeltavaa käyttää 7zip:iä arkistojen purkamiseen, koska Windows Explorerin purkutyökalu on erittäin hidas.
HarmonyOS NEXT -komentorivityökalujen manuaalinen asennus
HarmonyOS NEXT commandline tools sisältää OpenHarmony SDK:n ja seuraavat lisätyökalut:
codelinter(linter)hstack(crash dump stack analysis tool)hvigor/hvigorw(build tool)ohpm(package manager)
Tällä hetkellä komentorivityökalupaketti ei ole julkisesti saatavilla ja vaatii kiinalaisen Huawei-tilin lataamiseen.
hvigorin manuaalinen asennus ilman komentorivityökaluja
hvigor (ei wrapper hvigorw) on saatavilla myös npm:n kautta.
-
Asenna sama nodejs-versio kuin komentorivityökalut toimittavat. HarmonyOS NEXT:lle toimitetaan Node 18. Varmista, että
node-binääri on PATH:ssa. -
Asenna Java suositellulla asennustavalla käyttöjärjestelmällesi. Käännösvaiheet toimivat tunnetusti OpenJDK v17, v21 ja v23:lla. macOS:lla, jos asennat Homebrew’n OpenJDK formula -kaavan, seuraava lisäkomento saattaa olla tarpeen asennuksen jälkeen:
# For the system Java wrappers to find this JDK, symlink it with sudo ln -sfn $HOMEBREW_PREFIX/opt/openjdk/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk.jdk -
Muokkaa
.npmrc-tiedostoasi sisältämään seuraava rivi:@ohos:registry=https://repo.harmonyos.com/npm/ -
Asenna hvigor ja hvigor-ohos-plugin. Tämä luo
node_modules-hakemiston nykyiseen hakemistoon.npm install @ohos/hvigor npm install @ohos/hvigor-ohos-plugin -
Nyt sinun pitäisi pystyä ajamaan
hvigor.jsOpenHarmony-projektissasi kääntääksesi hap-paketin:/path/to/node_modules/@ohos/hvigor/bin/hvigor.js assembleHap
hdc:n konfigurointi Linuxilla
hdc on OpenHarmony-laitteiden vastine adb:lle.
Löydät sen SDK:n toolchains-hakemistosta.
Käytännön syistä saatat haluta lisätä toolchainsin PATH:iin.
Muun muassa hdc:llä voi avata shellin tai siirtää tiedostoja laitteen ja isäntäjärjestelmän välillä.
hdc tarvitsee yhteyden fyysiseen laitteeseen usb:n kautta, mikä vaatii käyttäjältä oikeudet laitteen käyttöön.
On suositeltavaa lisätä udev-sääntö, jotta hdc pääsee laitteeseen ilman root-oikeuksia.
Tämä stackoverflow-vastaus pätee myös hdc:hen.
Aja lsusb ja tarkista laitteesi vendor id, luo sitten vastaava udev-sääntö.
Huomaa, että käyttäjäsi tulee olla GROUP="xxx":llä määritetyn ryhmän jäsen.
Jakelustasi riippuen saatat haluta käyttää eri ryhmää.
Tarkistaaksesi toimiiko hdc, aja hdc list targets — sen pitäisi näyttää laitteesi sarjanumero.
Jos se ei toimi, kokeile uudelleenkäynnistystä.
Huomaa, että laitteesi täytyy olla “Developer mode” -tilassa USB-debuggaus päällä. Prosessi on täsmälleen sama kuin Androidilla:
- Napauta build-numeroa useita kertoja ottaaksesi kehittäjätilan käyttöön.
- Siirry sitten kehittäjäasetuksiin ja ota USB-debuggaus käyttöön.
- Kun yhdistät laitteen ensimmäistä kertaa, vahvista ponnahdusikkuna, jossa kysytään luotatko yhdistettävään tietokoneeseen.
Allekirjoitusasetukset
Useimmat laitteet vaativat, että HAP on digitaalisesti allekirjoitettu kehittäjän toimesta asennusta varten.
hvigor-työkalulla tämä onnistuu asettamalla staattinen signingConfigs-objekti build-profile.json5-tiedostoon tai luomalla dynaamisesti signingConfigs-taulukko sovelluskontekstiobjektille hvigorfile.ts-skriptissä.
signingConfigs-ominaisuus on taulukko objekteja seuraavalla rakenteella:
[
{
"name": "default",
"type": "<OpenHarmony or HarmonyOS>",
"material": {
"certpath": "/path/to/app-signing-certificate.cer",
"storePassword": "<encrypted password>",
"keyAlias": "debugKey",
"keyPassword": "<encrypted password>",
"profile": "/path/to/signed-profile-certificate.p7b",
"signAlg": "SHA256withECDSA",
"storeFile": "/path/to/java-keystore-file.p12"
}
}
]
Tässä <encrypted password> on salasanan plaintext-esityksen heksadesimaalimerkkijono salauksen jälkeen.
Avain ja suola salasanojen salaamiseen luodaan DevEco Studio IDE:llä, ja ne tallennetaan levylle sertifikaattitiedostojen ja keystoren rinnalle, yleensä hakemistoon <USER HOME>/.ohos.
Luodaksesi salauksessa tarvittavat tiedot, vaaditut sovellus- ja profiilisertifikaattitiedostot ja itse keystoren, voit kloonata esimerkki-ArkTS-sovelluksen ja avata sen DevEco Studio IDE:llä. Huomaa, että koska allekirjoitustiedot sidotaan bundle-nimeen, kaikki ArkTS-sovellukset eivät toimi, ja siksi on erittäin suositeltavaa käyttää yllä mainittua esimerkki-ArkTS-sovellusta.
- Avaa Project Structure -valintaikkuna valikosta
File > Project Structure. - Välilehdellä ‘Signing Config’ ota käyttöön ‘Automatically generate signature’ -valintaruutu.
HUOM: Yllä automaattisesti luotu allekirjoitus on tarkoitettu vain kehitykseen ja testaukseen. Tuotantokäännöksiin ja jakeluun sovelluskaupan kautta tarvitaan asianmukainen konfiguraatio sovelluskaupan tarjoajalta.
Linux-käyttäjille DevEco Studio on saatavilla vain Windowsilla ja macOS:lla. Jatkaaksesi tarvitset toisen Windows- / macOS-koneen, jossa DevEco Studio IDE on asennettuna allekirjoitusavainten luomiseen. Jos kehität OpenHarmony-levyjä (kuten HopeRun-kehityslevy), voit nimetä
SigningConfigs:indefault. Muuten aseta se arvoonhos, jos kehität Servoa HarmonyOS-laitteille (kuten Huawei Mate -puhelinsarja).Kun avaimet on luotu, sinun täytyy siirtää koko hakemisto, joka tallentaa avaimet (yleensä
<USER HOME>/.ohos/), DevEco Studion luomalta Windows- / macOS-koneelta.Lisäksi sinun täytyy kopioida
SigningConfigsDevEco Studion luomastabuild-profile.json5:stä Windows- / macOS-koneelta.json-tiedostoon Linux-koneellasi. Tämä toimii “signing material” -lähteenä, johonmachvoi myöhemmin viitata.
Kun luotu, sinun täytyy osoittaa mach yllä olevaan “signing material” -konfiguraatioon SERVO_OHOS_SIGNING_CONFIG-ympäristömuuttujalla.
Muuttujan arvon täytyy olla polku kelvolliseen .json-tiedostoon, jolla on sama rakenne kuin yllä olevalla signingConfigs-ominaisuudella, mutta jossa certPath, storeFile ja profile on annettu polkuina suhteessa json-tiedostoon absoluuttisten polkujen sijaan.
servoshellin kääntäminen
Ennen Servon kääntämistä sinun täytyy asettaa joitakin ympäristömuuttujia.
direnv on kätevä työkalu, joka voi asettaa nämä muuttujat automaattisesti .envrc-tiedoston perusteella, mutta voit käyttää mitä tahansa muuta tapaa asettaaksesi vaaditut ympäristömuuttujat.
.envrc:
export OHOS_SDK_NATIVE=/path/to/openharmony-sdk/platform/api-version/native
# Required if the HAP must be signed. See the signing configuration section above.
export SERVO_OHOS_SIGNING_CONFIG=/path/to/signing-configs.json
# Required only when building for HarmonyOS:
export DEVECO_SDK_HOME=/path/to/command-line-tools/sdk # OR /path/to/DevEcoStudio/sdk OR on MacOS /Applications/DevEco-Studio.app/Contents/sdk
# Required only when building for OpenHarmony:
# Note: The openharmony sdk is under ${DEVECO_SDK_HOME}/default/openharmony
# Presumably you would need to replicate this directory structure
export OHOS_BASE_SDK_HOME=/path/to/openharmony-sdk/platform
# If you have the command-line tools installed:
export PATH="${PATH}:/path/to/command-line-tools/bin/"
export NODE_HOME=/path/to/command-line-tools/tool/node
# Alternatively, if you do NOT have the command-line tools installed:
export HVIGOR_PATH=/path/to/parent/directory/containing/node_modules # Not required if `hvigorw` is in $PATH
Jos käytät direnv:iä ja .envrc-tiedostoa, muista ajaa direnv allow . .envrc-tiedoston muokkaamisen jälkeen.
Muuten ympäristömuuttujia ei ladata.
Seuraavalla komennolla voit kääntää servoshell-sovelluksen 64-bittiselle ARM-laitteelle tai emulaattorille:
./mach build --ohos --release [--flavor=harmonyos]
Komennoissa mach build, mach install ja mach package --ohos on alias --target aarch64-unknown-linux-ohos:lle.
Kääntääksesi emulaattorille, joka ajaa x86-64-isännällä, käytä --target x86_64-unknown-linux-ohos.
Oletus ohos -käännös / pakkaus / asennus kohdistaa OpenHarmonyyn.
Jos haluat kääntää HarmonyOS:lle, voit lisätä --flavor=harmonyos.
Tarkista Allekirjoitusasetukset ja lisää konfiguraatio, jossa "name": "hos" ja "type": "HarmonyOS"" ja vastaavat allekirjoitussertifikaatit.
Asentaminen ja ajaminen laitteella
Seuraavalla komennolla voit asentaa aiemmin käännetyn servoshell-sovelluksen 64-bittiselle ARM-laitteelle tai emulaattorille:
./mach install --ohos --release [--flavor=harmonyos]
Lisälukemista
Vianmääritys
Katso Yleinen vianmääritys -osio, jos käännöksessä on ongelmia.
Offline-käännös
Servon julkaisut tarjoavat servo-<release-tag>-src-vendored.tar.gz -artifaktin, joka sisältää Servon lähdekoodin ja kaikki Rust-riippuvuudet vendoroituina.
Tiedoston .cargo/config.toml sisältää tarvittavan konfiguraation Servon offline-kääntämiseen vendoroituja riippuvuuksia käyttäen.
Linux
Katso Linux-kääntämisohjeet lisätietoja käännösriippuvuuksien asentamisesta.
Suosittelemme yleensä ./mach build -komentoa Servon kääntämiseen, mutta se vaatii uv:n asennuksen ja Python-riippuvuuksien synkronoinnin uv sync -komennolla etukäteen (muuten ./mach yrittää käyttää verkkoa Python-ympäristön asentamiseen).
# online pre-build environment (e.g. building a docker container)
uv sync
# offline build environment
./mach build --profile=production --frozen
Jos tämä on vaikeaa, voit kääntää Servon myös cargo:lla, jolloin mikä tahansa tuore Python-versio (>= 3.11) riittää (tätä ei testata CI:ssä).
Huomaa, että ./mach build ottaa media-gstreamer -ominaisuuden oletuksena käyttöön — cargo:lla sinun täytyy ottaa tämä ominaisuus käyttöön manuaalisesti ja asettaa gstreamer-liittyvät ympäristömuuttujat.
Gstreamer-ominaisuuden vaatimia ympäristömuuttujia ei ole dokumentoitu tässä, mutta dokumentaatioparannukset ./mach build -koodin pohjalta ovat tervetulleita.
# Build an offline release build with the production profile.
cargo build --profile=production --frozen
Windows ja macOS
Windowsilla ja macOS:lla ./mach bootstrap lataa lisäriippuvuuksia Servon kääntämiseen.
Näitä ei tällä hetkellä toimiteta tarballissa.
Jos offline-käännökset näille alustoille kiinnostavat, osallistuminen on tervetullutta (mutta ota ensin yhteyttä Zulipissa tai GitHub-issueissa).
Valmiiksi käännetyt SpiderMonkey-artifaktit
Online-käännökset käyttävät oletuksena valmiiksi käännetyitä SpiderMonkey-artifakteja, jotka on hostattu servo/mozjs -repon GitHub-julkaisuissa.
Jos haluat yksinkertaistaa tai nopeuttaa käännösympäristöäsi, voit ladata nämä artifaktit itse ja käyttää MOZJS_ARCHIVE=path/to/libmozjs.tar.gz offline-käännöksissä.
Voit varmistaa ladattujen artifaktien eheyden GitHub-attestointien avulla gh-työkalulla:
gh attestation verify path/to/libmozjs.tar.gz -R servo/mozjs
Yleinen vianmääritys
Katso tyyliopas ohjeisiin virheilmoitusten muotoilusta.
Jos Servon kääntämisessä ilmenee ongelmia, joita ei ole listattu muilla sivuilla, kokeile ensin alla olevia vaiheita:
- Varmista, että sinulla on kaikki listatut käännösvaatimukset. Erityisesti jos käytät harvinaista Linux-jakelua tai muuta Unix-tyyppistä järjestelmää, sinun täytyy ehkä selvittää tietyn riippuvuuden oikea nimi järjestelmässäsi.
- Tarkista uudelleen, että käännösvaatimukset on asennettu ja katso riippuvuusversiot.
- Aja
./mach boostraptai.\mach boostrapWindowsilla. Joskus Servon kääntämiseen tarvittavat työkalut tai riippuvuudet muuttuvat. Komennon voi ajaa useamman kerran turvallisesti. Varmista, ettei suorituksen aikana ilmoitettu virheitä. Jos olet asentanut muita riippuvuuksia manuaalisesti, sinun täytyy ehkä ajaa./mach bootstrap --skip-platform. - Päivitä ympäristösi. Tämä voi tarkoittaa:
- Shellin uudelleenkäynnistystä
- Uloskirjautumista ja takaisin sisäänkirjautumista
- Tietokoneen uudelleenkäynnistystä
Riippuvuusversiot
curl --versiontulostaa version kuten 7.83.1 tai 8.4.0- Windowsilla kirjoita
curl.exe --versionPowerShellinInvoke-WebRequest-aliasin välttämiseksi
- Windowsilla kirjoita
uv --versiontulostaa version 0.4.30 tai uudemman- Servon
mach-käännöstyökalu riippuuuv:sta kiinnitetyn Python-version (repossa.python-version-tiedostossa) tarjoamiseen ja paikallisen virtuaaliympäristön (.venv-hakemisto) luomiseen, johon Python-riippuvuusmoduulit asennetaan. - Jos järjestelmässä on jo vaaditun Python-version asennus,
uvlinkittää siihen levytilan säästämiseksi. - Jos versiot eivät täsmää tai Pythonia ei ole asennettuna,
uvlataa tarvittavat binäärit. - Ulkoisesti hallitun Python-asennuksen käyttöä
mach-skriptin ajamiseen ei tällä hetkellä tueta.
- Servon
rustup --versiontulostaa version kuten 1.26.0- Windows:
choco --versiontulostaa version kuten 2.2.2 - macOS:
brew --versiontulostaa version kuten 4.2.17
Et ole yksin!
Jos Servon kääntämisessä on ongelmia, joita et ratkaise, voit aina pyytää apua build issues -keskustelussa Zulipissa.
Yleiskuva: Servon upottaminen
Servo on selainmoottori, jonka on tarkoitus olla helppo upottaa muihin sovelluksiin. Tällä hetkellä dokumentaatio Servon upottamisesta on niukkaa, ja tämä luku on aktiivisesti työn alla. Ota rohkeasti yhteyttä Servo Zulip -keskustelussa, jos sinulla on kysyttävää.
Servon kääntäminen ilman machia
Servo voidaan kääntää suoraan cargo:lla, vaikka joudut todennäköisesti toteuttamaan osan machin toiminnallisuudesta uudelleen.
Alla on lyhyt yleiskuva asioista, joita kannattaa pitää mielessä.
Ympäristömuuttujat
./mach asettaa useita ympäristömuuttujia käännöksen ohjaamiseen, mikä on erityisen tarpeellista ristiinkäännöksessä esim. Androidille tai OpenHarmonylle.
Voit ajaa ./mach print-env nähdäksesi mitkä muuttujat asetetaan, ja käyttää sitä käännöksen konfigurointiin.
Mediatuki
./mach build ottaa media-gstreamer -ominaisuuden oletuksena käyttöön, mikä ei päde tavallisiin käännöksiin.
media-gstreamer vaaditaan mediatuelle yleisillä työpöytäalustoilla.
Linuxilla sinun täytyy asentaa vaaditut gstreamer-kirjastot paketinhallinnan kautta (esim. ajamalla ./mach bootstrap).
macOS:lla ./mach bootstrap asentaa vaaditut gstreamer-kirjastot asentamalla uusimmat paketit osoitteesta https://github.com/servo/servo-build-deps/releases/tag/macOS.
Windowsilla voit asentaa gstreamer-kirjastot osoitteesta https://github.com/servo/servo-build-deps/releases/tag/msvc-deps (versio 1.22.8).
Resurssit
Servo tarvitsee resursseja ja tarjoaa oletusversiot servo-default-resources -craten kautta, jos baked-in-resources -ominaisuus on käytössä.
Tämä toteutetaan upottamalla resurssit binääriin.
Upottajat voivat kieltäytyä tästä poistamalla default-features -ominaisuudet käytöstä ja tarjoamalla oman resurssienlukumekanismin servo_embedder_traits::submit_resource_reader:n kautta.
Tällöin ResourceReader-toteutuksen vastuulla on tarjota kaikki resurssit.
Esimerkki on OpenHarmony-portti, joka lukee kaikki resurssit tiedostojärjestelmästä: ohos/resources.rs.
Servon LTS-julkaisut
Kuukausittaisten julkaisujemme lisäksi Servo-yhteisö tarjoaa parhaan ponnistelun mukaisia pitkäaikaistuen (LTS) -julkaisuja. Koska Servon julkinen API on vielä kehittymässä, nämä LTS-julkaisut voivat sopia upottajille, joilla on rajalliset resurssit pysyä ajan tasalla uusimmasta Servo-julkaisusta. LTS-julkaisut antavat upottajille aikataulutetut päivitysikkunat ja hyödyn tietoturvakorjauksista, mukaan lukien JavaScript-moottorimme tietoturvakorjaukset.
LTS-julkaisujen laajuus
Servo toimitetaan SELLAISENAAN eikä sille anneta erityisiä takuita. LTS-julkaisut (ja alla olevat yksityiskohdat) tarjotaan parhaan ponnistelun mukaisesti. Toistaiseksi tämä tarkoittaa:
- Uusi LTS-julkaisu / haara otetaan käyttöön 6 kuukauden välein, perustuen silloisen tavallisen julkaisun versioon.
- Odotettu tukikesto on 9 kuukautta, mikä antaa upottajille aikaa siirtyä seuraavaan LTS-julkaisuun.
- LTS-julkaisu saa vain tietoturvakorjauksia.
- Korjausjulkaisut tehdään tarpeen mukaan; kiinteää aikataulua ei ole.
- Laajuudessa on vain
servo-kirjasto ja sen riippuvuudet. Selaindemo servoshell on nimenomaisesti laajuuden ulkopuolella. - Tuettua vähimmäis-Rust-versiota (MSRV) ei nosteta LTS-haarassa, mutta se voi nousta siirryttäessä seuraavaan LTS-versioon
- Julkaisut julkaistaan crates.io:hon jos mahdollista, mutta upottajien tulee varautua siihen, että
git-riippuvuuksia saatetaan vaatia.
CVE-korjausten paikkaaminen alavirta-cratesissa
Monet Rust-kirjastot eivät yleensä tuo CVE-korjauksia vanhempiin julkaisuihin / haaroihin.
Koska MSRV-nostot käsitellään taaksepäin yhteensopimattomina muutoksina, tämä voi johtaa siihen, ettei voimme päivittää kirjaston uudempaan julkaistuun versioon (joka korjaa CVE:n).
Nämä tilanteet käsitellään tapauskohtaisesti, ihanteellisesti yhteistyössä upstream-ylläpitäjän kanssa, ja ne sisältävät todennäköisesti kirjaston paikatun version hakemisen git:n kautta.
Tämä tarkoittaa, että Servon LTS-korjausjulkaisuja ei pidä odottaa crates.io:ssa, koska niissä voi olla git-riippuvuuksia.
Rajoitukset
- Servo toimitetaan SELLAISENAAN eikä sille anneta erityisiä takuita, mukaan lukien tietoturvatakuut. LTS-julkaisut tarjotaan parhaan ponnistelun mukaisesti kiinnostuneiden yhteisön jäsenten toimesta.
- Kuten yllä mainittiin, Servolla ei ole vielä 1.0-julkaisua, mikä tarkoittaa että Servon tuotantokäyttöä tulee arvioida huolellisesti. Servon käyttö sovelluksessa tunnetun, luotetun sisällön renderöintiin on hyvin erilainen riskiprofiili kuin Servon käyttö selaimena mielivaltaisen sisällön renderöintiin.
LTS-julkaisujen ylläpitäjät
- @jschwe (Jonathan Schwender)
- TBD
Aloitus
Servo toivottaa kaikki avustajat tervetulleiksi. Verkkomoottorin parissa työskentely voi olla haastavaa ja joskus turhauttavaa, mutta se voi olla myös hyvin palkitsevaa ja hauskaa. Jos käytät aikaa ja vaivaa osallistumiseen, opit jatkuvasti ja kehityt kehittäjänä ja avoimen lähdekoodin avustajana. Aloita seuraavasti:
- Lue loput tästä sivusta saadaksesi perustiedot Servoon avustamisesta.
- Hae Servon repositorio onnistuneesti ja käännä Servo.
- Luo Servon fork ja opi Gitin perusteet seuraamalla Git-asetukset -luvun ohjeita.
- Opettele hieman Rustia. Verkossa on paljon resursseja, mutta yksi parhaista on virallinen Learning Rust -dokumentaatio. Jos tunnet muut imperatiiviset ohjelmointikielet, voit oppia Rustia työskennellessäsi Servon parissa, mutta perustuntemus kielestä on hyödyllinen alussa.
- Aseta editorisi niin, että se integroituu
rust-analyzer-työkalun kanssa. - Lue tyyliohjeemme ja tutustu odotuksiin tekemäsi koodin suhteen.
- Lue ja seuraa pull requestin tekemisen vaiheet.
Työskentely issuen parissa
Jos haluat työskennellä issuen parissa, jätä siihen kommentti ilmoittaaksesi, että otat sen työn alle. Näin vältetään päällekkäinen työ samassa issuessa.
Viesti “@servo-highfive assign me” osoittaa issuen sinulle.
Siirry Servo Starters -sivustolle löytääksesi hyviä tehtäviä aloittelijalle.
Jos kohtaat outoja sanoja tai ammattislangia, tarkista ensin sanasto.
Jos sopivaa merkintää ei ole, tee pull request ja lisää uusi merkintä sisällöllä TODO, jotta voimme korjata sen!
Tekoälyavustukset
Avustukset eivät saa sisältää suurten kielimallien tai muiden probabilististen työkalujen tuottamaa sisältöä, mukaan lukien mutta ei rajoittuen Copilotiin tai ChatGPT:hen. Tämä käytäntö kattaa koodin, dokumentaation, pull requestit, issuet, kommentit ja kaikki muut Servo-projektin avustukset.
Toistaiseksi suhtaudumme näihin työkaluihin varovaisesti niiden vaikutusten vuoksi — sekä tuntemattomien että havaittujen — projektin terveyteen ja ylläpitotaakkaan. Alue kehittyy nopeasti, joten olemme avoimia käytännön uudelleen arvioinnille myöhemmin, jos esitetään ehdotuksia työkaluista, jotka lieventävät näitä vaikutuksia. Perustelumme ovat seuraavat:
Ylläpitäjien taakka: Arvioijat luottavat siihen, että avustajat kirjoittavat ja testaavat koodinsa ennen lähettämistä. Olemme havainneet, että nämä työkalut helpottavat suurten määrien uskottavalta näyttävän koodin tuottamista, jota avustaja ei ymmärrä, jota usein ei ole testattu ja joka ei toimi oikein. Tämä kuormittaa arvioijiemme (jo valmiiksi rajallista) aikaa ja energiaa.
Oikeellisuus ja turvallisuus: Vaikka tekoälytyökalujen tuottama koodi näyttäisi toimivan, oikeellisuudesta ei ole takeita eikä merkkejä mahdollisista turvallisuusvaikutuksista. Selainmoottori on rakennettu toimimaan vihamielisissä suoritusympäristöissä, joten kaiken koodin on otettava huomioon mahdolliset turvallisuusongelmat. Avustajilla on suuri rooli näiden asioiden pohtimisessa avustuksia luodessaan — emme voi luottaa tekoälytyökalun tekevän tätä.
Tekijänoikeuskysymykset: Julkisesti saatavilla olevat mallit on koulutettu tekijänoikeudella suojatulla sisällöllä sekä vahingossa että tarkoituksella, ja niiden tuotos sisältää usein kyseistä sisältöä sanatarkasti. Koska tämän laillisuus on epävarmaa, avustukset voivat rikkoa tekijänoikeudella suojattujen teosten lisenssejä.
Eettiset kysymykset: Tekoälytyökalujen rakentaminen ja käyttö vaatii kohtuuttoman paljon energiaa ja vettä, niiden mallit rakennetaan raskaasti hyväksikäytetyillä työntekijöillä hyväksymättömissä työoloissa, ja niitä käytetään työvoiman heikentämiseen ja irtisanomisten oikeuttamiseen. Emme halua jatkaa näitä haittoja, edes epäsuorasti.
Huomaa, että koodin tai muiden avustusten tuottamisen lisäksi tekoälytyökalut voivat joskus vastata Servoa koskeviin kysymyksiisi, mutta olemme havainneet näiden vastausten olevan usein virheellisiä tai hyvin harhaanjohtavia.
Yleisesti ottaen älä oleta tekoälytyökalujen olevan totuuden lähde Servon toiminnasta. Harkitse kysymysten esittämistä Zulipissa sen sijaan.
Tekoälykäytännön FAQ
Voinko käyttää tekoälytyökaluja kääntäessäni äidinkielestäni englanniksi?
Kyllä.
Voinko käyttää tekoälytyökalua auttamaan bugien tai turvallisuusongelmien löytämisessä Servossa?
Kyllä, mutta sinun on varmennettava tekoälytyökalun tuotos ennen issuen avaamista Servo-projektia vastaan. Projektia vastaan avattujen issuen odotetaan noudattavan projektin tekoälykäytäntöä — sinun on pystyttävä toistamaan ja validoimaan havainnot, et pelkästään luottamaan työkalun tuotokseen.
Voinko käyttää tekoälytyökalua ymmärtääkseni Servon koodikantaa paremmin?
Kyllä, mutta katso aiempi varoitus näiden työkalujen luotettavuudesta.
Voinko lähettää pull requestin, joka sisältää tekoälytyökalujen tuottamaa koodia?
Et. Tämä kattaa (mutta ei rajoitu) kaikki generatiiviset tekoälytyökalut, kuten Clauden, Codexin, ChatGPT:n, Cursorin, Geminin ja Windsurfin.
Voinko käyttää tekoälytyökalua pull requestin tiivistämiseen?
Et. Tämä kattaa (mutta ei rajoitu) kaikki generatiiviset tekoälytyökalut, kuten Clauden, Codexin, ChatGPT:n, Cursorin, Geminin ja Windsurfin. Kuvaile pull requestisi noudattamalla projektin parhaita käytäntöjä.
Voinko käyttää tekoälyarvioijaa pull requestilleni?
Kyllä, mutta älä tee sitä. Tulokset ovat epäluotettavia ja meluisia.
Voinko käyttää tekoälytyökalua uuden issuen kuvauksen tai kommentin kirjoittamiseen?
Et. Tämä kattaa (mutta ei rajoitu) kaikki generatiiviset tekoälytyökalut, kuten Clauden, Codexin, ChatGPT:n, Cursorin, Geminin ja Windsurfin.
Mitä tapahtuu, jos rikon tätä tekoälykäytäntöä?
Servon ylläpitäjät pidättävät oikeuden sulkea minkä tahansa pull requestin, joka ei täytä tämän käytännön vaatimuksia. Kaikki kommentit, kuvaukset ja muut ei-koodiset artefaktit, joita aiemmat FAQ-kohdat eivät salli, on kirjoitettava uudelleen ilman tekoälytyökalujen käyttöä.
Käyttäytyminen
Servon käyttäytymissäännöt on julkaistu osoitteessa https://servo.org/coc/.
Hallinto
Servon hallinto määritellään Technical Steering Committee (TSC) -elimellä, ja se on dokumentoitu servo/project-repositoriossa.
Tehtävien löytäminen
Servon issue tracker sisältää paljon issueita, ja sopivan tehtävän etsiminen voi tuntua ylivoimaiselta. Tässä on hyödyllisiä vinkkejä issue-tunnisteista, joita kannattaa etsiä:
Vähemmän monimutkaiset issuet
E-less-complex -tunniste tarkoittaa, että joku katsoo issuen sopivan uudelle avustajalle. Näiden tunnisteiden issuen pitäisi sisältää selkeä kuvaus ongelmasta, selkeät vaiheet sen korjaamiseksi ja odotetut varmistusvaiheet.
Monimutkaisemmat issuet
E-more-complex -tunniste tarkoittaa, että joku katsoo issuen sopivan hieman kokemusta omaavalle.
Kuten E-less-complex-issuet, myös näiden tunnisteiden issuen pitäisi sisältää selkeä kuvaus ongelmasta, selkeät vaiheet sen korjaamiseksi ja odotetut varmistusvaiheet.
Ero kahden tunnisteen välillä on ratkaisuun odotettu vaadittu työmäärä, ja ne voivat vaatia lisätutkimusta.
Panicien korjaaminen minimoiduilla testitapauksilla
Servo voidaan saada panikoimaan monin tavoin, ja näitä löydetään usein fuzzaamalla Servoa. On paljon esimerkkejä issueista, joissa on minimoidut testitapaukset (eli pienin HTML/JS/CSS, jolla ongelma toistuu) ja jotka on merkitty tunnisteilla I-panic ja C-has-manual-testcase.
Nämä voivat olla hyviä issueita, koska panic-backtrace voi antaa vihjeitä relevantista koodista, ja voit keskittyä ymmärtämään panicin laukaisevat olosuhteet.
Testitapausten minimointi
On helppo avata issue siitä, että Servo renderöi verkkosivun väärin, mutta näihin issueihin on usein vaikea reagoida.
On hyvin hyödyllistä etsiä issueita C-needs minimized testcase -tunnisteella ja työskennellä ongelman toistamiseen tarvittavan HTML/CSS/JS:n eristämiseksi.
Katso opas vinkkejä ei-triviaalisten sivujen minimointiin.
Epäonnistuvien Web Platform Tests -testien diagnosointi
Web Platform Tests (WPT) ovat Servon pääasiallinen automatisoitujen yhteensopivuustestien lähde.
On paljon testejä, joita Servo ei vielä läpäise, ja ne löytyvät testien metatietohakemistosta.
Jokainen .ini-tiedosto kyseisessä hakemistossa vastaa testin lähdetiedostoa, ja voi olla hyödyllistä valita sinua kiinnostavasta hakemistosta tiedosto ja diagnosoida, mikä estää testin läpäisyn.
Voit myös tutkia kaikkia testejä, joita Servo epäonnistuu, verkkopohjaisessa wpt.fyi-käyttöliittymässä. Katso opas vinkkejä WPT-testien epäonnistumisten syiden tunnistamiseen.
Git-asetukset
Jos olet uusi Gitin tai hajautetun versionhallinnan parissa, on erittäin suositeltavaa käyttää aikaa perusteiden opetteluun ennen jatkamista. Verkossa on monia erinomaisia resursseja Gitin oppimiseen. Esimerkiksi Zulip-projekti ylläpitää hyvin kattavaa opasta Gitin käyttöön avoimen lähdekoodin projektiin avustamisessa. Tiedot ovat usein hyvin relevantteja myös Servon parissa työskentelyyn. Gitin hallinta on taito, josta on hyötyä monenlaisissa ohjelmistokehitystehtävissä, ja siihen käytetty aika on sen arvoista.
Kun kloonasit Servon alun perin, upstream-Servo-repositorio osoitteessa https://github.com/servo/servo oli upstreamisi.
Voit pitää tuon konfiguraation, mutta suositeltu työnkulku on seuraava:
- Forkkaa upstream-Servo-repositorio.
- Checkoutaa klooni juuri forkkaamastasi Servo-kopiosta.
Huomaa, ettägit clone --depth 10 https://github.com/<username>/servo.git--depth 10-argumentit hylkäävät suurimman osan Servon commit-historiasta paremman suorituskyvyn vuoksi. Ne voidaan jättää pois. - Lisää uusi remote nimeltä
upstream, joka osoittaaservo/servo-repoon.git remote add upstream https://github.com/servo/servo.git
Uuden muutoksen aloittaminen
Kun haluat työskennellä uuden muutoksen parissa, älä tee sitä main-haarassa, koska siellä haluat pitää upstream-repositorion kopion ajan tasalla.
Tee työsi sen sijaan haarassa.
- Päivitä
main-haarasi upstreamin uusimpiin muutoksiin.git checkout main git pull origin main - Luo uusi haara
main-haaran pohjalta.git checkout -b issue-12345 - Tee muutoksesi ja commitoi ne kyseiselle haaralle.
Muista myös allekirjoittaa jokainen commit!
git commit --signoff -m "script: Add a stub interface for MessagePort"
Seuraavaksi haluat todennäköisesti tehdä pull requestin muutoksillasi.
Editorin asetukset
On erittäin suositeltavaa asettaa editorisi tukemaan rust-analyzer-työkalua.
Vaikka se vaatii kohtuullisen määrän RAM-muistia ja CPU:ta, se parantaa Servon parissa työskentelyä merkittävästi, koska editorisi voi tarjota koodin täydentämistä, reaaliaikaisia käännösvirheitä ja varoituksia sekä helposti saatavilla olevan rustdoc-dokumentaation.
Valitettavasti rust-analyzer yrittää ajaa cargo-komentoa ilman mach-komentoa, mikä aiheuttaa ongelmia Servon erityisen käännöskonfiguraation vuoksi.
Käytä seuraavia ohjeita IDE:n konfigurointiin.
Lisäykset ovat tervetulleita!
Visual Studio Code
On suositeltavaa lisätä seuraava projektikohtaisiin asetuksiin tiedostoon .vscode/settings.json:
{
"rust-analyzer.rustfmt.overrideCommand": [ "./mach", "fmt" ],
"rust-analyzer.check.overrideCommand": [
"./mach",
"clippy",
"--message-format=json",
"--target-dir",
"target/lsp",
"--features",
"tracing,tracing-perfetto"
],
"rust-analyzer.cargo.buildScripts.overrideCommand": [
"./mach",
"clippy",
"--message-format=json",
"--target-dir",
"target/lsp",
"--features",
"tracing,tracing-perfetto" ],
}
Huomioita:
- Yllä olevassa katkelmassa kielipalvelin kääntää omaan target-hakemistoonsa
target/lsp, jotta vältetään ei-toivotut uudelleenkäännökset. Jos haluat säästää levytilaa, voit poistaa--target-dir- jatarget/lsp-argumentit, jolloin käytetään oletustarget-hakemistoa. - Ota valinnaiset käännösasetukset käyttöön lisäämällä ne konfiguraatiotiedoston build-argumenttilistaan.
- Windows: Windowsissa sinun on käytettävä
./mach.bat-komentoa./mach-komennon sijaan. Muuten saatat saada virheen, että suoritettu komento ei ole kelvollinen Win32-sovellus. - Ristikäännös: Jos ristikäännät, voit ohittaa cargo-käytettävän targetin lisäämällä
"rust-analyzer.cargo.target": "aarch64-linux-android". Huomaa, että jotkin LSP-ominaisuudet eivät välttämättä toimi tässä konfiguraatiossa.
Zed
Jos käytät Zedia, sinun on tehtävä hyvin samanlaista kuin Visual Studio Code -kohdassa kuvataan, mutta Zed-konfiguraatiotiedosto odottaa hieman erilaista syntaksia.
Tiedostossa ./zed/settings.json tarvitset jotain tällaista:
{
"lsp": {
"rust-analyzer": {
"initialization_options": {
"checkOnSave": true,
"check": {
"overrideCommand": [
"./mach",
"clippy",
"--message-format=json",
"--target-dir",
"target/lsp",
"--feature",
"tracing,tracing-perfetto"
]
},
"cargo": {
"allTargets": false,
"buildScripts": {
"overrideCommand": [
"./mach",
"clippy",
"--message-format=json",
"--target-dir",
"target/lsp",
"--feature",
"tracing,tracing-perfetto"
]
}
},
"rustfmt": {
"extraArgs": [
"--config",
"unstable_features=true",
"--config",
"binop_separator=Back",
"--config",
"imports_granularity=Module",
"--config",
"group_imports=StdExternalCrate"
]
}
}
}
}
}
Python
Servo sisältää Python-skriptejä osana build-työkaluja ja tiettyjä testityyppejä. Zedin oletus-Python-konfiguraatio ei välttämättä tarjoa kunnollista staattista koodianalyysia.
Servo on konfiguroitu toimimaan Pyrefly-kielipalvelimen kanssa, jonka voit ottaa käyttöön alla olevan kaltaisella konfiguraatiolla. Tarvitset myös Pyrefly Zed-laajennuksen.
{
"lsp": {
"pyrefly": {
"binary": {
"path": ".venv/bin/pyrefly",
"arguments": ["lsp"],
},
"settings": {
"python": {
"pythonPath": ".venv/bin/python",
},
"pyrefly": {
"python_interpreter": ".venv/bin/python",
},
},
},
},
"languages": {
"Python": {
"language_servers": ["pyrefly", "!pyright", "!pylsp"],
},
},
}
NixOS
NixOS:ssa saatat saada virheitä pkg-config- tai crown-paketeista:
thread ‘main’ panicked at ’called `Result::unwrap()` on an `Err` value: “Could not run `PKG_CONFIG_ALLOW_SYSTEM_CFLAGS=\“1\” PKG_CONFIG_ALLOW_SYSTEM_LIBS=\“1\” \“pkg-config\” \“–libs\” \“–cflags\” \“fontconfig\”`
[ERROR rust_analyzer::main_loop] FetchWorkspaceError: rust-analyzer failed to load workspace: Failed to load the project at /path/to/servo/Cargo.toml: Failed to read Cargo metadata from Cargo.toml file /path/to/servo/Cargo.toml, Some(Version { major: 1, minor: 74, patch: 1 }): Failed to run `cd “/path/to/servo” && “cargo” “metadata” “–format-version” “1” “–manifest-path” “/path/to/servo/Cargo.toml” “–filter-platform” “x86_64-unknown-linux-gnu”`: `cargo metadata` exited with an error: error: could not execute process `crown -vV` (never executed)
mach välittää eri RUSTFLAGS-arvot Rust-kääntäjälle kuin pelkkä cargo, joten jos yrität kääntää Servon cargo-komennolla, se kumoaa mach-komennon työn (ja päinvastoin).
Tämän vuoksi, ja koska Servo voidaan tällä hetkellä kääntää vain mach-komennolla, sinun on konfiguroitava rust-analyzer-laajennus käyttämään mach-komentoa tiedostossa .vscode/settings.json:
crown-käyttö
Jos käytät --use-crown-valitsinta, sinun pitäisi myös asettaa CARGO_BUILD_RUSTC tiedostossa .vscode/settings.json seuraavasti, jossa /nix/store/.../crown on komennon nix-shell --run 'command -v crown' tulos.
{
"rust-analyzer.server.extraEnv": {
"CARGO_BUILD_RUSTC": "/nix/store/.../crown",
},
}
Näiden asetusten pitäisi riittää siihen, ettei sinun tarvitse ajaa code . nix-shell-ympäristöstä, mutta voit kokeilla sitä, jos ongelmia on yhä.
Ongelmia proc-makrojen kanssa
Kun otat rust-analyzerin proc-makrotuen käyttöön, saatat alkaa nähdä virheitä kuten
proc macro `MallocSizeOf` not expanded: Cannot create expander for /path/to/servo/target/debug/deps/libfoo-0781e5a02b945749.so: unsupported ABI `rustc 1.69.0-nightly (dc1d9d50f 2023-01-31)` rust-analyzer(unresolved-proc-macro)
Tämä tarkoittaa, että rust-analyzer käyttää väärää proc-makropalvelinta, ja sinun on konfiguroitava oikea manuaalisesti. Käytä mach-komentoa kysyäksesi nykyisen sysroot-polun ja kopioi tulosteen viimeinen rivi:
$ ./mach rustc --print sysroot
NOTE: Entering nix-shell /path/to/servo/shell.nix
info: component 'llvm-tools' for target 'x86_64-unknown-linux-gnu' is up to date
/home/me/.rustup/toolchains/nightly-2023-02-01-x86_64-unknown-linux-gnu
Konfiguroi sitten joko sysroot-polku tai proc-makropalvelimen polku tiedostossa .vscode/settings.json:
{
"rust-analyzer.procMacro.enable": true,
"rust-analyzer.cargo.sysroot": "[paste what you copied]",
"rust-analyzer.procMacro.server": "[paste what you copied]/libexec/rust-analyzer-proc-macro-srv",
}
Emacs
Emacsissa on kaksi LSP-asiakasimplementaatiota: eglot, joka on Emacsin sisäänrakennettu paketti, ja emacs-lsp.
Eglot
Komentojen ohittamiseksi meidän on asetettava eglot-workspace-configuration. Luo tätä varten .dir-locals.el-tiedosto Servo-checkoutisi ylätason hakemistoon seuraavalla sisällöllä:
;;; Directory Local Variables -*- no-byte-compile: t; -*-
;;; For more information see (info "(emacs) Directory Variables")
((nil . ((eglot-workspace-configuration
. (:rust-analyzer
(:rustfmt (:overrideCommand ["./mach" "fmt"])
:check (:overrideCommand
["./mach" "clippy" "--message-format=json" "--target-dir" "target/lsp" "--features" "tracing,tracing-perfetto"])
:cargo (:buildScripts
(:overrideCommand
["./mach" "clippy" "--message-format=json" "--target-dir" "target/lsp" "--features" "tracing,tracing-perfetto"]))))))))
Kun olet käynnistänyt eglotin (M-x eglot), voit tarkistaa käytössä olevan workspace-konfiguraation komennolla M-x eglot-show-workspace-configuration.
Tyyliohje
Suurin osa tyylisuosituksistamme pakotetaan automaattisesti lintereillämme. Tässä dokumentissa on ohjeita, joita on vaikeampi lintata.
Paljon Servon koodia kirjoitettiin ennen kuin nämä suositukset hyväksyttiin. Tervetulleita ovat pull requestit, jotka tuovat projektin koodin ajan tasalle nykyaikaisten ohjeiden mukaiseksi.
Rust
Yleisesti ottaen kaikki Servon Rust-koodi formatoidaan automaattisesti rustfmt-työkalulla, kun ajat ./mach fmt, mikä pitäisi kohdistaa koodisi viralliseen Rust Style Guide -oppaaseen.
Lisäksi Rust-koodin pitäisi noudattaa Rust API naming conventions -käytäntöjä.
Nimeämiskäytäntöoppaassa on muutamia epäilmeisiä kohtia, kuten:
get_-etuliitettä ei yleensä käytetä gettereissä Rust-koodissa. Poikkeus tähän sääntöön on, kun sitä käytetäänget()-metodin variantille kutenstd::cell::Cell::get_mut().- Camel case -kirjoituksessa lyhenteet ja yhdys-sanojen supistukset lasketaan yhdeksi sanaksi.
Esimerkiksi structin pitäisi olla nimeltään
HtmlParser, eiHTMLParser.
Sisennys
Monimutkaisten funktioiden ja metodien kulun seuraamisen helpottamiseksi pyrimme minimoimaan sisennystä käyttämällä varhaisia return-lauseita.
Tämä vastaa myös monissa tapauksissa spesifikaatioissa käytettyä kieltä.
Kun funktion logiikka saavuttaa 2 tai 3 sisennystasoa, tai kun lyhyt ehtolohko on poikkeustapaus funktion lopussa, harkitse varhaisen return-lauseen käyttöä.
Varhaiset return-lauseet toimivat hyvin yhdistettynä Option- tai enum-varianttien purkamiseen.
Suosi seuraavaa syntaksia, kun palaat varhaisesti, jos Option-arvo on None:
#![allow(unused)]
fn main() {
let Some(inner_value) = option_value else {
return
};
}
Tämä toimii myös enum-varianttien kanssa:
#![allow(unused)]
fn main() {
enum Pet {
Dog(usize),
Cat(usize),
}
let pet = Pet::Dog(10);
let Pet::Dog(age) = pet else {
return;
};
}
Lyhenteet
Servo noudattaa Google C++ -oppaan nimeämissääntöjä. Vältä lyhenteitä, joita joku projektin ulkopuolella ei tuntisi. Älä lyhennä poistamalla kirjaimia sanojen keskeltä.
Poikkeus::
Voit käyttää joitain yleisesti tunnettuja lyhenteitä, kuten i silmukkaindeksille.
Voit myös käyttää yksittäisiä kirjaimia, kuten T Rust-tyyppiparametreille.
Enum-variantit
Luettavuuden vuoksi vältä enum-varianttien suoraa use-tuontia.
Viittaa sen sijaan enumeihin täydellisellä nimellä (eli Enum::Variant).
Nimeäristiriitojen välttämisen lisäksi tämä auttaa koodia tuntemattomia lukemaan helpommin koodissa käytetyn tyypin.
Kuollut koodi
Lähes kaikissa tapauksissa älä commitoi kuollutta koodia tai kommentoitua koodia repositorioon. Kommentoitu koodi voi bit rot -ilmiön vuoksi rappeutua helposti, eikä kuollutta koodia testata. Kun koodista tulee kuollutta, koska sitä ei käytetä lainkaan, se pitäisi poistaa.
Poikkeus:
Poikkeus on, kun koodi on kuollutta vain joissakin käännöskonfiguraatioissa.
Siinä tapauksessa käytät expect(dead_code) -kääntäjädirektiiviä konfiguraatioqualifierin kanssa.
Esimerkiksi:
#![allow(unused)]
fn main() {
#[cfg_attr(any(target_os = "android", target_env = "ohos"), expect(dead_code))]
pub(crate) const LINE_HEIGHT: f32 = 76.0;
}
Tässä tapauksessa LINE_HEIGHT-vakio käännetyään, mutta sen odotetaan olevan kuollutta Android- tai OpenHarmony-käännöksessä.
unsafe-koodi
Pyri välttämään unsafe-koodia.
Valitettavasti selainmoottori on monimutkainen, joten jonkin verran unsafe-koodia on Servossa väistämätöntä.
Jos joudut tekemään unsafe-funktion, käytä Safety comments -kommentteja, jotka selittävät, miksi lohko on turvallinen ja mitkä turvallisuusinvariantit ovat voimassa.
Käytä harkintaa siitä, milloin lisätä safety-kommentteja funktioiden sisällä oleviin unsafe-lohkoihin.
Assertiot
Kun Servon sisäisen logiikan pitäisi tehdä tietystä ehdosta mahdoton, käytä assert!- tai debug_assert!-lausetta varmistaaksesi sen.
Ajattele assert!-lausetta sekä eräänlaisena testinä että dokumentaationa.
Jos assertiossa ilmaistu invariantti joskus muuttuu epätodeksi, Servo voi alkaa kaatua testejä ajaessa, mikä estää logiikkavirheiden pääsyn koodiin.
Lisäksi koodia lukevat voivat tietää vahvemmin kuin kommentti sallii, mitä kirjoittaja oletti todeksi tietyssä kohdassa.
Jos tietty koodin osa on saavuttamaton, esimerkiksi jos enum-variantti on käsitelty aiemmin eikä sitä pitäisi kohdata myöhemmin samassa funktiossa, käytä unreachable!(), mutta täytä teksti aina sillä, miksi koodi on saavuttamaton.
Option::map ja Result::map/Result::map_err
map-API:ta pitäisi käyttää vain yhden tyypin muuntamiseen toiseen, ei ohjausvirran muodossa.
Suosi match-, if let- tai let/else-rakenteita, kun kirjoitat koodia, joka vaikuttaa vain tiettyyn varianttiin.
unwrap() ja expect()
unwrap-kutsua Option- tai Result-tyypille ei pitäisi lähes koskaan käyttää.
Käsittele sen sijaan None- tai Err-tapaus ja tee tarvittava virheenkäsittely.
Servon ei pitäisi kaatua, kun se on mahdollista.
Jos None tai Err on mahdoton Servon sisäisen logiikan vuoksi joka ei liity ulkoiseen syötteeseen tai crateihin, voit käyttää expect()-kutsua kuten assertiota.
expect()-kutsulle annetun tekstin pitäisi ilmaista, miksi arvo ei voi olla None tai Err.
Poikkeus::
Kun käsitellään Rustin std::sync::Mutex-tyyppiä tai muita samanaikaisuusprimitiivejä, jotka käyttävät poisoning-mekanismia, unwrap-kutsu on sopiva.
todo!() ja unimplemented!()
Saavutettavassa koodissa älä käytä todo!- tai unimplemented!-makroja.
Nämä makrot saavat Servon panikoimaan, eikä normaalin verkkosisällön pitäisi saada Servoa panikoimaan.
Sen sijaan pyri tekemään tällaiset tapaukset saavuttamattomiksi ja palauttamaan asianmukaisia virhearvoja tai yksinkertaisesti jättämään koodin tekemättä mitään.
Makrot
Makrot peittävät toteutustiedot, ja kutsukohdat ovat usein vaikeampia lukea kuin inline Rust-koodi.
Kun mahdollista, suosi geneerisiä/parametrisoituja funktioita macro_rules!-makrojen sijaan.
Ilmoitetut makrot pitäisi yrittää näyttää mahdollisimman paljon inline-kelpoiselta Rust-koodilta.
Poikkeus:
Kun on yleisiä ohjausvirran kuvioita (esim. virheen tai välimuistissa olevan arvon tarkistus ja varhainen paluu), joita ei voi toistaa Result/Option-tyypeillä ja ?-operaattorilla, makrot ovat yksi tapa vähentää toistuvaa boilerplate-koodia.
Poikkeus: Kun monta uniikkia tyyppiä pitää ilmoittaa identtisellä kuviolla, makrot ovat yksi tapa vähentää boilerplate-koodia.
Shell-skriptit
Shell-skriptit sopivat pieniin tehtäviin tai wrappereihin, mutta on parempi käyttää Pythonia kaikkeen, jossa on vähänkin monimutkaisuutta tai yleisesti ottaen.
Shell-skriptit kirjoitetaan bashilla, alkaen tällä shebangilla:
#!/usr/bin/env bash
Huomaa, että macOS:n oletusbash on melko vanha, joten ole varovainen uusien ominaisuuksien kanssa.
Skriptien alussa pitäisi ottaa käyttöön muutama valitsin vankkuuden vuoksi:
set -o errexit
set -o nounset
set -o pipefail
Muista lainata kaikki muuttujat täydellisessä muodossa: "${SOME_VARIABLE}".
Käytä "$(some-command)" backtickien sijaan komentokorvauksessa.
Huomaa, että nämäkin pitäisi lainata.
Servo Book
- Käytä permalinkkejä linkatessasi lähdekoodirepoihin — paina
YGitHubissa saadaksesi pysyvän URL-osoitteen
Markdown-lähde
- Käytä yhtä lausetta per rivi ilman sarakeleveyttä, jotta diffit ja historia ovat helpompia ymmärtää
Lauserivien jakamiseen voit korvata ([.!?]) → $1\n, mutta varo tapauksia kuten “e.g.”.
Yksinkertaisten listojen sisennysten korjaamiseen voit korvata ^([*-] .*\n([* -].*\n)*)([^\n* -]) → $1 $3, mutta tämä ei toimi sisäkkäisille tai monimutkaisemmille listoille.
- Johdonmukaisuuden vuoksi sisennä sisäkkäiset listat kahdella välilyönnillä ja käytä
--merkkiä järjestämättömissä listoissa
Notaatio
- Käytä lihavoitua tekstiä viitattaessa käyttöliittymäelementteihin kuten valikkovalintoihin, esim. “click Inspect”
- Käytä
backtick-merkkejä viitattaessa yksikirjaimisiin näppäimiin, esim. “pressAor Ctrl+A”
Virheilmoitukset
- Kun mahdollista, sisällytä aina linkki dokumentaatioon, Zulip-chatiin tai lähdekoodiin — tämä auttaa säilyttämään alkuperäisen kontekstin ja auttaa meitä tarkistamaan ja päivittämään neuvoamme ajan myötä
Loput virheilmoitusten säännöt on suunniteltu varmistamaan, että teksti on mahdollisimman luettavaa ja että lukija voi liittää virheilmoituksensa find-in-page -hakuun mahdollisimman vähällä väärillä osumilla, ilman että säännöt ovat liian hankalia noudattaa.
Kääri virheilmoitus <pre><samp>-elementteihin, <pre> rivin alussa (ei sisennettynä).
Jos haluat tyylitellä virheilmoituksen lainauksena, kääri se <pre><blockquote><samp>-elementteihin.
<pre> käsittelee rivinvaihdot rivinvaihdoiksi, ja rivin alussa se estää Markdown-syntaksin vahingossa aktivoitumisen, kun virheilmoituksessa on tyhjiä rivejä.
<samp> merkitsee tekstin tietokoneen tuotokseksi, jossa meillä on CSS, joka saa sen rivittymään kuten terminaalissa.
Koodilohkot (<pre><code>) eivät rivity, joten ne voivat tehdä pitkistä virheistä vaikeasti luettavia.
Korvaa jokainen & merkillä &, sitten jokainen < merkillä <.
Teksti <pre>-elementin sisällä ei koskaan käsitellä Markdownina, mutta se on silti HTML-merkkausta, joten se on escapattava.
Tarkista aina renderöity tulos varmistaaksesi, että kaikki symbolit säilyivät.
Saatat huomata, että sinun on yhä escapattava osaa Markdownista \-merkillä, jotta called `Result::unwrap()` on an `Err` value ei renderöidy muodossa called Result::unwrap() on an Err value.
| Virheilmoitus | Markdown |
|---|---|
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: "Could not run `PKG_CONFIG_ALLOW_SYSTEM_CFLAGS=\"1\" PKG_CONFIG_ALLOW_SYSTEM_LIBS=\"1\" \"pkg-config\" \"--libs\" \"--cflags\" \"fontconfig\"` |
|
error[E0765]: ...
--> src/main.rs:2:14
|
2 | println!("```);
| ______________^
3 | | }
| |__^
|
|
Pull requestin tekeminen
Avustukset Servoon tai sen riippuvuuksiin tehdään GitHub pull request -muodossa. Jokainen pull request arvioi ydinavustaja (henkilö, jolla on oikeus landata patcheja), ja se joko landataan pääpuuhun tai siihen annetaan palautetta vaadituista muutoksista. Kaikkien avustusten pitäisi noudattaa tätä muotoa, myös ydinavustajien.
Pull request -tarkistuslista
-
Haaroita
main-haarasta ja tarvittaessa rebasaa haarasimain-haaraan ennen pull requestin lähettämistä. Jos se ei yhdisty siististimain-haaraan, sinua voidaan pyytää rebasaamaan muutoksesi. -
Aja
./mach fmtja./mach test-tidymuutoksellesi. -
Commitit pitäisi olla mahdollisimman pieniä, mutta niin, että jokainen commit on itsenäisesti oikea (eli jokaisen commitin pitäisi kääntyä ja läpäistä testit).
-
Commiteihin liittyy Developer Certificate of Origin -allekirjoitus, joka osoittaa, että sinä (ja tarvittaessa työnantajasi) sitoudutte projektin lisenssin ehtoihin. Gitissä tämä on
git commit-komennon-s-valitsin. -
Jos patchiasi ei arvioida, tai tarvitset tietyn henkilön arvioivan sen, voit @-vastata arvioijalle pyytäen arviointia pull requestissa tai kommentissa, tai pyytää arviointia Servo-chatin kautta.
-
Lisää testit, jotka liittyvät korjattuun bugiin tai uuteen ominaisuuteen. DOM-muutoksessa tämä on yleensä web platform test; asettelussa reftest. Katso testausopas lisätietoja varten.
Pull requestin avaaminen
Ensin pushaa haarasi origin-remoteen.
Seuraavaksi avaa joko onnistuneen pushin palauttama URL aloittaaksesi pull requestin,
tai vieraile Servo-forkissasi selaimessa ja seuraa käyttöliittymän ohjeita.
jdm@pathfinder servo % git push origin issue-12345
Enumerating objects: 43, done.
Counting objects: 100% (43/43), done.
Delta compression using up to 12 threads
Compressing objects: 100% (29/29), done.
Writing objects: 100% (29/29), 5.13 KiB | 5.13 MiB/s, done.
Total 29 (delta 25), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (25/25), completed with 14 local objects.
remote:
remote: Create a pull request for 'issue-12345' on GitHub by visiting:
remote: https://github.com/jdm/servo/pull/new/issue-12345
remote:

Otsikko ja kuvaus
Servossa pull requestien commitit squashataan, ja pull requestin otsikko ja kuvaus käytetään lopullisen commit-viestin luomiseen (esimerkki). On tärkeää, että sekä otsikko että kuvaus kuvaavat muutoksen täysin, koska se tekee commitista hyödyllisen repositorion historian tarkastelijoille ja tekee Servosta terveemmän projektin kokonaisuutena.
Otsikon pitäisi tiiviisti kuvata, mitä muutos tekee. Muutamia vinkkejä:
- Etuliite otsikossa on sen craten nimi pienillä kirjaimilla, jota työstät. Esimerkiksi jos muutos koskee “script”-cratea, etuliite on “script: “. Jos muutos vaikuttaa useisiin crateihin, tunnista, mikä crate on muutoksen ensisijainen “lähde”, tai jätä etuliite pois.
- Otsikot kirjoitetaan imperatiivisena (pyyntö- tai käskylauseena) verbin kanssa. Esimerkiksi “layout: Skip box tree construction when possible.” Vältä geneerisiä verbejä kuten “fix”, “correct” tai “improve” ja kuvaile sen sijaan, mitä korjaus tekee. Koodia voidaan korjata useita kertoja, mutta viestin pitäisi tunnistaa muutos yksilöllisemmin.
- Etuliitteet kirjoitetaan pienillä kirjaimilla, ja otsikon lopun osan pitäisi capitalisoida vain ensimmäinen sana ja erisnimet (kuten tietorakenteiden nimet tai spesifikaatiokäsitteet kuten WebDriver). Epävarmuuden vallitessa seuraa spesifikaatiossa kirjoitettua. Älä käytä “Title Casing for Commit Messages” -tyyliä.
Commit-kuvauksen pitäisi:
- Kuvata alkuperäinen ongelma tai tilanne (linkaten tarvittaessa avoimiin bugeihin).
- Kuvata, miten muutos korjaa ongelman, parantaa koodia tai valmistelee seuraavaa muutosta.
- Selittää muutoksen varaukset, kuten uudet epäonnistuvat testit, suorituskyvyn heikkeneminen tai paljastumattomat reunatapaukset. Keskustele siitä, miten nämä voidaan käsitellä tulevaisuudessa.
- Olla kirjoitettu usean lauseen kappaleina joko yhtenäisellä rivityksellä (80 merkkiä tai vähemmän) tai ilman rivitystä (GitHub tekee tämän automaattisesti).
Oletuspull request -malline sisältää useita kehotteita; täytä ne korvaamalla alkuperäiset ohjeet.
“Testing”-kehotus on erityisen tärkeä, koska se helpottaa arviointiprosessia. Se kysyy:
- Onko muuttuvaa koodia jo kattavia automatisoituja testejä?
- Jos ei, sisältääkö pull request uusia automatisoituja testejä?
- Jos ei, mikä estää vähintään yhden uuden testin lisäämisen?
Jos et tiedä vastausta, kirjoita se ylös! Sen voi aina kirjoittaa uudelleen arvioijan palautteen perusteella.
Arviointikommenttien käsittely
Lisää uusia commiteja haaraan mieluummin kuin muokkaat olemassa olevia commiteja. Tämä helpottaa Servon arvioijien tarkastella vain muutoksia, mikä nopeuttaa pull requestien arviointia.
git commit -s -m "script: Fix deadlock with cross-origin iframes."
git push origin issue-12345
Yhdistämisristiriitojen käsittely
Kun pull requestissa on yhdistämisristiriitoja, yleisimmät tavat käsitellä ne ovat merge ja rebase. Älä paina pull requestin “Update branch” -painiketta; se suorittaa mergen ja estää osan Servon CI-toiminnallisuudesta toimimasta oikein.

Sen sijaan päivitä ensin paikallinen main-haarasi, rebasaa sitten feature-haarasi main-haaran päälle ja force pushaa muutokset.
git checkout issue-12345
git pull --rebase upstream main
git push -f origin issue-12345
Kun rebase kohtaa ristiriitoja, sinun on käsiteltävä ne:
jdm@pathfinder servo % git rebase main issue-12345
Auto-merging components/script/dom/bindings/root.rs
CONFLICT (content): Merge conflict in components/script/dom/bindings/root.rs
Auto-merging components/script/dom/node.rs
error: could not apply 932c8d3e97d... script: Remove unused field from nodes.
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
Seuraa GitHubin dokumentaatiota ristiriitojen ratkaisemisesta.
Testien ajaminen pull requesteissa
Kun pushaat pull requestiin, GitHub tarkistaa automaattisesti, ettei muutoksissasi ole käännös-, lint- tai tidy-virheitä.
Ajaaksesi yksikkötestejä tai Web Platform Tests -testejä pull requestia vastaan, lisää yksi tai useampi alla olevista tunnisteista pull requestiisi. Jos sinulla ei ole oikeutta lisätä tunnisteita pull requestiisi, lisää kommentti bugiin pyytäen niiden lisäämistä.
| Tunniste | Ajaa yksikkötestit | Ajaa web-testit |
|---|---|---|
T-full | Kaikilla alustoilla | Linux |
T-linux-wpt | Linux | Linux |
T-macos | macOS | (ei mitään) |
T-windows | Windows | (ei mitään) |
DevTools-testit ovat kokeellisia eivätkä ole vielä oletuksena käytössä.
On erittäin suositeltavaa, että pull requestit, jotka muokkaavat DevTools-koodia, ajavat ne.
Lisää tätä varten T-linux-devtools-tunniste.
Kuten Web Platform Tests -testeissä, jos sinulla ei ole oikeutta lisätä tunnisteita, pyydä kommentilla niiden lisäämistä.
Testaus
Tämä on tylsää. Mutta PR:ääsi ei hyväksytä ilman testiä.
Servossa on kolmea testityyppiä.
- Koodin formatointitestit (
./mach test-tidy). - Yksikkötestit (
./mach test-unit). - Integraatiotestit (
./mach test-wpt).
Tämän dokumentin painopiste on integraatiotesteissä, mutta haluamme mainita muut testit ensin.
Jokaisen lähetyksen on täytettävä koodin formatointitestit. Suurin osa formatoinnista voidaan tehdä
automaattisesti komennolla ./mach fmt.
Yksikkötestit ovat eri tiedostoissa koko koodikannassa tyypillisillä rust #[cfg(test)]- ja
#[test]-annotaatioilla. Yksikkötestit ajetaan komennolla ./mach test-unit. Esimerkkikutsuja:
# Run all unit tests in the net crate
./mach test-unit -p servo-net
# Run a specific unit test in the net crate
./mach test-unit -p servo-net test_fetch_response_is_not_network_error
Koko testisarjan ajaminen voi olla hyvin muistia kuluttavaa; voit lieventää tätä käyttäytymistä
rajoittamalla käännettävien cratejen määrää komennolla ./mach test-unit -j 4.
Integraatiotestit
Testit sijaitsevat tests-hakemistossa.
Huomaat, että siellä on paljon tiedostoja, joten oikean sijainnin löytäminen testillesi ei aina ole ilmeistä.
Katso ensin “Testing”-osio komennossa ./mach --help ymmärtääksesi eri testikategoriat.
Löydät myös joitain update-*-komentoja.
Niitä käytetään odotettujen tulosten listan päivittämiseen.
Testin ajaminen:
./mach test-wpt tests/wpt/yourtest
Uuden testin lisääminen
Jos sinun on luotava uusi testitiedosto, sen pitäisi sijaita hakemistossa tests/wpt/mozilla/tests tai hakemistossa tests/wpt/tests, jos se ei riipu vain Servo-ominaisuuksista.
Sinun on sitten päivitettävä testien lista ja odotettujen tulosten lista:
./mach test-wpt --manifest-update
Testin debuggaus
Katso debuggausopas aloittaaksesi Servon debuggauksen.
Web Platform Tests (tests/wpt)
Tämä kansio sisältää Web Platform Tests -testit ja koodin, jota tarvitaan niiden integroimiseen Servoon. Lisäksi on WebGPU- ja WebGL-testejä, jotka on tuotu ja muunnettu Web Platform Test -tyylisiksi testeiksi.
tests/wpt-hakemiston sisältö
Erityisesti tämä kansio sisältää:
config.ini: konfiguraatio Web Platform Tests -testeilleinclude.ini: Web Platform Tests -testien osajoukko, jota ajamme tällä hetkellätests: Web Platform Tests -testien kopio repossameta: odotetut epäonnistumiset ajamillemme Web Platform Tests -testeillemozilla: Web Platform Test -tyylisiä testejä, joita ei voi upstreamatawebgl: tuodut WebGL-testitwebgpu: tuodut WebGPU-testit (katso WebGPU -luku lisätietoja varten)
Web Platform Tests -testien ajaminen
Yksinkertaisin tapa ajaa Web Platform Tests -testit Servossa on ./mach test-wpt juurihakemistossa.
Tämä ajaa include.ini-tiedostossa määritellyn JavaScript-testien osajoukon ja kirjaa tulosteen stdoutiin.
Testien osajoukkoa voi ajaa antamalla positionaalisia argumentteja mach-komennolle joko tiedostojärjestelmäpolkuina tai testi-URL:ina, esim.
./mach test-wpt tests/wpt/tests/dom/historical.html
ajaaksesi testin dom/historical.html, tai
./mach test-wpt dom
ajaaksesi kaikki DOM-testit.
Test harness hyväksyy myös suuren määrän komentorivivalitsimia; ne on dokumentoitu ajamalla --help.
WPT-testien ajaminen debug-käännöksellä johtaa usein timeouteihin.
Sen sijaan harkitse kääntämistä komennolla mach build -r ja testaamista komennolla mach test-wpt -r.
Web Platform Tests -testien ajaminen GitHub-forkissasi
Vaihtoehtoisesti voit suorittaa testit GitHubin isännöimillä runnereilla komennolla mach try.
Yleensä mach try linux-wpt (kaikki testit, linux) riittää.
Voit tarkastella ajotuloksia forkissasi “Actions”-välilehdeltä. Epäonnistuneet tehtävät sisältävät listan vakaista odottamattomista tuloksista lokin lopussa. Odottamattomat tulokset, jotka ovat tunnetusti intermittentejä, voidaan todennäköisesti jättää huomiotta.
Kun avaat PR:n, voit sisällyttää linkin ajoon. Muuten arvioijat ajavat testit uudelleen.
Web Platform Test -odotusten päivittäminen
Kun korjaat bugin, joka muuttaa testin tulosta, kyseisen testin odotetut tulokset on muutettava.
Tämä voidaan tehdä manuaalisesti muokkaamalla .ini-tiedostoa meta-kansiossa, joka vastaa testiä.
Poista tässä tapauksessa viittaukset testeihin, joiden odotus on nyt PASS, ja poista .ini-tiedostot, jotka eivät enää sisällä odotuksia.
Kun tarvitaan suurempi määrä muutoksia, prosessi voidaan automatisoida:
./mach test-wpt --update-expectations path/to/tests/
Voit myös päivittää testiodotukset CI:llä suoritetuista Try-ajoista. Jokainen CI-ajo tallentaa automaattisesti .log-tiedoston, jonka voit antaa update-wpt-komennolle:
./mach update-wpt https://github.com/servo/servo/actions/runs/<ID-OF-CI-RUN>
Kaikkien Web Platform Tests -testien ajaminen paikallisesti kestää kauan ja aiheuttaa usein liittymättömiä epäonnistumisia (kuten runnerin ylittäessä järjestelmän maksimimäärän avoimia tiedostoja). Testiodotukset asetetaan myös Servon CI-koneiden tulosten perusteella, joten ympäristösi erot voivat aiheuttaa epäonnistumisia.
Sinulla on yleensä karkea käsitys siitä, missä muutoksiisi liittyvät testit ovat.
Esimerkiksi lähes kaikki SubtleCrypto -koodin testit ovat WebCryptoAPI -hakemistossa.
Tässä tapauksessa voit ajaa vain nämä testit komennolla ./mach test-wpt WebCryptoAPI, ja sitten ./mach update-wpt kuten yllä kuvataan.
Varmistaaksesi, ettei muita testejä rikkoutunut, tee sen jälkeen try run.
WebGPU-odotusten päivittämiseen katso WebGPU -luku.
Web Platform Tests -testien muokkaaminen
Katso Web Platform Test -testien Writing Tests guide testien kirjoittamiseen. Yleisesti hyvä tapa aloittaa on seurata näitä vaiheita:
- Etsi hakemisto, joka testaa haluamaasi ominaisuutta.
- Etsi hakemistosta testi, joka testaa samankaltaista käyttäytymistä, kopioi testi sopivalla nimellä ja tee muutoksesi.
- Jos testi on reference test, kopioi myös referenssi, jos sen pitää muuttua, seuraten muokkaamasi hakemiston nimeämiskäytäntöä.
- Aja
./mach update-manifestpäivittääksesi WPT-manifestin uusilla testeillä.
Sinun on myös ajettava ./mach update-manifest aina, kun muokkaat testiä, referenssiä tai tukitiedostoa.
Kaikki muutokset repossa oleviin Web Platform Tests -testeihin upstreamataan automaattisesti, kun PR:si mergeataan.
Servo-spesifiset testit
mozilla-hakemisto sisältää testejä, joita ei voi upstreamata jostain syystä (esim. koska ne riippuvat Servo-spesifisistä API:sta), sekä joitain legacy-testejä, jotka pitäisi upstreamata jossain vaiheessa.
Kun ne ajetaan, ne mountataan palvelimelle polkuun /_mozilla/.
Reftest-tulosten analysointi
Reftest-tuloksia voi analysoida raakalokitiedostosta.
Luo se ajamalla --log-raw-valitsimella, esim.
./mach test-wpt --log-raw wpt.log
Tämän tiedoston voi syöttää reftest analyzer -työkalulle, joka näyttää kaikki epäonnistuneet testit (ei vain niitä, joilla on odottamaton tulos). Huomaa, että tämä syö lokit eri muodossa kuin työkalun alkuperäinen versio, joka on kirjoitettu gecko-reftesteille.
Reftest analyzer mahdollistaa testin ja referenssin kuvakaappausten vertailun pikselitasolla.
Testit, jotka sekä epäonnistuvat että joilla on odottamaton tulos, on merkitty !-merkillä.
WPT-manifestin päivittäminen
MANIFEST.json voidaan regeneroida automaattisesti mach-komennolla update-manifest, esim.
./mach update-manifest
Tämä on ekvivalentti ajolle
./mach test-wpt --manifest-update SKIP_TESTS
DevTools-testien ajaminen
Yksinkertaisin tapa ajaa DevTools-testit Servossa on ./mach test-devtools juurihakemistosta.
Tämä ajaa kaikki devtools_tests/test_*.py-tiedostoissa määritellyt testit. Kaikki DevTools-liittyvät testitiedostot ovat hakemistossa python/servo/devtools_tests.
Vaihtoehtoja web platform tests -testien ajamiseen
Web platform tests -testejä voi ajaa myös muilla tavoilla. Näitä ei suositella tyypillisissä kehitystyönkuluissa, koska ne vaativat mukautetun asennuksen. Joskus näitä ajoja tarvitaan kuitenkin monimutkaisten vuorovaikutusten debuggaamiseen.
Web Platform Tests -testien ajaminen ulkoisella palvelimella
Normaalisti wptrunner käynnistää oman WPT-palvelimensa, mutta joskus saatat haluta ajaa useita mach test-wpt -instansseja, esimerkiksi debugatessasi yhtä testiä samalla kun ajat koko sarjaa taustalla, tai kun ajat yhtä testiä monta kertaa rinnakkain (–processes toimii vain eri testien välillä).
Tämä johtaisi “Failed to start HTTP server” -virheisiin, koska vain yksi WPT-palvelin voi olla kerrallaan käynnissä. Korjaa näin:
- Seuraa vaiheita kohdassa Web-testien manuaalinen ajaminen
- Lisää
breakkohtaan start_servers in serve.py seuraavasti:
--- a/tests/wpt/tests/tools/serve/serve.py
+++ b/tests/wpt/tests/tools/serve/serve.py
@@ -746,6 +746,7 @@ def start_servers(logger, host, ports, paths, routes, bind_address, config,
mp_context, log_handlers, **kwargs):
servers = defaultdict(list)
for scheme, ports in ports.items():
+ break
assert len(ports) == {"http": 2, "https": 2}.get(scheme, 1)
# If trying to start HTTP/2.0 server, check compatibility
- Aja
mach test-wptniin monta kertaa kuin tarvitset
Jos saat odottamattomia TIMEOUT-virheitä testharness-testeissä, custom testharnessreport.js on ehkä asennettu väärin (katso Web-testien manuaalinen ajaminen lisätietoja varten).
Web Platform Tests -testien manuaalinen ajaminen
(Katso myös upstream README:n relevantti osio.)
On hyödyllistä ajaa testi ilman test runnerin häiriötä, esimerkiksi käyttäessä debuggeria kuten gdb.
Tätä varten WPT-palvelin on käynnistettävä manuaalisesti, mikä vaatii lisäkonfiguraatiota.
Lisää ensin seuraava järjestelmän hosts-tiedostoon:
127.0.0.1 www.web-platform.test
127.0.0.1 www1.web-platform.test
127.0.0.1 www2.web-platform.test
127.0.0.1 web-platform.test
127.0.0.1 xn--n8j6ds53lwwkrqhv28a.web-platform.test
127.0.0.1 xn--lve-6lad.web-platform.test
Siirry hakemistoon tests/wpt/web-platform-tests tämän osion loppuosaa varten.
Normaalisti wptrunner asentaa Servon version testharnessreport.js:stä, mutta kun WPT-palvelin käynnistetään manuaalisesti, saamme oletusversion, joka ei raportoi testituloksia oikein. Korjaa näin:
- Luo hakemisto
local-resources - Kopioi
tools/wptrunner/wptrunner/testharnessreport-servo.js→local-resources/testharnessreport.js - Muokkaa
local-resources/testharnessreport.jskorvaten muuttujat seuraavasti:
%(output)d- →
1jos haluat leikkiä testillä interaktiivisesti (≈ pause-after-test) - →
0jos et välitä siitä (vaikka1on ok aina)
- →
%(debug)s→true
- Luo
./config.jsonseuraavasti (katsotools/wave/config.default.jsonoletuksia varten):
{"aliases": [{
"url-path": "/resources/testharnessreport.js",
"local-dir": "local-resources"
}]}
Käynnistä palvelin komennolla ./wpt serve.
Tarkistaaksesi, asennettiinko testharnessreport.js oikein:
- Komennon
curl http://web-platform.test:8000/resources/testharnessreport.jsstandarditulosteen pitäisi näyttää testharnessreport-servo.js:ltä, ei the default testharnessreport.js:ltä - Komennon
target/release/servo http://web-platform.test:8000/css/css-pseudo/highlight-pseudos-computed.htmlstandardituloste (tai mikä tahansa testharness test) pitäisi sisältää rivit, jotka alkavat:TEST STARTTEST STEPTEST DONEALERT: RESULT:
Estääksesi selaimen SSL-varoitukset HTTPS-testejä ajaessa paikallisesti, sinun on ajettava Servo valitsimella --certificate-path resources/cert-wpt-only.
Web Platform Tests -testien ajaminen Firefoxissa
Testien parissa työskennellessä saatat haluta vertailla Servon tulosta Firefoxiin.
Voit antaa --product firefox sekä polun Firefox-binääriin (sekä muutamia muita asioita) ajaaaksesi testejä Firefoxissa Servo-checkoutistasi:
GECKO="$HOME/projects/mozilla/gecko"
GECKO_BINS="$GECKO/obj-firefox-release-artifact/dist/Nightly.app/Contents/MacOS"
./mach test-wpt dom --product firefox --binary $GECKO_BINS/firefox --certutil-binary $GECKO_BINS/certutil --prefs-root $GECKO/testing/profiles
Debuggaus
Yksi yksinkertaisimmista tavoista debugata Servoa on tulostaa kiinnostavia muuttujia println!-, eprintln!- tai dbg!-makroilla.
Yleensä niitä tulisi käyttää vain tilapäisesti; sinun täytyy poistaa ne tai muuntaa ne kunnolliseksi debug-lokituksesi ennen kuin pull request yhdistetään.
Debug-lokitus log-kirjastolla ja RUST_LOG-muuttujalla
Servo käyttää log-kirjastoa pitkäaikaiseen debug-lokitukseen ja virheviesteihin:
#![allow(unused)]
fn main() {
log::error!("hello");
log::warn!("hello");
log::info!("hello");
log::debug!("hello");
log::trace!("hello");
}
Toisin kuin println!-kaltaiset makrot, log lisää aikaleiman ja kertoo, mistä viesti tuli:
[2024-05-01T09:07:42Z ERROR servoshell::app] hello
[2024-05-01T09:07:42Z WARN servoshell::app] hello
[2024-05-01T09:07:42Z INFO servoshell::app] hello
[2024-05-01T09:07:42Z DEBUG servoshell::app] hello
[2024-05-01T09:07:42Z TRACE servoshell::app] hello
Voit suodattaa log-kirjaston tulostetta RUST_LOG-muuttujalla tason (off, error, warn, info, debug, trace) ja/tai viestin lähteen, eli niin sanotun „targetin”, mukaan.
Yleensä target on Rust-moduulin polku kuten servoshell::app, mutta on myös erityisiä targeteja (ks. § Tapahtumien jäljittäminen).
Aseta RUST_LOG lisäämällä se komennon eteen tai käyttämällä export-komentoa:
$ RUST_LOG=warn ./mach run -d test.html # Uses the prepended RUST_LOG.
$ export RUST_LOG=warn
$ ./mach run -d test.html # Uses the exported RUST_LOG.
Katso env_logger-dokumentaatiosta lisätietoja, mutta tässä muutamia esimerkkejä:
- ota käyttöön kaikki viestit
debug-tasolle asti, mutta eitrace-tasoa:RUST_LOG=debug - ota käyttöön kaikki viestit kohteista
servo::*,servoshell::*tai mistä tahansa targetista, joka alkaaservo:RUST_LOG=servo=trace(tai pelkkäRUST_LOG=servo) - ota käyttöön kaikki viestit kohteista, jotka alkavat
style, mutta vainerror- jawarn-viestit kohteestastyle::rule_tree:RUST_LOG=style,style::rule_tree=warn
Huomaa, että vaikka lokiviesti suodatetaan pois, se voi silti vaikuttaa suorituskykyyn, vaikkakin vain hieman.
Eräät käännökset Servosta, mukaan lukien viralliset yöjulkaisut, poistavat DEBUG- ja TRACE-viestit käännösaikana, joten niiden ottaminen käyttöön RUST_LOG-muuttujalla ei vaikuta mihinkään.
Tapahtumien jäljittäminen
Constellationissa, compositorissa ja servoshellissä lokataan muihin komponentteihin lähetetyt ja niistä vastaanotetut viestit targeteilla muodossa component>other@Event tai component<other@Event.
Tämä tarkoittaa, että voit valita ajonaikaisesti, mitä tapahtumatyyppejä lokataan RUST_LOG-muuttujalla!
Esimerkiksi constellationissa (lisätietoja):
- jäljitä vain scriptin tapahtumat:
RUST_LOG='constellation<=off,constellation<script@' - jäljitä kaikki tapahtumat paitsi ReadyToPresent-tapahtumat:
RUST_LOG='constellation<,constellation<compositor@ReadyToPresent=off' - jäljitä vain scriptin InitiateNavigateRequest-tapahtumat:
RUST_LOG='constellation<=off,constellation<script@InitiateNavigateRequest'
Compositorissa (lisätietoja):
- jäljitä vain MoveResizeWebView-tapahtumat:
RUST_LOG='compositor<constellation@MoveResizeWebView' - jäljitä kaikki tapahtumat paitsi Forwarded-tapahtumat:
RUST_LOG=compositor<,compositor<constellation@Forwarded=off
Servoshellissä (lisätietoja):
- jäljitä vain servon tapahtumat:
RUST_LOG='servoshell<=off,servoshell>=off,servoshell<servo@' - jäljitä kaikki tapahtumat paitsi AxisMotion-tapahtumat:
RUST_LOG='servoshell<,servoshell>,servoshell<winit@WindowEvent(AxisMotion)=off' - jäljitä vain winitin ikkunan siirto -tapahtumat:
RUST_LOG='servoshell<=off,servoshell>=off,servoshell<winit@WindowEvent(Moved)'
Tapahtumien jäljittäminen voi tuottaa valtavan määrän tulostetta. Yleensä suosittelemme seuraavaa konfiguraatiota, jotta tuloste pysyy käyttökelpoisena:
constellation<,constellation>,constellation<compositor@ForwardEvent(MouseMoveEvent)=off,constellation<compositor@LogEntry=off,constellation<compositor@ReadyToPresent=off,constellation<script@LogEntry=offcompositor<,compositor>servoshell<,servoshell>,servoshell<winit@DeviceEvent=off,servoshell<winit@MainEventsCleared=off,servoshell<winit@NewEvents(WaitCancelled)=off,servoshell<winit@RedrawEventsCleared=off,servoshell<winit@RedrawRequested=off,servoshell<winit@UserEvent(WakerEvent)=off,servoshell<winit@WindowEvent(CursorMoved)=off,servoshell<winit@WindowEvent(AxisMotion)=off
Muu debug-lokitus
mach run tekee tämän automaattisesti, mutta tulosta backtrace, kun Servo panikoi:
$ RUST_BACKTRACE=1 target/debug/servo test.html
Käytä -Z (-- --debug) ottaaksesi debug-asetukset käyttöön.
Esimerkiksi tulosta stacking context -puu jokaisen layoutin jälkeen tai hae apua näihin asetuksiin:
$ ./mach run -Z stacking-context-tree test.html
$ ./mach run -Z help # Lists available debug options.
$ ./mach run -- --debug help # Same as above: lists available debug options.
$ ./mach run --debug # Not the same! This just chooses target/debug.
Vaihtoehtoisesti voit käyttää SERVO_DIAGNOSTICS-ympäristömuuttujaa diagnostiikka-asetusten määrittämiseen.
$ SERVO_DIAGNOSTICS=style-tree ./mach run test.html
$ SERVO_DIAGNOSTICS=help ./mach run # Lists available debug options.
$ export SERVO_DIAGNOSTICS=style-tree,display-list
$ ./mach run test.html # Uses the exported SERVO_DIAGNOSTICS.
SERVO_DIAGNOSTICS-ympäristömuuttuja hyväksyy pilkuilla erotetut diagnostiikka-asetukset, samat kuin -Z-valinnan kautta saatavilla olevat.
Tämä ominaisuus on saatavilla vain debug- ja release-käännöksissä, ei production-käännöksissä.
macOS:llä voit myös lisätä Cocoa-spesifisiä debug-asetuksia ylimääräisen ---merkitsimen jälkeen:
$ ./mach run -- test.html -- -NSShowAllViews YES
Servoshellin ajaminen debuggerilla
Aja servoshell debuggerilla käyttämällä --debugger-cmd-valintaa.
Huomaa, että jos valitset gdb tai lldb, käytämme automaattisesti rust-gdb:tä ja rust-lldb:tä.
$ ./mach run --debugger-cmd=gdb test.html # Same as `--debugger-cmd=rust-gdb`.
$ ./mach run --debugger-cmd=lldb test.html # Same as `--debugger-cmd=rust-lldb`.
Välittääksesi debuggerille lisäasetuksia sinun täytyy ajaa debugger itse:
$ ./mach run --debugger-cmd=gdb -ex=r test.html # Passes `-ex=r` to servoshell.
$ rust-gdb -ex=r --args target/debug/servo test.html # Passes `-ex=r` to gdb.
$ ./mach run --debugger-cmd=lldb -o r test.html # Passes `-o r` to servoshell.
$ rust-lldb -o r -- target/debug/servo test.html # Passes `-o r` to lldb.
$ ./mach run --debugger-cmd=rr -M test.html # Passes `-M` to servoshell.
$ rr record -M target/debug/servo test.html # Passes `-M` to rr.
Monet debuggerit tarvitsevat lisäasetuksia erottamaan servoshellin argumentit omista valinnoistaan, ja --debugger-cmd välittää nämä asetukset automaattisesti muutamille debuggereille, mukaan lukien gdb ja lldb.
Muille debuggereille --debugger-cmd toimii vain, jos debugger ei tarvitse ylimääräisiä asetuksia:
$ ./mach run --debugger-cmd=rr test.html # Good, because it’s...
# servoshell arguments ^^^^^^^^^
$ rr target/debug/servo test.html # equivalent to this.
# servoshell arguments ^^^^^^^^^
$ ./mach run --debugger-cmd=renderdoccmd capture test.html # Bad, because it’s...
# renderdoccmd arguments? ^^^^^^^
# servoshell arguments ^^^^^^^^^
$ renderdoccmd target/debug/servo capture test.html # equivalent to this.
# => target/debug/servo is not a valid command.
$ renderdoccmd capture target/debug/servo test.html # Good.
# ^^^^^^^ renderdoccmd arguments
# servoshell arguments ^^^^^^^^^
Debuggaus gdb:llä tai lldb:llä
Etsi funktio nimen tai regexin perusteella:
(lldb) image lookup -r -n <name>
(gdb) info functions <name>
Listaa käynnissä olevat säikeet:
(lldb) thread list
(lldb) info threads
Muita gdb- tai lldb-komentoja:
(gdb) b a_servo_function # Add a breakpoint.
(gdb) run # Run until breakpoint is reached.
(gdb) bt # Print backtrace.
(gdb) frame n # Choose the stack frame by its number in `bt`.
(gdb) next # Run one line of code, stepping over function calls.
(gdb) step # Run one line of code, stepping into function calls.
(gdb) print varname # Print a variable in the current scope.
Katso tätä gdb-oppasta tai tätä lldb-oppasta lisätietoja varten.
Voit tarkastella muuttujia lldb:ssä myös kirjoittamalla gui ja käyttämällä nuolinäppäimiä muuttujien laajentamiseen:
(lldb) gui
┌──<Variables>───────────────────────────────────────────────────────────────────────────┐
│ ◆─(&mut gfx::paint_task::PaintTask<Box<CompositorProxy>>) self = 0x000070000163a5b0 │
│ ├─◆─(msg::constellation_msg::PipelineId) id │
│ ├─◆─(url::Url) _url │
│ │ ├─◆─(collections::string::String) scheme │
│ │ │ └─◆─(collections::vec::Vec<u8>) vec │
│ │ ├─◆─(url::SchemeData) scheme_data │
│ │ ├─◆─(core::option::Option<collections::string::String>) query │
│ │ └─◆─(core::option::Option<collections::string::String>) fragment │
│ ├─◆─(std::sync::mpsc::Receiver<gfx::paint_task::LayoutToPaintMsg>) layout_to_paint_port│
│ ├─◆─(std::sync::mpsc::Receiver<gfx::paint_task::ChromeToPaintMsg>) chrome_to_paint_port│
└────────────────────────────────────────────────────────────────────────────────────────┘
Jos lldb kaatuu tietyillä riveillä, joissa on profile()-funktio, et ole ainoa.
Kommentoi profilointikoodi pois ja pidä vain sisäinen funktio — sen pitäisi riittää.
Kääntävä debuggaus rr:llä (vain Linux)
rr on kuin gdb, mutta sen avulla voit kelata taaksepäin. Aloita ajamalla servoshell rr:n kautta:
$ ./mach run --debugger=rr test.html # Either this...
$ rr target/debug/servo test.html # ...or this.
Toista sitten jälki ja käytä gdb- tai rr-komentoja:
$ rr replay
(rr) continue
(rr) reverse-cont
Aja yksi tai useampi testi toistuvasti, kunnes tulos on odottamaton:
$ ./mach test-wpt --chaos path/to/test [path/to/test ...]
rr:n tallentamat jäljet voivat viedä paljon tilaa.
Poista ne hakemistosta ~/.local/share/rr.
OpenGL-debuggaus RenderDocilla (vain Linux tai Windows)
RenderDoc mahdollistaa Servon OpenGL-toiminnan debuggauksen. Aloita ajamalla servoshell renderdoccmd:n kautta:
$ renderdoccmd capture -d . target/debug/servo test.html
Kun servoshell on käynnissä, aja qrenderdoc ja valitse File > Attach to Running Instance.
Kun yhteys on muodostettu, voit painaa F12 tai Print Screen kaapataksesi ruudun.
Debuggaus OpenHarmonylla
On suositeltavaa lukea ensin yleiset ohjeet Debuggaus-osiosta. Tämä osio käsittelee vain OpenHarmonyyn liittyviä eroja.
Servoshellin käynnistäminen komentoriviltä
Debuggauksessa on usein hyödyllistä käynnistää servo komentoriviltä sovelluskuvakkeen sijaan, koska voimme välittää parametreja komentoriviltä.
# Run this command to see which parameters can be passed to an ohos app
hdc shell aa start --help
# Start servo from the commandline
hdc shell aa start -a EntryAbility -b org.servo.servo
# --ps=<arg> <value> can be used to pass arguments with values to servoshell.
# The space between arg and value is mandatory when using `--ps`, meaning `--ps=--log-filter warn` is
# correct while `--ps=--log-filter=warn` is not.
# For pure flags without a value use `--psn <flag>`
hdc shell aa start -a EntryAbility -b org.servo.servo --ps=--log-filter "warn"
# Use `-U <url>` to let servo load a custom URL.
hdc shell aa start -a EntryAbility -b org.servo.servo -U https://servo.org
Lokitus
OpenHarmony-laitteilla lokiviestit voidaan tallentaa ja hakea hilog-palvelun kautta:
# See the hilog help for a full list of arguments supported by hilog
hdc shell hilog --help
# View all logs (very verbose, includes all other apps)
hdc shell hilog
# All servo and Spidermonkey related logs
hdc shell hilog --domain=0xE0C3,0xE0C4
# Only Rust code from servo
hdc shell hilog --domain=0xE0C3
# Only spidermonkey C++ code
hdc shell hilog --domain=0xE0C4
# Filter by domain and log level
hdc shell hilog --domain=0xE0C3 --level=ERROR
Lokitaso
Riippuu useista ehdoista, näkyvätkö lokiviestit:
log-kirjaston käännösaikainen maksimilokitaso. Katso log compile-time filters. Huom:log-kirjastonrelease_max_level_<level>-ominaisuudet tarkistavat, onkodebug_assertions = falseasetettu määrittääkseen, sovelletaanko release-suodattimia.- Ajonaikainen
log-kirjaston globaali suodatin moduuleittain, joka on asetettu servoshellissä. Koska ympäristömuuttujat eivät ole vaihtoehto lokitason mukauttamiseen,servoshell:lla on--log-filter-valinta ohos-kohteilla, joka mahdollistaalog-kirjaston lokisuodattimen mukauttamisen. Oletuksena servoshell asettaa lokisuodattimen, joka piilottaa lokiviestit monista crateista, joten todennäköisesti joudut asettamaan mukautetun log-filterin, jos et näe debuggaamasi craten lokeja. hilog-palvelun peruslokisuodatin.hdc shell hilog --base-level=<log_level>. Voidaan yhdistää--domain- ja--tag- valintoihin mukauttaaksesi mitkä lokit tallennetaan.hilog-palvelun lokisuodatin lokeja näytettäessä:hdc shell hilog --level=<level>
Useimmiten vaihtoehtoja 2 ja/tai 4 tulisi käyttää, koska ne mahdollistavat nopeat muutokset ilman uudelleenkääntämistä.
Hilog-domainit
hilog mahdollistaa mukautetun kokonaisluvun „domain” (välillä 0–0xFFFF) asettamisen lokittaessa, mikä helpottaa lokien suodattamista domainin mukaan.
Servon Rust-koodissa, joka lokataan log-kirjaston kautta, käytämme domainia 0xE0C3 ja Spidermonkeyn C++-koodissa domainia 0xE0C4.
Nämä arvot on valittu melko mielivaltaisesti.
Hilog-yksityisyysominaisuus
hilog:lla on yksityisyysominaisuus, joka oletuksena piilottaa arvot lokeissa (esim. %d- tai %s-korvausten kohdalla).
Rustin lokiviestit eivät yleensä ole tämän vaikutuksen alaisia, koska merkkijonojen muotoilu tehdään Rust-puolella.
Jos kohtaat tämän ongelman C/C++-lokeja katsellessa, voit poistaa yksityisyysominaisuuden väliaikaisesti käytöstä ajamalla:
hdc shell hilog -p off
DevTools ja porttien välitys
Voit ottaa DevTools-palvelimen käyttöön ja yhdistää siihen etänä Firefoxilla. Helpoin tapa on komentorivi:
hdc shell aa start -a EntryAbility -b org.servo.servo --psn=--devtools=6080
Yhdistääksesi Servo-instanssiin sinun täytyy välittää portti komennolla
hdc fport tcp:6080 tcp:6080. Sinun pitäisi nähdä viesti, että välitys onnistui. Nyt voit
yhdistää DevTools-palvelimeen osoitteella localhost:6080.
Profilointi
Kun profiloit Servoa tai vianmetsästät suorituskykyongelmia, varmista, että käännöksesi on optimoitu mutta silti sallii tarkan profilointidatan.
./mach build --profile profiling --with-frame-pointer
- –profile profiling kääntää Servon profilointikonfiguraatiollamme
- –with-frame-pointer kääntää Servon pinot-kehyspointtereilla kaikilla alustoilla
Vastaava profiili on valittava Servoa ajettaessa:
./mach run --profile profiling http://example.org
Useita tapoja saada profilointitietoa Servon ajoista:
Tracing Perfetton kanssa
Tracing toimii instrumentoimalla tiettyjä funktioita (tai koodin osia) eksplisiittisillä annotaatioilla kuten time_profile! ja servo_tracing::*.
Se tallentaa deterministisesti jokaisen kutsun instrumentoidun koodin läpi, mutta ei tarjoa näkyvyyttä koodiin, jota ei ole instrumentoitu.
Sitä vastoin sampling-profilerit näkevät kaiken, mutta vain probabilistisesti, ja tarkentuvat siten pidemmillä silmukoilla.
Tracingin käyttöön ota käyttöön liittyvät compile-time-ominaisuudet:
./mach build --profile profiling --features tracing tracing-perfetto
Aja sitten Servo SERVO_TRACING-ympäristömuuttujalla, joka on asetettu EnvFilter directives -direktiiveihin valitaksesi, mitkä trace:t otetaan käyttöön:
SERVO_TRACING=… ./mach run --profile profiling http://example.org
Esimerkiksi:
SERVO_TRACING=offpoistaa kaiken tracingin käytöstä (tämä on oletus)SERVO_TRACING=traceottaa kaiken tracingin käyttöön (tuottaa valtavia trace-tiedostojacompositing-moduulin vuoksi)SERVO_TRACING=[{servo_profiling}]tekee saman, koska suodatamme implisiittisestiservo_profiling-arvollaSERVO_TRACING=infoottaisi käyttöön vaininfo-tason ja yläpuolella olevat, mutta emme vielä käytä tasojaSERVO_TRACING=layoutottaa tracingin käyttöön vainlayout-cratessaSERVO_TRACING=trace,compositing=offottaa kaiken tracingin käyttöön paitsicompositing-cratessaSERVO_TRACING=[handle_reflow]ottaa tracingin käyttöön spaneissa nimeltä “handle_reflow” tai niiden jälkeläisissä
Tämä luo servo.pftrace-tiedoston nykyiseen hakemistoon, jota voi visualisoida osoitteessa ui.perfetto.dev.
Interval Profiling
Käyttämällä -p-valitsinta ja sen jälkeen numeroa (aikajakso sekunteina) voit tulostaa profilointitietoa terminaaliin säännöllisesti.
Tätä varten aja Servo halutulla sivustolla (URL-osoitteet ja paikalliset tiedostopolut molemmat tuettuja) profilointi käytössä:
./mach run --profile profiling http://example.org -p 5
Yllä olevassa esimerkissä, kun Servo on yhä käynnissä (JA käsittelee uusia pass-vaiheita), profilointitieto tulostetaan terminaaliin 5 sekunnin välein.
Kun sivu on ladattu, paina ESC (tai sulje sovellus) poistuaksesi. Profilointituloste tarjotaan jaoteltuna selainmoottorin alueisiin ja URL:ään. Esimerkiksi saatat saada alla olevan muotoisen tulosteen:
_category_ _incremental?_ _iframe?_ _url_ _mean (ms)_ _median (ms)_ _min (ms)_ _max (ms)_ _events_
Painting N/A N/A N/A 6.8177 0.9512 0.0035 30.7573 6
Layout yes yes http://example.org/ 0.0016 0.0016 0.0016 0.0016 1
Layout no yes http://example.org/ 14.4966 14.4966 14.4966 14.4966 1
ScriptParseHTML no yes http://example.org/ 0.8507 1.7009 0.0004 1.7009 2
TimeToFirstPaint no yes http://example.org/ 0.0000 0.0000 0.0000 0.0000 1
TimeToFirstContentfulPaint no yes http://example.org/ 0.0000 0.0000 0.0000 0.0000 1
_url_ _blocked layout queries_
Tässä esimerkissä sivun latauksessa suoritimme yhden täyden asettelun ja yhden inkrementaalisen asettelun.
TSV Profiling
Käyttämällä -p-valitsinta ja sen jälkeen tiedostonimeä voit tulostaa Servon suorituksen profilointitiedot TSV-tiedostoon (tab-separated, koska tietyt url:t sisältävät pilkkuja).
Tiedot kirjoitetaan tiedostoon vasta Servon lopettamisen yhteydessä.
Tämä toimii hyvin -x-, -z- ja -o-valitsimien kanssa, jotta suorituskykytietoa voidaan kerätä automatisoiduissa ajoissa.
Esimerkkikäyttö:
./mach run --profile profiling http://example.org -zxo out.png -p out.tsv
Interval- ja TSV Profiling -valintojen profilointitiedon formaatit ovat käytännössä samat; url-nimiä ei katkaista TSV Profiling -valinnossa.
Generating Timelines
Lisää --profiler-trace-path /timeline/output/path.html -lippu tulostaaksesi profilointidatan itse sisältävänä HTML-aikajanana.
Koska se on itse sisältävä tiedosto (kaikki CSS ja JS inline), sitä on helppo jakaa, ladata tai linkittää bugiraportteihin.
./mach run --profile profiling http://example.org -p 5 --profiler-trace-path trace.html
Usage:
-
Käytä hiiren rullaa tai trackpadin scrollausta, hiiren ollessa aikajanan yläosassa, zoomataksesi näkymää sisään tai ulos.
-
Tartu valittuun alueeseen yläosassa ja vedä vasemmalle tai oikealle sivusuuntaiseen scrollaukseen.
-
Vie hiiri trace:n päälle nähdäksesi lisätietoja.
Hacking
Aikajanan JS, CSS ja HTML tulee reposta fitzgen/servo-trace-dump, ja siellä on skripti Servon kopion päivittämiseen.
Kaikki muu koodi on hakemistossa components/profile/.
Sampling profiler
Servo sisältää sampling-profilerin, joka tuottaa profiileja, jotka voidaan avata Gecko profiling tools -työkaluissa. Käyttö:
- Aja Servo lataamalla profiloitava sivu
- Paina Ctrl+P (tai Cmd+P macOS:ssa) käynnistääksesi profilerin (konsolin pitäisi näyttää “Enabling profiler”)
- Paina Ctrl+P (tai Cmd+P macOS:ssa) pysäyttääksesi profilerin (konsolin pitäisi näyttää “Stopping profiler”)
- Pidä Servo käynnissä, kunnes symbolien resoluutio on valmis (konsolin pitäisi näyttää lopuksi “Resolving N/N”)
- Aja
python etc/profilicate.py samples.json >gecko_samples.jsonmuuntaaksesi profiilin muotoon, jonka Gecko profiler ymmärtää - Lataa
gecko_samples.jsonosoitteeseen https://profiler.firefox.com/
Tulostetiedoston nimen hallintaan aseta PROFILE_OUTPUT-ympäristömuuttuja.
Näytteenottotaajuuden hallintaan (oletus 10 ms) aseta SAMPLING_RATE-ympäristömuuttuja.
Memory Profiling
- Aja Servoshell normaalisti
- Avaa uusi välilehti
- Navigoi osoitteeseen
about:memory - Napsauta
Measure - Näet raportin, joka muistuttaa tätä:
115.15 MiB -- explicit
101.15 MiB -- jemalloc-heap-unclassified
14.00 MiB -- url(http://example.org/)
10.01 MiB -- layout-thread
10.00 MiB -- font-context
0.00 MiB -- stylist
0.00 MiB -- display-list
4.00 MiB -- js
2.75 MiB -- malloc-heap
1.00 MiB -- gc-heap
0.56 MiB -- decommitted
0.35 MiB -- used
0.06 MiB -- unused
0.02 MiB -- admin
0.25 MiB -- non-heap
0.00 MiB -- memory-cache
0.00 MiB -- private
0.00 MiB -- public
121.89 MiB -- jemalloc-heap-active
111.16 MiB -- jemalloc-heap-allocated
203.02 MiB -- jemalloc-heap-mapped
272.61 MiB -- resident
Using macOS Instruments
Xcodessa on instruments -työkalu helppoon profilointiin.
Ensin asenna Xcode instruments:
xcode-select --install
Toiseksi asenna cargo-instruments Homebrewin kautta:
brew install cargo-instruments
Sitten voit ajaa sen suoraan CLI:stä:
cargo instruments -t Allocations
Tässä on linkkejä ja resursseja Instrumentsin käyttöön (jotkut streamaavat vain Safarissa):
- cargo-instruments on crates.io
- Using Time Profiler in Instruments
- Profiling in Depth
- System Trace in Depth
- Threads, virtual memory, and locking
- Core Data Performance Optimization and Debugging
- Learning Instruments
Profiling WebRender
Kun ajat Servoshelliä, paina CTRL+F12 näyttääksesi (tai piilottaaksesi) WebRender-overlayn.
Webpage snapshots
On mahdollista käyttää mitmproxy-työkalua Servon liikenteen sieppaamiseen ja luoda paikallinen snapshot (dump) mielivaltaisesta verkkosivusta, jota voidaan sitten tarjoilla paikallisesti profilointitarkoituksiin.
mitmproxy tukee useita tapoja siepata liikennettä, mukaan lukien proxy-tila portissa :8080, joten voit asettaa selaimen vain:
./target/release/servo \
--pref=network_http_proxy_uri=http://127.0.0.1:8080 \
--ignore-certificate-errors
[!info] The default
mitmproxycerts are in the~/.mitmproxyor you can generate some usingmitmproxy, but I have just set my browser to ignore cert errors
[!warning] ignoring certs is easy, but be cautious of risks
Default mitmproxy
Oletusverkossa mitmproxy luo paikallisen proxy-palvelimen porttiin :8080, ja asettamalla sen selaimessa tai antamalla http_proxy=localhost:8080 ja/tai https_proxy=localhost:8080 (ja valinnaisesti poistamalla no_proxy-asetuksen) voit dumppata ja tarjoilla liikennettä.
Creating a dump
mitmproxy -w <dumpfile>
Serving a dump
mitmproxy --server-replay <dumpfile>
Tuloksena oleva dump-tiedosto on noin ~5MB per sivu, joten se kasvaa nopeasti suureksi, koska työkalu on hyvin verbose ja voi tallentaa kuvia.
Chain-proxy
Toisen ensisijaisen proxy-yhteyden tapauksessa meidän on välitettävä upstream pääproxy:lle mitmproxy:sta, ja jos pääproxyllä on myös custom-sertifikaatteja, on tärkeää välittää ne tai jättää ne huomiotta
[!warning] ignoring certs is easy, but be cautious of risks
Creating a dump
mitmproxy --mode upstream:${http_proxy} -w <dump-path>\
--set ssl_insecure=true
#### Serving the dump
```bash
mitmproxy -v --server-replay ~/dev/recodings/servo_org_3.dump \
--set server_replay_extra=404 \
--set server_replay_ignore_host=true \
--set connection_strategy=lazy \
--set server_replay_reuse=true
[!info] the
replay_extraandreplay_reuseare optional, and may cause unexpected behaviour
OpenHarmony
Työkalua voi käyttää etäpuhelimen liikenteen sieppaamiseen, mukaan lukien OpenHarmony-kohteet. Avaa käänteinen proxy-portti hdc:llä ja aja sitten servo proxy- ja sertifikaattiasetuksilla.
reverse port
hdc rport tcp:8080 tcp:8080
run with args
hdc shell aa start -a EntryAbility \
-b org.servo.servo -U https://servo.org \
--psn=--pref=network_http_proxy_uri=http://127.0.0.1:8080 \
--psn=--ignore-certificate-errors
Crate-riippuvuudet
Rust-kirjastoa kutsutaan crateksi.
Servo käyttää paljon crateja.
Nämä cratet ovat riippuvuuksia.
Ne on listattu tiedostoissa nimeltä Cargo.toml.
Servo on jaettu komponentteihin ja portteihin (katso components- ja ports-hakemistot).
Jokaisella on omat riippuvuutensa ja oma Cargo.toml-tiedostonsa.
Cargo.toml-tiedostot listaavat riippuvuudet.
Voit muokata tätä tiedostoa.
Esimerkiksi components/net_traits/Cargo.toml sisältää:
[dependencies.stb_image]
git = "https://github.com/servo/rust-stb-image"
Mutta koska rust-stb-image-API voi muuttua ajan myötä, ei ole turvallista kääntää rust-stb-image-repon HEAD-versiota vastaan.
Cargo.lock-tiedosto on Cargo.toml-tiedoston tilannekuva, joka sisältää viitteen tarkkaan revisioon ja varmistaa, että kaikki kääntävät aina samalla konfiguraatiolla:
[[package]]
name = "stb_image"
source = "git+https://github.com/servo/rust-stb-image#f4c5380cd586bfe16326e05e2518aa044397894b"
Tätä tiedostoa ei pidä muokata käsin.
Normaalissa Rust-projektissa git-revisiota päivittäisi komennolla cargo update -p stb_image, mutta Servossa käytä ./mach cargo-update -p stb_image.
Myös muut cargo-argumentit ymmärretään, esim. käytä –precise ‘0.2.3’ päivittääksesi kyseisen craten versioon 0.2.3.
Katso Cargon dokumentaatio Cargo.toml- ja Cargo.lock-tiedostoista.
Työskentely craten parissa
Kuten yllä selitetään, Servo riippuu monista kirjastoista, mikä tekee siitä hyvin modulaarisen.
Työskennellessäsi Servon bugiin päädyt usein johonkin sen riippuvuuksista.
Haluat silloin kääntää oman versionsi riippuvuudesta (ja ehkä kääntäminen kirjaston HEAD-versiota vastaan korjaa ongelman!).
Esimerkiksi yritän tuoda joitain cocoa-tapahtumia Servoon. Servon ikkuna työpöydällä rakennetaan kirjastolla nimeltä winit. winit riippuu cocoa-kirjastosta nimeltä cocoa-rs. Kun rakennat Servon, kaikki nämä riippuvuudet ladataan ja käännätään automaattisesti. Mutta koska haluan työskennellä tämän cocoa-tapahtumaominaisuuden parissa, haluan Servon käyttävän omaa versiotani winit- ja cocoa-rs-kirjastoista.
Projektini on järjestetty näin:
~/my-projects/servo/
~/my-projects/cocoa-rs/
Molemmat kansiot ovat git-repositorioita.
Jotta Servo käyttäisi polkua ~/my-projects/cocoa-rs/, selvitä ensin, mitä versiota cratesta Servo käyttää ja onko se git- vai crates.io-riippuvuus.
Molemmat tiedot löytyvät komennolla, tässä esimerkissä, cargo pkgid cocoa (cocoa on paketin nimi, joka ei välttämättä vastaa repo-kansion nimeä).
Jos tulos on muodossa https://github.com/servo/cocoa-rs#cocoa:0.0.0, kyseessä on git-riippuvuus ja sinun on muokattava tiedostoa ~/my-projects/servo/Cargo.toml ja lisättävä loppuun:
[patch]
"https://github.com/servo/cocoa-rs#cocoa:0.0.0" = { path = '../cocoa-rs' }
Jos tulos on muodossa https://github.com/rust-lang/crates.io-index#cocoa#0.0.0, kyseessä on crates.io-riippuvuus ja sinun on muokattava tiedostoa ~/my-projects/servo/Cargo.toml seuraavasti:
[patch]
"cocoa:0.0.0" = { path = '../cocoa-rs' }
Molemmat kertovat mille tahansa cargo-projektille, ettei se käytä riippuvuuden verkkoversiota vaan paikallista klooniasi.
Lisätietoja riippuvuuksien ohittamisesta: Cargon dokumentaatio.
Crate-julkaisujen pyytäminen
Servon selainmoottorin luomisen lisäksi Servo-projekti julkaisee modulaarisia komponentteja, kun ne voivat hyödyttää laajempaa Rust-kehittäjäyhteisöä.
Esimerkki tällaisesta cratesta on rust-url.
Pyrimme olemaan hyviä ylläpitäjiä, mutta selainmoottorin ja ulkoisten kirjastojen kokoelman hallinta voi olla paljon työtä, joten emme takaa säännöllisiä julkaisuja näille modulaarisille crateille.
Jos koet, että jonkin näistä crateista julkaisu on ajankohtainen, vastaamme pyyntöihin uusista julkaisuista. Uuden julkaisun pyytämisen prosessi on:
- Luo yksi tai useampi pull request, joka valmistelee craten uutta julkaisua varten.
- Luo pull request, joka nostaa versionumeron repositoriossa, ollen tarkkana siitä, mikä version osa pitäisi kasvaa edellisestä julkaisusta. Tämä tarkoittaa, että sinun on ehkä merkittävä, onko mukana breaking change -muutoksia.
- Pyydä pull requestissa uuden version julkaisemista. Muutoksen landaava henkilö on vastuussa uuden version julkaisemisesta tai selittää, miksi sitä ei voida julkaista pull requestin landauksen yhteydessä.
DevTools
Firefox DevTools on joukko web-kehittäjätyökaluja, joilla voi tarkastella, muokata ja debugata verkkosivun HTML:ää, CSS:ää ja JavaScriptiä. Servo tukee osajoukkoa DevTools-toiminnallisuudesta, mikä mahdollistaa yksinkertaisen debuggauksen.
Yhdistäminen Servoon
- Aja servoshell DevTools-palvelin käytössä.
Luku
devtools-parametrin jälkeen on palvelimen käyttämä portti.
./mach run --devtools=6080
-
Avaa Firefox ja siirry osoitteeseen
about:debugging. Jos käytät DevTools-integraatiota ensimmäistä kertaa, siirry Setup-välilehdelle ja lisäälocalhost:6080verkkosijainniksi. Porttinumeron on oltava sama kuin edellisessä vaiheessa. -
Napsauta sivupalkissa Connect kohdan
localhost:6080vieressä.

- Palaa Firefoxissa, valitse webview ja napsauta Inspect. Uuden ikkunan pitäisi avautua sivun inspectorilla.

Inspectorin käyttö
Inspector-ikkuna on jaettu eri välilehtiin, joilla on eri työtiloja. Tällä hetkellä Inspector ja Console toimivat.
Inspector-välilehdellä on kolme saraketta. Vasemmalta oikealle:
- HTML tree näyttää dokumentin solmut. Tämän avulla voit nähdä, lisätä tai muokata attribuutteja kaksoisnapsauttamalla tagin nimeä tai attribuuttia.
- style inspector näyttää valitun elementin CSS-tyylit. Merkinnät tulevat elementin style-attribuutista, vastaavista tyylitiedoston säännöistä tai perittynä muilta elementeiltä. Tyylejä voi lisätä tai muokata napsauttamalla selektoria tai ominaisuutta, tai napsauttamalla tyhjää tilaa alapuolella.
- extra column sisältää lisähyödyllisiä työkaluja:
- Layout sisältää tietoa elementin box model -ominaisuuksista. Huomaa, että flex ja grid eivät vielä toimi.
- Computed, joka sisältää kaikki CSS-computed values suhteellisten yksiköiden kaltaisten asioiden ratkaisemisen jälkeen.

Console-välilehti sisältää JavaScript-konsolin, joka liittyy Servossa näytettävään verkkosivustoon. Virheet, varoitukset ja tiedot, joita verkkosivusto tuottaa, kirjataan tänne. Sitä voi käyttää myös JavaScript-koodin suorittamiseen suoraan verkkosivustolla, esimerkiksi dokumentin sisällön muuttamiseen tai sivun uudelleenlataamiseen:
document.write("Hello, Servo!")
location.reload()
DevTools-ominaisuuksien tuki on yhä kesken, ja se voi rikkoutua tulevissa Firefox-versioissa, jos viestintäprotokollaan tulee muutoksia.
DevToolsin kehittäminen
Lue täydellinen protokollakuvaus syvällistä katsausta varten tärkeistä käsitteistä.
- Client: Frontend, joka sisältää eri työkalupaneelit (Inspector, Debugger, Console, …) ja lähettää pyyntöjä palvelimelle.
Tällä hetkellä tämä on Firefoxin
about:debugging-sivu. - Server: Selain, jota client tarkastelee. Vastaanottaa viestit ja välittää ne sopivalle actorille, jotta se voi vastata.
- Actor: Koodi palvelimella, joka voi vaihtaa viestejä clientin kanssa.
- Message: JSON-paketti, jota vaihdetaan palvelimen ja clientin välillä.
- Clientin viesteissä on oltava
to-kenttä actorin nimellä, jolle ne on suunnattu, jatype-kenttä, joka määrittää paketin tyypin. - Palvelimen viesteissä on oltava
from-kenttä actorin nimellä, joka lähettää ne.
- Clientin viesteissä on oltava
sequenceDiagram
participant Client
participant Server
actor Actor1
Client->>Server: {"to": "Actor1", "type": "SayHi"}
Server-->>Actor1: {"to": "Actor1", "type": "SayHi"}
Actor1-->>Server: {"from": "Actor1", "content": "hi!"}
Server->>Client: {"from": "Actor1", "content": "hi!"}
Protokollaliikenteen näyttäminen
Siirry Protokollaliikenteen kaappaus ja käsittely -osioon hyödyllisempää työkalua lokianalyysiin varten.
Servo ↔ Firefox
Servo voi näyttää DevTools-palvelimelle lähetetyt ja sieltä vastaanotetut viestit.
Ota käyttöön oikea lokitaso devtools-moduulille:
RUST_LOG="error,devtools=debug" ./mach run --devtools=6080
Tulosteessa lähetetyt viestit on etuliitteellä <- ja vastaanotetut viestit ilman etuliitettä.
Tässä näemme, miten Servo lähettää alkuyhteyden tiedot ja Firefox vastaa yhteyspyynnöllä ja versionumerollaan.
[2025-11-07T11:37:35Z INFO devtools] Connection established to 127.0.0.1:47496
[2025-11-07T11:37:35Z DEBUG devtools::protocol] <- {"from":"root","applicationType":"browser","traits":{"sources":false,"highlightable":true,"customHighlighters":true,"networkMonitor":true}}
[2025-11-07T11:37:35Z DEBUG devtools::protocol] {"type":"connect","frontendVersion":"144.0.2","to":"root"}
[2025-11-07T11:37:35Z DEBUG devtools::protocol] <- {"from":"root"}
Firefox ↔ Firefox
Paljon työtä Servon kehittäjätyökalujen parantamiseksi vaatii reverse-engineering-työtä Firefoxin toimivasta toteutuksesta. Yksi tehokkaimmista tavoista on tarkkailla onnistunutta sessiota Firefoxissa ja tallentaa kaksisuuntaista protokollaliikennettä palvelimen ja clientin välillä.
Ensimmäisellä ajolla
- Luo uusi Firefox-profiili komennolla
firefox --createprofile devtools-testing. - Käynnistä Firefox komennolla
firefox --new-instance -P devtools-testing. - Avaa about:config ja napsauta “Accept the Risk and Continue”.
- Muuta seuraavat asetukset:
# To see logs in the terminal window
browser.dom.window.dump.enabled = true
devtools.debugger.log = true
devtools.debugger.log.verbose = true
# To enable debugging
devtools.chrome.enabled = true
devtools.debugger.remote-enabled = true
# Optional, avoids having to confirm every time there is a connection
devtools.debugger.prompt-connection = false
Kun Firefox on konfiguroitu, se voidaan käynnistää terminaalista DevTools-palvelin päällä:
firefox --new-instance --start-debugger-server 6080 -P devtools-testing
# (on macOS you may need `/Applications/Firefox.app/Contents/MacOS/firefox`)
Tässä tapauksessa voit käyttää samaa Firefox-instanssia sekä clientina että palvelimena. “This Firefox” -vaihtoehtoa ei kuitenkaan suositella, koska se ei anna pääsyä välilehtiin ja viestit voivat olla erilaisia. Sen sijaan, käytitpä samaa vai eri instanssia, seuraa Yhdistäminen Servoon -osion ohjeita ohittaen ensimmäinen vaihe.
Terminaali-ikkuna sisältää nyt täydet debug-palvelinlokit; kopioi ne johonkin myöhempää analyysia varten.
Protokollaliikenteen kaappaus ja käsittely
Olemme nähneet yksinkertaisen tavan hankkia viestilokeja Servosta ja Firefoxista.
Tämä kuitenkin monimutkaistuu nopeasti, kun halutaan vertailla lokia näiden välillä eri formaattien vuoksi tai suorittaa kyselyitä niihin.
Prosessin helpottamiseen on pieni skripti: etc/devtools_parser.py.
Se perustuu Wireshark-verkkopakettianalysaattoriin; tarkemmin sen CLI-työkaluun tshark.
Se on konfiguroitu lokittamaan paikallisverkossa lähetetyt paketit portissa, jossa DevTools-palvelin pyörii.
Se voi lukea näiden pakettien payloadit, jotka ovat pieniä paloja JSON DevTools -protokollasta.
tshark on asennettava, jotta skripti toimii.
Asenna se paketinhallinnalla tai hanki täydellinen Wireshark-julkaisu viralliselta sivustolta.
# Linux (Debian based)
sudo apt install tshark
# Linux (Arch based)
sudo pacman -S wireshark-cli
# Linux (Fedora)
sudo dnf install wireshark-cli
# MacOS (With homebrew):
brew install --cask wireshark
# Windows (With chocolatey):
choco install wireshark
Saatat joutua lisäämään käyttäjäsi wireshark-ryhmään rootless-kaappausten sallimiseksi. Käytä usermod -a -G wireshark $USER.
Varmista lopuksi Firefox-profiilin asettaminen debuggausta varten.
Sessio kaappaus
- Aja joko Servo tai Firefox DevTools-palvelin käytössä:
./mach run --devtools 6080
firefox --new-instance --start-debugger-server 6080 -P devtools-testing
- Toisessa terminaalissa käynnistä skripti capture-tilassa (
-w) määrittäen saman portin kuin aiemmin:
./etc/devtools_parser.py -p 6080 -w capture.pcap
- Yhdistä
about:debugging-sivulta seuraamalla samoja ohjeita. - Suorita kaikki toiminnot, jotka haluat tallentaa.
- Paina
Ctrl-Cparseria ajavassa terminaalissa lopettaaksesi tallennuksen. Tämä tekee kaksi asiaa:- Tallentaa tulokset
.pcap-tiedostoon, jonka määritit-w-lipulla. Tämä on Wiresharkin binääritiedostomuoto, mutta voimme lukea sen myöhemmin samalla työkalulla. - Tulostaa viestilokin.
On kaksi tilaa: tavallinen, jossa viestit tulostetaan ystävällisessä muodossa, ja
--json, joka tuottaa rivierotetun JSONin jokaisesta viestistä.
- Tallentaa tulokset
- Voit nyt sulkea Servon tai Firefoxin.
Kaappauksen lukeminen
On hyödyllistä tallentaa useita kaappauksia ja vertailla niitä myöhemmin.
Vaikka tshark tallentaa ne oletuksena .pcap-muodossa, voimme käyttää samaa skriptiä parempaan tulostukseen.
Tässä --json-valitsin on hyvin hyödyllinen, koska se mahdollistaa työkalujen kuten jq tai nushell käytön datan kyselyyn ja manipulointiin.
# Pretty print the messages
./etc/devtools_parser.py -r capture.pcap
# Save the capture in an NDJSON format
./etc/devtools_parser.py -r capture.pcap --json > capture.json
# Example of a query with jq to get unique message types
./etc/devtools_parser.py -r capture.pcap --json | jq -cs 'map({actor: (.from//.to) | gsub("[0-9]";""), type: .type} | select(.type != null)) | .[]' | sort -u
JSON-kaappaus voidaan tallentaa alusta asti komennolla ./etc/devtools_parser.py -w capture.pcap --json > capture.json.
Tässä on katkelma kaappauksen tulosteesta:
{"to": "root", "type": "getRoot"}
{"from": "root", "deviceActor": "device1", "performanceActor": "performance0", "preferenceActor": "preference2", "selected": 0}
{"to": "device1", "type": "getDescription"}
{"from": "device1", "value": {"apptype": "servo", "version": "0.0.1", "appbuildid": "20251106175140", "platformversion": "133.0", "brandName": "Servo"}}
Oppaat
Tämä osio sisältää muutamia oppaita yleisiin tehtäviin Servon parissa työskennellessä.
Verkkosisällön bugien korjaaminen
Servossa havaittavissa on pääasiassa kahta web-yhteensopivuusongelman luokkaa. Visuaaliset bugit johtuvat usein puuttuvista ominaisuuksista tai bugeista Servon CSS- ja layout-tuessa, kun taas interaktiivisuusongelmat ja rikkinäinen sisältö johtuvat usein bugeista tai puuttuvista ominaisuuksista Servon DOM- ja JavaScript-toteutuksessa.
- Apua DOM-toteutuksen bugin korjaamiseen: DOM-virheiden diagnosointi.
- Apua ongelmien kaventamiseen, olipa kyse layoutista tai DOM:sta: Minimaalinen toistettava testitapaus.
Uusien ominaisuuksien lisääminen
Ominaisuuksien lisääminen ei ole hyvä tehtävä uudelle kontribuuttorille, koska web-moottorissa ominaisuuden täydellinen toteuttaminen vaatii usein pitkän sarjan muutoksia. Aloita lukemalla DOM-rajapinnan toteuttaminen.
Minimaalinen toistettava testitapaus
Jotta voit tunnistaa tarkalleen, mikä sivulla menee pieleen, on erittäin tärkeää osata luoda minimaalinen toistettava testitapaus. Vaikka et aikoisikaan korjata ongelmaa itse, testitapauksen tarjoaminen helpottaa muiden korjaustyötä huomattavasti ja säilyttää epäonnistumisen, vaikka alkuperäinen sivu muuttuisi. Testitapauksen luominen on melko systemaattista prosessia, jonka voi tehdä jopa hyvin uusi web-alustan kehittäjä. Minimaalisesti toistettava testitapaus on lähes aina ensimmäinen askel ongelman korjaamisessa, ja ne voidaan usein helposti muuntaa Web Platform Testeiksi.
Peruslähestymistapa
Peruslähestymistapa minimaalisen toistettavan testitapauksen luomiseen on poistaa vähitellen tarpeetonta sisältöä sivulta, kunnes jäljellä on vain ongelmallinen osa. Tämä tarkoittaa, että alkuperäinen layout-ongelma, DOM-virhe tai kaatuminen tapahtuu edelleen, vaikka lähdekoodi on paljon pienempi. On mahdollista, ettei virhe näytä tai toimi täsmälleen samalta testitapauksessa, mutta sen pitäisi silti tuottaa huonoja tuloksia verrattuna muihin selaimiin, kaatua tai tuottaa virheen. Tärkeä vaihe on vertailla tuloksia useampaan muuhun selainmoottoriin nähdäksesi, onko kyseessä oikeasti spesifikaatio-ongelma. On suositeltavaa ajaa testitapaus myös Chromessa, Firefoxissa ja WebKit-pohjaisessa selaimessa kuten Safarissa.
Minimointi
Luodaksesi minimaalisen toistettavan testitapauksen tarvitset ensin kopion sivusta tietokoneellesi. Chromessa tallenna ongelmallinen sivu valinnalla „Webpage, Complete.” Näin varmistat, että kaikki kuvat, CSS- ja JavaScript-tiedostot tallentuvat myös tietokoneellesi. Seuraavaksi lataa tallennettu HTML-tiedosto Chromessa ja Servossa varmistaaksesi, että sivu toimii edelleen ja bugi näkyy Servossa. Nyt on aika pienentää! Voit käyttää muutamia tekniikoita:
- Etsi sivun osa, joka ei liity ongelmaan, kuten ylä- tai alatunniste. Poista ne ladatusta HTML-tiedostosta Web Inspectorissa, esimerkiksi korostamalla elementit ja painamalla Delete-näppäintä. Tallenna sivu uudelleen ja varmista, että bugi on edelleen olemassa lataamalla uudelleen tallennettu sivu. Jatka!
- Jos ongelma on layout-ongelma, kokeile poistaa kaikki sivulla ladattu JavaScript. Jos JavaScriptin poistaminen poistaa ongelman, peru muutos ja kokeile poistaa muuta JavaScriptiä.
- Kokeile poistaa viittaukset ulkoisiin tyylitiedostoihin. Jos tyylitiedoston poistaminen poistaa myös bugin, upota tyylitiedosto inline-muotoon ja poista vähitellen asiaankuulumattomia sääntöjä. Tarvittaessa voit käyttää tyyppistä binääristä eliminointia tyylisäännöille.
- Korvaa ladatut kuvat yksinkertaisella image-tagilla, jossa on
widthjaheight. Ulkoisen resurssin lataamatta jättäminen helpottaa testitapauksen ymmärtämistä huomattavasti. - Kun sivulla on vain muutama elementti jäljellä, kokeile poistaa
class-,id- tai muita tarpeettomia attribuutteja.
Jatka pienentämistä, kunnes testitapaus on mahdollisimman pieni. Usein tämän aikana bugin luonne selviää, ja olet jo puolivälissä korjausta.
Lithium
Lithium on työkalu yllä kuvatun prosessin automatisointiin. Se toimii erityisen hyvin kaatumisten kanssa ja kestää ei-deterministiset bugit.
DOM-rajapinnan toteuttaminen
Osa 1: Web API:n perusasetukset
- Lue relevantti spesifikaatio.
- Lisää
.webidl-tiedosto(t) tähän hakemistoon jokaiselle toteutettavalle rajapinnalle. Jos tiedosto on jo olemassa, lisää siihen puuttuvat osat. - Jokaiselle rajapinnalle tämä luo traitin nimeltä
{interface_name}Methods, johon pääsee käsiksi komennollause crate::dom::bindings::codegen::Bindings::{interface_name}Binding. - Käytä traitia:
- Lisäämällä vastaavan structin
#[dom_struct]-attribuutilla - Lisäämällä metodeja, joiden runko on
todo!.
- Lisäämällä vastaavan structin
- Tässä vaiheessa structilla voi olla vain yksi jäsen:
reflector_: Reflector,- Struct pitää dokumentoida linkillä sen rajapintaan spesifikaatiossa,
- Trait-metodit pitää dokumentoida linkillä niiden määritelmiin rajapinnassa.
- Esimerkkitulos.
- Palaa spesifikaatioon,
- Lue DOM-rajapinnat.
- Käyttäen oppimaasi, jokaiselle rajapinnan internal slotille:
- Lisää sopiva jäsen kohdassa 4 lisättyihin structeihin.
- Jos tämä vaatii muiden structien tai enumien määrittelyä, niiden pitää derivoida
JSTraceablejaMallocSizeOf(esimerkki). - Kaikki yllä lisätyt
JSTraceable-structit, jotka sisältävät jäseniä, jotka täytyy rootata koska ne ovat joko JS-arvoja tai DOM-objekteja, pitää merkitä#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]. Esimerkki, jossa lintti tarvitaanJSVal-jäsenen vuoksi. - Jos tällainen struct assignataan muuttujaan, tee
impl js::gc::Rootablestructille ja käytärooted!rootataksesi muuttujan (esimerkki). - Kaikki tämä voidaan muuttaa myöhemmin, joten käytä parasta arvostelukykyäsi tässä vaiheessa.
- Lisää metodeja rakentamiseen (älä sekoita Web API:n osana olevaa
Constructor-metodia). - Esimerkkitulos.
Osa 2: Ensimmäisen luonnoksen kirjoittaminen
- Jokaiselle osan 1 kohdassa 3 mainitun bindings-traitin metodille:
- Yleensä seuraa spesifikaation rakennetta: jos metodi kutsuu toista nimettyä algoritmia, toteuta se erillisenä structin yksityisenä metodina, jota trait-metodi kutsuu. Jos myöhemmin huomaat, että tätä yksityistä metodia voi käyttää muista structeista, tee siitä
pub(crate). - Jokaiselle spesifikaation algoritmivaiheelle:
- Kopioi rivi spesifikaatiosta.
- Toteuta spesifikaatio koodissa (voi vaatia useamman rivin ja lisäkommentteja).
- Yleensä seuraa spesifikaation rakennetta: jos metodi kutsuu toista nimettyä algoritmia, toteuta se erillisenä structin yksityisenä metodina, jota trait-metodi kutsuu. Jos myöhemmin huomaat, että tätä yksityistä metodia voi käyttää muista structeista, tee siitä
- Huom: tietyt asiat tarvitaan usein algoritmin osana:
JSContexttaiCurrentRealm, jotka ovat toisensa poissulkevia, saadaan generoidun trait-metodin argumenttina tämän konfiguraatiotiedoston avullaGlobalScope: saadaanself.global()-kutsulladom_struct-structilla taiGlobalScope::from_current_realm-kutsulla- On parasta hakea ne mahdollisimman aikaisin, esimerkiksi trait-metodin toteutuksen alussa, ja välittää ne alaspäin ref:inä (useimmissa tapauksissa
JSContext/CurrentRealmtäytyy olla&mut-viitteen takana) - On suositeltavaa, että
JSContext/CurrentRealmon ensimmäinen argumentti, sen jälkeen&GlobalScopetarvittaessa, ja muut tarvittavat argumentit perässä
- Tämän pitäisi antaa täydellinen ensimmäinen luonnos.
Osa 3: Testien ajaminen ja bugien korjaaminen
- Nyt on aika tunnistaa, mitä WPT-testiä ajetaan ensimmäistä luonnosta vasten. Löydät ne täältä.
- Tämä voi vaatia niiden ottamista käyttöön tällä konfiguraatiolla.
- Testi voi epäonnistua, koska:
- Koodissa on bugi. Nämä pitää korjata.
- Testi käyttää muita API:ja, joita ei vielä tueta (yleensä
ERROR).
- Bugit pitää korjata. Copilotista on tässä vähän hyötyä.
- Odotetut epäonnistumiset voidaan merkitä sellaisiksi tässä kuvatussa prosessissa.
- Tämä osa on valmis, kun odottamattomia testituloksia ei enää ole.
- Joskus reviewaajan neuvosta voit tehdä issuen ja kuvata epäonnistumisen, jota et voi korjata, merkitä testin epäonnistumiseksi ja jättää sen seuraavaan työvaiheeseen.
Osa 4: Refaktorointi ja lopullisen reviewn pyytäminen
- Voit pyytää reviewa milloin tahansa, jos olet jumissa, mutta nyt on aika katsoa koodia viimeisen kerran ja päättää, haluatko refaktoroida jotain.
- Jos olet tyytyväinen, nyt on aika pyytää lopullinen review.
- Onnittelut, toteuttamasi uusi Web API pitäisi pian yhdistää.
Virheiden diagnosointi
DOM-virheiden diagnosointi
Seuraavan kaltaiset virheviestit kertovat selvästi, että tiettyä DOM-rajapintaa ei ole vielä toteutettu Servossa:
[2024-08-16T01:56:15Z ERROR script::dom::bindings::error] Error at https://github.githubassets.com/assets/vendors-node_modules_github_mini-throttle_dist_index_js-node_modules_smoothscroll-polyfill_di-75db2e-686488490524.js:1:9976 AbortSignal is not defined
Seuraavan kaltaiset virheviestit eivät kuitenkaan anna paljon ohjausta:
[2024-08-16T01:58:25Z ERROR script::dom::bindings::error] Error at https://github.githubassets.com/assets/react-lib-7b7b5264f6c1.js:25:12596 e is undefined
Virheviestissä linkitetyn JS-tiedoston avaaminen näyttää usein minifioidun, obfusoidun JS-skriptin, jota on lähes mahdotonta lukea.
Aloitetaan minifioidun koodin purkamisella. Varmista, että js-beautify-binääri on polussasi, tai asenna se komennolla:
npm install -g js-beautify
Aja ongelmasivu Servossa uudelleen sisäänrakennetulla minifiointipalautuksella käytössä:
./mach run https://github.com/servo/servo/activity --unminify-js
Tämä luo unminified-js-hakemiston Servo-repositorion juureen ja tallentaa automaattisesti minifioidut kopiot jokaisesta ulkoisesta JS-skriptistä,
joka haetaan sivun elinkaaren aikana. Servo myös evaluoi skriptien minifioidut versiot, joten rivi- ja sarakenumerot
virheviesteissä muuttuvat:
[2024-08-16T02:05:34Z ERROR script::dom::bindings::error] Error at https://github.githubassets.com/assets/react-lib-7b7b5264f6c1.js:3377:66 e is undefined
Löydät react-lib-7b7b5264f6c1.js-tiedoston hakemistosta ./unminified-js/github.githubassets.com/assets/, ja jos katsot riviä 3377,
voit alkaa lukea ympäröivää koodia selvittääksesi (toivottavasti), mikä sivulla menee pieleen. Jos koodin tarkastelu ei riitä,
Servo tukee myös minifioidun JS:n muokkaamista paikallisessa välimuistissa!
./mach run https://github.com/servo/servo/activity --local-script-source unminified-js
Kun --local-script-source-argumentti on käytössä, Servo etsii JS-tiedostoja annetusta hakemistosta ensin ennen kuin yrittää hakea
niitä internetistä. Tämä mahdollistaa console.log(..)-lauseiden ja muiden hyödyllisten debuggaustekniikoiden lisäämisen ymmärtääksesi,
mitä oikeat verkkosivut havaitsevat. Jos sinun täytyy palata alkuperäiseen sivulähteeseen, aja uudelleen
--unminify-js-argumentilla korvataksesi ne uusilla minifioiduilla lähdekooditiedostoilla.
Vakaiden WPT-virheiden diagnosointi
FAIL-tuloksen diagnosointi
Aloita avaamalla testitiedoston .ini-tiedosto, joka sisältää odotetut epäonnistumiset.
Se löytyy hakemistosta tests/wpt/meta/ rinnakkaisessa hakemistopuussa suhteessa tests/wpt/tests/-hakemistoon.
WPT-testikehys suppressoi suurimman osan .ini-tiedostossa odotetuiksi merkittyihin epäonnistumisiin liittyvästä tulosteesta.
Nähdäksesi kaikki testitiedoston epäonnistumiset, muuta ylätason [filename.html]-kohtaa niin, ettei se vastaa todellista tiedostonimeä; tämä saa kehyksen jättämään .ini-tiedoston kokonaan huomiotta.
Nähdäksesi lisätietoja yhdestä alitestistä, poista se .ini-tiedostosta ja aja testi uudelleen.
Kehys näyttää epäonnistuvat testiväitteet sekä JS-stack tracen, kun epäonnistumiset tapahtuvat.
ERROR-tuloksen diagnosointi
ERROR-tulokset syntyvät, kun poikkeus heitetään ilman että sitä käsitellään. Testikehyksen stack tracen pitäisi näyttää alitesti, jossa käsittelemätön poikkeus havaittiin, sekä virheen tyyppi.
Jos poikkeus tulee Rustissa toteutetun API-metodin kutsumisesta, sinun täytyy löytää kyseinen metoditoteutus ja etsiä koodia, joka palauttaa vastaavan Error-variantin.
TIMEOUT-tuloksen diagnosointi
Testien timeout tapahtuu, kun async/promise-alitesti on määritelty mutta ei koskaan valmistu. Sinun täytyy tunnistaa kaksi asiaa:
- viimeinen testikoodi, joka suoritetaan onnistuneesti
- miksi seuraavaa koodia, joka pitäisi suorittaa, ei koskaan ajeta
Nopein tapa selvittää ensimmäinen tietopiste on lisätä console.log-lauseita todistamaan, että koodipolut suoritetaan.
Koodi, jota ei suoriteta, on yleensä:
- tapahtumakäsittelijä (joko tapahtumaa ei koskaan laukaista, tai käsittelijässä on suodatuslogiikka, joka aktivoituu)
- promise-käsittelijä (promisea ei koskaan resolvata/rejectata)
- await-lause (promisea ei koskaan resolvata/rejectata)
Kussakin tapauksessa on hyödyllistä aloittaa koodista, jonka on tarkoitus laukaista puuttuva vaihe (esim. relevantti event.fire(..) Rust-koodissa), ja työskennellä taaksepäin selvittääksesi, miksi sitä ei koskaan suoriteta.
NOTRUN-tuloksen diagnosointi
Nämä epäonnistumiset tapahtuvat, kun async-alitesti on määritelty (esim. let some_test = async_test("frobbing the whatsit");) mutta sitä ei koskaan suoriteta (esim. some_test.step(() => ...)).
Tämä tapahtuu yleensä, kun testitiedosto määrittää monta alitestiä ja yrittää ajaa ne peräkkäin, mutta kohtaa poikkeuksen tai timeoutin, joka estää jatkosuorituksen.
Nämä tulokset ovat yleensä oire jostain muusta ongelmasta, jonka testitiedosto paljastaa, ja näitä muita ongelmia pitäisi tutkia ensin.
Reftest-epäonnistumisen diagnosointi
Nähdäksesi visuaalisen esityksen eroista testitiedoston ja sen referenssitiedoston välillä, voit käyttää reftest-analysaattoria.
Voit nopeasti tarkastella reftestin ulkoasua ajamalla tiedoston suoraan (./mach run tests/wpt/tests/css/CSS2/some-file.html).
Jos tiedosto riippuu muista resursseista testisuitesta, sinun täytyy ehkä käynnistää WPT-web-palvelin ensin:
cd tests/wpt/tests; ./wpt serve./mach run http://localhost:8000/css/CSS2/some-file.html
Debuggerin käyttö Web Platform Testeissä
Liittääksesi debuggerin Servoon WPT-testiä ajaessasi, lisää --debugger-lippu ./mach test-wpt-komentoon.
On kaksi toimintatapaa:
- Kun käytät
servodriver-testikehystä (oletus), sinun täytyy ajaa komento debuggerin liittämiseksi toisessa terminaalissa. Esimerkkikomento annetaan./mach test-wpt-komennon tulosteessa; testikehys odottaa sitten 30 sekuntia ennen suorituksen jatkamista. - Kun käytät
servo-testikehystä (--product=servo), debugger liitetään automaattisesti. Jatkaaksesi testikehyksen suoritusta, käytä debuggerin kehotteessarun-komentoa.
Satunnaisten WPT-virheiden diagnosointi
Yleisimmät satunnaisten epäonnistumisten lähteet Web Platform Testeissä ovat:
- Ajoitus (esim. useita säikeitä ajetaan samanaikaisesti tai rinnakkain)
- Käyttöjärjestelmävuorovaikutukset (esim. socket read/write verkkopyynnöissä)
- Ei-deterministinen tehtävän valinta
Jokainen näistä voi muuttaa tapahtumien järjestystä Servossa ei-deterministisesti, paljastaen odottamatonta tai suunnittelematonta käyttäytymistä moottorissa.
Servossa tämä ei-determinismi ilmenee usein koodissa, joka:
- käyttää mutexeja tai jaettua muistia kanavien sijaan.
- jonottaa useita tehtäviä, jotka ajetaan yhdellä säikeellä mutta eri task source -lähteistä.
- käyttää timeouteja havaitakseen, tapahtuiko tapahtuma.
Epäonnistumisen toistaminen
Vaikka tietylle satunnaiselle epäonnistumiselle voi keksiä teorian, on hyödyllistä näyttää ennen/jälkeen-epäonnistumisprosentti yritykselle tehdä korjaus.
Strategioita satunnaisten epäonnistumisten toistamiseen:
- Aja
--repeat-until-unexpected-valinnalla toistaaksesi testin, kunnes raportoidaan odottamaton tulos - Aja testi suuren kuormituksen alla (esim. aja puhdas release-käännös toisessa terminaalissa testiä toistuvasti ajaessasi)
- Kokeile eri käännös- tai ajonaikaisia konfiguraatioita:
./mach build --dev./mach build --release./mach build --debug-mozjs./mach test-wpt ... --binary-args=--force-ipc./mach test-wpt ... --binary-args=--multiprocess
Varmista, että test-wpt-komentosi käyttää samaa ajonaikaista binääriä kuin tekemäsi käännös!
Ongelman diagnosointi
Kun olet toistanut epäonnistumisen, sinun täytyy selvittää, mikä eroaa ajoissa, jotka raportoivat eri tuloksia. Testatessasi muutoksia pidä mielessä satunnaisten tulosten esiintymistiheys. Älä hyppää johtopäätöksiin odottamatta tarpeeksi kauan!
Aloita kommentoimalla pois niin paljon testistä kuin voit ja silti toistaen epäonnistumisen.
Kokeile lisätä console.log-kutsuja näyttääksesi eri tapahtumien järjestyksen, ja vertaa tulostetta yleiseen tapaukseen ja satunnaiseen tapaukseen.
Saatat joutua asettamaan RUST_LOG-ympäristömuuttujan nähdäksesi relevanttien cratejen ja moduulien sisäiset Servo-jäljitet lokit.
Lisää eksplisiittisiä viiveitä testin osiin havaitaksesi, tapahtuvatko epäonnistumiset todennäköisemmin vai harvemmin:
- siirrä osa testistä closureen, joka suoritetaan kiinteän viiveen jälkeen, kuten
test_object.step_timeout(() => ..., 1000) - lisää viive verkkopyynnön vastaukseen
Layout-testien ongelmien diagnosointi
Jos testi varmistaa layout-ominaisuuksia (joko reftest tai testi, joka käyttää layout-API:ja kuten getBoundingClientRect(), scrollTop, offsetParent jne.), yleisiä satunnaisten tulosten lähteitä ovat:
- inkrementaalinen layout toimii väärin tietylle muutokselle, mutta tämä peittyy toisella async-operaatiolla, joka laukaisee lisälayoutin
- kuvakaappaus otetaan liian aikaisin/myöhään suhteessa johonkin muuhun muutokseen (esim. web-fontin lataus)
Tehdäksesi inkrementaalisen layoutin ongelmista näkyvämpiä, kokeile:
- viivästää sivun muokkausta, kunnes kaikki muut sivupäivitykset on valmis (kokeile hyvin viivästettyä
setTimeout-kutsua). - ajaa testi oikealla ikkunalla (
--no-headless). - olla koskematta hiireen, kunnes sivun muokkaus tapahtuu, ja sitten muuttaa ikkunan kokoa.
Selvittääksesi, onko kuvakaappauksen ajoitus ongelma, käytä reftest-analysaattoria nähdäksesi testikehyksen vastaanottaman kuvakaappauksen. Jos se ei vastaa tulosta, jonka näet testitiedostoa ajaessasi, kuvakaappauksen ajoitus voi olla syypää.
Julkaisun tekeminen
Uuden Servo-version julkaiseminen
Servo-version nostaminen main-haarassa
Tällä hetkellä julkaisemme uuden Servo-version kuukausittain.
Kuukauden lopussa valmistele haara viimeisimmän main-haaran pohjalta.
Aja ./mach release X.Y.Z nostaaksesi versionumerot ja commitoi muutokset.
Avaa pull request servossa yhdistääksesi haaran main-haaraan.
Ihannetapauksessa pull request yhdistetään ajoissa kuukauden viimeisenä tai seuraavan kuukauden ensimmäisenä päivänä, jotta versionumeron nosto korreloi läheisesti blogipostin aikavälin kanssa.
Blogipostin aikaväli on viimeisen kuukauden yöjulkaisun päähän asti (mukaan lukien).
Versionoston pitäisi yhdistyä sen jälkeen, jotta kaikki blogipostissa mainitut muutokset sisältyvät julkaisuun.
Julkaisuhaaran luominen
Luo haara nimellä release/vX.Y.Z versionumeron nostaneen commitin pohjalta (main-haarassa).
Jos yhdistämispäivä oli (merkittävästi) myöhemmin ja merkittäviä muutoksia tehtiin, julkaisuhaara voidaan perustaa myös aiempaan committiin ja versionumeron nosto backportata / tehdä uudelleen.
Haara pitää pushata upstream servo -repositorioon.
Luonnosjulkaisun luominen testausta varten
Siirry servo-repositorion actions-välilehteen ja valitse Release-workflow.
Valitse Run workflow -painike oikeasta yläkulmasta.
Valitse haara release/vX.Y.Z (jonka juuri pushasit) workflow ajettavaksi.
Jätä valintaruutu valitsematta, jotta julkaisu luodaan nightly-releases-repositorioon, koska se mahdollistaa ei-maintainerien auttamisen julkaisun testauksessa.
Anna tag-arvoksi vX.Y.Z-beta1 luodaksesi esijulkaisun testausta varten.
Klikkaa Run workflow.
Luotu workflow ajaa ja luo (julkisen) julkaisun nightly-releases-repositorioon.
Kun julkaisu on luotu, voit avata ketjun Zulipissa ja tehdä kutsun eri artefaktien testaamiseen.
Muutosten backporttaaminen julkaisuhaaraan
Jos julkaisuhaaraan täytyy soveltaa kriittisiä korjauksia (esim. manuaalisessa testauksessa havaittujen kaatumisten korjaus), PR pitää avata haaraa vastaan tavanomaisen review-prosessin mukaisesti. Tämän jälkeen pitäisi suorittaa uusi testauskierros, joten backporttaa vain välttämättömissä tapauksissa.
Julkaisun valmistelu
Kun testijulkaisu nightly-repositoriossa on testattu manuaalisesti, voit valmistella julkaisun ajamalla release-workflow uudelleen, mutta tällä kertaa valitsemalla ruudun luodaksesi julkaisun upstream servo -repositorioon.
Tämä luo vain luonnosjulkaisun upstream servo -repositorioon.
Kun artefaktit on ladattu julkaisuun, klikkaa muokkauspainiketta muokataksesi luonnosjulkaisua.
Tagin pitäisi jo oikein olla vX.Y.Z.
Muuta target arvosta main arvoon release/vX.Y.Z.
Klikkaa Generate release notes ja kääri sitten generoidut release notes seuraavaan lohkoon:
<details>
<summary>Generated Release notes</summary>
Release notes here.
</details>
Ota yhteyttä macOS-artefaktin allekirjoittajaan ja pyydä häntä allekirjoittamaan julkaisu. Tämä voi kestää jonkin aikaa, joten se pitäisi tehdä pari päivää ennen suunniteltua julkaisupäivää.
Lopuksi lisää tavanomainen release notes -yhteenvetomme, jossa linkki blogipostiin ja yleisiin ongelmiin (katso aiempien release notes -kohtien esimerkit). Kun blogiposti on julkaistu, julkaisemme julkaisun.
Arkkitehtuuri
Servo on projekti uuden verkkoselaimen moottorin kehittämiseksi. Tavoitteemme on luoda arkkitehtuuri, joka hyödyntää rinnakkaisuutta monilla tasoilla samalla kun eliminoimme yleisiä virheiden ja tietoturva-aukkojen lähteitä, jotka liittyvät virheelliseen muistinhallintaan ja datakilpailuihin.
Koska C++ sopii huonosti näiden ongelmien estämiseen, Servo on kirjoitettu Rustilla, modernilla kielellä, joka on suunniteltu erityisesti Servon vaatimusten huomioon ottaen. Rust tarjoaa tehtäväpohjaisen rinnakkaisuusinfrastruktuurin ja vahvan tyyppijärjestelmän, joka pakottaa muistiturvallisuuden ja datan kilpailuttamattomuuden.
flowchart TB
subgraph Web-sisällön prosessi
ScriptA[Script-säie]-->PipelineA[Pipeline A]
PipelineA
PipelineA-->ImageA[Kuvavälimuisti]
PipelineA-->FontA[Fonttivälimuisti]
PipelineA-->LayoutA[Layout]
LayoutA-->ImageA
LayoutA-->FontA
ScriptA[Script-säie]-->PipelineB[Pipeline B]
PipelineB
PipelineB-->ImageB[Kuvavälimuisti]
PipelineB-->FontB[Fonttivälimuisti]
PipelineB-->LayoutB[Layout]
LayoutB-->ImageB
LayoutB-->FontB
end
subgraph Upotusprosessi
direction TB
Embedder-->Constellation[Constellation-säie]
Embedder<-->Renderer[Renderer]
Constellation<-->Renderer
Renderer-->WebRender
Constellation-->SystemFont[Järjestelmäfonttivälimuisti]
Constellation-->Resource[Resurssienhallinta]
end
Constellation<-->ScriptA
FontA-->SystemFont
PipelineA-->Renderer
FontB-->SystemFont
PipelineB-->Renderer
Tämä kaavio näyttää moniprosessisen Servon arkkitehtuurin, kun se ajetaan yhdellä web-sisällön prosessilla. Kun moniprosessitila on käytössä, jokainen script-säie ajaa omassa web-sisällön prosessissaan. Kun moniprosessitila on pois päältä, kaikki script-säieet ajavat upotusprosessissa. Jokaisella script-säieellä on joukko viestintäkanavia constellationin ja upotusprosessin upotus-API-osien kanssa. Yhtenäiset viivat osoittavat viestintäkanavia tai API-kutsuja.
Constellation, script-säieet ja pipeline:t
Jokaisella Servo-instanssilla on yksi constellation, joka hallinnoi web-sisällön prosesseja kaikille kehyksille kaikissa WebView-instansseissa.
Web-sisällön prosessin script-säie voi hallita useita pipelineja, yhden jokaiselle <iframe>-elementille tai WebView-instanssin pääkehykselle.
Script-säieen pipeline vastaa syötteen vastaanottamisesta, JavaScriptin suorittamisesta DOM:ia vasten, layoutin suorittamisesta, display listien rakentamisesta ja display listien lähettämisestä rendererille.
Servo-instanssilla on yksi renderer koko instanssille, ja se hallinnoi useita WebRender-instansseja, jotka renderöivät erilaisiin RenderingContext-instansseihin (käytännössä OpenGL-konteksteihin alustan pinnoilla).
Pipeline koostuu kolmesta pääosasta:
- Script: Scriptin ensisijainen tehtävä on luoda ja omistaa DOM ja suorittaa JavaScript-moottoria. Se vastaanottaa tapahtumia useista lähteistä, mukaan lukien navigointitapahtumat, ja reitittää ne tarpeen mukaan.
- Layout: Layout käynnistyy aluksi samalla säieellä kuin Script, mutta se voi käyttää worker-säieitä sivun layoutin rinnakkaiseen suorittamiseen. Se laskee tyylit ja rakentaa kaksi päälayout-tietorakennetta, box tree ja fragment tree. Fragment treeä käytetään solmujen muuntamattomien sijaintien määrittämiseen ja siitä rakennetaan display list, joka lähetetään rendererille.
- Renderer: Renderer (tunnetaan myös compositorina) välittää display listit WebRenderille, joka on sisällön rasterointi- ja näyttömoottori, jota sekä Servo että Firefox käyttävät. Se käyttää GPU:ta sivun lopullisen kuvan renderöintiin. Upottajan käyttöliittymäsäieellä ajettava renderer vastaanottaa myös ensimmäisenä syöte-tapahtumat, jotka yleensä lähetetään heti constellationille ja sitten script-säieelle käsittelyä varten. Jotkin tapahtumat, kuten scroll- ja kosketustapahtumat, voidaan käsitellä aluksi rendererissä responsiivisuuden vuoksi.
Rinnakkaisuus ja rinnakkaisuus (concurrency vs parallelism)
Rinnakkaisuus (concurrency) on tehtävien erottelua vuorottelevan suorituksen tarjoamiseksi. Rinnakkaisuus (parallelism) on useiden työpalojen samanaikaista suorittamista nopeuden lisäämiseksi. Näin hyödynnämme molempia:
- Tehtäväpohjainen arkkitehtuuri: Järjestelmän pääkomponentit tulisi jakaa näyttelijöiksi (actors) eristetyillä keoilla, selkeillä raja-arvoilla virheille ja palautumiselle. Tämä kannustaa myös löyhään kytkentään koko järjestelmässä, mikä mahdollistaa komponenttien vaihtamisen kokeilu- ja tutkimustarkoituksiin.
- Rinnakkainen renderöinti: Renderöinti on erillinen säie, joka on irrotettu layoutista responsiivisuuden ylläpitämiseksi. Renderer-säie hallitsee muistiaan manuaalisesti välttääkseen roskienkeruun (garbage collection) tauot.
- Selektorien täsmäytys: Tämä on helposti rinnakkaistettava ongelma. Kuten Gecko, Servo tekee selektorien täsmäytyksen erillisessä läpäisyssä flow tree -rakentamisen sijaan, jotta se on helpompi rinnakkaistaa.
- Rinnakkainen layout: Rakennamme flow tree:n rinnakkaisella DOM-käynnillä, joka kunnioittaa elementtien, kuten floatien, luomia peräkkäisiä riippuvuuksia.
- Jäsennys: Olemme kirjoittaneet uuden HTML-parserin Rustilla, keskittyen sekä turvallisuuteen että spesifikaation noudattamiseen. Emme ole vielä lisänneet spekulatiivista jäsennystä tai rinnakkaisuutta parseriin.
- Kuvien dekoodaus: Useiden kuvien dekoodaus rinnakkain on suoraviivaista.
- Muiden resurssien dekoodaus: Tämä on todennäköisesti vähemmän tärkeää kuin kuvien dekoodaus, mutta kaikki, mitä sivun täytyy ladata, voidaan tehdä rinnakkain, esim. kokonaisten tyylitiedostojen jäsentäminen tai videoiden dekoodaus. Tyylitiedostot jäsennetään rinnakkain aina kun mahdollista.
Haasteet
- Rinnakkaisuutta vastustavat kirjastot: Jotkin tarvitsemamme kolmannen osapuolen kirjastot eivät toimi hyvin monisäieisissä ympäristöissä. Fontit ovat olleet erityisen hankalia. Vaikka kirjastot olisivat teknisesti säie-turvallisia, säie-turvallisuus saavutetaan usein kirjaston laajuisella mutex-lukolla, mikä heikentää rinnakkaisuusmahdollisuuksiamme.
- Liian monta säiettä: Jos heitämme maksimaalisen rinnakkaisuuden ja samanaikaisuuden kaikkeen, ylikuormitamme järjestelmän liian monella säieellä.
- Liian monta avointa tiedostokahvaa: IPC-viestintä vaatii yleensä tiedostokahvan avaamisen järjestelmässä. Olemme törmänneet ongelmiin (#23910, #33672, #23905 tiedostokahvojen loppumiseen IPC-mekanismien liiallisen käytön vuoksi.
JavaScript ja DOM-bindings
Käytämme tällä hetkellä SpiderMonkeyta, vaikka vaihdettavat moottorit ovat pitkän aikavälin, matalan prioriteetin tavoite. Jokainen web-sisällön prosessi saa oman JavaScript-runtimeensa. DOM-bindings käyttävät natiivia JavaScript-moottorin API:a XPCOM:n sijaan, ja ne generoidaan automaattisesti WebIDL:n kautta.
Moniprosessiarkkitehtuuri
Kuten Chromiumissa ja WebKit2:ssa, tarkoituksemme on luoda luotettu upotusprosessi ja useita vähemmän luotettavia web-sisällön prosesseja. Korkean tason API on IPC-pohjainen, ei-IPC-toteutuksilla testausta ja yksiprosessikäyttötapauksia varten, vaikka odotetaankin, että useimmat vakavat käyttötapaukset käyttävät useita prosesseja. Moottoriprosessit käyttävät käyttöjärjestelmän sandboxointimahdollisuuksia rajoittaakseen pääsyä järjestelmäresursseihin.
Rustin tyyppijärjestelmä lisää myös merkittävän puolustuskerroksen muistiturvallisuusaukkoja vastaan. Tämä yksinään ei tee sandboxista vähemmän tärkeää turvallisen koodin, tyyppijärjestelmän virheiden ja kolmannen osapuolen/isäntäkirjastojen puolustamiseksi, mutta se pienentää Servon hyökkäyspintaa merkittävästi verrattuna muihin selainmoottoreihin. Lisäksi meillä on suorituskykyyn liittyviä huolia joistakin sandboxointitekniikoista (esimerkiksi kaikkien OpenGL-kutsujen välittäminen erilliseen prosessiin).
I/O ja resurssienhallinta
Verkkosivut riippuvat laajasta valikoimasta ulkoisia resursseja, joilla on monia hakemiseen ja dekoodaukseen liittyviä mekanismeja. Nämä resursseja välimuistitetaan useilla tasoilla — levylle, muistiin ja/tai dekoodatussa muodossa. Rinnakkaisessa selainympäristössä nämä resurssit on jaettava samanaikaisille worker-säieille.
Perinteisesti selaimet ovat olleet yksisäieisiä, suorittaen I/O:n “pääsäieellä”, jossa suurin osa laskennasta tapahtuu. Tämä johtaa viiveongelmiin. Servossa ei ole “pääsäiettä”, ja kaikkien ulkoisten resurssien latauksen hoitaa yksi resource manager -tehtävä.
Selaimilla on monia välimuisteja, ja Servon tehtäväpohjainen arkkitehtuuri tarkoittaa, että niitä on todennäköisesti enemmän kuin olemassa olevissa selainmoottoreissa (esim. meillä voi olla sekä globaali tehtäväpohjainen välimuisti että tehtäväkohtainen välimuisti, joka tallentaa tuloksia globaalista välimuistista säästääkseen schedulerin kierroksen). Servolla tulisi olla yhtenäinen välimuistitarina, säädettävillä välimuisteilla, jotka toimivat hyvin vähämuistisissa ympäristöissä.
Viitteet
Tärkeää tutkimusta ja kertynyttä tietoa selaimen toteutuksesta, rinnakkaisesta layoutista jne.:
- How Browsers Work - perustason selitys nykyaikaisten verkkoselaimien yleisestä suunnittelusta Gecko-insinööri Ehsan Akhgari
- More how browsers work - artikkeli, joka on vanhentunut mutta sisältää paljon enemmän yksityiskohtia
- Webkit overview
- Fast and parallel web page layout (2010) - Leo Meyerovichin vaikutusvaltainen rinnakkaiset selektorit, layout ja fontit. Se suosittelee rinnakkaisten selektorien erottamista rinnakkaisesta cascade:sta muistinkäytön parantamiseksi. Katso myös 2013 artikkeli layoutin automatisoinnista ja 2009 artikkeli, joka käsittelee spekulatiivista lexing/jäsentämistä.
- Servo layout on mozilla wiki
- Robert O’Callahan’s mega-presentation - Paljon tietoa selaimista
- ZOOMM paper - Qualcommin verkon esihaku ja yhdistetyt selektorit/cascade
- Strings in Blink
- Incoherencies in Web Access Control Policies - Analyysi document.domainin, cross-origin iframejen ja muun outouden yleisyydestä
- A Case for Parallelizing Web Pages – Sam Kingin palvelinproxy verkkosivujen partitiointiin. Katso myös hänen prosessieristystyönsä, joka raportoi rinnakkaisuuden hyödyistä.
- High-Performance and Energy-Efficient Mobile Web Browsing on Big/Little Systems Säästä virtaa vaihtamalla dynaamisesti käytettävää ydintä automaattisen työkuorman heuristiikan perusteella
- C3: An Experimental, Extensible, Reconfigurable Platform for HTML-based Applications Microsoft Researchin C#-selainprototyyppi, joka tarjosi samanaikaisen (vaikkakaan ei onnistuneesti rinnakkaistetun) arkkitehtuurin
- CSS Inline vertical alignment and line wrapping around floats - dbaron jakaa viisautta floateista
- Quark - Muodollisesti verifioitu selainkernel
- HPar: A Practical Parallel Parser for HTML
- Gecko HTML parser threading
Projektin rakenne
- components
- bluetooth — Bluetooth-säieen toteutus.
- canvas — 2D- ja WebGL-canvasien maalaussäieiden toteutus.
- compositing — Integraatio OS:n ikkunointi/renderöinti- ja tapahtumasilmukkaan.
- constellation — Resurssien hallinta ylätason selauskontekstille (ts. välilehdelle).
- devtools — Prosessin sisäinen palvelin selaininstanssien manipulointiin etä-Firefox-kehittäjätyökaluasiakkaan kautta.
- fonts — Koodi fonttien ja tekstin muotoilun käsittelyyn.
- layout — Muuntaa sivun sisällön sijoitetuiksi, tyylitetyiksi laatikoiksi ja välittää tuloksen rendererille.
- layout_thread — Ajaa layout-säieitä, viestii script-säieen kanssa ja kutsuu layout-cratea layoutin suorittamiseksi.
- msg — Jaetut API:t viestintään tiettyjen säieiden ja cratejen välillä.
- net — Verkkoprotokollien toteutukset sekä tilan ja resurssien hallinta (välimuisti, evästeet jne.).
- plugins — Syntaksilaajennukset, mukautetut attribuutit ja lintit.
- profile — Muistin ja ajan profilointityökalut.
- script — DOM:n toteutus (natiivi Rust-koodi ja bindings SpiderMonkeyhin).
- script_bindings - Tukikoodi ja WebIDL-tiedostoista generoidut bindings.
Bindings koostuvat trait:eista, jotka edustavat WebIDL-rajapintoja, ja liimakoodista
SpiderMonkey JavaScript -moottorille.
Varsinaiset trait-toteutukset sijaitsevat
script-crate:ssa. Nämä on jaettu kahteen crateen inkrementaalisten käännösten nopeuttamiseksi. - script_layout_interface — API, jonka script-crate tarjoaa layout-cratelle.
- selectors — CSS-selektorien täsmäytys.
- servo — Entry pointit servo-sovellukselle ja libservo-upotuskirjastolle.
- shared — Jaetut trait:t/koodi, joita useat komponentit käyttävät ilman riippuvuutta pääcrateen käännösnopeussyistä.
- style — API:t CSS:n jäsentämiseen ja tyylitiedostojen ja tyylitettyjen elementtien käsittelyyn.
- util — Sekalaisia apumetodeja ja -tyyppejä, joita käytetään laajasti projektissa.
- webdriver_server — Prosessin sisäinen palvelin selaininstanssien manipulointiin WebDriver-asiakkaan kautta.
- webgpu — WebGPU API:n säieiden toteutus.
- etc — Hyödyllisiä työkaluja ja skriptejä kehittäjille.
- ports
- servoshell — Esimerkkiselain, joka käyttää servoa.
- python
- mach — Komentorivityökalu kehittäjätehtävien helpottamiseen.
- servo — Servo-spesifisten mach-komentojen toteutukset.
- tidy — Python-paketti koodilinteistä, jotka ajetaan automaattisesti ennen muutosten yhdistämistä.
- resources — Ajonaikaiset tiedostot. Ne täytyy jotenkin sisällyttää, kun binäärikäännöksiä jaetaan.
- support
- android — Kirjastot, jotka vaativat erityiskäsittelyä Android-alustoille kääntäessä
- target
- debug —
./mach build --debug-komennolla generoidut käännösartefaktit. - doc — Dokumentaatio generoidaan tänne
rustdoc-työkalulla ajettaessa./mach doc - release —
./mach build --release-komennolla generoidut käännösartefaktit.
- debug —
- tests
- dromaeo — Harness Dromaeo-testisarjan automaattiseen ajoon.
- html — Manuaaliset testit ja kokeilut.
- jquery — Harness jQuery-testisarjan automaattiseen ajoon.
- power — Työkalut virrankulutuksen mittaamiseen.
- unit — Yksikkötestit rustc:n sisäänrakennetulla test harnessilla.
- wpt — W3C web-platform-tests ja csswg-tests työkaluineen niiden ajamiseen ja odotettuihin epäonnistumisiin.
Repositoriot
Servo-projekti ylläpitää useita repositorioita, jotka joko julkaistaan Servosta riippumatta tai on forkattu upstream-projektista.
Laajasti käytetty Rust-ekosysteemissä
- euclid: Geometriset tyypit
- ipc-channel: Prosessienvälinen viestintäkanava
- html5ever: HTML5-parseri Rustilla
- rust-cssparser: CSS-parseri Rustilla
- rust-url: URL-kirjasto Rustille, perustuu URL Standardiin. Tunnetaan myös nimellä
url. - string-cache: Merkkijonojen internointikirjasto
Forkit
- mozjs: Servon fork SpiderMonkeysta ja Rust-bindingsista
- stylo: Servon CSS-toteutus säännöllisellä synkronoinnilla upstream-versioon Gecko-repositoriossa
- webrender: Firefoxin WebRenderin fork pienillä Servo-spesifisillä muutoksilla
Servo-sisäiset
- book: Tämä kirja!
- ci-runners: Skriptit ja työkalut Servon CI:lle (continuous integration)
- malloc_size_of: Arvojen ajonaikaisen koon mittaus
- media: Mediat backend, jota Servo käyttää, tällä hetkellä vain GStreamer
- servo: Päärepositorio Servo web platform -moottorille
- surfman: Matalan tason cross-platform Rust-kirjasto graafisten pintojen hallintaan
- wpt: Servon fork Web Platform Testsistä
Kokeelliset web-alustan ominaisuudet
Tämä on luettelo web-alustan ominaisuuksista, joilla on osittainen toteutus Servossa ja jotka on rajattu valinnaisen pref-asetuksen taakse.
Seuraavat ominaisuudet otetaan käyttöön kokeellisella renderöintitilalla tai --enable-experimental-web-platform-features -lipulla.
| Ominaisuus | Seuranta-issue | Pref |
|---|---|---|
| CSS Font Loading API | #29376 | dom_fontface_enabled |
| CSS Grid | #34479 | layout_grid_enabled |
| CSS Multicol | #22397 | layout_columns_enabled |
| Clipboard API | #36084 | dom_async_clipboard_enabled |
| Document.execCommand | #25005 | dom_exec_command_enabled |
| IndexedDB | #6963 | dom_indexeddb_enabled |
| IntersectionObserver | #35767 | dom_intersection_observer_enabled |
| Navigator.registerProtocolHandler() | #40615 | dom_navigator_protocol_handlers_enabled |
| Notification API | #34841 | dom_notification_enabled |
| OffscreenCanvas | #34111 | dom_offscreen_canvas_enabled |
| Permissions API | #31235 | dom_permissions_enabled |
| Sanitizer API | #43948 | dom_sanitizer_enabled |
| Storage API | #43976 | dom_storage_manager_api_enabled |
| Variable fonts | #38800 | layout_variable_fonts_enabled |
| WebGL2 | #41394 | dom_webgl2_enabled |
| WebGPU | #24706 | dom_webgpu_enabled |
Seuraavat ominaisuudet ovat oletuksena pois päältä, mutta ne voi kytkeä päälle komentorivillä (esim. --pref dom_webgpu_enabled).
| Ominaisuus | Seuranta-issue | Pref |
|---|---|---|
| Adopted Stylesheet | #38132 | dom_adoptedstylesheet_enabled |
| CSS writing modes | #2560 | layout_writing_mode_enabled |
| CookieStore | #37674 | dom_cookiestore_enabled |
| Credential Management API | #38788 | dom_credential_management_enabled |
| File and Directory Entries API | #45653 | dom_entries_api_enabled |
| Geolocation API | #38903 | dom_geolocation_enabled |
| Largest Contentful Paint | #42000 | largest_contentful_paint_enabled |
| Media Capture and Streams API | #26861 | dom_canvas_capture_enabled |
| Screen Wake Lock API | #43615 | dom_wakelock_enabled |
| ServiceWorker | #36538 | dom_serviceworker_enabled |
| VisualViewport | #41341 | dom_visual_viewport_enabled |
| Web Animations | #36950 | dom_web_animations_enabled |
| WebRTC | #41396 | dom_webrtc_enabled |
| WebRTC Transceiver | #41396 | dom_webrtc_transceiver_enabled |
| WebVTT | #22312 | dom_webvtt_enabled |
| WebXR Layers | #27468 | dom_webxr_layers_enabled |
Käytössä olevat web-alustan ominaisuudet
Tämä on luettelo web-alustan ominaisuuksista, joiden toteutus on riittävän valmis oletuskäyttöön.
Ne voidaan silti poistaa käytöstä valinnaisella pref-asetuksella (esim. --pref dom_webgpu_enabled=false).
| Ominaisuus | Seuranta-issue | Pref |
|---|---|---|
| AbortController | #34866 | dom_abort_controller_enabled |
| Gamepad API | #10977 | dom_gamepad_enabled |
| MutationObserver | #6633 | dom_mutation_observer_enabled |
| ResizeObserver | #39790 | dom_resize_observer_enabled |
| SharedWorker | #7458 | dom_sharedworker_enabled |
| WebCrypto API | #40687 | dom_crypto_subtle_enabled |
Script
Tämän dokumentin pitäisi tuoda sinut ajan tasalle Script Threadistä, rootingista ja Gc:stä. Se ei millään tavoin ole täydellinen.
Servo on ainutlaatuinen siinä, että se käyttää roskienkeruuta (garbage collection) joihinkin asioihin, jotka eivät ole ilmeisiä.
Esimerkiksi jokainen DOM-objekti (struct, jossa on #[dom_struct]) on SpiderMonkeyn roskienkeruun omistama.
Tämä edellyttää, että moottorin API:t, jotka vuorovaikuttavat näiden objektien kanssa, ovat turvallisia, kun roskienkeruu voi tapahtua monissa ohjelman kohdissa.
Vaikka roskienkeruujärjestelmä (GC) on monimutkainen ja sillä on useita tiloja, voimme olettaa, että aina kun GC ajetaan, Rust-ohjelma ei aja.
Rooting ja rooted-tyypit
Tärkeä osa roskienkeruuta on objektigraafin juurten määrittäminen. Juuri kertoo roskienkeruulle kaksi asiaa:
- Älä poista mitään arvoa, johon tästä juuresta on transitiivisesti pääsy.
- Jos roskienkeruu siirtää tämän juuritetun arvon muistissa, kaikki osoittimet tähän arvoon päivitetään.
Servon koodissa juuret luodaan automaattisesti käyttämällä DomRoot<T>, Root<T> ja Rooted<T> -tyyppejä.
Katso moduulin dokumentaatio lisätietoja eroista. Nämä tyypit toteuttavat Deref:in, joten voimme käsitellä niitä
tavallisina viitteinä.
Seuraavat esimerkit sisältävät yksinkertaistuksia oikeista Servo-koodimalleista helpottamaan ymmärtämistä.
Oletetaan seuraava koodi, joka määrittelee Kittens-tyypin, joka sisältää osoittimia Cat-tyyppeihin, ja kaikki nämä ovat roskienkeruun omistamia:
#![allow(unused)]
fn main() {
#[dom_struct]
struct Kittens {
children: Vec<Dom<Cat>>
}
fn play_with_kittens(kittens: &Kittens) {
let children = & cats.children;
play_with(children)
}
}
Ilman rootingia GC voisi keskeyttää ohjelman sen jälkeen, kun olemme saaneet viitteen children:iin, siirtää Kittens-structin ympäriinsä
ja meillä olisi virheellinen pääsy leikkiessämme niiden kanssa!
Tämä pätee, vaikka Kittens olisi juuritettu jollakin muulla mekanismilla aiemmin kutsuketjussa.
Muista, että roskienkeruu ei voi muuttaa paikallisen muuttujamme ‘children’ osoittimia, jos se ei tiedä niistä.
Siksi meidän täytyy muuttaa koodi muotoon
#![allow(unused)]
fn main() {
#[dom_struct]
struct Kittens {
children: Vec<Dom<Cat>>
}
fn play_with_kittens(cats: &Kittens) {
let children: Vec<DomRoot<Cat>> = cats.children.iter().map(|cat| cat.as_rooted()).collect();
play_with(children)
}
}
Oletamme, että kissaviitteen hankkiminen ja juurittaminen on yksi atomitoiminto.
Juuren poisto (käänteinen operaatio) tapahtuu automaattisesti DomRoot<T>:n Drop-toteutuksen kautta.
Varmistaakseen, että web API -toteutukset Servossa ovat turvallisia, moottorikoodi on konservatiivinen ja palauttaa yleensä juuritettyjä tyyppejä (kuten DomRoot<Node>).
Tämä on hyväksyttävä kompromissi turvallisuuden ja suorituskyvyn välillä, koska juurittaminen ja juuren poisto ovat tehokkaita; ne käytännössä vain push:avat ja pop:avat vektorin elementtejä.
Crown ja CanGc
On helppoa unohtaa juurittamiseen liittyvät huolenaiheet toteuttaessa uusia API:ja.
Crown on vastaus (jos työskentelet Script-asioissa, sinun tulisi ajaa ./mach build --use-crown varmistaaksesi, että se tarkistaa asiat).
Pohjimmiltaan Crown vain tarkistaa, ettei juurittamista ole unohdettu, ja joskus näet koodissa tiettyjä linttejä, jotka viittaavat crown:iin, kuten #[cfg_attr(crown, allow(crown::unrooted_must_root))]. Nämä käytännössä poistavat crown-tarkistuksen käytöstä ja niitä tulisi käyttää vain hyvin erityisissä olosuhteissa.
Mutta on toinenkin palanen palapelissä, joka liittyy sivuttain. Vaikka juurittaminen antaa meille tavan pakottaa GC:n käyttäytymään kunnolla Rust-osoittimiemme kanssa, meillä on myös Rust RefCell:it. Vaikka näiden osoittimet käsitellään nyt oikein GC:n toimesta, GC:n täytyy lainata RefCell:iä testatakseen saavutettavuutta ja ohjatakseen osoitinta uudelleen.
Mutta voimme lainata RefCell:iä vain ei samanaikaisesti. Mitä tapahtuu, jos GC keskeyttää ohjelman, kun meillä on cell-laina aktiivisena?
#![allow(unused)]
fn main() {
struct CatCarrier {
cat: RefCell<Dom<Cat>>,
}
fn some_function(carrier: &CatCarrier) {
let mutable_cat = carrier.inner_cat.borrow_mut().as_rooted();
play_with_cat_mutably(mutable_cat);
cleanup_playspace();
}
}
Oletetaan nyt, että cleanup_playspace voi kutsua GC:tä. Silloin voi tapahtua, että
- Pidämme mutable-lainaa kissalle carrier:in sisällä.
- Siivoamme kissan jälkeen.
- GC keskeyttää ja yrittää jäljittää juuritetun
mutable_cat:in lainaamalla RefCell:iä. - Panikoi, koska RefCell:iä voi lainata mutably vain kerran!
Kutsumme tätä borrow hazard -tilanteeksi. Estääksemme tämän, meillä on seuraava ratkaisu.
#![allow(unused)]
fn main() {
fn some_function(carrier: &CatCarrier, can_gc: CanGc) {
{
let mutable_cat = carrier.inner_cat.borrow_mut().as_rooted();
play_with_cat_mutably(mutable_cat);
}
cleanup_playspace(can_gc);
}
}
Nyt tämä esimerkki ei ole täydellinen ja on täällä vain seuraavan pointin havainnollistamiseksi.
CanGC (joka on triviaali tyyppi ja helposti kopioitavissa) otettiin käyttöön, ei muodollisena borrow hazard -estona vaan muistutuksena ohjelmoijalle. Se sanoo:
Ole varovainen, jos haluat mutable-lainan, ettei se ylitä funktion rajoja, joka ottaa CanGc:n.
Lisätietoja siitä, miten borrow hazard -tilanteet tunnistetaan ja käsitellään, on täällä.
Haluamme käyttää tätä vain motivoivana esimerkkinä seuraavalle osiolle &JSContext
ja &mut JSContext.
Käynnissä oleva esimerkkimme näyttäisi sitten suunnilleen tältä:
#![allow(unused)]
fn main() {
fn some_function(cats: &Kittens, can_gc: CanGc) {
let children: Vec<DomRoot<Cat>> = cats.children.iter().map(|cat| cat.as_rooted()).collect();
play_with_cats(children);
cleanup_after_cats(children, can_gc);
}
}
Tarkka käsitys on, että voimme olla varmoja, ettei GC tapahdu, kun kutsumme play_with_cats:ia, mutta GC voi tapahtua, kun kutsumme cleanup_after_cats:ia. Syy siihen, miksi jotkin metodit voivat aiheuttaa GC:n ja jotkin eivät, on syvällä SpiderMonkey-yhteyksissä servoon, eikä se yleensä ole ilmeistä.
Mitä tämä tarkoittaa sinulle?
Pohjimmiltaan, jos kutsumasi metodi tarvitsee CanGc:n, metodisi tulisi käyttää CanGc:ä,
jotta kaikki voivat muistaa olla varovaisia borrow hazard -tilanteiden suhteen koodin ympärillä.
JSContext, &mut JSContext
Mutta kuten näet, tämä voi olla vaarallista. Entä jos joku unohti käyttää CanGc-attribuuttia
funktiokutsussaan, mutta itse asiassa kutsuu GC:tä jossain syvällä kutsupinossa?
Silloin loimme borrow hazard -tilanteen, joka johtaa kaatumisiin, joita emme ehkä ymmärrä.
Ratkaistaksemme tämän otamme käyttöön JSContext:in ja &mut JSContext:in.
Toisin kuin CanGc, nämä tyypit käyttävät Rust-kääntäjän lainaus-sääntöjä ja SpiderMonkey API -wrappeja varmistaakseen, että mikä tahansa API, joka voi käynnistää roskienkeruun, vaatii &mut JSContext -argumentin.
Koska nämä arvot ovat uniikkeja, kutsujien täytyy välittää ne.
Vastaavasti mikä tahansa API-funktio, joka ei voi GC:ttä mutta tarvitsee silti pääsyn JS-kontekstiin, ottaa vain &JSContext -argumentin.
On myös NoGc-tyyppi, joka voidaan konstruoida JSContext:ista.
Koska tämä tyyppi lainaa &mut JSContext:ia, se tekee mahdottomaksi kutsua mitään koodia, joka vaatii &mut JSContext -argumentin (ts. voi käynnistää GC-operaation), kun NoGc-arvo on olemassa.
Huomautus: Tällä hetkellä Servo-koodikanta muuttuu aiemmasta
CanGc-lähestymistavastaJSContext-lähestymistapaan. Saatat nähdä molempia koodikannassa sekä useita escape hatch -ratkaisuja.
Rootingin suorituskyky
#![allow(unused)]
fn main() {
#[dom_struct]
struct Kittens {
children: Vec<Cat>
}
impl Kittens {
fn children(&self) -> Vec<DomRoot<Cat>> {
self.children.iter().map(|cat| cat.as_rooted()).collect()
}
}
fn some_function(cats: &Kittens) {
let happy = cats.children().iter().any(|cat| cat.is_purring());
if happy {
println!("Happy cat found!");
}
}
}
Tämä API kissojen kanssa vuorovaikutukseen on turvallisesti juuritettu, mutta kun lapsia on paljon, juurittaminen ja juuren poisto voivat kasaantua.
Voimme käyttää JSContext-tyyppejä varmistaaksemme, ettei rooting-sääntöjä rikkova koodi käynnistä GC-operaatioita, jotka voisivat havaita nämä rikkomukset.
Koska &mut on uniikki lainaus, voimme esitellä uuden tyypin:
#![allow(unused)]
fn main() {
struct UnrootedDom<'a, T> {
inner_cat: Dom<T>,
js_context: &mut 'a JSContext,
}
}
Sitten aina kun meillä on käsissä UnrootedDom, tiedämme, että niin kauan kuin se elää, emme voi kutsua mitään metodeja, joilla on GC.
Seuraava on virheellistä koodia.
#![allow(unused)]
fn main() {
#[dom_struct]
struct Kittens {
children: Vec<UnrootedDom<'_, Cat>>,
}
fn make_cats(cx: &mut JSContext) -> Kittens {}
fn play_with_cat(cx: &JSContext, cat: &Cat) {}
fn cleanup_after_cats(cx: &mut JSContext, cat: &Cat) {}
fn some_function(cx: &mut JSContext) {
let cats = make_cats(cx);
for cat in cats.children {
play_with_cat(cx, cat.inner_cat)
}
for cat in cats.children {
cleanup_after_cats(cx, cat)
}
}
}
Saamme kääntäjävirheen, että cx on lainattu mutably kerran ‘make_cats’:issa ja kerran ‘cleanup_after_cats’:issa. Mutta huomaa, että kutsu ‘play_with_cat’:iin on täysin ok.
Tämä on ‘UnrootedDomNode’:in ja vastaavien ‘Unrooted’-metodien ydin. Jotkut näistä voivat myös ottaa ‘NoGC’-argumentin
#![allow(unused)]
fn main() {
fn play_with_cats<'a>(no_gc: &'a NoGC, cat: Cat) {}
fn some_function(cx: &mut JSContext, cat: &Cat) {
play_with_cats(cx.no_gc(), cat);
}
}
Lisätietoja
TODO:
- https://github.com/servo/servo/blob/main/components/script/script_thread.rs
- JavaScript: Servo’s only garbage collector
SpiderMonkey
Servon SpiderMonkey-integraation nykytila ja näkymät: https://github.com/gterzian/spidermonkey_servo
Script Thread
DOM Bindings
DOM-bindings ovat WebIDL -rajapintojen toteutuksia natiivissa Rust-koodissa.
Koodigeneraattori tuottaa liimakoodia, joka altistaa nämä natiivi Rust -toteutukset JavaScriptille SpiderMonkey API:n kautta.
WebIDL-tiedostot sijaitsevat components/script_bindings/webidls/ -hakemistossa.
Nämä tiedostot sisältävät kunkin rajapinnan määrittelyn, mukaan lukien niiden nimet, attribuutit ja metodit.
Näiden rajapintojen Rust-toteutukset sijaitsevat components/script/dom -hakemistossa.
Jokainen Rust-toteutus on erityinen Rust struct, joka sisältää kunkin DOM-objektin tilan.
Layout Wrappers
JavaScript ajaa yhdellä säieellä, eikä DOM-rajapinnat ole säie-turvallisia.
Layoutin täytyy päästä käsiksi DOM:iin, mutta sen odotetaan ajavan eri säieillä.
Teoriassa tämä voi toimia, kunhan säie ei yritä lukea tai mutatoida DOM-objektia, kun toinen säie mutatoi samaa objektia.
Yritämme tehdä tästä unsafety-osiosta helpommin hallittavan rajoittamalla, miten layout voi käyttää DOM-objekteja wrapper struct:in kautta, joka altistaa rajoitetun, mutta yhteensopivan, toiminnallisuuden.
On kaksi käyttömallia:
- Layout olettaa itse, että vain yksi säie “omistaa” DOM-wrapperin jokaiselle solmulle, joten DOM:iin kirjoittaminen pitäisi olla turvallista. Solmun lapset voidaan käsitellä muilla säieillä samanaikaisesti. Toisaalta vanhempaan pääsy on erittäin vaarallista, koska toinen säie voi kirjoittaa ja lukea vanhempasolmua.
stylojaselectorsolettavat, että solmuihin pääsee mistä tahansa säieestä, mutta vain yksi säie kirjoittaa solmuun kerrallaan. Tämä tarkoittaa, että vanhempiin ja lapsiin pääsy on turvallista, mutta solmuun kirjoittaminen on erittäin vaarallista.
Lisäksi layout riippuu script:ista, joten DOM-instanssien välittäminen suoraan script:ista layout:iin ei ole mahdollista, muuten meillä olisi riippuvuussykli.
Sen sijaan layout-api altistaa trait-pohjaisen rajapinnan ja script toteuttaa sen.
Tämä mahdollistaa Layout-rajapinnan käsittelemään solmuja suoraan.
Neljä trait:ia, joita altistamme, ovat:
LayoutNode: Tämä on perusrajapinta DOM-solmulle, jota käytetään layoutissa.DangerousStyleNode: Tämä on rajapinta, joka toteuttaastylo- jaselectors-trait:t solmujen kanssa vuorovaikutukseen. Tämä voidaan luodaLayoutNode:sta kutsumalla unsafe-metodiaLayoutNode::dangerous_style_node(). Yleensä näitä solmuja ei tulisi käyttää layout-koodissa, ellei niitä välitetä suoraanstylo- taiselectors-kutsuun.LayoutElement: Tämä on perusrajapinta DOM-elementille, jota käytetään layoutissa.DangerousStyleElement: Tämä on rajapinta, joka toteuttaastylo- jaselectors-trait:t elementtien kanssa vuorovaikutukseen. Tämä voidaan luodaLayoutElement:ista kutsumalla unsafe-metodiaLayoutElement::dangerous_style_element(). Yleensä näitä elementtejä ei tulisi käyttää layout-koodissa, ellei niitä välitetä suoraanstylo- taiselectors-kutsuun.
script toteuttaa nämä trait:t tyypeillä ServoLayoutNode, ServoDangerousStyleNode, ServoLayoutElement ja ServoDangerousLayoutElement.
Lisäksi script altistaa kaksi muuta struct:ia, jotka toteuttavat stylo-trait:t: ServoDangerousStyleDocument ja ServoDangerousStyleShadowRoot.
Säännöt Layout Wrappers -käytölle
- Yksinkertaisuuden ja nopeampien käännösaikojen vuoksi trait-määrittelyissä (
LayoutNodejaLayoutElement) ei tulisi olla oletusmetodeja. Kaikki toteutuskoodi tulisi ollascript:issa. - Layout ei saisi käyttää
DangerousStyleNode:a jaDangerousStyleElement:iä, ellei se kutsustylo:on taiselectors:iin. Tällä hetkellä on muutamia poikkeuksia, mutta ne poistetaan vähitellen. - Layout ei saisi luottaa metodeihin, jotka on määritelty vain
ServoLayoutNode:ssa jaServoLayoutElement:issa. Sen sijaan uutta toiminnallisuutta tulisi lisätäLayoutNode- taiLayoutElement-trait:eihin ja sitten toteuttaaServoLayoutNode:ssa taiServoLayoutElement:issa. Tämä mahdollistaaTrustedNodeAddress:in poistamisen tulevaisuudessa jaLayoutNode:ien välittämisen suoraan layoutille, poistaen unsafe-koodin lähteen.
Microtasks
HTML-spesifikaation mukaan microtask on: “arkikielinen tapa viitata tehtävään, joka luotiin queue a microtask algorithm -algoritmin kautta” (lähde). Jokaisella event-loopilla — eli window, worker tai worklet — on oma microtask-jononsa. Jonoon lisätyt tehtävät ajetaan osana perform a microtask checkpoint -algoritmia, jota kutsutaan useista paikoista, pääasiallisesti tehtävän ajamisen jälkeen tehtäväjonosta, joka ei ole microtask-jono, ja jokainen kutsu tähän algoritmiin tyhjentää microtask-jonon — ajamalla kaikki siihen asti jonoon lisätyt tehtävät (ilman uudelleensisääntuloisuutta).
Microtask-jono Servossa
MicroTaskQueue on suoraviivainen spesifikaatioon perustuva toteutus: tehtävälista ja boolean uudelleensisääntuloisuuden estämiseksi checkpointissa.
Yksi luodaan jokaiselle runtime:lle, mikä vastaa spesifikaatiota, koska runtime luodaan per event-loop.
Window event-loopille, joka voi sisältää useita window-objekteja, jono jaetaan kaikkien sen sisältämien GlobalScope:ien kesken.
Dedicated workerit käyttävät child-runtime:a, mutta sillä on silti oma microtask-jononsa.
Microtask-jonotus
Tehtävä voidaan jonottaa microtask-jonoon sekä Rustista että JS-moottorista.
- JS:stä: JS-moottori kutsuu
enqueue_promise_jobaina, kun sen täytyy jonottaa microtask promise-käsittelijöiden kutsumiseksi. Tämä callback-mekanismi asetetaan kerran per runtime. Tämä tarkoittaa, että promisen ratkaiseminen, joko Rustista tai JS:stä, johtaa tähän callbackiin kutsumiseen ja microtaskin jonotukseen. Tiukasti ottaen microtask jonotetaan silti Rustista. - Rustista on useita paikkoja, joista microtaskit jonotetaan eksplisiittisesti “natiivista” Rustista:
- await a stable state -algoritmin toteuttamiseen script-threadin kautta, ilmeisesti vain script-threadin kautta, mikä tarkoittaa, että worker event-loopit eivät koskaan käytä tätä algoritmia.
- dom-queuemicrotask -algoritmin toteuttamiseen sekä window- että worker event-loopeissa.
- Ja useissa muissa paikoissa DOM:issa, jotka kaikki voidaan jäljittää
Microtask-enumin variantteihin - Microtask voidaan jonottaa vain vaiheista, jotka ajetaan tehtävän sisällä, ei koskaan vaiheista, jotka ajetaan “in-parallel” event-loopin kanssa.
Microtask Checkpointien ajaminen
perform-a-microtask-checkpoint vastaa MicrotaskQueue::checkpoint -metodia, ja sitä kutsutaan useissa kohdissa:
- Parserissa, kun törmätään
script-tagiin tokenisoinnin osana. Tämä vastaa #parsing-main-incdata:perform-a-microtask-checkpoint -kohtaa. - Uudelleen parserissa, osana elementin luomista. Tämä vastaa #creating-and-inserting-nodes:perform-a-microtask-checkpoint -kohtaa.
- Osana skriptin ajamisen jälkeistä siivousta. Tämä vastaa #calling-scripts:perform-a-microtask-checkpoint -kohtaa.
- Kahdessa kohdassa (yksi, kaksi)
CustomElementRegistry:ssä spesifikaation alkuperä näistä kutsuista on epäselvä: ne näyttävät olevan “clean-up after script”, mutta metodien dokumentaatiossa viitatuissa spesifikaation osissa ei ole viittauksia tähän. - Worker event-loopissa, osana event-loop-processing-model -algoritmin vaihetta 2.8
- Kahdessa paikassa (yksi, kaksi) window event-loopissa (
ScriptThread), jälleen osana event-loop-processing-model -algoritmin vaihetta 2.8. Tämä täytyy yhdistää yhdeksi kutsuksi, ja se, mikä on “tehtävä”, täytyy selventää (TODO(#32003)). - Paint worklet -toteutuksemme ei näytä vielä ajavan tätä algoritmia.
Roskienkeruu ja RefCell
Servon integraatio SpiderMonkeyn roskienkeruujärjestelmään ja Rustin malli jaetulle omistajuudelle vuorovaikuttavat hienovaraisesti.
Koska DOM-objektit Servossa eivät ole uniikisti omistettuja, meidän täytyy käyttää RefCell/DomRefCell:iä jäsenille, joita voidaan mutatoida.
Kun roskienkeruu (GC) käynnistetään SpiderMonkeysta, jokainen DOM-objekti jäljitetään löytääkseen saavutettavat JS-arvot.
Tämä jäljitys on toteutettu JSTraceable-derive:llä, joka kutsuu JSTraceable::trace:a jokaiselle DOM-objektin jäsenelle (ellei sitä ole annotoitu #[no_trace]-attribuutilla).
Koska RefCell:in JSTraceable-toteutus lainaa solua, tämä tarkoittaa, että mikä tahansa DOM-objektin jäsenen mutable-laina aiheuttaa paniikin, jos GC tapahtuu, kun laina on vielä aktiivinen.
Kutsumme tätä usein Servossa borrow hazard -tilanteeksi.
Borrow hazard -tilanteiden tunnistaminen: CanGc
Servossa on tyyppi nimeltä CanGc, jota käytetään osoittamaan, milloin GC voi tapahtua ennen kuin kutsuttu funktio palaa.
On yksi sääntö: kun kutsutaan funktiota, joka hyväksyy CanGc-argumentin, kutsujan täytyy myös hyväksyä CanGc-argumentti.
Tähän sääntöön on poikkeuksia:
- trait-metodit, jotka on määritelty
script/script_bindings-cratejen ulkopuolella, eivät voi propagoidaCanGc:ä, joten toteutusten täytyy käyttääCanGc::note():a, jos kutsuttu funktio vaatiiCanGc-argumentin - asynkronisten tehtävien täytyy käyttää
CanGc::note():a, koska ne suoritetaan riippumatta kutsujan stack frame:sta extern "C"-funktioiden täytyy käyttääCanGc::note():a, koska ne vaativat vastaavan allekirjoituksen ulkoiselle kirjastolle
Kun CanGc propagoidaan oikein koodin läpi, borrow hazard -tilanteet voidaan tunnistaa etsimällä borrow_mut()-käyttöjä can_gc:n käytön läheltä.
Erityisesti, kun borrow_mut():n palautusarvo tallennetaan muuttujaan, ja muuttuja on vielä elossa, kun funktiokutsu sisältää can_gc-argumentin, on erittäin todennäköistä, että kyseessä on paniikki odottamassa laukeamistaan!
Katso esimerkki-issue, joka korostaa borrow hazard -tilannetta. Lue lisää alkuperäisestä issue:sta, joka ehdotti staattista analyysiä.
Borrow hazard -tilanteiden varmentaminen
Varmistaaksemme, että tietty mutable-laina voi laukaista paniikin GC:n tapahtuessa, tarvitsemme 1) deterministisen roskienkeruun, 2) tavan ajaa epäilyttävä koodi.
Tehdäksesi roskienkeruusta deterministisen, sinun täytyy ensin kääntää Servo --debug-mozjs:llä, sitten ajaa se --pref js_mem_gc_zeal_level=2 --pref js_mem_gc_zeal_frequency=1 -asetuksilla.
Tämä ottaa käyttöön tilan, jossa roskienkeruu ajetaan aina JS-allokaation tapahtuessa, ja se varmasti laukaisee kaikki piilevät borrow hazard -tilanteet.
Se on myös erittäin hidas, joten testitapauksen minimointi säästää aikaa.
Jos et ole varma, miten epäilyttävä koodi laukaistaan, lisää siihen paniikki ja aja WPT-testejä sopivasta hakemistosta, kunnes löydät testitiedoston, joka panikoi.
Mallit borrow hazard -tilanteiden korjaamiseen
- Pakota laina pudotettavaksi aiemmin scopettamalla se (
{ ... }) - Kloonaa väliaikainen arvo lainatusta arvosta, jotta laina voidaan pudottaa aiemmin
- Sen sijaan, että käytät
RefCell<SomeStruct>:ia, teeSomeStruct:in jäsenet käyttämäänRefCell/Cell:iä - Jaa sekoitettu immutable/mutable-laina useiksi scopatuiksi immutable-lainauksiksi ja käytä mutable-lainauksia vain mutaation tapahtuessa
Esimerkkejä borrow hazard -tilanteiden korjaamisesta
- https://github.com/servo/servo/pull/40139
- https://github.com/servo/servo/pull/40138
Esimerkkejä CanGc-argumenttien propagoinnista
- https://github.com/servo/servo/pull/40033
- https://github.com/servo/servo/pull/36180
- https://github.com/servo/servo/pull/40325
CanGc-argumenttien lisääminen generoituihin DOM-metoditrait:eihin
WebIDL-metodien ylimääräiset argumentit kontrolloidaan Bindings.conf -tiedostolla.
CanGc-argumentit kontrolloidaan erityisesti canGc-avaimella tietylle rajapinnalle.
Jos rajapintaa ei ole vielä listattu tiedostossa, voit vapaasti lisätä sen.
Servon tyylisysteemin yleiskatsaus
Tämä dokumentti tarjoaa yleiskatsauksen Servon tyylisysteemistä. Laajempia yksityiskohtia varten katso style doc comments tai wikin Styling Overview, joka sisältää keskustelun Boris Zbarskyn ja Patrick Waltonin välillä siitä, miten tyylien jakaminen toimii.
Selektoritoteutus
Stylo-yhteensopivuuden varmistamiseksi (projekti, joka integroi Servon tyylisysteemin Geckoon) selektorien täytyy olla yhdenmukaisia.
Yhdenmukaisuus on toteutettu selectors’ SelectorImpl -kohdassa, joka sisältää logiikan pseudo-elementtien ja muiden pseudo-luokkien jäsentämiseen puurakenteellisten pseudo-luokkien lisäksi.
Servo laajentaa selektoritoteutuksen trait:ia salliakseen muutamien asioiden jakamisen Stylon ja Servon välillä.
Servon pääasiallinen toteutus (jota käytetään tavallisissa käännöksissä) on SelectorImpl.
DOM-liima
DOM:n, layoutin ja tyylin pitäminen eri moduuleissa vaatii muutamia trait:eja.
Stylen dom-trait:t (TDocument, TElement, TNode, TRestyleDamage) ovat pääasiallinen “muuri” layoutin ja tyylin välillä.
Layoutin wrapper-moduuli varmistaa, että layout-trait:eilla on vaaditut trait:t toteutettuina.
Stylist
stylist-rakenne sisältää kaikki selektorit ja laitteen ominaisuudet tietylle dokumentille.
Tyylitiedostojen CSS-säännöt muunnetaan Rule-objekteiksi.
Ne sijoitetaan sitten SelectorMap -rakenteeseen pseudo-elementin (katso PerPseudoElementSelectorMap), tyylitiedoston originin (katso PerOriginSelectorMap) ja prioriteetin (katso normal- ja important-kentät PerOriginSelectorMap -rakenteessa) mukaan.
Tämä rakenne luodaan käytännössä kerran per pipeline, vastaavassa LayoutThread:ssä.
properties-moduuli
properties module on mako-malli.
Sen monimutkaisuus johtuu koodista, joka tallentaa ominaisuuksia, cascade-funktiosta ja palautetun arvon laskentalogiikasta, joka on altistettu pääfunktiossa.
Layout
Servon nykyinen layout-järjestelmä tunnetaan myös nimellä Layout 2020. Se korvasi alkuperäisen layout-järjestelmän, joka tunnettiin myös nimellä Layout 2013.
Layout tapahtuu kolmessa vaiheessa: box tree -rakentaminen, fragment tree -rakentaminen ja display list -rakentaminen. Kun display list on generoitu, se lähetetään WebRenderille renderöintiä varten. Aina kun mahdollista puurakentamisen aikana, layout yrittää käyttää rinnakkaisuutta Rayonin avulla. Tietyt CSS-ominaisuudet estävät rinnakkaisuuden, kuten floatit tai laskurit. Sama koodi käytetään sekä rinnakkaisessa että peräkkäisessä layoutissa.
Box Tree
Box tree on puu, joka edustaa sisäkkäisiä formatting contexteja CSS-spesifikaatiossa kuvatulla tavalla. Formatting contexteja on erilaisia, kuten block formatting context (block flow:lle), inline formatting context (inline flow:lle), table formatting context ja flex formatting context. Jokaisella formatting contextilla on eri säännöt laatikoiden sijoittelulle kontekstin sisällä. Servo edustaa tätä kontekstipuuta sisäkkäisillä enum:eilla, jotka varmistavat, että kontekstin sisältö voi olla vain sellaista sisältöä, jota spesifikaatio kuvaa.
Box tree on vain layout-tilan alkuperäinen esitys, ja yleisesti ottaen seuraava vaihe on ajaa layout-algoritmi box tree:llä ja tuottaa fragment tree.
CSS:n fragmentit ovat tuloksia elementtien jakamisesta box tree:ssä useisiin fragmentteihin rivinvaihtojen, sarakkeiden ja sivutuksen vuoksi.
Lisäksi layout-vaiheessa Servo sijoittaa ja mitoittaa tuloksena olevat fragmentit suhteessa niiden containing blockeihin.
Muunnos tapahtuu yleensä funktiossa layout(...) eri box tree -tietorakenteilla.
Box tree:n layout fragment tree:ksi tehdään rinnakkain, kunnes tullaan puun osaan, jossa on floatit. Näissä osissa tehdään peräkkäinen läpäisy, ja rinnakkainen layout voi jatkua uudelleen, kun layout-algoritmi siirtyy floatit sisältävän block formatting contextin rajojen yli, joko laskeutumalla riippumattomaan formatting contextiin tai viimeistelemällä float-kontin layoutin.
Fragment Tree
Layout-vaiheen tuote on fragment tree.
Tässä puussa elementeillä, jotka on jaettu eri paloihin rivinvaihtojen, sarakkeiden tai sivutuksen vuoksi, on fragmentti jokaiselle palalle.
Lisäksi jokainen fragmentti on sijoitettu suhteessa fragmenttiin, joka vastaa sen containing blockia.
Positionoituja fragmentteja varten alkuperäiseen puun sijaintiin jätetään ylimääräinen placeholder-fragmentti AbsoluteOrFixedPositioned.
Tätä placeholderia käytetään display listin rakentamiseen oikeassa järjestyksessä CSS:n maalausjärjestyksen mukaan.
Display List -rakentaminen
Kun layout on luonut fragment tree:n, se voi siirtyä renderöinnin seuraavaan vaiheeseen, joka on display listin tuottaminen puulle. Tässä vaiheessa fragment tree muunnetaan WebRender -display listiksi, joka koostuu display list -kohteista (suorakulmiot, viivat, kuvat, tekstijaksot, varjot jne.). WebRender ei tarvitse suurta valikoimaa display list -kohteita web-sisällön edustamiseen.
Normaalien display list -kohteiden lisäksi WebRender käyttää spatial node -puuta muunnosten, scrollattavien alueiden ja sticky-sisällön edustamiseen. Tämä puu on käytännössä kuvaus siitä, miten post-layout-muunnoksia sovelletaan display list -kohteisiin. Kun sivua scrollataan, juuren scrollaus-solmun offsetia voidaan säätää ilman välitöntä layoutia. Samoin WebRender voi soveltaa muunnoksia, mukaan lukien 3D-muunnoksia, web-sisältöön spatial node -tyypillä, jota kutsutaan reference frame:ksi.
Leikkaus, olipa se CSS-leikkauksesta tai CSS:n overflow-ominaisuuden tuomasta leikkauksesta, käsitellään toisella clip node -puulla.
Näille solmuille on myös määritetty spatial node:t, jotta leikkaukset pysyvät synkassa muun web-sisällön kanssa.
WebRender päättää, miten parhaiten soveltaa sarjan leikkauksia jokaiseen kohteeseen.
Kun display list on rakennettu, se lähetetään compositorille, joka välittää sen WebRenderille.
Compositor
TODO: Katso https://github.com/servo/servo/blob/main/components/compositing/compositor.rs
Canvas
Servo tukee neljää canvas-kontekstityyppiä:
CanvasRenderingContext2D(2d-konteksti)WebGLRenderingContext(webgl-konteksti)WebGL2RenderingContext(webgl2-konteksti)GPUCanvasContext(webgpu-konteksti)
Jokainen canvas-konteksti toteuttaa CanvasContext-traitin, joka vaatii kontekstien toteuttavan joitakin yhteisiä ominaisuuksia yhtenäisellä tavalla:
context_idresize: tämä metodi tyhjentää maalarin kuvan asettamalla sen läpinäkyväksi alfaksi (kaikki tavut nolliksi)get_image_data: käytetään canvas-kuvan hankkimiseen, yleensä kutsumallatoDataUrl,toBlob,createImageBitmapcanvas-elementillä tai epäsuorasti piirtämällä yhden canvasin toiseenupdate_the_rendering: renderöinnin päivityksen käynnistämiseen (yleensä vaihtamalla screen-buffer ja back-buffer)canvas: hanki kytketty canvas-elementti (tämä voi ollaHTMLCanvasElementtaiOffscreenCanvas, joka voidaan myös kytkeäHTMLCanvasElement-elementtiin kontekstillaplaceholder) samalla tarjoten hyviä oletustoteutuksia (onscreen,origin_is_clean,size,mark_as_dirty).mark_as_dirtykutsutaan funktioista, jotka vaikuttavat maalarin kuvaan, ja se kertoo layoutille renderöimään canvas-elementin uudelleen (merkitsemälläHTMLCanvasElementlikaiseksi solmuksi).
HTML-tapahtumasilmukka ja renderöinti
flowchart TB
subgraph Sisältöprosessi
subgraph Script-kulku
JS-->utr[Päivitä renderöinti]-->Layout
end
end
subgraph Pääprosessi
subgraph Maalarit
WGPU[WGPU-säie]
WEBGL[WebGL-säie]
CPT[Canvas Paint Thread]
end
%% actual update in painters
Painters--CreateImage-->Compositor
Painters--UpdateImage-->Compositor
Compositor-->WR
WR[WebRender]--lock,unlock-->Painters
end
%% init canvas
JS--create context-->Painters--ImageKey, CanvasId-->JS
%% update canvas rendering
utr<--Update rendering-->Painters
%% rendering
Layout--DisplayList (contains ImageKey)-->Compositor
HTML-tapahtumasilmukan osana script-säie suorittaa tehtävän (jäsentäminen, skriptin evaluointi, callbackit, tapahtumat, …) ja sen jälkeen se suorittaa microtask-checkpointin, joka tyhjentää microtask-jonon.
Window event loopissa jonotamme globaalin tehtävän renderöinnin päivittämiseen, jos on rendering opportunity (yleensä compositorin ohjaama laitteistopäivitystaajuuden perusteella).
Servossa emme itse asiassa jonota tehtävää, vaan ajamme update the rendering -algoritmin ScriptThreadin IPC-viestien jälkeen ja sitten suoritamme myös microtask-checkpointin, kuten tapahtumasilmukka olisi tehnyt tehtävän valmistuttua.
Update the rendering suorittaa erilaisia resize-, scroll- ja animaatiovaiheita (mukaan lukien microtask-checkpointin avoimien promisejen ratkaisemiseksi) ja sitten ajaa animation frame -callbackit (callbackit, jotka on lisätty requestAnimationFrame -kutsulla).
Tässä vaiheessa piirtokomennot lähetetään maalareille uuden animaatiokehyksen luomiseksi.
Lopuksi käynnistämme reflow’n (layout), joka ensin päivittää canvasien renderöinnin (fluskaamalla likaiset canvasit) ja animoidut kuvat, sitten käy DOM:n ja sen tyylit läpi, rakentaa DisplayList:in ja lähettää sen WebRenderille renderöintiä varten.
Kun canvas-kontekstin luontia pyydetään (canvas.getContext('2d')), script-säie blokkaa maalarisäieellä sen alustuessa ja luodessa uuden WebRender-kuvan (CreateImage), ja lopulta lähettää siihen liittyvän ImageKey:n takaisin scriptille.
sequenceDiagram
Script->>Constellation: Create Context
Constellation->>Painter: Create Context
Painter->>Compositor: GenerateImageKey
Compositor->>WebRender: GenerateImageKey
opt
Painter<<->>Compositor: ExternalImageId
end
WebRender->>Compositor: ImageKey
Compositor->>Painter: ImageKey
Painter->>Compositor: CreateImage
Compositor->>WebRender: CreateImage
Painter->>Script: PainterIPCSender, ImageKey, CanvasId
Jokainen canvas-konteksti toteuttaa LayoutCanvasRenderingContextHelpers, joka palauttaa ImageKey:n, jota layout käyttää DisplayList:issään, tai None, jos canvas on tyhjennetty tai muuten ei maalattavissa koon vuoksi.
WebRender lukee tuloksena olevan kuvadatan renderöinnin yhteydessä annetun ImageKey:n perusteella.
WebGL- ja WebGPU-maalareissa tämä tehdään toteuttamalla mukautettu WebrenderExternalImageApi; se tarjoaa lock- ja unlock-metodit WebRenderille varsinaisen kuvadatan hankkimiseksi.
2D-canvaksissa kuvadata toimitetaan suoraan CreateImage- ja UpdateImage-IPC-viestien kautta.
sequenceDiagram
Script->>Painter:Update rendering (flush)
Painter->>Compositor:UpdateImage
Compositor->>WebRender: UpdateImage
opt
Painter->>Script: Done
end
Note over Script: Layout
Script->>Compositor: DisplayList
Compositor->>WebRender: DisplayList
opt
Compositor<<->>WebRender: Query ExternalImage Registery
WebRender->>+Painter: lock ExternalImage
WebRender->>Painter: unlock ExternalImage
deactivate Painter
end
2D-canvas-konteksti
flowchart LR
CanvasRenderingContext2d --- HTMLCanvasContext
subgraph OffscreenCanvasRenderingContext2D
subgraph CanvasRenderingContext2d
CS'[CanvasState]
end
end
OffscreenCanvasRenderingContext2D --- OffscreenCanvas
PaintRenderingContext2D --- PaintWorklet
subgraph PaintRenderingContext2D
CS''[CanvasState]
end
Useimmat canvasit käyttävät samaa DOM-tyyppiä onscreen- ja offscreen-konteksteilleen, mutta 2D-canvaksissa näin ei ole niiden pitkän historian vuoksi. Web-standardit määrittelevät kolme 2D-canvas-kontekstityyppiä:
CanvasRenderingContext2D(kytkettyHTMLCanvasContext-elementtiin)OffscreenCanvasRenderingContext2D(kytkettyOffscreenCanvas-elementtiin)PaintRenderingContext2D(saatavilla vainPaintWorklet:issä)
CanvasRenderingContext2D ja PaintRenderingContext2D on toteutettu wrapper:eina CanvasState:n ympärille, kun taas OffscreenCanvasRenderingContext2D on toteutettu wrapper:ina CanvasRenderingContext2D:n ympärille samankaltaisen logiikan vuoksi duplikaation välttämiseksi.
flowchart LR
HTMLCanvasElement --getContext('2d')--> CanvasRenderingContext2d
CanvasRenderingContext2d --strokeRect--> CanvasState
CanvasState --IPC
strokeRect--> CanvasPaintThread
CanvasPaintThread --Done--> CanvasState
CanvasState toteuttaa varsinaisen 2D-piirron logiikan asettamalla sopivan tilan ja lähettämällä IPC-viestejä Canvas Paint Threadille.
Jotkin komennot muuttavat vain sisäistä tilaa, mutta eivät lähetä viestejä ennen kuin on varsinainen piirtokomento.
Kaikki “likaiset” 2D-canvasit tallennetaan Document:iin ja flusataan reflow’n aikana lähettämällä IPC-viestejä, jotka käynnistävät update_the_rendering-metodin jokaiselle canvasille.
Kun piirretään yksi 2D-canvas toiseen 2D-canvasiin, lähetämme DrawImageInOther-viestin, erityisen IPC-viestin, joka välttää bitmapin kopioimisen canvas paint thread -säieeltä ulos.
WebGL-canvas-konteksti
flowchart LR
WebGLRenderingContext --- c["HTMLCanvasElement
OffscreenCanvas"]
subgraph WebGL2RenderingContext
WebGLRenderingContext
end
WebGL(2)-canvas-kontekstit ovat WebGLRenderingContext tai WebGL2RenderingContext, ja Servossa WebGL2RenderingContext wrap:aa ja laajentaa WebGLRenderingContext:ia.
Nämä kontekstit tallentavat tilaa ja lähettävät IPC-viestejä WebGL-säieelle, joka suorittaa varsinaiset OpenGL- (tai OpenGL ES) -komennot ja palauttaa tulokset IPC:n kautta.
Script-säie blokkaa WebGL-säieellä odottaen jokaisen operaation valmistumista.
Kaikki “likaiset” WebGL-canvasit tallennetaan Document:iin ja flusataan reflow’n osana lähettämällä yksi IPC-viesti, joka sisältää kaikki likaiset kontekstitunnukset, ja sitten blokkaamalla WebGL-säieellä, kunnes kaikki canvasit on flusattu.
Fluskaus vaihtaa framebufferin, joista toinen on esitystä varten (WebRender lukee sen) ja toista käytetään piirtämiseen GL-komentojen kohteena.
WebGPU-canvas-konteksti
WebGPU-esitys on erityisin, koska se on täysin asynkroninen (ei-blokkaava). Lisätietoa siitä, miten asynkronisuus toteutetaan WebGPU:ssa, löytyy WebGPU-luvusta.
sequenceDiagram
loop Context Creation
Script->>WGPU: CreteContext
WGPU->>WebRender: CreateImage
WebRender->>WGPU: ImageKey
WGPU->>Script: ImageKey
end
alt animation Callback
Note over Script: getCurrentTexture
Script-)WGPU:CreateTexture
activate Script
Note over Script: draw operations into current texture
else update the rendering
Note over Script: expire current texture
Script-)WGPU:SwapchainPresent
WGPU-)WGPU: Copy texture to one of staging buffer
WGPU-)+WGPU poller: Map stagging buffer to CPU as GPUPresentationBuffer
opt presentationId is newer than existing
WGPU poller -)-WebRender: UpdateImage
end
WGPU poller -)WGPU poller: Unmap GPUPresentationBuffer
Script-)WGPU:DestroyTexture
deactivate Script
end
loop rendering
WebRender<<->>+WGPU: lock ExternalImage and read GPUPresentationBuffer
WebRender->>WGPU: unlock ExternalImage
deactivate WGPU
end
Kaikilla onscreen WebGPU-konteksteilla update_the_rendering suoritetaan osana renderöinnin päivitystä HTML-tapahtumasilmukassa.
Tämä vanhentaa (tuhoaa) current texture -objektin, mutta ennen sitä lähetämme SwapChainPresent-pyynnön, joka kopioi tekstuuridatan yhteen 10 esityspuskurista GPU:lla.
Kopioinnin valmistuttua map:ataan uusi puskuri asynkronisesti CPU:lle.
Koska prosessi on asynkroninen, merkitsemme jokaisen esityspuskurin kasvavalla u64-tunnuksella, ja korvaamme aktiivisen esityspuskurin vain, jos puskurimme tunnus on uudempi.
Epäaktiivinen esityspuskuri unmap:ataan.
flowchart TD
S[Staging Presentation Buffer] --copy_texture_to_buffer, mapAsync-->
Mapping --mapAsync done-->
UpdateWR --yes-->
Mapped[Mapped, Unmapped old]
UpdateWR--else unmap-->S
Tämä on mallinnettu myös TLA+:ssa: https://gist.github.com/gterzian/aa5d96a89db280017b04917eee67f6ac
Sekä WebRenderin lock että get_image_data käyttävät aktiivisen esityspuskurin sisältöä.
Resurssit
- https://medium.com/@polyglot_factotum/fixing-servos-event-loop-490c0fd74f8d
- Update the rendering of canvas (#35733)
- webgpu: renovate gpucanvascontext and webgpu presentation to match the spec (#33521)
- webgpu: Fix HTML event loop integration (#34631)
- webgpu: Introduce PresentationId to ensure updates with newer presentation (#33613)
- webgpu: Make uploading data to wr with less copies (#33368)
Miten WebXR toimii Servossa
Terminologia
Servon WebXR-toteutus koostuu kolmesta pääkomponentista:
- Script-säie (ajaa kaiken JS:n sivulle)
- WebGL-säie (ylläpitää WebGL-canvas-datan ja kutsuu GL-operaatioita, jotka vastaavat WebGL API:ja)
- Compositor (eli pääsäie)
Lisäksi on useita WebXR-spesifisiä käsitteitä:
- discovery object (eli miten Servo havaitsee, voiko laite tarjota WebXR-session)
- WebXR registry (compositorin rajapinta WebXR:ään)
- layer manager (hallinnoi WebXR-kerroksia tietylle sessiolle ja kehystoimintoja näillä kerroksilla)
- layer grand manager (hallinnoi kaikkia layer managereita WebXR-sessioille)
Lopuksi on grafiikkaan liittyviä käsitteitä, jotka ovat tärkeitä WebXR-renderöinnin matalan tason yksityiskohtien kannalta:
- Surfman on crate, joka abstrahoi alustakohtaiset yksityiskohdat OpenGL-laitteistokiihdytetystä renderöinnistä.
- surface on laitteistopuskuri, joka on sidottu tiettyyn OpenGL-kontekstiin.
- surface texture on OpenGL-tekstuuri, joka wrap:aa pinnan. Surface textureja voidaan jakaa OpenGL-kontekstien välillä.
- surfman context edustaa tiettyä OpenGL-kontekstia, ja sen taustalla on alustakohtaisia toteutuksia (kuten EGL Unix-pohjaisilla alustoilla).
- ANGLE on OpenGL-toteutus Direct3D:n päällä, jota Servo käyttää tarjotakseen yhtenäisen OpenGL-backendin Windows-alustoilla.
Miten Servon compositor käynnistyy
Upottaja on vastuussa ikkunan luomisesta ja renderöintikontekstin luonnin käynnistämisestä asianmukaisesti. Servo luo renderöintikontekstin luomalla surfman-kontekstin, jota compositor käyttää kaikkiin web-sisällön renderöintitoimintoihin.
Miten sessio käynnistyy
Kun verkkosivu kutsuu navigator.xr.requestSession(..) JS:n kautta, tämä vastaa Servon XrSystem::RequestSession -metodia.
Tämä metodi lähettää viestin WebXR-viestinkäsittelijälle, joka elää pääsäieellä compositorin hallinnassa.
WebXR-viestinkäsittelijä käy läpi kaikki tunnetut discovery objectit ja yrittää pyytää sessiota jokaiselta. Discovery objectit kapseloivat session luomisen jokaiselle tuetulle backendille.
Heinäkuun 19, 2024 tilanteessa on kolme WebXR-backendiä:
- headless - tukee ikkunatonta, laitteetonta laitetta automatisoiduille testeille
- glwindow - tukee GL-pohjaista ikkunaa manuaaliseen testaukseen työpöytäympäristöissä ilman oikeita laitteita
- openxr - tukee laitteita, jotka toteuttavat OpenXR-standardin
WebXR-sessioiden täytyy luoda layer manager jossain vaiheessa, jotta ne voivat luoda ja renderöidä WebXR-kerroksiin. Tämä tapahtuu useassa vaiheessa:
- Jotakin alustusta tapahtuu pääsäieellä
- Pääsäie lähettää synkronisen viestin WebGL-säieelle
- WebGL-säie vastaanottaa viestin
- Backend-spesifistä, grafiikka-spesifistä alustusta tapahtuu WebGL-säieellä, layer manager factory -abstraktion takana
- Uusi layer manager tallennetaan WebGL-säieelle
- Pääsäie vastaanottaa yksilöllisen tunnisteen uudelle layer managerille
Tämä säieiden välinen tanssi on tärkeä, koska renderöintiä suorittavalla laitteella on usein tiukat vaatimukset yhteensopivuudelle kaikille renderöintiin käytetyille WebGL-konteksteille, ja suurin osa GL-tilasta on havaittavissa vain säieellä, joka loi sen.
Miten OpenXR-sessio luodaan
OpenXR-discovery-prosessi alkaa OpenXrDiscovery::request_session -kohdasta. Discovery objectilla on pääsy vain siihen tilaan, joka välitettiin sen konstruktorissa, sekä SessionBuilder -objektiin, joka sisältää uuden session luomiseen tarvittavat arvot.
OpenXR-session luominen luo ensin OpenXR-instanssin, joka mahdollistaa käytössä olevien laajennusten konfiguroinnin. Eri alustoilla OpenXR:n alustukseen käytetään eri laajennuksia; Windowsilla käytetään XR_KHR_D3D11_enable extension, koska Servo luottaa ANGLEen OpenGL-toteutuksessaan.
Kun OpenXR-instanssi on olemassa, session builderia käytetään uuden WebXR-session luomiseen, joka ajaa omassa säieessään. Kaikki WebXR-sessiot voivat joko ajaa säieessä tai Servo voi ajaa ne pääsäieellä. Tällä valinnalla on vaikutuksia siihen, miten WebXR-session grafiikka voidaan konfiguroida, sen perusteella, mitä GL-tilaa täytyy olla saatavilla jaettavaksi.
OpenXR:n uusi session-säie alustaa OpenXR-laitteen, joka on vastuussa varsinaisen OpenXR-session luomisesta. Tämä session-objekti luodaan WebGL-säieellä osana OpenXR layer managerin luomista, koska se luottaa WebGL-säieen käyttämän GPU-laitteen jakamiseen.
Kun session-objekti on luotu, pääsäie voi hankkia kopion ja jatkaa uuden laitteen jäljellä olevien ominaisuuksien alustusta.
WebGPU
Servon WebGPU-toteutus perustuu wgpu(-core) -kirjastoon, ja se koostuu kahdesta osasta:
- DOM-toteutus
- WGPU-toteutus
flowchart LR
subgraph Sisältöprosessi
Script[Script-säie]
end
subgraph Pääprosessi
WGPU[WGPU-säie]
poller[WGPU poller]
WebRender
Constellation
end
%% init
Script--RequestAdapter-->Constellation
Constellation--RequestAdapter/WebRender-->WGPU
Script--WebGPURequest-->WGPU
WGPU--Adapter/WebGPU chan-->Script
%% normal operation
WGPU--token(), wake()-->poller
WGPU--Create/Update Image-->WebRender
WGPU--WebGPUResponse/WebGPUMsg-->Script
DOM-toteutus
DOM-toteutus sijaitsee components/script/dom/webgpu -hakemistossa, ja se toteuttaa JS-rajapinnat, jotka on määritelty WebGPU IDL -tiedostossa ja jotka on altistettu web-alustalle.
Täällä toteutamme vain logiikan, joka on kuvattu WebGPU-spesifikaatiossa content timeline -osiossa. Tämä sisältää pääasiassa JS-tyyppien muuntamisen wgpu-types-kuvauksiksi, jotka lähetetään WGPU-säieelle IPC-viesteillä, jotka on määritelty https://github.com/servo/servo/blob/main/components/shared/webgpu/messages/recv.rs. WebGPU on suunniteltu asynkroniseksi, joten WGPU-säieen operaatioiden valmistumista ei tarvitse odottaa. Tämä tehdään tallentamalla tunnuksia DOM WebGPU -objekteihin, jotka linkittävät WGPU-säieellä eläviin WGPU-objekteihin (joita wgpu-core tarjoaa). Lisätietoa tästä suunnittelusta on saatavilla wgpu-repositoriossa.
WGPU-toteutus
Varsinainen käsittely tapahtuu kahdella omistetulla säieellä pääselainprosessissa: yksi WGPU:lle ja yksi WGPU poller:ille.
Nämä säieet käynnistetään laiskasti ensimmäisellä adapter-pyynnöllä.
WGPU-säie toteuttaa device timeline -osiossa määritellyt vaiheet dispatch:amalla wgpu-core-funktioita vastauksena scriptiltä tuleviin IPC-viesteihin.
Jotkin kutsut herättävät myös WGPU poller -säieen, joka ajaa tehokkaasti queue timeline -osioita kutsumalla poll_all_devices wgpu-coresta.
WebGPU CTS -odotusten päivittäminen
WebGPU CTS -odotukset ovat valtavia, joten mach update-wpt:n sijaan käytämme moz-webgpu-cts -työkalun forkkia odotusten päivittämiseen.
Odotusten päivittämiseksi sinun täytyy hankkia ajon wptreport-loki joko käynnistämällä täysi CTS-ajo CI:ssä (mach try webgpu) tai ajamalla tiettyjä testejä paikallisesti:
$ mach test-wpt -r --log-wptreport report.json [tests ...]
Huomaa, että odotukset asetetaan release- ja production-käännöksille, koska debug-käännökset ovat liian hitaita. Päivitä odotukset seuraavasti:
$ moz-webgpu-cts --servo process-reports --preset set report.json
Voit myös testata Servoa live CTS:ää vastaan:
$ mach run -r --pref dom.webgpu.enabled 'https://gpuweb.github.io/cts/standalone/?runnow=1&q=<test>'
Tällä hetkellä meillä on useita epävakaita tehtäviä webgpu:shader,execution,expression -kategoriassa, joita seurataan #31397 -issue:ssa.
Ne voidaan jättää huomiotta, jos ne ilmestyvät try-ajojesi odottamattomiin tuloksiin.
Työskentely upstream gfx-rs/wgpu -projektissa
Servoa voidaan käyttää wgpu-muutosten testaamiseen WebGPU CTS:ää vasten seuraavasti:
- Päivitä wgpu Servon Cargo.toml:ssa uusimpaan committiin (valinnainen, mutta suositeltavaa jos Servo on vanhentunut)
- Perusta wgpu-muutoksesi samaan wgpu-committiin, jota Servo käyttää
- Päivitä wgpu Servon Cargo.toml:ssa haaraan, jossa muutoksesi ovat
- Testaa muutoksesi käynnistämällä täysi CTS-ajo:
mach try webgpu - Sisällytä linkki testituloksiin wgpu-pull requestiisi
Lisäresurssit
Servodriver-testiharness
Servodriver on wptrunner-kehyksen ja WebDriver-palvelimen päälle rakennettu testiharness.
Se ei ole vielä oletuksena käytössä, mutta sen voi ajaa lisäämällä --product servodriver -argumentin mihin tahansa test-wpt-komentoon.
Servodriver koostuu kolmesta pääkomponentista: Python-testiharness, joka orkestroi selainta, Servon sisäinen web-palvelin, joka toteuttaa WebDriver-spesifikaation, ja testisivujen sisällä ladattavat skriptit.
wptrunner-harness
Wptrunner on harness, joka käyttää executor- ja browser-yhdistelmää tuen tuotteen käynnistämiseen.
browser määrittelee Python-luokat instanssien luomiseen ja metodit tuettujen konfiguraatioiden kutsumiseen sekä argumentit Servo-binääriä käynnistettäessä.
Se delegoi kaiken WebDriver-spesifisen logiikan perus WebDriverBrowser-luokalle, joka on yhteinen kaikille WebDriveriin luottaville selaimille.
Servodriverin executor määrittelee Servo-spesifisen testien alustuksen, tulosten käsittelyn ja testien välisen tilan hallinnan. Esimerkiksi Servo määrittelee WebDriver-laajennusmetodit preferenssien hallintaan, ja näitä kutsutaan testien välillä varmistaakseen, että jokainen testi ajaa tarkoitetulla konfiguraatiollamme.
Servodriver-executormme delegoi paljon logiikkaa yhteiselle WebDriverTestharnessExecutor -luokalle. Tämä executor on vastuussa testdriver.js-harnessin suorittamisesta ja mahdollistaa Python-harnessin hakevan testitulokset selaimesta.
Servon WebDriver-toteutus
Tässä toteutuksessa on kolme pääkomponenttia: server handler, script handler ja input handler.
Server handler
Kun wptrunner yhdistää WebDriver-palvelimeen uudessa Servo-instanssissa, se luo uuden session -instanssin.
Tämä sessio säilyttää tilaa WebDriver API -kutsujen välillä.
Selaimen kanssa vuorovaikuttavat API-kutsut reititetään constellationin kautta ConstellationMsg::WebDriverCommand -viesteinä, ja ne, joiden täytyy vuorovaikuttaa suoraan dokumentin sisällön kanssa, kuuluvat WebDriverScriptCommand -enum:iin.
Monet näistä API:sta vaativat synkronisen vastauksen IpcSender-kanavan kautta, jota Servon WebDriver-palvelin käyttää odottaakseen vastausta.
Tapaukset kuten navigointi ja asynkronisten skriptien suoritus sisältävät kuitenkin lisäsynkronointia.
Navigointi
Kun navigointia pyydetään, constellation vastaanottaa IpcSenderin, jonka se tallentaa. Kun navigointi valmistuu, constellation tarkistaa, vastaako pipeline WebDriverin navigointia, ja ilmoittaa WebDriver-palvelimelle alkuperäistä kanavaa käyttäen.
Asynkroniset skriptit
Kun asynkronisen skriptin suoritus aloitetaan, WebDriver-spesifikaatio tarjoaa tavan skriptien kommunikoida tulosta palvelimelle. Skripti kutsutaan anonyyminä funktiona lisäfunktioargumentilla, joka lähettää vastauksen palvelimelle.
Script handler
Kun WebDriver-viesti, joka kohdistuu tiettyyn selauskontekstiin, vastaanotetaan, ScriptThread, joka sisältää aktiivisen dokumentin, käsittelee sen. Kunkin komennon käsittelylogiikka sijaitsee webdriver_handlers.rs -tiedostossa. Mikä tahansa komento, joka palauttaa web-sisällöstä johdetun arvon, täytyy serialisoida JS-arvot arvoiksi, jotka WebDriver-palvelin voi muuntaa API-arvotyypeiksi.
Altistamme kaksi webistä saavutettavaa metodia asynkronisten tulosten kommunikointiin WebDriver-palvelimelle: Window.webdriverCallback ja Window.webdriverTimeout.
Input handler
Kun WebDriver-palvelin vastaanottaa syöte-toimintokomentoja (esim. osoitin- tai hiiritoiminnot), se luo toimintosekvenssin ja dispatch:aa ne asteittain compositorille constellationin kautta. Compositor käsittelee nämä tapahtumat samalla tavalla kuin upottajalta vastaanotetut syöte-tapahtumat (poislukien tunnetut bugit).
Testisivujen skriptit
testdriver-harness yhdistää kaikki nämä elementit yhteen.
Executor avaa uuden ikkunan ja kutsuu asynkronista skriptiä, joka asettaa testdriver-callbackin arvoon Window.webdriverCallback (arguments[arguments.length - 1]).
Tämä ikkuna luo viestijonon, jota executor-harness lukee.
Myöhemmin jokainen ajettava testi avataan uutena ikkunana; nämä ikkunat voivat käyttää opener.postMessage kommunikoidakseen alkuperäisen ikkunan kanssa, mikä mahdollistaa testdriver API:en lähettää viestejä, jotka edustavat WebDriver API -kutsuja.
Debuggausvinkit
Aloita aina seuraavalla RUST_LOG:lla:
RUST_LOG=webdriver_server,webdriver,script::webdriver_handlers,constellation
Tämä yleensä tekee selväksi, käsitelläänkö odotetut API-kutsut.
Kun debuggaat syöte-ongelmia, lisää JS-debug-rivit, jotka loggaavat klikattavan elementin getBoundingClientRect()-arvon, ja vertaa compositorin vastaanottamia koordinaatteja manuaalisessa klikkauksessa vs. WebDriver-palvelimen lähettämiä koordinaatteja.
Android-sovelluksen arkkitehtuuri
Android-sovelluksen toteutus on jaettu useisiin komponentteihin:
- jaettu Android/OpenHarmony-toteutus
servoshell:lle (ports/servoshell/egl) - Android-spesifinen
servoshell-integraatio (ports/servoshell/egl/android.rs) - pääaktiviteetti (
support/android/apk/servoapp/src/main/java/org/servoshell) - ServoView-komponentti (
support/android/apk/servoview/src/main/java/org/servo/servoview)- Android SurfaceView (
ServoView.java) - Servo-moottorin wrapper (
Servo.java) - JNI servoshell-integraatio (
JNIServo.java)
- Android SurfaceView (
Ohjauskulku
Upottaja -> Servo
Sovelluksen sisällä alkavat tapahtumat käynnistyvät joko natiivin sovellus-UI:n toimesta (esim. URL:n lataus) tai osana ServoView-komponenttia (esim. kosketussyöte). Kaikki natiivi sovellus-UI määritellään pääaktiviteetissa ja käyttää ServoView-komponentin julkista API:a vuorovaikutukseen taustalla olevan Servo-instanssin kanssa.
ServoView on vastuussa koordinoinnista kahden säieen välillä — GL-säie, joka ajaa varsinaista Servo-instanssia, ja UI-säie. Se on myös vastuussa syöte-tapahtumien välittämisestä moottorille ja alustatapahtumien, kuten pinnan koon muutoksen, käsittelystä.
Servo -> Upottaja
Moottorin sisällä alkavat tapahtumat täytyy saada upotussovelluksen eri kerroksiin.
Alin taso on Servo-moottorin wrapper, joka toteuttaa JNIServo.Callbacks-rajapinnan.
Nämä callbackit mahdollistavat moottorin wrapperin käynnistää callbackit UI- ja GL-säieillä tarvittavan toiminnon mukaan.
UI-säieellä tapahtuvat toiminnot sisältävät kehotteen näyttämisen ja näppäimistön käynnistämisen, kun taas GL-säie-toiminnot sisältävät Servo-tapahtumasilmukan pyörittämisen ja GL-renderöintitoiminnot.
Servo-komponentti altistaa Client-rajapinnan UI-säie-toiminnoille, mahdollistaen viestinnän upotussovelluksen ylimpien kerrosten kanssa.
JNI-integraatio
Jokainen JNIServo-luokan native-jäsen on toteutettu android.rs-tiedostossa #[unsafe(no_mangle)]-funktiona, jolla on vastaava nimi.
jni-rs-craten dokumentaatio sisältää lisätietoa tästä integraatiosta.
Dokumentaatio vanhoille versioille
Osa tästä kirjasta ei välttämättä päde vanhoihin Servo-versioihin.
Jos sinun täytyy työskennellä hyvin vanhan Servo-version kanssa, näistä dokumenteista voi olla apua:
- README.md
- CONTRIBUTING.md
- docs/COMMAND_LINE_ARGS.md
- docs/HACKING_QUICKSTART.md
- docs/ORGANIZATION.md
- docs/STYLE_GUIDE.md
- docs/debugging.md
- docs/glossary.md
- docs/components/style.md
- docs/components/webxr.md
- tests/wpt/README.md
- Servon kääntäminen (wikissä)
- Kääntäminen Androidille (wikissä)
- Design (wikissä)
- Profilointi (wikissä)
TODO: docs/glossary.md
Sanaston käyttö
Tämä on kokoelma yleisiä termejä, joilla on erityinen merkitys Servo-projektin kontekstissa. Tavoitteena on tarjota korkean tason määritelmiä ja hyödyllisiä linkkejä lisälukemiseen, eikä täydellistä dokumentaatiota koodin yksittäisistä osista.
Jos Servon koodissa, issue trackerissa, mailing listillä jne. on sana tai lause, joka on hämmentävä, tee pull request, joka lisää sen tähän tiedostoon rungolla TODO.
Tämä signaaloi asiantuntijoille lisäämään merkityksellisemmän määritelmän.
Sanasto
Compositor
Säie, joka vastaanottaa syötetapahtumat käyttöjärjestelmältä ja välittää ne constellationille. Se vastaa myös web-sisällön valmiiden renderöintien compositoinnista ja niiden näyttämisestä ruudulla mahdollisimman nopeasti.
Constellation
Säie, joka hallitsee joukkoa toisiinsa liittyvää web-sisältöä. Tätä voi ajatella yksittäisen välilehden omistajana välilehdellisessä web-selaimessa; se kapseloi istuntohistorian, tietää kaikista kehysten puussa olevista kehyksistä ja omistaa pipeline:n jokaiselle sisältyvälle kehykselle.
Display list
Lista konkreettisia renderöintiohjeita. Display list on layoutin jälkeen, joten kaikilla kohteilla on stacking context -suhteiset pikselisijainnit, ja z-index on jo sovellettu, joten myöhemmät kohteet display listissä ovat aina aiempien päällä.
Layout thread
Säie, joka vastaa DOM-puun layoutoinnista laatikoiden kerroksiin tietylle dokumentille. Vastaanottaa komentoja script-säikeeltä layoutoida sivu ja joko luo uuden display listin renderer-säikeen käyttöön tai palauttaa sivun layoutin kyselyn tulokset scriptin käyttöön.
Pipeline
Yksikkö, joka kapseloi viestintätavan script-, layout- ja renderer-säikeiden kanssa tietylle dokumentille. Jokaisella pipelinella on globaalisti yksilöllinen id, jolla siihen pääsee käsiksi constellationista.
Renderer thread (vaihtoehtoisesti paint thread)
Säie, joka kääntää display listin sarjaksi piirtokomentoja, jotka renderöivät liittyvän dokumentin sisällön puskuriin, joka lähetetään sitten compositorille.
Script thread (vaihtoehtoisesti script task)
Säie, joka suorittaa JavaScriptiä ja tallentaa DOM-esityksen kaikista dokumenteista, joilla on yhteinen origin.
Tämä säie kääntää constellationilta vastaanotetut syötetapahtumat DOM-tapahtumiksi spesifikaation mukaisesti, kutsuu HTML-parserin, kun uutta sivun sisältöä vastaanotetaan, ja evaluoi JS:ää tapahtumille kuten timereille ja <script>-elementeille.