内容简介:If a custom target triple is not available for your platform, you must create a custom target file that describes your target to rustc.Keep in mind that it is required to use a nightly compiler to build the core library, which must be done for a target unk
If a custom target triple is not available for your platform, you must create a custom target file that describes your target to rustc.
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.
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 ; 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.
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
thebuilt-in targets for inspiration.
The VENDOR part is optional and describes the manufacturer. Omitting this field is the same as
using unknown
.
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.
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.
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
.
The recommended way is to base your target file on the specification of a built-in target that's
similar to your target system, then tweak it to match the properties of your target system. To do
so, use the command rustc +nightly -Z unstable-options --print target-spec-json --target $SOME_SIMILAR_TARGET
, using a target that's already built into the compiler
.
You can pretty much copy that output into your file. Start with a few modifications:
-
Remove
"is-builtin": true
-
Fill
llvm-target
with the triple that LLVM expects -
Decide on a panicking strategy. A bare metal implementation will likely use
"panic-strategy": "abort"
. If you decide not toabort
on panicking, unless youtell Cargo to per-project, you must define aneh_personality function. -
Configure atomics. Pick the first option that describes your target:
-
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. Incorrectly using this option may result in UB if using threads or interrupts. -
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. -
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 128, then implement all of the atomic and sync functions expected by LLVM as#[no_mangle] unsafe extern "C"
. These functions have been standardized by gcc, so the gcc documentation may have more notes. Missing functions will cause a linker error, while incorrectly implemented functions will possibly cause UB. For example, if you have a single-core, single-thread processor with interrupts, you can implement these functions to disable interrupts, perform the regular operation, and then re-enable them. -
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
.
-
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
-
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"
andlinker
to the command name of your linker. If you require additional linker arguments, usepre-link-args
andpost-link-args
as so:"pre-link-args": { "gcc": [ "-Wl,--as-needed", "-Wl,-z,noexecstack", "-m64" ] }, "post-link-args": { "gcc": [ "-Wl,--allow-multiple-definition", "-Wl,--start-group,-lc,-lm,-lgcc,-lstdc++,-lsupc++,--end-group" ] }
Ensure that the linker type is the key withinlink-args
. -
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 enablestrict-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. -
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
.
Verify that it is readable by rustc:
❱ rustc --print cfg --target foo.json # or just foo if in the current directory debug_assertions target_arch="arm" target_endian="little" target_env="" target_feature="mclass" target_feature="v7" target_has_atomic="16" target_has_atomic="32" target_has_atomic="8" target_has_atomic="cas" target_has_atomic="ptr" target_os="none" target_pointer_width="32" target_vendor=""
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.
Start with a bare minimum
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.
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
. However, you'll currently have to
use the flag -Z build-std=core
as that option is unstable.
Build additional built-in crates
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
.
language item required, but not found: eh_personality
Either add "panic-strategy": "abort"
to your target file, or define aneh_personality function.
Alternatively, tell Cargo to ignore it
.
undefined reference to __sync_val_compare_and_swap_#
Rust thinks that your target has atomic instructions, but LLVM doesn't. Go back to the step about. You will need to reduce the number in max-atomic-width
.
See #58500
for more details.
could not find sync
in alloc
Similar to the above case, Rust doesn't think that you have atomics. You must implement them yourself ortell Rust that you have atomic instructions.
multiple definition of __(something)
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:
"post-link-args": { "gcc": [ "-Wl,--allow-multiple-definition" ] }
Switch to cargo's build-std
feature and update your compiler. This was a bug
introduced
for a few compiler builds that tried to pass in internal Rust object to an external linker.
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Erlang趣学指南
邓辉、孙鸣 / 人民邮电出版社 / 2016-9-7 / 79.00元
这是一本讲解Erlang编程语言的入门指南,内容通俗易懂,插图生动幽默,示例短小清晰,结构安排合理。书中从Erlang的基础知识讲起,融汇所有的基本概念和语法。内容涉及模块、函数、类型、递归、错误和异常、常用数据结构、并行编程、多处理、OTP、事件处理,以及所有Erlang的重要特性和强大功能。一起来看看 《Erlang趣学指南》 这本书的介绍吧!