]> git.lizzy.rs Git - rust.git/blob - src/doc/rustc/src/platform-support/fuchsia.md
Rollup merge of #94467 - ibraheemdev:master, r=pnkfelix
[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 aarch_64-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/sysroot/lib",
129     "-Lnative", "<SDK_PATH>/arch/x64/lib"
130 ]
131 ```
132
133 *Note: Make sure to fill out `<SDK_PATH>` with the path to the downloaded [Fuchsia SDK].*
134
135 In total, our new project will look like:
136
137 **Current directory structure**
138 ```txt
139 hello_fuchsia/
140 ┣━ src/
141 ┃  ┗━ main.rs
142 ┣━ Cargo.toml
143 ┗━ .cargo/
144    ┗━ config.toml
145 ```
146
147 Finally, we can build our rust binary as:
148
149 ```sh
150 cargo build --target x86_64-fuchsia
151 ```
152
153 Now we have a Rust binary at `target/x86_64-fuchsia/debug/hello_fuchsia`,
154 targeting our desired Fuchsia target.
155
156 **Current directory structure**
157 ```txt
158 hello_fuchsia/
159 ┣━ src/
160 ┃  ┗━ main.rs
161 ┣━ target/
162 ┃  ┗━ x86_64-fuchsia/
163 ┃     ┗━ debug/
164 ┃        ┗━ hello_fuchsia
165 ┣━ Cargo.toml
166 ┗━ .cargo/
167    ┗━ config.toml
168 ```
169
170 ### Targeting Fuchsia with a compiler built from source
171
172 An alternative to the first workflow is to target Fuchsia by using
173 `rustc` built from source.
174
175 Before building Rust for Fuchsia, you'll need a clang toolchain that supports
176 Fuchsia as well. A recent version (14+) of clang should be sufficient to compile
177 Rust for Fuchsia.
178
179 x86-64 and AArch64 Fuchsia targets can be enabled using the following
180 configuration.
181
182 In `config.toml`, add:
183
184 ```toml
185 [build]
186 target = ["<host_platform>", "aarch64-fuchsia", "x86_64-fuchsia"]
187 ```
188
189 Additionally, the following environment variables must be configured (for
190 example, using a script like `config-env.sh`):
191
192 ```sh
193 # Configure this environment variable to be the path to the downloaded SDK
194 export SDK_PATH="<SDK path goes here>"
195
196 export CFLAGS_aarch64_fuchsia="--target=aarch64-fuchsia --sysroot=${SDK_PATH}/arch/arm64/sysroot -I${SDK_PATH}/pkg/fdio/include"
197 export CXXFLAGS_aarch64_fuchsia="--target=aarch64-fuchsia --sysroot=${SDK_PATH}/arch/arm64/sysroot -I${SDK_PATH}/pkg/fdio/include"
198 export LDFLAGS_aarch64_fuchsia="--target=aarch64-fuchsia --sysroot=${SDK_PATH}/arch/arm64/sysroot -L${SDK_PATH}/arch/arm64/lib"
199 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"
200 export CFLAGS_x86_64_fuchsia="--target=x86_64-fuchsia --sysroot=${SDK_PATH}/arch/x64/sysroot -I${SDK_PATH}/pkg/fdio/include"
201 export CXXFLAGS_x86_64_fuchsia="--target=x86_64-fuchsia --sysroot=${SDK_PATH}/arch/x64/sysroot -I${SDK_PATH}/pkg/fdio/include"
202 export LDFLAGS_x86_64_fuchsia="--target=x86_64-fuchsia --sysroot=${SDK_PATH}/arch/x64/sysroot -L${SDK_PATH}/arch/x64/lib"
203 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"
204 ```
205
206 These can be run together in a shell environment by executing
207 `(source config-env.sh && ./x.py install)`.
208
209 Once `rustc` is installed, we can create a new working directory to work from,
210 `hello_fuchsia` along with `hello_fuchsia/src`:
211
212 ```sh
213 mkdir hello_fuchsia
214 cd hello_fuchsia
215 mkdir src
216 ```
217
218 *Note: From this point onwards, all commands will be issued from the `hello_fuchsia/`
219 directory, and all `hello_fuchsia/` prefixes will be removed from references for sake of brevity.*
220
221 There, we can create a new file named `src/hello_fuchsia.rs`:
222
223 **`src/hello_fuchsia.rs`**
224 ```rust
225 fn main() {
226     println!("Hello Fuchsia!");
227 }
228
229 #[test]
230 fn it_works() {
231     assert_eq!(2 + 2, 4);
232 }
233 ```
234
235 **Current directory structure**
236 ```txt
237 hello_fuchsia/
238 ┗━ src/
239     ┗━ hello_fuchsia.rs
240 ```
241
242 Using your freshly installed `rustc`, you can compile a binary for Fuchsia using
243 the following options:
244
245 * `--target x86_64-fuchsia`/`--target aarch64-fuchsia`: Targets the Fuchsia
246   platform of your choice
247 * `-Lnative ${SDK_PATH}/arch/${ARCH}/lib`: Link against Fuchsia libraries from
248   the SDK
249 * `-Lnative ${SDK_PATH}/arch/${ARCH}/sysroot/lib`: Link against Fuchsia kernel
250   libraries from the SDK
251
252 Putting it all together:
253
254 ```sh
255 # Configure these for the Fuchsia target of your choice
256 TARGET_ARCH="<x86_64-fuchsia|aarch64-fuchsia>"
257 ARCH="<x64|aarch64>"
258
259 rustc \
260     --target ${TARGET_ARCH} \
261     -Lnative=${SDK_PATH}/arch/${ARCH}/lib \
262     -Lnative=${SDK_PATH}/arch/${ARCH}/sysroot/lib \
263     --out-dir bin src/hello_fuchsia.rs
264 ```
265
266 **Current directory structure**
267 ```txt
268 hello_fuchsia/
269 ┣━ src/
270 ┃   ┗━ hello_fuchsia.rs
271 ┗━ bin/
272    ┗━ hello_fuchsia
273 ```
274
275 ## Creating a Fuchsia package
276
277 Before moving on, double check your directory structure:
278
279 **Current directory structure**
280 ```txt
281 hello_fuchsia/
282 ┣━ src/                     (if using rustc)
283 ┃   ┗━ hello_fuchsia.rs     ...
284 ┣━ bin/                     ...
285 ┃  ┗━ hello_fuchsia         ...
286 ┣━ src/                     (if using cargo)
287 ┃  ┗━ main.rs               ...
288 ┗━ target/                  ...
289    ┗━ x86_64-fuchsia/       ...
290       ┗━ debug/             ...
291          ┗━ hello_fuchsia   ...
292 ```
293
294 With our Rust binary built, we can move to creating a Fuchsia package.
295 On Fuchsia, a package is the unit of distribution for software. We'll need to
296 create a new package directory where we will place files like our finished
297 binary and any data it may need.
298
299 To start, make the `pkg`, and `pkg/meta` directories:
300
301 ```sh
302 mkdir pkg
303 mkdir pkg/meta
304 ```
305
306 **Current directory structure**
307 ```txt
308 hello_fuchsia/
309 ┗━ pkg/
310    ┗━ meta/
311 ```
312
313 Now, create the following files inside:
314
315 **`pkg/meta/package`**
316 ```json
317 {
318   "name": "hello_fuchsia",
319   "version": "0"
320 }
321 ```
322
323 The `package` file describes our package's name and version number. Every
324 package must contain one.
325
326 **`pkg/hello_fuchsia.manifest`**
327 ```txt
328 bin/hello_fuchsia=target/x86_64-fuchsia/debug/hello_fuchsia     # If using cargo...
329 bin/hello_fuchsia=bin/hello_fuchsia                             # If using rustc...
330 lib/ld.so.1=<SDK_PATH>/arch/x64/sysroot/dist/lib/ld.so.1
331 lib/libfdio.so=<SDK_PATH>/arch/x64/dist/libfdio.so
332 meta/package=pkg/meta/package
333 meta/hello_fuchsia.cm=pkg/meta/hello_fuchsia.cm
334 ```
335
336 *Note: Relative manifest paths are resolved starting from the working directory
337 of `pm`. Make sure to fill out `<SDK_PATH>` with the path to the downloaded
338 SDK.*
339
340 The `.manifest` file will be used to describe the contents of the package by
341 relating their location when installed to their location on the file system. The
342 `bin/hello_fuchsia=` entry will be different depending on how your Rust binary
343 was built, so choose accordingly.
344
345 **Current directory structure**
346 ```txt
347 hello_fuchsia/
348 ┗━ pkg/
349    ┣━ meta/
350    ┃  ┗━ package
351    ┗━ hello_fuchsia.manifest
352 ```
353
354 ### Creating a Fuchsia component
355
356 On Fuchsia, components require a component manifest written in Fuchsia's markup
357 language called CML. The Fuchsia devsite contains an [overview of CML] and a
358 [reference for the file format]. Here's a basic one that can run our single binary:
359
360 **`pkg/hello_fuchsia.cml`**
361 ```txt
362 {
363     include: [ "syslog/client.shard.cml" ],
364     program: {
365         runner: "elf",
366         binary: "bin/hello_fuchsia",
367     },
368 }
369 ```
370
371 ```txt
372 hello_fuchsia/
373 ┗━ pkg/
374    ┣━ meta/
375    ┃  ┗━ package
376    ┣━ hello_fuchsia.manifest
377    ┗━ hello_fuchsia.cml
378 ```
379
380 Now we can compile that CML into a component manifest:
381
382 ```sh
383 ${SDK_PATH}/tools/${ARCH}/cmc compile \
384     pkg/hello_fuchsia.cml \
385     --includepath ${SDK_PATH}/pkg \
386     -o pkg/meta/hello_fuchsia.cm
387 ```
388
389 **Current directory structure**
390 ```txt
391 hello_fuchsia/
392 ┗━ pkg/
393    ┣━ meta/
394    ┃  ┣━ package
395    ┃  ┗━ hello_fuchsia.cm
396    ┣━ hello_fuchsia.manifest
397    ┗━ hello_fuchsia.cml
398 ```
399
400 *Note: `--includepath` tells the compiler where to look for `include`s from our CML.
401 In our case, we're only using `syslog/client.shard.cml`.*
402
403 ### Building a Fuchsia package
404
405 Next, we'll build a package manifest as defined by our manifest:
406
407 ```sh
408 ${SDK_PATH}/tools/${ARCH}/pm \
409     -o hello_fuchsia_manifest \
410     -m pkg/hello_fuchsia.manifest \
411     build \
412     -output-package-manifest hello_fuchsia_package_manifest
413 ```
414
415 This will produce `pkg/hello_fuchsia_manifest/` which is a package manifest we can
416 publish directly to a repository.
417
418 **Current directory structure**
419 ```txt
420 hello_fuchsia/
421 ┗━ pkg/
422    ┣━ meta/
423    ┃  ┣━ package
424    ┃  ┗━ hello_fuchsia.cm
425    ┣━ hello_fuchsia_manifest/
426    ┃  ┗━ ...
427    ┣━ hello_fuchsia.manifest
428    ┣━ hello_fuchsia.cml
429    ┗━ hello_fuchsia_package_manifest
430 ```
431
432 We are now ready to publish the package.
433
434 ## Publishing a Fuchsia package
435
436 With our package and component manifests setup,
437 we can now publish our package. The first step will
438 be to create a Fuchsia package repository to publish
439 to.
440
441 ### Creating a Fuchsia package repository
442
443 We can set up our repository with:
444
445 ```sh
446 ${SDK_PATH}/tools/${ARCH}/pm newrepo \
447     -repo pkg/repo
448 ```
449
450 **Current directory structure**
451 ```txt
452 hello_fuchsia/
453 ┗━ pkg/
454    ┣━ meta/
455    ┃  ┣━ package
456    ┃  ┗━ hello_fuchsia.cm
457    ┣━ hello_fuchsia_manifest/
458    ┃  ┗━ ...
459    ┣━ repo/
460    ┃  ┗━ ...
461    ┣━ hello_fuchsia.manifest
462    ┣━ hello_fuchsia.cml
463    ┗━ hello_fuchsia_package_manifest
464 ```
465
466 ## Publishing Fuchsia package to repository
467
468 We can publish our new package to that repository with:
469
470 ```sh
471 ${SDK_PATH}/tools/${ARCH}/pm publish \
472     -repo repo \
473     -lp -f <(echo "hello_fuchsia_package_manifest")
474 ```
475
476 Then we can add the repository to `ffx`'s package server as `hello-fuchsia` using:
477
478 ```sh
479 ${SDK_PATH}/tools/${ARCH}/ffx repository add-from-pm \
480     repo \
481     -r hello-fuchsia
482 ```
483
484 ## Running a Fuchsia component on an emulator
485
486 At this point, we are ready to run our Fuchsia
487 component. For reference, our final directory
488 structure will look like:
489
490 **Final directory structure**
491 ```txt
492 hello_fuchsia/
493 ┣━ src/                     (if using rustc)
494 ┃   ┗━ hello_fuchsia.rs     ...
495 ┣━ bin/                     ...
496 ┃  ┗━ hello_fuchsia         ...
497 ┣━ src/                     (if using cargo)
498 ┃  ┗━ main.rs               ...
499 ┣━ target/                  ...
500 ┃  ┗━ x86_64-fuchsia/       ...
501 ┃     ┗━ debug/             ...
502 ┃        ┗━ hello_fuchsia   ...
503 ┗━ pkg/
504    ┣━ meta/
505    ┃  ┣━ package
506    ┃  ┗━ hello_fuchsia.cm
507    ┣━ hello_fuchsia_manifest/
508    ┃  ┗━ ...
509    ┣━ repo/
510    ┃  ┗━ ...
511    ┣━ hello_fuchsia.manifest
512    ┣━ hello_fuchsia.cml
513    ┗━ hello_fuchsia_package_manifest
514 ```
515
516 ### Starting the Fuchsia emulator
517
518 Start a Fuchsia emulator in a new terminal using:
519
520 ```sh
521 ${SDK_PATH}/tools/${ARCH}/ffx product-bundle get workstation_eng.qemu-${ARCH}
522 ${SDK_PATH}/tools/${ARCH}/ffx emu start workstation_eng.qemu-${ARCH} --headless
523 ```
524
525 ### Watching emulator logs
526
527 Once the emulator is running, open a separate terminal to watch the emulator logs:
528
529 **In separate terminal**
530 ```sh
531 ${SDK_PATH}/tools/${ARCH}/ffx log \
532     --since now
533 ```
534
535 ### Serving a Fuchsia package
536
537 Now, start a package repository server to serve our
538 package to the emulator:
539
540 ```sh
541 ${SDK_PATH}/tools/${ARCH}/ffx repository server start
542 ```
543
544 Once the repository server is up and running, register it with the target Fuchsia system running in the emulator:
545
546 ```sh
547 ${SDK_PATH}/tools/${ARCH}/ffx target repository register \
548     --repository hello-fuchsia
549 ```
550
551 ### Running a Fuchsia component
552
553 Finally, run the component:
554
555 ```sh
556 ${SDK_PATH}/tools/${ARCH}/ffx component run \
557     fuchsia-pkg://hello-fuchsia/hello_fuchsia_manifest#meta/hello_fuchsia.cm
558 ```
559
560 On reruns of the component, the `--recreate` argument may also need to be
561 passed.
562
563 ```sh
564 ${SDK_PATH}/tools/${ARCH}/ffx component run \
565     --recreate \
566     fuchsia-pkg://hello-fuchsia/hello_fuchsia_manifest#meta/hello_fuchsia.cm
567 ```
568
569 ## `.gitignore` extensions
570
571 Optionally, we can create/extend our `.gitignore` file to ignore files and
572 directories that are not helpful to track:
573
574 ```txt
575 pkg/repo
576 pkg/meta/hello_fuchsia.cm
577 pkg/hello_fuchsia_manifest
578 pkg/hello_fuchsia_package_manifest
579 ```
580
581 ## Testing
582
583 ### Running unit tests
584
585 Tests can be run in the same way as a regular binary.
586
587 * If using `cargo`, you can simply pass `test --no-run`
588 to the `cargo` invocation and then repackage and rerun the Fuchsia package. From our previous example,
589 this would look like `cargo test --target x86_64-fuchsia --no-run`, and moving the executable
590 binary path found from the line `Executable unittests src/main.rs (target/x86_64-fuchsia/debug/deps/hello_fuchsia-<HASH>)`
591 into `pkg/hello_fuchsia.manifest`.
592
593 * If using the compiled `rustc`, you can simply pass `--test`
594 to the `rustc` invocation and then repackage and rerun the Fuchsia package.
595
596 The test harness will run the applicable unit tests.
597
598 Often when testing, you may want to pass additional command line arguments to
599 your binary. Additional arguments can be set in the component manifest:
600
601 **`pkg/hello_fuchsia.cml`**
602 ```txt
603 {
604     include: [ "syslog/client.shard.cml" ],
605     program: {
606         runner: "elf",
607         binary: "bin/hello_fuchsia",
608         args: ["it_works"],
609     },
610 }
611 ```
612
613 This will pass the argument `it_works` to the binary, filtering the tests to
614 only those tests that match the pattern. There are many more configuration
615 options available in CML including environment variables. More documentation is
616 available on the [Fuchsia devsite].
617
618 ### Running the compiler test suite
619
620 Running the Rust test suite on Fuchsia is [not currently supported], but work is
621 underway to enable it.
622
623 [Fuchsia team]: https://team-api.infra.rust-lang.org/v1/teams/fuchsia.json
624 [Fuchsia]: https://fuchsia.dev/
625 [source tree]: https://fuchsia.dev/fuchsia-src/get-started/learn/build
626 [rustup]: https://rustup.rs/
627 [cargo]: https://doc.rust-lang.org/cargo/
628 [Fuchsia SDK]: https://chrome-infra-packages.appspot.com/p/fuchsia/sdk/core
629 [overview of CML]: https://fuchsia.dev/fuchsia-src/concepts/components/v2/component_manifests
630 [reference for the file format]: https://fuchsia.dev/reference/cml
631 [Fuchsia devsite]: https://fuchsia.dev/reference/cml
632 [not currently supported]: https://fxbug.dev/105393