Rust 2018开发环境配置与开发效率工具集
一句话概括:macOS/Linux用户首选CLion + Rust插件,折腾VSCode收益太低。以下内容来自参与开发gfx-rs/hal、gfx-rs/wgpu等Rust主流开源图形项目的经历总结。
配置Rust编译环境
使用Rust开发macOS、iOS、Android等跨平台共享源码的项目,开发环境避免不了这些系统所要求的开发环境,即:
- macOS、iOS需要安装Xcode
- Android需要Android Studio、Android SDK、Android NDK,并且配置SDK、NDK到环境变量。如果不想手工配置SDK、NDK变量,对于macOS,推荐先安装Android Studio到Application,之后通过Android Studio安装Android SDK、NDK,然后向profile、zsh配置文件等写入SDK、NDK变量。
- 修改Rust软件更新源为中科大站点对国内用户而言可以提高下载速度,已翻墙可不考虑。
// 1. 打开环境变量配置文件 vi ~/.bashrc // 2. 加入如下内容 export RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static export RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup // 3. 激活新配置内容 source ~/.bashrc
- 安装Rust,如果要安装nightly编译工具链才加
--channel=nightly
根据朋友反馈,2018年11月21日用下面的中科大源安装会报错,官方源没问题。// !!! 以下命令二选一 !!! // 中科大源 curl -sSf https://mirrors.ustc.edu.cn/rust-static/rustup.sh | sh # -s -- --channel=nightly // 官方源 curl https://sh.rustup.rs -sSf | sh
- cargo环境变量设置
根据朋友反馈,安装Rust 1.30以上版本,cargo配置是自动完成的,在terminal中输入
cargo --version
测试cargo是否已配置,若结果类似cargo 1.32.0-nightly (1fa308820 2018-10-31)
表明一切正常,后面这些操作可跳过。当前版本(1.26)的cargo装好后,并不自动设置环境变量。在此进行手动配置,方便后面使用cargo安装的效率工具。在此以macOS为例,mac上的cargo一般安装在~/.cargo/bin
下。export PATH="$HOME/.cargo/bin:$PATH"
IDE配置
CLion与推荐插件
- Rust插件(最关键的插件) 提供代码提示、补全、跳转等功能,比Rust Language Server(RLS)稳定、好用,插件功能的更新速度快。
- Toml
方便编写
Cargo.toml
文件。 - Active Intellij Tab Hightlighter 高亮当前打开的Tab页。
- Dash 查文档方便
- Git Conflict 在源文件中用颜色区分代码冲突,比Intellij系列产品原生做法更直观。
- Grep Console 过滤控制台输出,可配置色彩输出,比默认功能更强。
- HighlightBracketPair
高亮显示光标所在的区域,比如在某个
{}
,()
或[]
内。
值得注意的是,由于gfx-rs项目组的几个核心成员都没用CLion,导致gfx-rs系列项目的examples等测试项目用CLion打开后都没有hal和各backend数据结构跳转功能。
新建引用gfx的项目时,加上正确的#[cfg(any(feature = "vulkan", feature = "metal"))]
,CLion也可以代码跳转到gfx里面,这个问题坑了我几个月,泪奔。
小八卦,他们用什么编辑工具?我在gitter上私聊过他们,Dzmitry Malyshau(kvark,火狐WebRender团队成员) 用Sublime Text,Josh Groves(grovesNL)用Visual Studio Code。
不推荐Visual Studio Code的原因
RLS不稳定导致代码跳转经常失效是最重要的原因,但是,VSCode的优势是,在没有代码跳转的情况下还能提供比CLion更强的代码提示,这让我感到意外。
另外,由于我个人很少使用VSCode,VSCode配置起来对我而言是比较麻烦的,而且Rust有几个组件要正常配置才能在VSCode上实现单步调试,个人认为对Rust新手不友好。 其实,我在7月刚学习Rust时用的就是VSCode,跟着老外的博客配了半天才弄好LLDB单步调试,我觉得不值得,我当时的核心任务应该是环境就绪情况下学习Rust语法以及用它合理地解决问题,而不是折腾开发环境。
提高开发维护效率的工具集
CI配置、代码风格化与编译缓存
CI配置appveyor与travis
appveyor与travis都支持GitHub项目,在此给出它们的Rust编译、单元测试配置。
- appveyor配置文件
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
- travis配置文件
.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
rustfmt 统一代码风格
为避免无意义的风格争论,推荐使用Rust官方出品的统一代码风格组件rustfmt。以下所有命令都需要在已配置好Rust环境的终端上执行。可在CI上搭配。
- 安装
rustup component add rustfmt-preview
- 更新rustfmt版本,使用
rustup update
命令可更新所有rustup已安装的组件。 - 使用
cargo fmt
自定义rustfmt代码风格
不建议自定义代码风格,最好和官方默认代码保持一致。 定制风格规则参考rustfmt#configuring-rustfmt。
sccahe 多工作区共享编译缓存
目前Rust只支持工作区workspace内部多个项目间的编译缓存,不支持workspace之间的缓存。对于多个workspace引用了部分相同版本的组件,每个工作区或独立项目都要编译这些相同版本的组件,花费了多余的编译时间,没意义。借助第三方工具mozilla/sccache 可解决此问题,它支持远程服务器编译共享,也支持本地共享。
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.
- 安装sccache
cargo install sccache
- 配置sccache环境变量
export RUSTC_WRAPPER=sccache
- (最重要的一步) 配置sccache全局编译缓存路径
提高Rust与C接口交互的开发效率
cbindgen 给Rust代码自动生成C头文件
给iOS/Android等编写跨平台C++/Rust项目最终还是以C接口方式让外部使用,当提供较多接口时,手写容易出错、开发慢,此时用自动头文件生成器是更合理的选择,cbindgen可帮我们实现这一目标。
- 安装
cargo install cbindgen
- 更新cbindgen
cargo install --force cbindgen
- 使用方式一:命令行执行
cbindgen crate/ -o crate/bindings.h
- 使用方式二:作为项目的预处理使用方式写成
build.rs
,对于复杂项目,推荐用此方案。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"); }
bindgen 给C头文件生成Rust绑定代码
和cbindgen相反,bindgen可生成Rust调用C函数所需的FFI绑定代码,但是这个工具在遇到多重包含如#include "other_file.h"
时会出错,详细说明见官方文档。
- 安装
cargo install bindgen
- 使用
bindgen input.h -o bindings.rs
--rust-target
指定Rust版本,如--rust-target 1.30
--rust-target nightly
使用nightly工具链
提高Rust开发SDK项目的维护效率
用built输出Rust项目构建信息
built是个构建依赖(build-dependencies)类型的开源项目,详细用法见项目说明。 built 0.3.0默认不支持built_info::DEPENDENCIES_STR。
-
配置Cargo.toml
[package] build = "build.rs" [build-dependencies] built = "0.3"
-
添加build.rs,与Cargo.toml同级。更详细的信息需要配置built。
extern crate built; fn main() { built::write_built_file().expect("Failed to acquire build-time information"); }
-
使用示例
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);
输出信息:
Version 0.1.0 (git 62eb1e2), 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, ...
tokei统计项目代码行数,支持C/C++/Rust等语言
tokei几乎支持所有编程语言或脚本的行数统计(有效代码与注释都正常区分开),非常好用,下面给个我们项目的统计。
--------------------------------------------------------------------------------
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
--------------------------------------------------------------------------------
提高Rust项目多模块管理效率
cargo-modules是查看多个模块信息的有效工具,比如树形显示crate的mod、mod的可见性等,非常好用,在此只放张官方动图,详情见项目文档。

