]> git.proxmox.com Git - rustc.git/blob - src/doc/rustc/src/platform-support/fuchsia.md
5643c6a0188a9fdb4c16c4c63063ac0b3500f343
[rustc.git] / src / doc / rustc / src / platform-support / fuchsia.md
1 # `aarch64-unknown-fuchsia` and `x86_64-unknown-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 - David Koloski ([@djkoloski](https://github.com/djkoloski))
14 - Julia Ryan ([@P1n3appl3](https://github.com/P1n3appl3))
15 - Erick Tryzelaar ([@erickt](https://github.com/erickt))
16
17 As the team evolves over time, the specific members listed here may differ from
18 the members reported by the API. The API should be considered to be
19 authoritative if this occurs. Instead of pinging individual members, use
20 `@rustbot ping fuchsia` to contact the team on GitHub.
21
22 ## Table of contents
23
24 1. [Requirements](#requirements)
25 1. [Walkthrough structure](#walkthrough-structure)
26 1. [Compiling a Rust binary targeting Fuchsia](#compiling-a-rust-binary-targeting-fuchsia)
27 1. [Targeting Fuchsia with rustup and cargo](#targeting-fuchsia-with-rustup-and-cargo)
28 1. [Targeting Fuchsia with a compiler built from source](#targeting-fuchsia-with-a-compiler-built-from-source)
29 1. [Creating a Fuchsia package](#creating-a-fuchsia-package)
30 1. [Creating a Fuchsia component](#creating-a-fuchsia-component)
31 1. [Building a Fuchsia package](#building-a-fuchsia-package)
32 1. [Publishing a Fuchsia package](#publishing-a-fuchsia-package)
33 1. [Creating a Fuchsia package repository](#creating-a-fuchsia-package-repository)
34 1. [Publishing Fuchsia package to repository](#publishing-fuchsia-package-to-repository)
35 1. [Running a Fuchsia component on an emulator](#running-a-fuchsia-component-on-an-emulator)
36 1. [Starting the Fuchsia emulator](#starting-the-fuchsia-emulator)
37 1. [Watching emulator logs](#watching-emulator-logs)
38 1. [Serving a Fuchsia package](#serving-a-fuchsia-package)
39 1. [Running a Fuchsia component](#running-a-fuchsia-component)
40 1. [`.gitignore` extensions](#gitignore-extensions)
41 1. [Testing](#testing)
42 1. [Running unit tests](#running-unit-tests)
43 1. [Running the compiler test suite](#running-the-compiler-test-suite)
44 1. [Debugging](#debugging)
45 1. [`zxdb`](#zxdb)
46 1. [Attaching `zxdb`](#attaching-zxdb)
47 1. [Using `zxdb`](#using-zxdb)
48 1. [Displaying source code in `zxdb`](#displaying-source-code-in-zxdb)
49
50 ## Requirements
51
52 This target is cross-compiled from a host environment. You will need a recent
53 copy of the [Fuchsia SDK], which provides the tools, libraries, and binaries
54 required to build and link programs for Fuchsia.
55
56 Development may also be done from the [source tree].
57
58 Fuchsia targets support `std` and follow the `sysv64` calling convention on
59 x86_64. Fuchsia binaries use the ELF file format.
60
61 ## Walkthrough structure
62
63 This walkthrough will cover:
64
65 1. Compiling a Rust binary targeting Fuchsia.
66 1. Building a Fuchsia package.
67 1. Publishing and running a Fuchsia package to a Fuchsia emulator.
68
69 For the purposes of this walkthrough, we will only target `x86_64-unknown-fuchsia`.
70
71 ## Compiling a Rust binary targeting Fuchsia
72
73 Today, there are two main ways to build a Rust binary targeting Fuchsia
74 using the Fuchsia SDK:
75 1. Allow [rustup] to handle the installation of Fuchsia targets for you.
76 1. Build a toolchain locally that can target Fuchsia.
77
78 ### Targeting Fuchsia with rustup and cargo
79
80 The easiest way to build a Rust binary targeting Fuchsia is by allowing [rustup]
81 to handle the installation of Fuchsia targets for you. This can be done by issuing
82 the following commands:
83
84 ```sh
85 rustup target add x86_64-unknown-fuchsia
86 rustup target add aarch64-unknown-fuchsia
87 ```
88
89 After installing our Fuchsia targets, we can now compile a Rust binary that targets
90 Fuchsia.
91
92 To create our Rust project, we can use [`cargo`][cargo] as follows:
93
94 **From base working directory**
95 ```sh
96 cargo new hello_fuchsia
97 ```
98
99 The rest of this walkthrough will take place from `hello_fuchsia`, so we can
100 change into that directory now:
101
102 ```sh
103 cd hello_fuchsia
104 ```
105
106 *Note: From this point onwards, all commands will be issued from the `hello_fuchsia/`
107 directory, and all `hello_fuchsia/` prefixes will be removed from references for sake of brevity.*
108
109 We can edit our `src/main.rs` to include a test as follows:
110
111 **`src/main.rs`**
112 ```rust
113 fn main() {
114 println!("Hello Fuchsia!");
115 }
116
117 #[test]
118 fn it_works() {
119 assert_eq!(2 + 2, 4);
120 }
121 ```
122
123 In addition to the standard workspace created, we will want to create a
124 `.cargo/config.toml` file to link necessary libraries
125 during compilation:
126
127 **`.cargo/config.toml`**
128 ```txt
129 [target.x86_64-unknown-fuchsia]
130
131 rustflags = [
132 "-Lnative=<SDK_PATH>/arch/x64/lib",
133 "-Lnative=<SDK_PATH>/arch/x64/sysroot/lib"
134 ]
135 ```
136
137 *Note: Make sure to fill out `<SDK_PATH>` with the path to the downloaded [Fuchsia SDK].*
138
139 These options configure the following:
140
141 * `-Lnative=${SDK_PATH}/arch/${ARCH}/lib`: Link against Fuchsia libraries from
142 the SDK
143 * `-Lnative=${SDK_PATH}/arch/${ARCH}/sysroot/lib`: Link against Fuchsia sysroot
144 libraries from the SDK
145
146 In total, our new project will look like:
147
148 **Current directory structure**
149 ```txt
150 hello_fuchsia/
151 ┣━ src/
152 ┃ ┗━ main.rs
153 ┣━ Cargo.toml
154 ┗━ .cargo/
155 ┗━ config.toml
156 ```
157
158 Finally, we can build our rust binary as:
159
160 ```sh
161 cargo build --target x86_64-unknown-fuchsia
162 ```
163
164 Now we have a Rust binary at `target/x86_64-unknown-fuchsia/debug/hello_fuchsia`,
165 targeting our desired Fuchsia target.
166
167 **Current directory structure**
168 ```txt
169 hello_fuchsia/
170 ┣━ src/
171 ┃ ┗━ main.rs
172 ┣━ target/
173 ┃ ┗━ x86_64-unknown-fuchsia/
174 ┃ ┗━ debug/
175 ┃ ┗━ hello_fuchsia
176 ┣━ Cargo.toml
177 ┗━ .cargo/
178 ┗━ config.toml
179 ```
180
181 ### Targeting Fuchsia with a compiler built from source
182
183 An alternative to the first workflow is to target Fuchsia by using
184 `rustc` built from source.
185
186 Before building Rust for Fuchsia, you'll need a clang toolchain that supports
187 Fuchsia as well. A recent version (14+) of clang should be sufficient to compile
188 Rust for Fuchsia.
189
190 x86-64 and AArch64 Fuchsia targets can be enabled using the following
191 configuration in `config.toml`:
192
193 ```toml
194 [build]
195 target = ["<host_platform>", "aarch64-unknown-fuchsia", "x86_64-unknown-fuchsia"]
196
197 [rust]
198 lld = true
199
200 [llvm]
201 download-ci-llvm = false
202
203 [target.x86_64-unknown-fuchsia]
204 cc = "clang"
205 cxx = "clang++"
206
207 [target.aarch64-unknown-fuchsia]
208 cc = "clang"
209 cxx = "clang++"
210 ```
211
212 Though not strictly required, you may also want to use `clang` for your host
213 target as well:
214
215 ```toml
216 [target.<host_platform>]
217 cc = "clang"
218 cxx = "clang++"
219 ```
220
221 By default, the Rust compiler installs itself to `/usr/local` on most UNIX
222 systems. You may want to install it to another location (e.g. a local `install`
223 directory) by setting a custom prefix in `config.toml`:
224
225 ```toml
226 [install]
227 # Make sure to use the absolute path to your install directory
228 prefix = "<RUST_SRC_PATH>/install"
229 ```
230
231 Next, the following environment variables must be configured. For example, using
232 a script we name `config-env.sh`:
233
234 ```sh
235 # Configure this environment variable to be the path to the downloaded SDK
236 export SDK_PATH="<SDK path goes here>"
237
238 export CFLAGS_aarch64_unknown_fuchsia="--target=aarch64-unknown-fuchsia --sysroot=${SDK_PATH}/arch/arm64/sysroot -I${SDK_PATH}/pkg/fdio/include"
239 export CXXFLAGS_aarch64_unknown_fuchsia="--target=aarch64-unknown-fuchsia --sysroot=${SDK_PATH}/arch/arm64/sysroot -I${SDK_PATH}/pkg/fdio/include"
240 export LDFLAGS_aarch64_unknown_fuchsia="--target=aarch64-unknown-fuchsia --sysroot=${SDK_PATH}/arch/arm64/sysroot -L${SDK_PATH}/arch/arm64/lib"
241 export CARGO_TARGET_AARCH64_UNKNOWN_FUCHSIA_RUSTFLAGS="-C link-arg=--sysroot=${SDK_PATH}/arch/arm64/sysroot -Lnative=${SDK_PATH}/arch/arm64/sysroot/lib -Lnative=${SDK_PATH}/arch/arm64/lib"
242 export CFLAGS_x86_64_unknown_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=${SDK_PATH}/arch/x64/sysroot -I${SDK_PATH}/pkg/fdio/include"
243 export CXXFLAGS_x86_64_unknown_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=${SDK_PATH}/arch/x64/sysroot -I${SDK_PATH}/pkg/fdio/include"
244 export LDFLAGS_x86_64_unknown_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=${SDK_PATH}/arch/x64/sysroot -L${SDK_PATH}/arch/x64/lib"
245 export CARGO_TARGET_X86_64_UNKNOWN_FUCHSIA_RUSTFLAGS="-C link-arg=--sysroot=${SDK_PATH}/arch/x64/sysroot -Lnative=${SDK_PATH}/arch/x64/sysroot/lib -Lnative=${SDK_PATH}/arch/x64/lib"
246 ```
247
248 Finally, the Rust compiler can be built and installed:
249
250 ```sh
251 (source config-env.sh && ./x.py install)
252 ```
253
254 Once `rustc` is installed, we can create a new working directory to work from,
255 `hello_fuchsia` along with `hello_fuchsia/src`:
256
257 ```sh
258 mkdir hello_fuchsia
259 cd hello_fuchsia
260 mkdir src
261 ```
262
263 *Note: From this point onwards, all commands will be issued from the `hello_fuchsia/`
264 directory, and all `hello_fuchsia/` prefixes will be removed from references for sake of brevity.*
265
266 There, we can create a new file named `src/hello_fuchsia.rs`:
267
268 **`src/hello_fuchsia.rs`**
269 ```rust
270 fn main() {
271 println!("Hello Fuchsia!");
272 }
273
274 #[test]
275 fn it_works() {
276 assert_eq!(2 + 2, 4);
277 }
278 ```
279
280 **Current directory structure**
281 ```txt
282 hello_fuchsia/
283 ┗━ src/
284 ┗━ hello_fuchsia.rs
285 ```
286
287 Using your freshly installed `rustc`, you can compile a binary for Fuchsia using
288 the following options:
289
290 * `--target x86_64-unknown-fuchsia`/`--target aarch64-unknown-fuchsia`: Targets the Fuchsia
291 platform of your choice
292 * `-Lnative ${SDK_PATH}/arch/${ARCH}/lib`: Link against Fuchsia libraries from
293 the SDK
294 * `-Lnative ${SDK_PATH}/arch/${ARCH}/sysroot/lib`: Link against Fuchsia sysroot
295 libraries from the SDK
296
297 Putting it all together:
298
299 ```sh
300 # Configure these for the Fuchsia target of your choice
301 TARGET_ARCH="<x86_64-unknown-fuchsia|aarch64-unknown-fuchsia>"
302 ARCH="<x64|aarch64>"
303
304 rustc \
305 --target ${TARGET_ARCH} \
306 -Lnative=${SDK_PATH}/arch/${ARCH}/lib \
307 -Lnative=${SDK_PATH}/arch/${ARCH}/sysroot/lib \
308 --out-dir bin src/hello_fuchsia.rs
309 ```
310
311 **Current directory structure**
312 ```txt
313 hello_fuchsia/
314 ┣━ src/
315 ┃ ┗━ hello_fuchsia.rs
316 ┗━ bin/
317 ┗━ hello_fuchsia
318 ```
319
320 ## Creating a Fuchsia package
321
322 Before moving on, double check your directory structure:
323
324 **Current directory structure**
325 ```txt
326 hello_fuchsia/
327 ┣━ src/ (if using rustc)
328 ┃ ┗━ hello_fuchsia.rs ...
329 ┣━ bin/ ...
330 ┃ ┗━ hello_fuchsia ...
331 ┣━ src/ (if using cargo)
332 ┃ ┗━ main.rs ...
333 ┗━ target/ ...
334 ┗━ x86_64-unknown-fuchsia/ ...
335 ┗━ debug/ ...
336 ┗━ hello_fuchsia ...
337 ```
338
339 With our Rust binary built, we can move to creating a Fuchsia package.
340 On Fuchsia, a package is the unit of distribution for software. We'll need to
341 create a new package directory where we will place files like our finished
342 binary and any data it may need.
343
344 To start, make the `pkg`, and `pkg/meta` directories:
345
346 ```sh
347 mkdir pkg
348 mkdir pkg/meta
349 ```
350
351 **Current directory structure**
352 ```txt
353 hello_fuchsia/
354 ┗━ pkg/
355 ┗━ meta/
356 ```
357
358 Now, create the following files inside:
359
360 **`pkg/meta/package`**
361 ```json
362 {
363 "name": "hello_fuchsia",
364 "version": "0"
365 }
366 ```
367
368 The `package` file describes our package's name and version number. Every
369 package must contain one.
370
371 **`pkg/hello_fuchsia.manifest` if using cargo**
372 ```txt
373 bin/hello_fuchsia=target/x86_64-unknown-fuchsia/debug/hello_fuchsia
374 lib/ld.so.1=<SDK_PATH>/arch/x64/sysroot/dist/lib/ld.so.1
375 lib/libfdio.so=<SDK_PATH>/arch/x64/dist/libfdio.so
376 meta/package=pkg/meta/package
377 meta/hello_fuchsia.cm=pkg/meta/hello_fuchsia.cm
378 ```
379
380 **`pkg/hello_fuchsia.manifest` if using rustc**
381 ```txt
382 bin/hello_fuchsia=bin/hello_fuchsia
383 lib/ld.so.1=<SDK_PATH>/arch/x64/sysroot/dist/lib/ld.so.1
384 lib/libfdio.so=<SDK_PATH>/arch/x64/dist/libfdio.so
385 meta/package=pkg/meta/package
386 meta/hello_fuchsia.cm=pkg/meta/hello_fuchsia.cm
387 ```
388
389 *Note: Relative manifest paths are resolved starting from the working directory
390 of `ffx`. Make sure to fill out `<SDK_PATH>` with the path to the downloaded
391 SDK.*
392
393 The `.manifest` file will be used to describe the contents of the package by
394 relating their location when installed to their location on the file system. The
395 `bin/hello_fuchsia=` entry will be different depending on how your Rust binary
396 was built, so choose accordingly.
397
398 **Current directory structure**
399 ```txt
400 hello_fuchsia/
401 ┗━ pkg/
402 ┣━ meta/
403 ┃ ┗━ package
404 ┗━ hello_fuchsia.manifest
405 ```
406
407 ### Creating a Fuchsia component
408
409 On Fuchsia, components require a component manifest written in Fuchsia's markup
410 language called CML. The Fuchsia devsite contains an [overview of CML] and a
411 [reference for the file format]. Here's a basic one that can run our single binary:
412
413 **`pkg/hello_fuchsia.cml`**
414 ```txt
415 {
416 include: [ "syslog/client.shard.cml" ],
417 program: {
418 runner: "elf",
419 binary: "bin/hello_fuchsia",
420 },
421 }
422 ```
423
424 **Current directory structure**
425 ```txt
426 hello_fuchsia/
427 ┗━ pkg/
428 ┣━ meta/
429 ┃ ┗━ package
430 ┣━ hello_fuchsia.manifest
431 ┗━ hello_fuchsia.cml
432 ```
433
434 Now we can compile that CML into a component manifest:
435
436 ```sh
437 ${SDK_PATH}/tools/${ARCH}/cmc compile \
438 pkg/hello_fuchsia.cml \
439 --includepath ${SDK_PATH}/pkg \
440 -o pkg/meta/hello_fuchsia.cm
441 ```
442
443 *Note: `--includepath` tells the compiler where to look for `include`s from our CML.
444 In our case, we're only using `syslog/client.shard.cml`.*
445
446 **Current directory structure**
447 ```txt
448 hello_fuchsia/
449 ┗━ pkg/
450 ┣━ meta/
451 ┃ ┣━ package
452 ┃ ┗━ hello_fuchsia.cm
453 ┣━ hello_fuchsia.manifest
454 ┗━ hello_fuchsia.cml
455 ```
456
457 ### Building a Fuchsia package
458
459 Next, we'll build a package manifest as defined by our manifest:
460
461 ```sh
462 ${SDK_PATH}/tools/${ARCH}/ffx package build \
463 --api-level $(${SDK_PATH}/tools/${ARCH}/ffx --machine json version | jq .tool_version.api_level) \
464 --out pkg/hello_fuchsia_manifest \
465 pkg/hello_fuchsia.manifest
466 ```
467
468 This will produce `pkg/hello_fuchsia_manifest/` which is a package manifest we can
469 publish directly to a repository.
470
471 **Current directory structure**
472 ```txt
473 hello_fuchsia/
474 ┗━ pkg/
475 ┣━ meta/
476 ┃ ┣━ package
477 ┃ ┗━ hello_fuchsia.cm
478 ┣━ hello_fuchsia_manifest/
479 ┃ ┗━ ...
480 ┣━ hello_fuchsia.manifest
481 ┣━ hello_fuchsia.cml
482 ┗━ hello_fuchsia_package_manifest
483 ```
484
485 We are now ready to publish the package.
486
487 ## Publishing a Fuchsia package
488
489 With our package and component manifests setup,
490 we can now publish our package. The first step will
491 be to create a Fuchsia package repository to publish
492 to.
493
494 ### Creating a Fuchsia package repository
495
496 We can set up our repository with:
497
498 ```sh
499 ${SDK_PATH}/tools/${ARCH}/ffx repository create pkg/repo
500 ```
501
502 **Current directory structure**
503 ```txt
504 hello_fuchsia/
505 ┗━ pkg/
506 ┣━ meta/
507 ┃ ┣━ package
508 ┃ ┗━ hello_fuchsia.cm
509 ┣━ hello_fuchsia_manifest/
510 ┃ ┗━ ...
511 ┣━ repo/
512 ┃ ┗━ ...
513 ┣━ hello_fuchsia.manifest
514 ┣━ hello_fuchsia.cml
515 ┗━ hello_fuchsia_package_manifest
516 ```
517
518 ## Publishing Fuchsia package to repository
519
520 We can publish our new package to that repository with:
521
522 ```sh
523 ${SDK_PATH}/tools/${ARCH}/ffx repository publish \
524 --package pkg/hello_fuchsia_package_manifest \
525 pkg/repo
526 ```
527
528 Then we can add the repository to `ffx`'s package server as `hello-fuchsia` using:
529
530 ```sh
531 ${SDK_PATH}/tools/${ARCH}/ffx repository add-from-pm \
532 --repository hello-fuchsia \
533 pkg/repo
534 ```
535
536 ## Running a Fuchsia component on an emulator
537
538 At this point, we are ready to run our Fuchsia
539 component. For reference, our final directory
540 structure will look like:
541
542 **Final directory structure**
543 ```txt
544 hello_fuchsia/
545 ┣━ src/ (if using rustc)
546 ┃ ┗━ hello_fuchsia.rs ...
547 ┣━ bin/ ...
548 ┃ ┗━ hello_fuchsia ...
549 ┣━ src/ (if using cargo)
550 ┃ ┗━ main.rs ...
551 ┣━ target/ ...
552 ┃ ┗━ x86_64-unknown-fuchsia/ ...
553 ┃ ┗━ debug/ ...
554 ┃ ┗━ hello_fuchsia ...
555 ┗━ pkg/
556 ┣━ meta/
557 ┃ ┣━ package
558 ┃ ┗━ hello_fuchsia.cm
559 ┣━ hello_fuchsia_manifest/
560 ┃ ┗━ ...
561 ┣━ repo/
562 ┃ ┗━ ...
563 ┣━ hello_fuchsia.manifest
564 ┣━ hello_fuchsia.cml
565 ┗━ hello_fuchsia_package_manifest
566 ```
567
568 ### Starting the Fuchsia emulator
569
570 Start a Fuchsia emulator in a new terminal using:
571
572 ```sh
573 ${SDK_PATH}/tools/${ARCH}/ffx product-bundle get workstation_eng.qemu-${ARCH}
574 ${SDK_PATH}/tools/${ARCH}/ffx emu start workstation_eng.qemu-${ARCH} --headless
575 ```
576
577 ### Watching emulator logs
578
579 Once the emulator is running, open a separate terminal to watch the emulator logs:
580
581 **In separate terminal**
582 ```sh
583 ${SDK_PATH}/tools/${ARCH}/ffx log \
584 --since now
585 ```
586
587 ### Serving a Fuchsia package
588
589 Now, start a package repository server to serve our
590 package to the emulator:
591
592 ```sh
593 ${SDK_PATH}/tools/${ARCH}/ffx repository server start
594 ```
595
596 Once the repository server is up and running, register it with the target Fuchsia system running in the emulator:
597
598 ```sh
599 ${SDK_PATH}/tools/${ARCH}/ffx target repository register \
600 --repository hello-fuchsia
601 ```
602
603 ### Running a Fuchsia component
604
605 Finally, run the component:
606
607 ```sh
608 ${SDK_PATH}/tools/${ARCH}/ffx component run \
609 /core/ffx-laboratory:hello_fuchsia \
610 fuchsia-pkg://hello-fuchsia/hello_fuchsia_manifest#meta/hello_fuchsia.cm
611 ```
612
613 On reruns of the component, the `--recreate` argument may also need to be
614 passed.
615
616 ```sh
617 ${SDK_PATH}/tools/${ARCH}/ffx component run \
618 --recreate \
619 /core/ffx-laboratory:hello_fuchsia \
620 fuchsia-pkg://hello-fuchsia/hello_fuchsia_manifest#meta/hello_fuchsia.cm
621 ```
622
623 ## `.gitignore` extensions
624
625 Optionally, we can create/extend our `.gitignore` file to ignore files and
626 directories that are not helpful to track:
627
628 ```txt
629 pkg/repo
630 pkg/meta/hello_fuchsia.cm
631 pkg/hello_fuchsia_manifest
632 pkg/hello_fuchsia_package_manifest
633 ```
634
635 ## Testing
636
637 ### Running unit tests
638
639 Tests can be run in the same way as a regular binary.
640
641 * If using `cargo`, you can simply pass `test --no-run`
642 to the `cargo` invocation and then repackage and rerun the Fuchsia package. From our previous example,
643 this would look like `cargo test --target x86_64-unknown-fuchsia --no-run`, and moving the executable
644 binary path found from the line `Executable unittests src/main.rs (target/x86_64-unknown-fuchsia/debug/deps/hello_fuchsia-<HASH>)`
645 into `pkg/hello_fuchsia.manifest`.
646
647 * If using the compiled `rustc`, you can simply pass `--test`
648 to the `rustc` invocation and then repackage and rerun the Fuchsia package.
649
650 The test harness will run the applicable unit tests.
651
652 Often when testing, you may want to pass additional command line arguments to
653 your binary. Additional arguments can be set in the component manifest:
654
655 **`pkg/hello_fuchsia.cml`**
656 ```txt
657 {
658 include: [ "syslog/client.shard.cml" ],
659 program: {
660 runner: "elf",
661 binary: "bin/hello_fuchsia",
662 args: ["it_works"],
663 },
664 }
665 ```
666
667 This will pass the argument `it_works` to the binary, filtering the tests to
668 only those tests that match the pattern. There are many more configuration
669 options available in CML including environment variables. More documentation is
670 available on the [Fuchsia devsite].
671
672 ### Running the compiler test suite
673
674 The commands in this section assume that they are being run from inside your
675 local Rust source checkout:
676
677 ```sh
678 cd ${RUST_SRC_PATH}
679 ```
680
681 To run the Rust test suite on an emulated Fuchsia device, you'll also need to
682 download a copy of the Fuchsia SDK. The current minimum supported SDK version is
683 [20.20240412.3.1][minimum_supported_sdk_version].
684
685 [minimum_supported_sdk_version]: https://chrome-infra-packages.appspot.com/p/fuchsia/sdk/core/linux-amd64/+/version:20.20240412.3.1
686
687 Fuchsia's test runner interacts with the Fuchsia emulator and is located at
688 `src/ci/docker/scripts/fuchsia-test-runner.py`. First, add the following
689 variables to your existing `config-env.sh`:
690
691 ```sh
692 # TEST_TOOLCHAIN_TMP_DIR can point anywhere, but it:
693 # - must be less than 108 characters, otherwise qemu can't handle the path
694 # - must be consistent across calls to this file (don't use `mktemp -d` here)
695 export TEST_TOOLCHAIN_TMP_DIR="/tmp/rust-tmp"
696
697 # Keep existing contents of `config-env.sh` from earlier, including SDK_PATH
698 ```
699
700 We can then use the script to start our test environment with:
701
702 ```sh
703 ( \
704 source config-env.sh && \
705 src/ci/docker/scripts/fuchsia-test-runner.py start \
706 --rust-build ${RUST_SRC_PATH}/build \
707 --sdk ${SDK_PATH} \
708 --target {x86_64-unknown-fuchsia|aarch64-unknown-fuchsia} \
709 --verbose \
710 )
711 ```
712
713 Where `${RUST_SRC_PATH}/build` is the `build-dir` set in `config.toml`.
714
715 Once our environment is started, we can run our tests using `x.py` as usual. The
716 test runner script will run the compiled tests on an emulated Fuchsia device. To
717 run the full `tests/ui` test suite:
718
719 ```sh
720 ( \
721 source config-env.sh && \
722 ./x.py \
723 --config config.toml \
724 --stage=2 \
725 test tests/ui \
726 --target x86_64-unknown-fuchsia \
727 --run=always \
728 --test-args --target-rustcflags \
729 --test-args -Lnative=${SDK_PATH}/arch/{x64|arm64}/sysroot/lib \
730 --test-args --target-rustcflags \
731 --test-args -Lnative=${SDK_PATH}/arch/{x64|arm64}/lib \
732 --test-args --target-rustcflags \
733 --test-args -Clink-arg=--undefined-version \
734 --test-args --remote-test-client \
735 --test-args src/ci/docker/scripts/fuchsia-test-runner.py \
736 )
737 ```
738
739 By default, `x.py` compiles test binaries with `panic=unwind`. If you built your
740 Rust toolchain with `-Cpanic=abort`, you need to tell `x.py` to compile test
741 binaries with `panic=abort` as well:
742
743 ```sh
744 --test-args --target-rustcflags \
745 --test-args -Cpanic=abort \
746 --test-args --target-rustcflags \
747 --test-args -Zpanic_abort_tests \
748 ```
749
750 When finished testing, the test runner can be used to stop the test environment:
751
752 ```sh
753 src/ci/docker/scripts/fuchsia-test-runner.py stop
754 ```
755
756 ## Debugging
757
758 ### `zxdb`
759
760 Debugging components running on a Fuchsia emulator can be done using the
761 console-mode debugger: [zxdb]. We will demonstrate attaching necessary symbol
762 paths to debug our `hello-fuchsia` component.
763
764 ### Attaching `zxdb`
765
766 In a separate terminal, issue the following command from our `hello_fuchsia`
767 directory to launch `zxdb`:
768
769 **In separate terminal**
770 ```sh
771 ${SDK_PATH}/tools/${ARCH}/ffx debug connect -- \
772 --symbol-path target/x86_64-unknown-fuchsia/debug
773 ```
774
775 * `--symbol-path` gets required symbol paths, which are
776 necessary for stepping through your program.
777
778 The "[displaying source code in `zxdb`](#displaying-source-code-in-zxdb)"
779 section describes how you can display Rust and/or Fuchsia source code in your
780 debugging session.
781
782 ### Using `zxdb`
783
784 Once launched, you will be presented with the window:
785
786 ```sh
787 Connecting (use "disconnect" to cancel)...
788 Connected successfully.
789 👉 To get started, try "status" or "help".
790 [zxdb]
791 ```
792
793 To attach to our program, we can run:
794
795 ```sh
796 [zxdb] attach hello_fuchsia
797 ```
798
799 **Expected output**
800 ```sh
801 Waiting for process matching "hello_fuchsia".
802 Type "filter" to see the current filters.
803 ```
804
805 Next, we can create a breakpoint at main using "b main":
806
807 ```sh
808 [zxdb] b main
809 ```
810
811 **Expected output**
812 ```sh
813 Created Breakpoint 1 @ main
814 ```
815
816 Finally, we can re-run the "hello_fuchsia" component from our original
817 terminal:
818
819 ```sh
820 ${SDK_PATH}/tools/${ARCH}/ffx component run \
821 --recreate \
822 fuchsia-pkg://hello-fuchsia/hello_fuchsia_manifest#meta/hello_fuchsia.cm
823 ```
824
825 Once our component is running, our `zxdb` window will stop execution
826 in our main as desired:
827
828 **Expected output**
829 ```txt
830 Breakpoint 1 now matching 1 addrs for main
831 🛑 on bp 1 hello_fuchsia::main() • main.rs:2
832 1 fn main() {
833 ▶ 2 println!("Hello Fuchsia!");
834 3 }
835 4
836 [zxdb]
837 ```
838
839 `zxdb` has similar commands to other debuggers like [gdb].
840 To list the available commands, run "help" in the
841 `zxdb` window or visit [the zxdb documentation].
842
843 ```sh
844 [zxdb] help
845 ```
846
847 **Expected output**
848 ```sh
849 Help!
850
851 Type "help <command>" for command-specific help.
852
853 Other help topics (see "help <topic>")
854 ...
855 ```
856
857 ### Displaying source code in `zxdb`
858
859 By default, the debugger will not be able to display
860 source code while debugging. For our user code, we displayed
861 source code by pointing our debugger to our debug binary via
862 the `--symbol-path` arg. To display library source code in
863 the debugger, you must provide paths to the source using
864 `--build-dir`. For example, to display the Rust and Fuchsia
865 source code:
866
867 ```sh
868 ${SDK_PATH}/tools/${ARCH}/ffx debug connect -- \
869 --symbol-path target/x86_64-unknown-fuchsia/debug \
870 --build-dir ${RUST_SRC_PATH}/rust \
871 --build-dir ${FUCHSIA_SRC_PATH}/fuchsia/out/default
872 ```
873
874 * `--build-dir` links against source code paths, which
875 are not strictly necessary for debugging, but is a nice-to-have
876 for displaying source code in `zxdb`.
877
878 Linking to a Fuchsia checkout can help with debugging Fuchsia libraries,
879 such as [fdio].
880
881 ### Debugging the compiler test suite
882
883 Debugging the compiler test suite requires some special configuration:
884
885 First, we have to properly configure zxdb so it will be able to find debug
886 symbols and source information for our test. The test runner can do this for us
887 with:
888
889 ```sh
890 src/ci/docker/scripts/fuchsia-test-runner.py debug \
891 --rust-src ${RUST_SRC_PATH} \
892 --fuchsia-src ${FUCHSIA_SRC_PATH} \
893 --test ${TEST}
894 ```
895
896 where `${TEST}` is relative to Rust's `tests` directory (e.g. `ui/abi/...`).
897
898 This will start a zxdb session that is properly configured for the specific test
899 being run. All three arguments are optional, so you can omit `--fuchsia-src` if
900 you don't have it downloaded. Now is a good time to set any desired breakpoints,
901 like `b main`.
902
903 Next, we have to tell `x.py` not to optimize or strip debug symbols from our
904 test suite binaries. We can do this by passing some new arguments to `rustc`
905 through our `x.py` invocation. The full invocation is:
906
907 ```sh
908 ( \
909 source config-env.sh && \
910 ./x.py \
911 --config config.toml \
912 --stage=2 \
913 test tests/${TEST} \
914 --target x86_64-unknown-fuchsia \
915 --run=always \
916 --test-args --target-rustcflags \
917 --test-args -Lnative=${SDK_PATH}/arch/{x64|arm64}/sysroot/lib \
918 --test-args --target-rustcflags \
919 --test-args -Lnative=${SDK_PATH}/arch/{x64|arm64}/lib \
920 --test-args --target-rustcflags \
921 --test-args -Clink-arg=--undefined-version \
922 --test-args --target-rustcflags \
923 --test-args -Cdebuginfo=2 \
924 --test-args --target-rustcflags \
925 --test-args -Copt-level=0 \
926 --test-args --target-rustcflags \
927 --test-args -Cstrip=none \
928 --test-args --remote-test-client \
929 --test-args src/ci/docker/scripts/fuchsia-test-runner.py \
930 )
931 ```
932
933 *If you built your Rust toolchain with `panic=abort`, make sure to include the
934 previous flags so your test binaries are also compiled with `panic=abort`.*
935
936 Upon running this command, the test suite binary will be run and zxdb will
937 attach and load any relevant debug symbols.
938
939 [Fuchsia team]: https://team-api.infra.rust-lang.org/v1/teams/fuchsia.json
940 [Fuchsia]: https://fuchsia.dev/
941 [source tree]: https://fuchsia.dev/fuchsia-src/get-started/learn/build
942 [rustup]: https://rustup.rs/
943 [cargo]: ../../cargo/index.html
944 [Fuchsia SDK]: https://chrome-infra-packages.appspot.com/p/fuchsia/sdk/core
945 [overview of CML]: https://fuchsia.dev/fuchsia-src/concepts/components/v2/component_manifests
946 [reference for the file format]: https://fuchsia.dev/reference/cml
947 [Fuchsia devsite]: https://fuchsia.dev/reference/cml
948 [not currently supported]: https://fxbug.dev/105393
949 [zxdb]: https://fuchsia.dev/fuchsia-src/development/debugger
950 [gdb]: https://www.sourceware.org/gdb/
951 [the zxdb documentation]: https://fuchsia.dev/fuchsia-src/development/debugger
952 [fdio]: https://cs.opensource.google/fuchsia/fuchsia/+/main:sdk/lib/fdio/