For a list of documents, see: Rust Mobile Complex Graphics Rendering Project Development Series summary (table of Contents)
In a word: macOS/Linux users prefer CLion + Rust, which makes VSCode less profitable. The following is a summary of my experience in developing mainstream Rust open source graphics projects such as GFX-RS/Hal and GFX-RS/WGPU.
Configure the Rust compilation environment
When developing cross-platform shared source code for macOS, iOS, Android and other projects using Rust, the development environment cannot avoid the development environment required by these systems, namely:
- Xcode is required for macOS and iOS
- Android requires Android Studio, Android SDK, Android NDK, and configure the SDK and NDK to environment variables. If you do not want to manually configure SDK and NDK variables, you are advised to install Android Studio to Application for macOS, and then install Android SDK and NDK through Android Studio. Then write SDK, NDK variables to profile, ZSH profile, etc.
- Change the update source of Rust software to uSTC website for domestic users can improve the download speed, not over the wall.
1. Open the environment variable configuration file vi ~/. Bashrc // 2. Add the followingexport RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static exportRUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup // 3. Activate the new configurationsource ~/.bashrc Copy the code
- Install Rust if you want to install the NIGHTLY compiler chain
--channel=nightly
According to my friend’s feedback, there will be an error when using the following USTC source installation on November 21, 2018. The official source is ok./ /!!!!!! Choose one of the following commands!! // The university of Science and Technology of China-sSf https://mirrors.ustc.edu.cn/rust-static/rustup.sh | sh # -s -- --channel=nightly// official source curl https://sh.rustup.rs-sSf | sh Copy the code
- Cargo Environment variable Settings
According to my friend’s feedback, when installing Rust 1.30 or above, cargo configuration is automatically completed, enter it in Terminalcargo --version
Tests whether cargo is configured, if the result is similarCargo 1.32.0 - the nightly fa308820 (1 2018-10-31)
It indicates that all is normal. You can skip the following operations. When cargo is installed in the current version (1.26), environment variables are not automatically set. Manual configuration is done here for later use of the efficiency tools installed by Cargo. Taking macOS as an example, Cargo is typically installed on a MAC~/.cargo/bin
Under.export PATH="$HOME/.cargo/bin:$PATH" Copy the code
IDE configuration
CLion and recommended plug-ins
- The Rust plug-in (the most critical plug-in) provides code hints, completion, and jumps, and is more stable and user-friendly than Rust Language Server(RLS), with faster updates to plug-in features.
- Toml
Convenient to writeCargo.toml
File. - Active Intellij Tab Hightlighter Highlights the currently open Tab page.
- Dash makes documentation easy
- Git Conflict uses color to distinguish code conflicts in source files, which is more intuitive than native to the Intellij family.
- Grep Console Filter Console output. You can configure color output, which is more powerful than the default function.
- HighlightBracketPair
Highlight the area where the cursor is located, such as in a{}
.(a)
or[]
Inside.
It should be noted that several core members of the GFX-RS project team did not use CLion. As a result, the examples and other test items of GFX-RS series projects did not have Hal and backend data structure transfer functions after being opened with CLion.
[CFG (any(feature = “vulkan”, feature = “metal”))]], CLion can also jump to GFX.
Gossip, what editing tools do they use? I’ve chatted privately about them in Gitter, Dzmitry Malyshau(Kvark, member of the Firefox WebRender team) uses Sublime Text and Josh Groves(grovesNL) uses Visual Studio Code.
Why Visual Studio Code is not recommended
RLS instability causing code jumps to fail frequently is the most important reason, but I was surprised by VSCode’s ability to provide stronger code hints than CLion without code jumps.
In addition, since I rarely use VSCode personally, it is troublesome for me to configure VSCode, and Rust has several components that need to be configured properly to implement single-step debugging on VSCode, which I think is unfriendly to beginners of Rust. In fact, when I first learned Rust in July, I used VSCode. It took me a long time to do LLDB single step debugging, but I felt it was not worth it. My core task should have been to learn Rust syntax when the environment was ready and use it to solve problems reasonably, not to mess with the development environment.
A set of tools to improve development and maintenance efficiency
CI configuration, code stylization, and compilation caching
CI is configured with Appveyor and Travis
Appveyor and Travis both support the GitHub project, and their Rust build, unit test configurations are shown here.
- Appveyor configuration files
appveyor.yml
language: rust sudo: false matrix: include: - rust: stable script: - cargo test --all --locked - rustup component add rustfmt-preview - cargo fmt -- --write-mode=diff Copy the code
- Travis configuration file
.travis.yml
language: rust rust: - stable - nightly branches: except: - staging.tmp before_install: # Do not run bors builds against the nightly compiler. # We want to find out about nightly bugs, so they're done in master, but we don't block on them. - if [[ $TRAVIS_RUST_VERSION= ="nightly" && $TRAVIS_BRANCH= ="staging"]].then exit; fi script: - cargo test - cargo build #--manifest-path your_project_path/Cargo.toml --features remote - cargo build #- (cd examples && make) #TODO Copy the code
Rustfmt unified code style
To avoid pointless style debates, use RustFmt, Rust’s official uniform code style component. All the following commands must be executed on the terminal with the Rust environment configured. Can be matched on CI.
- The installation
rustup component add rustfmt-preview
- Update rustFMT version to use
rustup update
Command to update all rustup installed components. - use
cargo fmt
Custom RustFMT code style
It is not recommended to customize the code style. It is better to keep the official default code. For custom style rules refer to RustMT #configuring- RustFmt.
Sccahe multiple workspaces share the compile cache
Currently Rust only supports compilation caches between multiple projects within workspaces, not between workspaces. For multiple workspaces that reference parts of the same version of components, each workspace or individual project will have to compile those components of the same version, spending unnecessary compilation time and making no sense. You can solve this problem with third-party tools, Mozilla/Sccache, which support remote server build sharing as well as local sharing.
Sccache is a ccache-like tool. It is used as a compiler wrapper and avoids compilation when possible, storing a cache in a remote storage using the Amazon Simple Cloud Storage Service (S3) API, the Google Cloud Storage (GCS) API, or Redis.
Sccache can also be used with local storage instead of remote.
- Install sccache
cargo install sccache
- Configure sccache environment variables
export RUSTC_WRAPPER=sccache
- The most important step is to configure the sccache global compile cache path
Improve the development efficiency of Rust and C interface interaction
Cbindgen automatically generates C header files for Rust code
Writing cross-platform C++/Rust projects for iOS/Android will eventually use C interface for external use. When many interfaces are provided, handwriting is prone to error and development is slow. In this case, automatic header generator is a more reasonable choice, cbindGen can help us achieve this goal.
- The installation
cargo install cbindgen
- Update cbindgen
cargo install --force cbindgen
- Usage Method 1: Run the command
cbindgen crate/ -o crate/bindings.h Copy the code
- Usage method 2: written as a pre-processing method for the project
build.rs
For complex projects, this solution is recommended.extern crate cbindgen; use std::env; fn main() { let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); cbindgen::Builder::new() .with_crate(crate_dir) .generate() .expect("Unable to generate bindings") .write_to_file("bindings.h"); } Copy the code
Bindgen generates Rust binding code for C header files
In contrast to CBindgen, Bindgen generates the FFI binding code required for Rust to call C functions, but the tool can fail when encountering multiple contains such as #include “other_file. H “, as described in the documentation.
- The installation
cargo install bindgen
- use
bindgen input.h -o bindings.rs
--rust-target
Specify the Rust version, such as- rust - target 1.30
--rust-target nightly
Use the Nightly tool chain
Improve the maintenance efficiency of Rust development SDK projects
Output Rust project build information with built
Built is an open source project of the type build-dependencies, described in the project description. Built 0.3.0 Default built_info::DEPENDENCIES_STR not supported.
-
Configuration Cargo. Toml
[package] build = "build.rs" [build-dependencies] built = "0.3" Copy the code
-
Add build.rs at the same level as Cargo. Toml. For more details, you need to configure built.
extern crate built; fn main() { built::write_built_file().expect("Failed to acquire build-time information"); } Copy the code
-
Use the sample
pub mod built_info { include! (concat! (env! ("OUT_DIR"), "/build.rs")); } info! ("Version {}{}, built for {} by {}.", built_info::PKG_VERSION, built_info::GIT_VERSION.map_or_else(|| "".to_owned(), |v| format! (" (git {})", v)), built_info::TARGET, built_info::RUSTC_VERSION); trace! ("Built with profile \"{}\", features \"{}\" on {} using {}", built_info::PROFILE, built_info::FEATURES_STR, built_info::BUILT_TIME_UTC, built_info::DEPENDENCIES_STR); Copy the code
Output information:
Version 0.1.0 from 62 eb1e2 (git), Built for x86_64-apple- Darwin by rustC 1.32.0- NIGHTLY (6b9b97BD9 2018-11-15). Built with profile "debug", Features "DEFAULT, ERR_PRINTLN" on Thu, 23 Nov 2018 19:00:08 GMT using bitflags 0.7.0, block 0.1.6, built 0.1.0, Byteorder 0.5.3, bytes 0.3.0, cgMath 0.7.0,...Copy the code
Tokei counts the number of project lines of code and supports C/C++/Rust and other languages
Tokei supports line count statistics for almost any programming language or script (valid code is normally separated from comments), which is very useful. Here is our project’s statistics.
-------------------------------------------------------------------------------- Language Files Lines Code Comments Blanks -------------------------------------------------------------------------------- C Header 1 5 5 0 0 GLSL 10 147 113 6 28 Makefile 1 83 58 12 13 Markdown 13 288 288 0 0 Rust 96 51261 41749 4316 5196 SVG 1 33 33 0 0 TOML 12 338 293 2 43 YAML 1 39 31 4 4 -------------------------------------------------------------------------------- Total 135 52194 , 42570, 4340, 5284 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --Copy the code
Improve the efficiency of multi-module management of Rust projects
Cargo -modules is a great tool for viewing information about multiple modules, such as the tree that displays Crate’s mod and mod visibility.
Improve Cargo management efficiency
One-click update of Cargo tool
Cargo -update One-click update of all or specified parts of the cargo tool installed locally.
- Install the cargo – update
cargo install cargo-update
- Use, one click to update all cargo tools
cargo install-update -a
Check and automatically update installed Cargo components that need to be updated - Update only the specified tools
cargo install-update crate1 crate2
Cargo install-update-a is used as an example. The following is how it is executed.
cargo install-update -a
Updating registry 'https://github.com/rust-lang/crates.io-index'Package Installed Latest Needs Update BAT V0.6.1 v0.9.0 Yes Bindgen v0.37.4 v0.43.1 Yes cargo- Lipo v2.0.0-beta-3 v2.0.0 Yes cargo- APk v0.4.0 v0.4.0 No cargo-update v1.7.0 v1.7.0 No exa v0.8.0 v0.8.0 No sccache v0.2.7 v0.2.7 No Updating Freight-lipo Updating crates. IO index Freight-lipo V2.0.0 Downloaded 1 crates (9.4KB)inAfter Compiling libc v0.2.44 Compiling VEC_map v0.6.0 Compiling, Installing cargo Lipo v2.0.0 Compiling num-traits v0.2.6 Compiling Ansi_term Compiling strsim v0.4.1 Compiling Serde v0.7.15 Compiling IToa v0.1.1 Compiling bitflags v0.5.0 Compiling unicode-width v0.1.5 Compiling clap v2.2.6 Compiling num-traits v0.1.43 Compiling serde_json v0.7.4 Compiling Cargo - Lipo v2.0.0 Finished Release [Optimized] Target (s)in12 Replacing /Users/ Your username /.cargo/bin/cargo- Lipo // Updated 3 packages.Copy the code
In the case of macOS, all cargo tools are installed by default under /Users/ your username /.cargo/bin/, such as /Users/ your username /.cargo/bin/cargo-lipo.
Rust develops productivity tools for iOS projects
cargo-lipo
Cargo Lipo compiles the five CPU architecture static libraries currently supported by iOS with a single command and automatically merges them into one all-in-one universal static library.
- The installation
cargo install cargo-lipo
- Execute anywhere in the Rust project
cargo lipo
Start compiling the iOS static library
The Rust project starts Bitcode compilation
RUSTFLAGS="-C llvm-args=\"-fembed-bitcode\"" cargo build
Copy the code
You can tell cargo to pass any argument you wish to the Rust compiler by setting the RUSTFLAGS environment variable. The Rustc compiler has a flag -C llvm-args=val that you can use to pass additional arguments to llvm.
Enable Bitcode Output in Cargo Build for iOS Targets?
Cargo Build specifies the required iOS version
IPHONEOS_DEPLOYMENT_TARGET = 7.0 cargo buildCopy the code
Reference: libc.travis. Yml file
Rust develops efficiency tools for Android JNI projects
cargo-rumo
Support Android/iOS cross-platform library compilation.
- Install the cargo – rumo
cargo install rumo
- Compile the current project to APK
rumo build
- Install APK to emulator or phone
rumo device-install
Jni-rs invokes jNI interfaces in Rust and exposes jNI interfaces to Java
Jni-rs/JNI-RS, as the name implies, writes Rust bindings to the JNI interface, allowing us to call jNI functions in Rust and load SO directly into Java code to call our exposed API without adding another header file. Here is an example.
/// Expose the JNI interface for android below
#[cfg(target_os = "android")]
#[allow(non_snake_case)]
pub mod android {
extern crate jni;
use self::jni::objects::{JClass, JString};
use self::jni::sys::{jlong, jstring};
use self::jni::JNIEnv;
#[no_mangle]
pub unsafe extern "C" fn Java_com_example_Rust_opengl_init(
env: JNIEnv,
_: JClass,
) -> jlong {
let res = Box::into_raw(rust_opengl_backend_init());
res as jlong
}
#[no_mangle]
pub unsafe extern "C" fn Java_com_example_Rust_opengl_draw_frame(
env: JNIEnv,
_: JClass,
handle: jlong,
) {
rust_opengl_backend_draw(&mut (*(handle as *mutOpenGLBackend))); }}Copy the code
Android_logger calls the Android Log function in Rust
As above, Nercury/ Android_logger-RS maps the Android Log function to Rust for easy invocation by Rust code.
- Configuration Cargo. Toml
[target.'cfg(target_os = "android")'.dependencies] android_logger = "0.5" Copy the code
- Use the sample
#[macro_use] extern crate log; extern crate android_logger; use android_logger::Filter; fn native_activity_create() { android_logger::init_once(Filter::default().with_min_level(Level::Trace), None); } Copy the code