提高Cargo管理效率
一键更新Cargo工具
cargo-update一键更新本地安装的Cargo工具,全部或指定部分。
- 安装cargo-update
cargo install cargo-update
- 使用,一键更新所有cargo工具
cargo install-update -a
检查并自动更新已安装的cargo组件中需要更新的部分 - 只更新指定的工具
cargo install-update crate1 crate2
以cargo install-update -a
为例,以下为它的具体执行过程。
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 cargo-lipo
Updating crates.io index
Downloaded cargo-lipo v2.0.0
Downloaded 1 crates (9.4 KB) in 3.14s
Installing cargo-lipo v2.0.0
Compiling num-traits v0.2.6
Compiling libc v0.2.44
Compiling vec_map v0.6.0
Compiling ansi_term v0.7.5
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) in 22.19s
Replacing /Users/你的用户名/.cargo/bin/cargo-lipo
// ...
Updated 3 packages.
以macOS为例,所有cargo工具默认都安装在/Users/你的用户名/.cargo/bin/下,比如/Users/你的用户名/.cargo/bin/cargo-lipo。
Rust开发iOS项目的效率工具
cargo-lipo
cargo lipo
一个命令可编译出iOS目前支持的5个CPU架构静态库,且自动合并成一个多合一的universal静态库。
- 安装
cargo install cargo-lipo
- 在Rust项目任意位置执行
cargo lipo
即可开始编译iOS静态库
Rust项目开启Bitcode编译
RUSTFLAGS="-C llvm-args=\"-fembed-bitcode\"" cargo build
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指定需要的iOS版本
IPHONEOS_DEPLOYMENT_TARGET=7.0 cargo build
Rust开发Android JNI项目的效率工具
cargo-rumo
支持编译Android/iOS跨平台库。
- 安装cargo-rumo
cargo install rumo
- 编译当前项目为APK
rumo build
- 安装APK到模拟器或手机
rumo device-install
jni-rs在Rust中调用JNI接口与暴露JNI接口给Java
jni-rs/jni-rs,顾名思义给JNI接口编写Rust绑定,让我们在Rust中调用JNI函数,在Java代码中直接加载so即可调用我们公开的API,无需再加一层头文件。下面是给一个示例。
/// 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 *mut OpenGLBackend)));
}
}
android_logger在Rust中调用Android Log函数
同上,Nercury/android_logger-rs映射Android Log函数到Rust,方便Rust代码调用。
- 配置Cargo.toml
[target.'cfg(target_os = "android")'.dependencies] android_logger = "0.5"
- 使用示例
#[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); }
转载自:https://juejin.cn/post/6844903712670875661