blob: 339bcc60eaa5afe25ad12343d63ff750327e5d66 [file] [log] [blame] [view]
While updating the Rust toolchain there are various issues that can arise.
Things can break, roadblocks can get in the way, and others might need to be
brought in. In this section we describe the different types of issues that can
occur, examples, and instruct on how to move past them.
They are organized by topics: - Section 2.1: Itemizes various breaks that can
occur when building Rust during Step Test-2 *Build locally*. - Section 2.2:
Describes roadblocks hit when testing during Step Test-3:*Test*, which is a part
of Step Release-8: *Testing Build* - Section 2.3: Proves some notes on updating
the prebuilts during Step Release-9:*Update Prebuilts* - Section 2.4: Describes
issues with uploading to Gerrit as done in both Step Release 6:*Upload* and Step
Release 10:*Upload to Gerrit*
# The Rust Build
Things that can break while building the Rust toolchain:
- Patch Application
- Directory Structure Change
- Binary Incompatibility
- Compilation Failure
- New Crate
- New flags
- Missing tools
## Patch Application
The Android project carries several patches for the Rust toolchain source.
Patches make changes to a code file. In order for a patch file to be
successfully applied the code that it is targeting needs to match the code file
closely enough for the algorithm in the `patch` program to identify the relevant
code. If a patch file fails to be applied then it is likely due to a change in
the targeted code base. In which case, the next step is to figure out if the
patch is still necessary to be applied or if that Patch file can be removed.
To know which patch file failed take a look at the terminal error message. The
error message will also say what *hunk #* and name of the Rust file. Open up the
patch file in `android_rust/patches` and the Rust file. At this point it'll
either look like (1) patch was already applied, (2) the codebase was otherwise
modified.
In the case of (1), it would be useful to verify that the patch was applied.
This can be done by look at the log history for that Rust file.If you do believe
that the patch was merged upstream then you just need to remove the patch from
the `patches/` directory, e.g.
```
pushd toolchain/android_rust
repo start update-rustc-$RUST_VERSION
git rm patches/rustc-000n-Already-merged.patch
git commit -m "Remove Foo patch that has landed upstream"
popd
```
In the case of (2), the codebase was changed in some way. Sometimes the
difference might be very simple. For instance, one time the difference was just
a variable name change and looking at the log history confirmed that.
To be able to successfully apply the patch the code in the patch must match the
code base exactly so go ahead and modify the patch code to match the code base.
If adding or removing lines of code be sure to update the number of lines that
is noted in the patch file. If you are unsure if the change upholds the intent
of the patch go ahead and email the patch owner, but note they will also be
added as a reviewer. When generating patch files using `git format-patch` be
sure to include extra context (`-U10`) as it is needed to successfully apply
some patches.
After editing the patch file, upload the change to Gerrit, and ask the patch
owner to review the changes to make sure the intent of the patch is still
Upheld. Use the topic with "source".
Here is an example of updating a patch file to correspond to changes in code
[CL](https://android-review.googlesource.com/c/toolchain/android_rust/+/1999334).
It may also be useful to create a new patch. The following:
```
git format-patch -U10 HEAD~
```
will generate a patch file for just the previous commit.
## Directory Structure Change
Sometimes another library needs to be imported. We can do this by adding to the
`STDLIB_SOURCES` definition in the `tools/build.py` script.
For example we got the following:
```shell
error: couldn't read prebuilts/rust/linux-x86/1.59.0/src/stdlibs/library/core/src/../../portable-simd/crates/core_simd/src/mod.rs: No such file or direct
ory (os error 2)
--> prebuilts/rust/linux-x86/1.59.0/src/stdlibs/library/core/src/lib.rs:415:1
|
415 | mod core_simd;
| ^^^^^^^^^^^^^^
error: aborting due to previous error
22:37:34 ninja failed with: exit status 1
#### failed to build some targets (18 seconds) ####
```
and as a result we added the portable-simd library as seen in this
[CL](https://android-review.googlesource.com/c/toolchain/android_rust/+/1999334/4/do_build.py).
## Binary Incompatibility
*TODO: text here to describe how the user will know this type of error occurred
and how to fix it*
## Compilation Failure
*TODO: text here to describe how the user will know this type of error occurred
and how to fix it*
## New Crate
Sometimes a new crate is added and a modification needs to be made to
`prebuilts/rustc/Android.bp`.
*TODO: text here to describe how the user will know this type of error occurred
and how to fix it*
## New Flags
The solution might be to disable a new flag that have been added to the build
process.
[Example CL](https://android-review.googlesource.com/c/toolchain/android_rust/+/2103672/3/templates/config.toml.template)
Check the `out` file `CMakeCache.txt` to see any additional flags that may have
been added during the build process. Try testing the new flags with the older
version of the compiler.
## Missing Tools
```
failed to execute command: "strip" "--strip-debug" "/usr/local/google/home/aosp/out/rustc/build/x86_64-unknown-linux-gnu/llvm/lib/libLLVM-17.so"
error: No such file or directory (os error 2)
```
This indicates that `strip` is not available on your local computer. We solved
this by adding a symbolic link to another tool
[CL](https://android-review.git.corp.google.com/c/toolchain/android_rust/+/2776808/8/build.py)
## Troubleshooting a Broken Sysroot Build
*Question: Should this be added to `Section 2.1 Build Error - Missing Crate` or
is it a different type of error?*
If the sysroot build is broken, check whether the error mentions a missing
crate. If it does, there have likely been new components added to the sysroot.
To address this, you will need to:
1. Add the relevant components to `STDLIB_SOURCES` in
`toolchain/android_rust/tools/build.py`.
2. Respin the toolchain via the process above, but with a fresh commit message
noting the reason for the respin. You may want to test this locally first as
more than one dependency may have been added. For local testing,
1. Build as before, using `DIST_DIR=$TOOLCHAIN/dist
./toolchain/android_rust/tools/build.py`
2. Make a local commit with the contents of the tarball now in `$DIST_DIR`
3. Go to `prebuilts/rust` in your Android tree and use `git fetch local`
followed by a checkout to get it imported into your Android tree.
3. Add the missing dependencies to `prebuilts/rust/Android.bp`. Except for
publicly exported crates (which you're not adding right now), all modules in
this file must be suffixed with `.rust_sysroot` to avoid confusion with user
crates. Dependency edges should all be of `rlib` form unless depending on a
publicly exported crate, in which case the dependency edge should match the
type of the final product. As examples, `libterm` (exported) depends by
`dylib` on `libstd`, but `libterm.static` (also exported) depends by `rlib`
on `libstd.static`.`libhashbrown.rust_sysroot` is built only as an `rlib`,
and is linked as an `rlib` everywhere it is used.
# Test
Things that can break during testing:
- Hermeticity breakage
- Build system breakage
- Android Source Warnings
- Miscompilation
- Deprecated Flag
## Hermeticity Breakage
A Hermeticity breakage occurs when the build uses a tool or header that is
different from what we expect. For instance, a crate including a build script
allowing a different compiler/library to be used than expected. Some of these
issues arise because of bugs in the upstream build system. Others can also be
caused because the environment they are built-in have certain defaults set and
carry unintended expectations.
*TODO* @Chriswailes: Describle how to approach this type of problem, given
lzma-sys example.
## Build System Breakage
There can be build breakage issues.
For instance, needing to change `"-C passes='sancov'"`, to `"-C
passes='sancov-module'"`, such as in this
[CL](https://android-review.googlesource.com/c/platform/build/soong/+/2003172/4/rust/sanitize.go).
## Android Source Warnings
A common issue is that this step triggers new warnings on existing source files.
If the compiler suggests a fix, apply it. Otherwise make the most reasonable
looking change necessary to keep the compiler happy and rely on the original
author to determine correctness during code review.
Here is an example of the workflow to modify file x.rs:
```
# navigate to the repo with file x.rs
repo start rust-1.59.0-fixes
# make changes to x.rs
git add x.rs
git commit
```
The commit message should include the testing strategy and buganizer ticket
number. Here is an example commit message from one of these types of
[CLs](https://android-review.googlesource.com/c/platform/system/security/+/2002316).
```
Changes for the Rust 1.59.0 update
bug: 215232614
Test: TreeHugger and compiling with m rust
Change-Id: I1d25f5550f60ff1046a3a312f7bd210483bf9364
```
Note, that it is preferable to create one commit per big change to a repo, so it
might be helpful to use amend when adding more changes to the code:
```shell
$ git commit --amend --no-edit
```
After committing the changes continue to upload them to Gerrit with
```shell
repo upload .
```
In Gerrit for the corresponding CL include the owners of the file as reviewers
and do not set a `topic`.
Next we will need to periodically check-in on these CLs. If they pass presubmit,
then we are waiting for the CLs to be approved/submitted by the file owners.
This can take a few days and may require a friendly nudge.
If the files do not pass presubmit then the changes may not have been backwards
compatible with Rust and we will need to compile it with the latest version of
Rust. If that is the case on Gerrit include it in the topic
`rust-update-prebuilts-1.59.0`, with an updated Rust version number.
We are not able to move to the final **Step 12** (tagging) until these CLs
created in this process has been submitted/accepted.
Clipper errors are typically pretty straightforward but sometimes it’s not clear
what to change. Try checking at the change history or how the change has been
implemented in other parts of the Rust codebase. For instance,
`builder.config.llvm_link_shared` was changed to `!builder.llvm_link_shared()`.
## Miscompilation
A miscompilation may have occured when it successfully compiles but the devices
fail to boot or pass CTS tests.
*TODO: text here to describe how the user will know this type of error occurred
and how to fix it*
## Deprecated flag
The following error:
```shell
warning: `-Z symbol-mangling-version` is deprecated; use `-C symbol-mangling-version`
```
led to changes where that variable was used with `-Z` was changed to `-C` in
`rust/config/global.go`.
[CL](https://android-review.googlesource.com/c/platform/build/soong/+/2003172/5/rust/config/global.go)
.
## Delete files
With this error
```
~/updates/aosp
: > ./toolchain/android_rust/tools/test_compiler.py --prebuilt-path dist/rust-dev.tar.xz --target aosp_cf_x86_6
4_phone --image
Test prebuilt directory already exists. Deleting contents.
Extracting archive /usr/local/google/home/chiw/updates/aosp/dist/rust-dev.tar.xz
/usr/local/google/home/chiw/updates/aosp/prebuilts/build-tools/linux-x86/bin/xz: /usr/local/google/home/c
hiw/updates/aosp/dist/rust-dev.tar: File exists
Traceback (most recent call last):
File "/usr/local/google/home/chiw/updates/aosp/./toolchain/android_rust/test_compiler.py", line 198, in
<module>
sys.exit(main())
^^^^^^
File "/usr/local/google/home/chiw/updates/aosp/./toolchain/android_rust/test_compiler.py", line 143, in
main
prepare_prebuilts(args.prebuilt_path)
File "/usr/local/google/home/chiw/updates/aosp/./toolchain/android_rust/test_compiler.py", line 129, in
prepare_prebuilts
(target_and_version_path / "bin" / "rustc").touch()
File "/usr/lib/python3.11/pathlib.py", line 1109, in touch
fd = os.open(self, flags, mode)
^^^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: '/usr/local/google/home/chiw/updates/aosp/prebuil
ts/rust/linux-x86/9.99.9/bin/rustc
```
Try
```
rm $DIST_DIR/rust-dev.tar
```
## New Build Breaking Lint/Clippy Errors
New lints/clippys can cause build breakage and may require significant
refactoring as the code base grows. To avoid blocking toolchain upgrades,
explicitly allow the breaking lints/clippys when first upgrading the toolchain.
1. Allow build breaking lints/clippys by adding them to the list in
`build/soong/rust/config/lints.go` with the `-A` flag.
2. If the new lint/clippy is beneficial enough to justify enable going forward,
file a bug to track the refactor effort.
# Update prebuilts
Things that can break when updating the prebuilts:
- File undefined
- Fetch ID
- Unknown manifest
## File undefined
Try deleting the branch `git branch -D rust-update-prebuilts-1.59.0-local`
## Fetching ID
```shell
: > ./toolchain/android_rust/tools/update_prebuilts.py
--chained 1.62.0 Unable to fetch LKGB build ID
```
This means you forgot to run gcert.
## Unknown Manifest
Note that some tests might fail during presubmit because of code that live in
other manifests. Make the appropriate changes as usual, but in the right place.
# Upload
Things that can break while uploading files to Gerrit:
- Geritt limitation
- Detached head
## Geritt Limitation
Help, Gerrit won't take my update!
First, try again. Sometimes Gerrit is just flaky and will take it on the second
or third try.
If that's still not working, you are likely hitting a size limitation (for
example, because `rustc` updated it's LLVM revision, so the diff is bigger than
usual). In this case, you will need to work with the build team to get them to
use a "direct push" to skip Gerrit's hooks. Look at the initial import
[bug](http://b/137197907) for an example conversation about importing oversized
changes.
## Detached head
Use this to get away from detached head:
```shell
git branch -u aosp/master
```
# Prebuilts Test failure
* Run tests locally
* Output Format
## Run test locally
If presbuilts failed presubmit, one thing you can do is try to run test locally
```shell
source build/envsetup.sh
lunch aosp_cf_x86_64_phone-staging-userdebug
m
acloud create --local-image
export ANDROID_SERIAL=<value printed by previous command>
atest bytes_test_tests_test_bytes
// or whatever tests are failing in the prebuilts
```
## Output Format
There could be an error parsing the results of running Rust tests.
A prior release Rust v.1.61 release notes include messages with ignored tests.
We had to modify how the trade federation code analyzes the result of running
tests (changed regex).
[CL](https://android-review.googlesource.com/c/platform/tools/tradefederation/+/2110829)
The Gerrit CL triggered the same changes in Critique.
# Other Helpful Debugging Tips
## Toolchain scripts
Sometimes it might be necessary to change the *android_rust* scripts
themselves. Here are some examples:
* audit.py: Add more .so files to the shared library allow list because they
are required by other .so files
* build.py: Useful to edit if you want to regenerate a lockfile, exclude a
test
* config.py: Change env rust flags
## Other
* build_error.log: Check the state of the builds and try to reproduce
locally. For example if Soongs prints `out/a` on failure then try running `m
out/a` to reproduce the issue locally. *
[upstream](https://github.com/rust-lang/rust/tree/beta) Check recent relevant
changes to the Rust upstream code since the last update