You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
If a custom target triple is not available for your platform, you must create a custom target.json file that describes your target to rustc.
4
+
5
+
Keep in mind that it is required to use a nightly compiler to build the core library, which must be done for a target unknown to rustc.
6
+
7
+
## Decide on a target triple
8
+
9
+
Many targets already have a known triple used to describe them, typically in the form ARCH-VENDOR-SYS-ABI. You should aim to use the same triple that [LLVM uses][llvm-target-triple]; however, it may differ if you need to specify additional information to Rust that LLVM does not know about. Although the triple is technically only for human use, it's important for it to be unique and descriptive especially if the target will be upstreamed in the future.
10
+
11
+
12
+
The ARCH part is typically just the architecture name, except in the case of 32-bit ARM. For example, you would probably use x86_64 for those processors, but specify the exact ARM architecture version. Typical values might be `armv7`, `armv5te`, or `thumbv7neon`. Take a look at the names of the [built-in targets][built-in-target] for inspiration.
13
+
14
+
The VENDOR part is optional, and describes the manufacturer. Omitting this field is the same as using `unknown`.
15
+
16
+
The SYS part describes the OS that is used. Typical values include `win32`, `linux`, and `darwin` for desktop platforms. `none` is used for bare-metal usage.
17
+
18
+
The ABI part describes how the process starts up. `eabi` is used for bare metal, while `gnu` is used for glibc, `musl` for musl, etc.
19
+
20
+
Now that you have a target triple, create a file with the name of the triple and a `.json` extension. For example, a file describing `armv7a-none-eabi` would have the filename `armv7a-none-eabi.json`.
The target file must be valid JSON. There are two places where its contents are described: [`Target`], where every field is mandatory, and [`TargetOptions`], where every field is optional. **All underscores are replaced with hyphens**.
27
+
28
+
The recommended way is to
29
+
base your target file on the specification of a built-in target that's similar to your target system, then
30
+
tweak it to match the properties of your target system. To do so, use the command
already built into the compiler][built-in-target].
33
+
34
+
You can pretty much copy that output into your file. Start with a few modifications:
35
+
* Remove `"is-builtin": true`
36
+
* Fill `llvm-target` with [the triple that LLVM expects][llvm-target-triple]
37
+
* Decide on a panicking strategy. A bare metal implementation will likely use `"panic-strategy": "abort"`. If you decide not to `abort` on panicking, even if you [tell Cargo to][aborting-on-panic], you must define an [eh_personality] function.
38
+
* Configure atomics. Pick the first option that describes your target:
39
+
* I have a single-core processor, no threads, no interrupts, or any way for multiple things to be happening in parallel: if you are **sure** that is the case, such as WASM (for now), you may set `"singlethread": true`. This will configure LLVM to convert all atomic operations to use their single threaded counterparts.
40
+
* I have native atomic operations: set `max-atomic-width` to the biggest type in bits that your target can operate on atomically. For example, many ARM cores have 32-bit atomic operations. You may set `"max-atomic-width": 32` in that case.
41
+
* I have no native atomic operations, but I can emulate them myself: set `max-atomic-width` to the highest number of bits that you can emulate up to 64, then implement all of the [atomic][libcalls-atomic] and [sync][libcalls-atomic] functions expected by LLVM as `#[no_mangle] unsafe extern "C"`. These functions have been standardized by gcc, so the [gcc documentation][gcc-sync] may have more notes. Missing functions will cause a linker error, while incorrectly implemented functions will possibly cause UB.
42
+
* I have no native atomic operations: you'll have to do some unsafe work to manually ensure synchronization in your code. You must set `"max-atomic-width": 0`.
43
+
* Change the linker if integrating with an existing toolchain. For example, if you're using a toolchain that uses a custom build of gcc, set `"linker-flavor": "gcc"` and `linker` to the command name of your linker. If you require additional linker arguments, use `pre-link-args` and `post-link-args` as so:
Ensure that the linker type is the key within `link-args`.
60
+
* Configure LLVM features. Run `llc -march=ARCH -mattr=help` where ARCH is the base architecture (not including the version in the case of ARM) to list the available features and their descriptions. **If your target requires strict memory alignment access (e.g. `armv5te`), make sure that you enable `strict-align`**. To enable a feature, place a plus before it. Likewise, to disable a feature, place a minus before it. Features should be comma separated like so: `"features": "+soft-float,+neon`. Note that this may not be necessary if LLVM knows enough about your target based on the provided triple and CPU.
61
+
* Configure the CPU that LLVM uses if you know it. This will enable CPU-specific optimizations and features. At the top of the output of the command in the last step, there is a list of known CPUs. If you know that you will be targeting a specific CPU, you may set it in the `cpu` field in the JSON target file.
Once you have a target specification file, you may refer to it by its path or by its name (i.e. excluding `.json`) if it is in the current directory or in `$RUST_TARGET_PATH`.
75
+
76
+
Verify that it is readable by rustc:
77
+
```sh
78
+
❱ rustc --print cfg --target foo.json # or just foo if in the current directory
79
+
debug_assertions
80
+
target_arch="arm"
81
+
target_endian="little"
82
+
target_env=""
83
+
target_feature="mclass"
84
+
target_feature="v7"
85
+
target_has_atomic="16"
86
+
target_has_atomic="32"
87
+
target_has_atomic="8"
88
+
target_has_atomic="cas"
89
+
target_has_atomic="ptr"
90
+
target_os="none"
91
+
target_pointer_width="32"
92
+
target_vendor=""
93
+
```
94
+
95
+
Now, you finally get to use it! Many resources have been recommending [`xargo`] or [`cargo-xbuild`]. However, its successor, cargo's `build-std` feature, has received a lot of work recently and has quickly reached feature parity with the other options. As such, this guide will only cover that option.
96
+
97
+
Start with a bare minimum [`no_std` program][no_std-program]. Now, run `cargo build -Z build-std=core --target foo.json`, again using the above rules about referencing the path. Hopefully, you should now have a binary in the target directory.
98
+
99
+
You may optionally configure cargo to always use your target. See the recommendations at the end of the page about [the smallest `no_std` program][no_std-program]. However, you'll currently have to use the flag `-Z build-std=core` as that option is unstable.
When using cargo's `build-std` feature, you can choose which crates to compile in. By default, when only passing `-Z build-std`, `std`, `core`, and `alloc` are compiled. However, you may want to exclude `std` when compiling for bare-metal. To do so, specify the crated you'd like after `build-std`. For example, to include `core` and `alloc`, pass `-Z build-std=core,alloc`.
108
+
109
+
## Troubleshooting
110
+
111
+
### language item required, but not found: `eh_personality`
112
+
113
+
Either add `"panic-strategy": "abort"` to your target file, or define an [eh_personality] function.
114
+
115
+
### undefined reference to `__sync_val_compare_and_swap_#`
116
+
117
+
Rust thinks that your target has atomic instructions, but LLVM doesn't. Go back to the step about [configuring atomics][fill-target-file]. You will need to reduce the number in `max-atomic-width`. See [#58500] for more details.
Similar to the above case, Rust doesn't think that you have atomics. You must implement them yourself or [tell Rust that you have atomic instructions][fill-target-file].
125
+
126
+
### multiple definition of `__(something)`
127
+
128
+
You're likely linking your Rust program with code built from another language, and the other language includes compiler built-ins that Rust also creates. To fix this, you'll need to tell your linker to allow multiple definitions. If using gcc, you may add:
129
+
130
+
```json
131
+
"post-link-args": {
132
+
"gcc": [
133
+
"-Wl,--allow-multiple-definition"
134
+
]
135
+
}
136
+
```
137
+
138
+
### error adding symbols: file format not recognized
139
+
140
+
Switch to cargo's `build-std` feature and update your compiler. This [was a bug][#8239] introduced for a few compiler builds that tried to pass in internal Rust object to an external linker.
0 commit comments