]> git.lizzy.rs Git - rust.git/blob - src/doc/rustc/src/platform-support/fuchsia.md
Rollup merge of #101529 - mousetail:patch-2, r=thomcc
[rust.git] / src / doc / rustc / src / platform-support / fuchsia.md
1 # `aarch64-fuchsia` and `x86_64-fuchsia`
2
3 **Tier: 2**
4
5 [Fuchsia] is a modern open source operating system that's simple, secure,
6 updatable, and performant.
7
8 ## Target maintainers
9
10 The [Fuchsia team]:
11
12 - Tyler Mandry ([@tmandry](https://github.com/tmandry))
13 - Dan Johnson ([@computerdruid](https://github.com/computerdruid))
14 - David Koloski ([@djkoloski](https://github.com/djkoloski))
15 - Andrew Pollack ([@andrewpollack](https://github.com/andrewpollack))
16 - Joseph Ryan ([@P1n3appl3](https://github.com/P1n3appl3))
17
18 As the team evolves over time, the specific members listed here may differ from
19 the members reported by the API. The API should be considered to be
20 authoritative if this occurs. Instead of pinging individual members, use
21 `@rustbot ping fuchsia` to contact the team on GitHub.
22
23 ## Table of contents
24
25 1. [Requirements](#requirements)
26 1. [Walkthrough structure](#walkthrough-structure)
27 1. [Compiling a Rust binary targeting Fuchsia](#compiling-a-rust-binary-targeting-fuchsia)
28     1. [Targeting Fuchsia with rustup and cargo](#targeting-fuchsia-with-rustup-and-cargo)
29     1. [Targeting Fuchsia with a compiler built from source](#targeting-fuchsia-with-a-compiler-built-from-source)
30 1. [Creating a Fuchsia package](#creating-a-fuchsia-package)
31     1. [Creating a Fuchsia component](#creating-a-fuchsia-component)
32     1. [Building a Fuchsia package](#building-a-fuchsia-package)
33 1. [Publishing a Fuchsia package](#publishing-a-fuchsia-package)
34     1. [Creating a Fuchsia package repository](#creating-a-fuchsia-package-repository)
35     1. [Publishing Fuchsia package to repository](#publishing-fuchsia-package-to-repository)
36 1. [Running a Fuchsia component on an emulator](#running-a-fuchsia-component-on-an-emulator)
37     1. [Starting the Fuchsia emulator](#starting-the-fuchsia-emulator)
38     1. [Watching emulator logs](#watching-emulator-logs)
39     1. [Serving a Fuchsia package](#serving-a-fuchsia-package)
40     1. [Running a Fuchsia component](#running-a-fuchsia-component)
41 1. [`.gitignore` extensions](#gitignore-extensions)
42 1. [Testing](#testing)
43     1. [Running unit tests](#running-unit-tests)
44     1. [Running the compiler test suite](#running-the-compiler-test-suite)
45
46 ## Requirements
47
48 This target is cross-compiled from a host environment. You will need a recent
49 copy of the [Fuchsia SDK], which provides the tools, libraries, and binaries
50 required to build and link programs for Fuchsia.
51
52 Development may also be done from the [source tree].
53
54 Fuchsia targets support `std` and follow the `sysv64` calling convention on
55 x86_64. Fuchsia binaries use the ELF file format.
56
57 ## Walkthrough structure
58
59 This walkthrough will cover:
60
61 1. Compiling a Rust binary targeting Fuchsia.
62 1. Building a Fuchsia package.
63 1. Publishing and running a Fuchsia package to a Fuchsia emulator.
64
65 For the purposes of this walkthrough, we will only target `x86_64-fuchsia`.
66
67 ## Compiling a Rust binary targeting Fuchsia
68
69 Today, there are two main ways to build a Rust binary targeting Fuchsia
70 using the Fuchsia SDK:
71 1. Allow [rustup] to handle the installation of Fuchsia targets for you.
72 1. Build a toolchain locally that can target Fuchsia.
73
74 ### Targeting Fuchsia with rustup and cargo
75
76 The easiest way to build a Rust binary targeting Fuchsia is by allowing [rustup]
77 to handle the installation of Fuchsia targets for you. This can be done by issuing
78 the following commands:
79
80 ```sh
81 rustup target add x86_64-fuchsia
82 rustup target add aarch64-fuchsia
83 ```
84
85 After installing our Fuchsia targets, we can now compile a Rust binary that targets
86 Fuchsia.
87
88 To create our Rust project, we can issue a standard `cargo` command as follows:
89
90 **From base working directory**
91 ```sh
92 cargo new hello_fuchsia
93 ```
94
95 The rest of this walkthrough will take place from `hello_fuchsia`, so we can
96 change into that directory now:
97
98 ```sh
99 cd hello_fuchsia
100 ```
101
102 *Note: From this point onwards, all commands will be issued from the `hello_fuchsia/`
103 directory, and all `hello_fuchsia/` prefixes will be removed from references for sake of brevity.*
104
105 We can edit our `src/main.rs` to include a test as follows:
106
107 **`src/main.rs`**
108 ```rust
109 fn main() {
110     println!("Hello Fuchsia!");
111 }
112
113 #[test]
114 fn it_works() {
115     assert_eq!(2 + 2, 4);
116 }
117 ```
118
119 In addition to the standard workspace created, we will want to create a
120 `.cargo/config.toml` file to link necessary libraries
121 during compilation:
122
123 **`.cargo/config.toml`**
124 ```txt
125 [target.x86_64-fuchsia]
126
127 rustflags = [
128     "-Lnative=<SDK_PATH>/arch/x64/lib",
129     "-Lnative=<SDK_PATH>/arch/x64/sysroot/lib"
130 ]
131 ```
132
133 *Note: Make sure to fill out `<SDK_PATH>` with the path to the downloaded [Fuchsia SDK].*
134
135 These options configure the following:
136
137 * `-Lnative=${SDK_PATH}/arch/${ARCH}/lib`: Link against Fuchsia libraries from
138   the SDK
139 * `-Lnative=${SDK_PATH}/arch/${ARCH}/sysroot/lib`: Link against Fuchsia kernel
140   libraries from the SDK
141
142 In total, our new project will look like:
143
144 **Current directory structure**
145 ```txt
146 hello_fuchsia/
147 ┣━ src/
148 ┃  ┗━ main.rs
149 ┣━ Cargo.toml
150 ┗━ .cargo/
151    ┗━ config.toml
152 ```
153
154 Finally, we can build our rust binary as:
155
156 ```sh
157 cargo build --target x86_64-fuchsia
158 ```
159
160 Now we have a Rust binary at `target/x86_64-fuchsia/debug/hello_fuchsia`,
161 targeting our desired Fuchsia target.
162
163 **Current directory structure**
164 ```txt
165 hello_fuchsia/
166 ┣━ src/
167 ┃  ┗━ main.rs
168 ┣━ target/
169 ┃  ┗━ x86_64-fuchsia/
170 ┃     ┗━ debug/
171 ┃        ┗━ hello_fuchsia
172 ┣━ Cargo.toml
173 ┗━ .cargo/
174    ┗━ config.toml
175 ```
176
177 ### Targeting Fuchsia with a compiler built from source
178
179 An alternative to the first workflow is to target Fuchsia by using
180 `rustc` built from source.
181
182 Before building Rust for Fuchsia, you'll need a clang toolchain that supports
183 Fuchsia as well. A recent version (14+) of clang should be sufficient to compile
184 Rust for Fuchsia.
185
186 x86-64 and AArch64 Fuchsia targets can be enabled using the following
187 configuration.
188
189 In `config.toml`, add:
190
191 ```toml
192 [build]
193 target = ["<host_platform>", "aarch64-fuchsia", "x86_64-fuchsia"]
194 ```
195
196 Additionally, the following environment variables must be configured (for
197 example, using a script like `config-env.sh`):
198
199 ```sh
200 # Configure this environment variable to be the path to the downloaded SDK
201 export SDK_PATH="<SDK path goes here>"
202
203 export CFLAGS_aarch64_fuchsia="--target=aarch64-fuchsia --sysroot=${SDK_PATH}/arch/arm64/sysroot -I${SDK_PATH}/pkg/fdio/include"
204 export CXXFLAGS_aarch64_fuchsia="--target=aarch64-fuchsia --sysroot=${SDK_PATH}/arch/arm64/sysroot -I${SDK_PATH}/pkg/fdio/include"
205 export LDFLAGS_aarch64_fuchsia="--target=aarch64-fuchsia --sysroot=${SDK_PATH}/arch/arm64/sysroot -L${SDK_PATH}/arch/arm64/lib"
206 export CARGO_TARGET_AARCH64_FUCHSIA_RUSTFLAGS="-C link-arg=--sysroot=${SDK_PATH}/arch/arm64/sysroot -Lnative=${SDK_PATH}/arch/arm64/sysroot/lib -Lnative=${SDK_PATH}/arch/arm64/lib"
207 export CFLAGS_x86_64_fuchsia="--target=x86_64-fuchsia --sysroot=${SDK_PATH}/arch/x64/sysroot -I${SDK_PATH}/pkg/fdio/include"
208 export CXXFLAGS_x86_64_fuchsia="--target=x86_64-fuchsia --sysroot=${SDK_PATH}/arch/x64/sysroot -I${SDK_PATH}/pkg/fdio/include"
209 export LDFLAGS_x86_64_fuchsia="--target=x86_64-fuchsia --sysroot=${SDK_PATH}/arch/x64/sysroot -L${SDK_PATH}/arch/x64/lib"
210 export CARGO_TARGET_X86_64_FUCHSIA_RUSTFLAGS="-C link-arg=--sysroot=${SDK_PATH}/arch/x64/sysroot -Lnative=${SDK_PATH}/arch/x64/sysroot/lib -Lnative=${SDK_PATH}/arch/x64/lib"
211 ```
212
213 These can be run together in a shell environment by executing
214 `(source config-env.sh && ./x.py install)`.
215
216 Once `rustc` is installed, we can create a new working directory to work from,
217 `hello_fuchsia` along with `hello_fuchsia/src`:
218
219 ```sh
220 mkdir hello_fuchsia
221 cd hello_fuchsia
222 mkdir src
223 ```
224
225 *Note: From this point onwards, all commands will be issued from the `hello_fuchsia/`
226 directory, and all `hello_fuchsia/` prefixes will be removed from references for sake of brevity.*
227
228 There, we can create a new file named `src/hello_fuchsia.rs`:
229
230 **`src/hello_fuchsia.rs`**
231 ```rust
232 fn main() {
233     println!("Hello Fuchsia!");
234 }
235
236 #[test]
237 fn it_works() {
238     assert_eq!(2 + 2, 4);
239 }
240 ```
241
242 **Current directory structure**
243 ```txt
244 hello_fuchsia/
245 ┗━ src/
246     ┗━ hello_fuchsia.rs
247 ```
248
249 Using your freshly installed `rustc`, you can compile a binary for Fuchsia using
250 the following options:
251
252 * `--target x86_64-fuchsia`/`--target aarch64-fuchsia`: Targets the Fuchsia
253   platform of your choice
254 * `-Lnative ${SDK_PATH}/arch/${ARCH}/lib`: Link against Fuchsia libraries from
255   the SDK
256 * `-Lnative ${SDK_PATH}/arch/${ARCH}/sysroot/lib`: Link against Fuchsia kernel
257   libraries from the SDK
258
259 Putting it all together:
260
261 ```sh
262 # Configure these for the Fuchsia target of your choice
263 TARGET_ARCH="<x86_64-fuchsia|aarch64-fuchsia>"
264 ARCH="<x64|aarch64>"
265
266 rustc \
267     --target ${TARGET_ARCH} \
268     -Lnative=${SDK_PATH}/arch/${ARCH}/lib \
269     -Lnative=${SDK_PATH}/arch/${ARCH}/sysroot/lib \
270     --out-dir bin src/hello_fuchsia.rs
271 ```
272
273 **Current directory structure**
274 ```txt
275 hello_fuchsia/
276 ┣━ src/
277 ┃   ┗━ hello_fuchsia.rs
278 ┗━ bin/
279    ┗━ hello_fuchsia
280 ```
281
282 ## Creating a Fuchsia package
283
284 Before moving on, double check your directory structure:
285
286 **Current directory structure**
287 ```txt
288 hello_fuchsia/
289 ┣━ src/                     (if using rustc)
290 ┃   ┗━ hello_fuchsia.rs     ...
291 ┣━ bin/                     ...
292 ┃  ┗━ hello_fuchsia         ...
293 ┣━ src/                     (if using cargo)
294 ┃  ┗━ main.rs               ...
295 ┗━ target/                  ...
296    ┗━ x86_64-fuchsia/       ...
297       ┗━ debug/             ...
298          ┗━ hello_fuchsia   ...
299 ```
300
301 With our Rust binary built, we can move to creating a Fuchsia package.
302 On Fuchsia, a package is the unit of distribution for software. We'll need to
303 create a new package directory where we will place files like our finished
304 binary and any data it may need.
305
306 To start, make the `pkg`, and `pkg/meta` directories:
307
308 ```sh
309 mkdir pkg
310 mkdir pkg/meta
311 ```
312
313 **Current directory structure**
314 ```txt
315 hello_fuchsia/
316 ┗━ pkg/
317    ┗━ meta/
318 ```
319
320 Now, create the following files inside:
321
322 **`pkg/meta/package`**
323 ```json
324 {
325   "name": "hello_fuchsia",
326   "version": "0"
327 }
328 ```
329
330 The `package` file describes our package's name and version number. Every
331 package must contain one.
332
333 **`pkg/hello_fuchsia.manifest` if using cargo**
334 ```txt
335 bin/hello_fuchsia=target/x86_64-fuchsia/debug/hello_fuchsia
336 lib/ld.so.1=<SDK_PATH>/arch/x64/sysroot/dist/lib/ld.so.1
337 lib/libfdio.so=<SDK_PATH>/arch/x64/dist/libfdio.so
338 meta/package=pkg/meta/package
339 meta/hello_fuchsia.cm=pkg/meta/hello_fuchsia.cm
340 ```
341
342 **`pkg/hello_fuchsia.manifest` if using rustc**
343 ```txt
344 bin/hello_fuchsia=bin/hello_fuchsia
345 lib/ld.so.1=<SDK_PATH>/arch/x64/sysroot/dist/lib/ld.so.1
346 lib/libfdio.so=<SDK_PATH>/arch/x64/dist/libfdio.so
347 meta/package=pkg/meta/package
348 meta/hello_fuchsia.cm=pkg/meta/hello_fuchsia.cm
349 ```
350
351 *Note: Relative manifest paths are resolved starting from the working directory
352 of `pm`. Make sure to fill out `<SDK_PATH>` with the path to the downloaded
353 SDK.*
354
355 The `.manifest` file will be used to describe the contents of the package by
356 relating their location when installed to their location on the file system. The
357 `bin/hello_fuchsia=` entry will be different depending on how your Rust binary
358 was built, so choose accordingly.
359
360 **Current directory structure**
361 ```txt
362 hello_fuchsia/
363 ┗━ pkg/
364    ┣━ meta/
365    ┃  ┗━ package
366    ┗━ hello_fuchsia.manifest
367 ```
368
369 ### Creating a Fuchsia component
370
371 On Fuchsia, components require a component manifest written in Fuchsia's markup
372 language called CML. The Fuchsia devsite contains an [overview of CML] and a
373 [reference for the file format]. Here's a basic one that can run our single binary:
374
375 **`pkg/hello_fuchsia.cml`**
376 ```txt
377 {
378     include: [ "syslog/client.shard.cml" ],
379     program: {
380         runner: "elf",
381         binary: "bin/hello_fuchsia",
382     },
383 }
384 ```
385
386 **Current directory structure**
387 ```txt
388 hello_fuchsia/
389 ┗━ pkg/
390    ┣━ meta/
391    ┃  ┗━ package
392    ┣━ hello_fuchsia.manifest
393    ┗━ hello_fuchsia.cml
394 ```
395
396 Now we can compile that CML into a component manifest:
397
398 ```sh
399 ${SDK_PATH}/tools/${ARCH}/cmc compile \
400     pkg/hello_fuchsia.cml \
401     --includepath ${SDK_PATH}/pkg \
402     -o pkg/meta/hello_fuchsia.cm
403 ```
404
405 *Note: `--includepath` tells the compiler where to look for `include`s from our CML.
406 In our case, we're only using `syslog/client.shard.cml`.*
407
408 **Current directory structure**
409 ```txt
410 hello_fuchsia/
411 ┗━ pkg/
412    ┣━ meta/
413    ┃  ┣━ package
414    ┃  ┗━ hello_fuchsia.cm
415    ┣━ hello_fuchsia.manifest
416    ┗━ hello_fuchsia.cml
417 ```
418
419 ### Building a Fuchsia package
420
421 Next, we'll build a package manifest as defined by our manifest:
422
423 ```sh
424 ${SDK_PATH}/tools/${ARCH}/pm \
425     -api-level $(${SDK_PATH}/tools/${ARCH}/ffx version -v | grep "api-level" | head -1 |  awk -F ' ' '{print $2}') \
426     -o pkg/hello_fuchsia_manifest \
427     -m pkg/hello_fuchsia.manifest \
428     build \
429     -output-package-manifest pkg/hello_fuchsia_package_manifest
430 ```
431
432 This will produce `pkg/hello_fuchsia_manifest/` which is a package manifest we can
433 publish directly to a repository.
434
435 **Current directory structure**
436 ```txt
437 hello_fuchsia/
438 ┗━ pkg/
439    ┣━ meta/
440    ┃  ┣━ package
441    ┃  ┗━ hello_fuchsia.cm
442    ┣━ hello_fuchsia_manifest/
443    ┃  ┗━ ...
444    ┣━ hello_fuchsia.manifest
445    ┣━ hello_fuchsia.cml
446    ┗━ hello_fuchsia_package_manifest
447 ```
448
449 We are now ready to publish the package.
450
451 ## Publishing a Fuchsia package
452
453 With our package and component manifests setup,
454 we can now publish our package. The first step will
455 be to create a Fuchsia package repository to publish
456 to.
457
458 ### Creating a Fuchsia package repository
459
460 We can set up our repository with:
461
462 ```sh
463 ${SDK_PATH}/tools/${ARCH}/pm newrepo \
464     -repo pkg/repo
465 ```
466
467 **Current directory structure**
468 ```txt
469 hello_fuchsia/
470 ┗━ pkg/
471    ┣━ meta/
472    ┃  ┣━ package
473    ┃  ┗━ hello_fuchsia.cm
474    ┣━ hello_fuchsia_manifest/
475    ┃  ┗━ ...
476    ┣━ repo/
477    ┃  ┗━ ...
478    ┣━ hello_fuchsia.manifest
479    ┣━ hello_fuchsia.cml
480    ┗━ hello_fuchsia_package_manifest
481 ```
482
483 ## Publishing Fuchsia package to repository
484
485 We can publish our new package to that repository with:
486
487 ```sh
488 ${SDK_PATH}/tools/${ARCH}/pm publish \
489     -repo pkg/repo \
490     -lp -f <(echo "pkg/hello_fuchsia_package_manifest")
491 ```
492
493 Then we can add the repository to `ffx`'s package server as `hello-fuchsia` using:
494
495 ```sh
496 ${SDK_PATH}/tools/${ARCH}/ffx repository add-from-pm \
497     pkg/repo \
498     -r hello-fuchsia
499 ```
500
501 ## Running a Fuchsia component on an emulator
502
503 At this point, we are ready to run our Fuchsia
504 component. For reference, our final directory
505 structure will look like:
506
507 **Final directory structure**
508 ```txt
509 hello_fuchsia/
510 ┣━ src/                     (if using rustc)
511 ┃   ┗━ hello_fuchsia.rs     ...
512 ┣━ bin/                     ...
513 ┃  ┗━ hello_fuchsia         ...
514 ┣━ src/                     (if using cargo)
515 ┃  ┗━ main.rs               ...
516 ┣━ target/                  ...
517 ┃  ┗━ x86_64-fuchsia/       ...
518 ┃     ┗━ debug/             ...
519 ┃        ┗━ hello_fuchsia   ...
520 ┗━ pkg/
521    ┣━ meta/
522    ┃  ┣━ package
523    ┃  ┗━ hello_fuchsia.cm
524    ┣━ hello_fuchsia_manifest/
525    ┃  ┗━ ...
526    ┣━ repo/
527    ┃  ┗━ ...
528    ┣━ hello_fuchsia.manifest
529    ┣━ hello_fuchsia.cml
530    ┗━ hello_fuchsia_package_manifest
531 ```
532
533 ### Starting the Fuchsia emulator
534
535 Start a Fuchsia emulator in a new terminal using:
536
537 ```sh
538 ${SDK_PATH}/tools/${ARCH}/ffx product-bundle get workstation_eng.qemu-${ARCH}
539 ${SDK_PATH}/tools/${ARCH}/ffx emu start workstation_eng.qemu-${ARCH} --headless
540 ```
541
542 ### Watching emulator logs
543
544 Once the emulator is running, open a separate terminal to watch the emulator logs:
545
546 **In separate terminal**
547 ```sh
548 ${SDK_PATH}/tools/${ARCH}/ffx log \
549     --since now
550 ```
551
552 ### Serving a Fuchsia package
553
554 Now, start a package repository server to serve our
555 package to the emulator:
556
557 ```sh
558 ${SDK_PATH}/tools/${ARCH}/ffx repository server start
559 ```
560
561 Once the repository server is up and running, register it with the target Fuchsia system running in the emulator:
562
563 ```sh
564 ${SDK_PATH}/tools/${ARCH}/ffx target repository register \
565     --repository hello-fuchsia
566 ```
567
568 ### Running a Fuchsia component
569
570 Finally, run the component:
571
572 ```sh
573 ${SDK_PATH}/tools/${ARCH}/ffx component run \
574     /core/ffx-laboratory:hello_fuchsia \
575     fuchsia-pkg://hello-fuchsia/hello_fuchsia_manifest#meta/hello_fuchsia.cm
576 ```
577
578 On reruns of the component, the `--recreate` argument may also need to be
579 passed.
580
581 ```sh
582 ${SDK_PATH}/tools/${ARCH}/ffx component run \
583     --recreate \
584     /core/ffx-laboratory:hello_fuchsia \
585     fuchsia-pkg://hello-fuchsia/hello_fuchsia_manifest#meta/hello_fuchsia.cm
586 ```
587
588 ## `.gitignore` extensions
589
590 Optionally, we can create/extend our `.gitignore` file to ignore files and
591 directories that are not helpful to track:
592
593 ```txt
594 pkg/repo
595 pkg/meta/hello_fuchsia.cm
596 pkg/hello_fuchsia_manifest
597 pkg/hello_fuchsia_package_manifest
598 ```
599
600 ## Testing
601
602 ### Running unit tests
603
604 Tests can be run in the same way as a regular binary.
605
606 * If using `cargo`, you can simply pass `test --no-run`
607 to the `cargo` invocation and then repackage and rerun the Fuchsia package. From our previous example,
608 this would look like `cargo test --target x86_64-fuchsia --no-run`, and moving the executable
609 binary path found from the line `Executable unittests src/main.rs (target/x86_64-fuchsia/debug/deps/hello_fuchsia-<HASH>)`
610 into `pkg/hello_fuchsia.manifest`.
611
612 * If using the compiled `rustc`, you can simply pass `--test`
613 to the `rustc` invocation and then repackage and rerun the Fuchsia package.
614
615 The test harness will run the applicable unit tests.
616
617 Often when testing, you may want to pass additional command line arguments to
618 your binary. Additional arguments can be set in the component manifest:
619
620 **`pkg/hello_fuchsia.cml`**
621 ```txt
622 {
623     include: [ "syslog/client.shard.cml" ],
624     program: {
625         runner: "elf",
626         binary: "bin/hello_fuchsia",
627         args: ["it_works"],
628     },
629 }
630 ```
631
632 This will pass the argument `it_works` to the binary, filtering the tests to
633 only those tests that match the pattern. There are many more configuration
634 options available in CML including environment variables. More documentation is
635 available on the [Fuchsia devsite].
636
637 ### Running the compiler test suite
638
639 Running the Rust test suite on Fuchsia is [not currently supported], but work is
640 underway to enable it.
641
642 [Fuchsia team]: https://team-api.infra.rust-lang.org/v1/teams/fuchsia.json
643 [Fuchsia]: https://fuchsia.dev/
644 [source tree]: https://fuchsia.dev/fuchsia-src/get-started/learn/build
645 [rustup]: https://rustup.rs/
646 [cargo]: https://doc.rust-lang.org/cargo/
647 [Fuchsia SDK]: https://chrome-infra-packages.appspot.com/p/fuchsia/sdk/core
648 [overview of CML]: https://fuchsia.dev/fuchsia-src/concepts/components/v2/component_manifests
649 [reference for the file format]: https://fuchsia.dev/reference/cml
650 [Fuchsia devsite]: https://fuchsia.dev/reference/cml
651 [not currently supported]: https://fxbug.dev/105393