[Rust]インストールからHello world, Cargoを使ったプロジェクト管理入門


入門書としてThe Rust Programming Language 日本語訳から学んだアウトプットです。

環境

Archlinux

Rustインストール

インストーラースクリプトを使う

追記
最初OSのパッケージマネージャーを使う方法で試しましたが、下記に述べるエラー?というか一手間が発生したので、入門書推奨のcurl https://sh.rustup.rs -sSf | shを使ったインストールスクリプトの方法を試します。

$ curl https://sh.rustup.rs -sSf | sh
info: downloading installer

Welcome to Rust!

This will download and install the official compiler for the Rust
programming language, and its package manager, Cargo.

Rustup metadata and toolchains will be installed into the Rustup
home directory, located at:

  /home/u1and0/.rustup

This can be modified with the RUSTUP_HOME environment variable.

The Cargo home directory located at:

  /home/u1and0/.cargo

This can be modified with the CARGO_HOME environment variable.

The cargo, rustc, rustup and other commands will be added to
Cargo's bin directory, located at:

  /home/u1and0/.cargo/bin

This path will then be added to your PATH environment variable by
modifying the profile files located at:

  /home/u1and0/.profile
  /home/u1and0/.bash_profile

You can uninstall at any time with rustup self uninstall and
these changes will be reverted.

Current installation options:


   default host triple: x86_64-unknown-linux-gnu
     default toolchain: stable (default)
               profile: default
  modify PATH variable: yes

1) Proceed with installation (default)
2) Customize installation
3) Cancel installation
>
# 対話的に聞いてくるので、Enter押すと(1)のデフォルト設定をしてくれる

info: profile set to 'default'
info: default host triple is x86_64-unknown-linux-gnu
info: syncing channel updates for 'stable-x86_64-unknown-linux-gnu'
info: latest update on 2020-07-16, rust version 1.45.0 (5c1f21c3b 2020-07-13)
info: downloading component 'cargo'
info: downloading component 'clippy'
info: downloading component 'rust-docs'
 12.2 MiB /  12.2 MiB (100 %)  10.9 MiB/s in  1s ETA:  0s
info: downloading component 'rust-std'
 15.8 MiB /  15.8 MiB (100 %)  10.7 MiB/s in  1s ETA:  0s
info: downloading component 'rustc'
 47.6 MiB /  47.6 MiB (100 %)  10.9 MiB/s in  4s ETA:  0s
info: downloading component 'rustfmt'
info: installing component 'cargo'
info: Defaulting to 500.0 MiB unpack ram
info: installing component 'clippy'
info: installing component 'rust-docs'
 12.2 MiB /  12.2 MiB (100 %)  12.1 MiB/s in  1s ETA:  0s
info: installing component 'rust-std'
 15.8 MiB /  15.8 MiB (100 %)  13.3 MiB/s in  1s ETA:  0s
info: installing component 'rustc'
 47.6 MiB /  47.6 MiB (100 %)  13.5 MiB/s in  3s ETA:  0s
info: installing component 'rustfmt'
info: default toolchain set to 'stable'

  stable installed - rustc 1.45.0 (5c1f21c3b 2020-07-13)


Rust is installed now. Great!

To get started you need Cargo's bin directory ($HOME/.cargo/bin) in your PATH
environment variable. Next time you log in this will be done
automatically.

To configure your current shell run source $HOME/.cargo/env

toolchain=stableを落としてきて、cargo, rust関連の実行ファイルをパスに追加してくれました。

インストーラースクリプトを使わずOSのパッケージマネージャーを使う

$ curl https://sh.rustup.rs -sSf | sh を打てと書いてありますが、せっかくArchlinuxなんでpacmanで環境構築してみます。

$ pacman -Syu rustup

archlinuxは古いものから新しいものまでpacmanで簡単にインストール・管理が出来るのがいいですね。
インストールしたらとりあえずバージョン確認。

$ rustc --version
error: no override and no default toolchain set

エラーでした。なんで?
この辺からは入門書に書いていないこと。

そもそもrustupってなんや
help見てみます。

$ rustup help
rustup 1.22.1 (2020-07-08)
The Rust toolchain installer

USAGE:
    rustup [FLAGS] [+toolchain] <SUBCOMMAND>
(snip...)
$ pacman -Qs rustup
local/rustup 1.22.1-1
    The Rust toolchain installer

rustupってtoolchainインストーラーなんだ。(toolchainってなんだ?とは思いつつ。)
つまりこのエラーはtoolchainがないから怒られているとうことで。helpに従いrustup [toolchain]をupdateしてみましょう。
次のコマンドで通りました。

$ rustup update stable
info: syncing channel updates for 'stable-x86_64-unknown-linux-gnu'
info: latest update on 2020-07-16, rust version 1.45.0 (5c1f21c3b 2020-07-13)
info: downloading component 'cargo'
info: downloading component 'clippy'
info: downloading component 'rust-docs'
12.2 MiB /  12.2 MiB (100 %)  10.7 MiB/s in  1s ETA:  0s
info: downloading component 'rust-std'
15.8 MiB /  15.8 MiB (100 %)  10.5 MiB/s in  1s ETA:  0s
info: downloading component 'rustc'
47.6 MiB /  47.6 MiB (100 %)  10.7 MiB/s in  4s ETA:  0s
info: downloading component 'rustfmt'
info: installing component 'cargo'
info: Defaulting to 500.0 MiB unpack ram
info: installing component 'clippy'
info: installing component 'rust-docs'
12.2 MiB /  12.2 MiB (100 %)   8.6 MiB/s in  1s ETA:  0s
info: installing component 'rust-std'
15.8 MiB /  15.8 MiB (100 %)  10.2 MiB/s in  1s ETA:  0s
info: installing component 'rustc'
47.6 MiB /  47.6 MiB (100 %)  10.3 MiB/s in  4s ETA:  0s
info: installing component 'rustfmt'

stable-x86_64-unknown-linux-gnu installed - rustc 1.45.0 (5c1f21c3b 2020-07-13)

info: default toolchain set to 'stable-x86_64-unknown-linux-gnu'

toolchainの種類は次のリンク先に書いてありました。
rust-lang/rustup/README

only contain the names of the three release channels, 'stable', 'beta', 'nightly',

Rust言語の開発者ではないので、stableを選択しました。

入門書に書いていないこと終わり

$ rustc --version
rustc 1.45.0 (5c1f21c3b 2020-07-13)

無事、Rustが使えるようになったようです。

続いて、cargoのパスを追加していきます。
入門書に書いてあることをアレンジして、~/.bashrcに下記を加えました。

```bash:~/.bashrc
# Rust path
[ -f "/usr/bin/cargo" ] && export PATH="$PATH:$HOME/.cargo/bin"
```

追記 OSのパッケージマネージャーを使うとグローバルのパス/usr/binにインストールされるのでパスに加える必要はないでしょう。ということで削除しました。

curl...shを使った場合とOSのパッケージマネージャーを使った場合の違い

  • curl...shを使うと、toolchain(stableなど)をrustup update stableする必要がない(curl ... | shがやってくれる)
  • curl...shを使うと、cargo, rustup, rustcなどの実行ファイルが~/.cargo/binに入る
    • パッケージマネージャーを使ってrustup update stableすれば/usr/bin/usr/sbin下に入る
    • すなわちcurl...shを使うと全てのユーザーがrustを使えない(curl...shを使ったユーザーのみがrustを触れる)
curl...shを使った場合
$ ls ~/.cargo/bin
cargo*         cargo-fmt*   clippy-driver*  rust-gdb*   rustc*    rustfmt*
cargo-clippy*  cargo-miri*  rls*            rust-lldb*  rustdoc*  rustup*
  • curl...shを使うと、~/.cargo/envが作られる
    • ~/.cargo/envはcargoやrustupの実行ファイルをパスに加えて実行できるようにするだけの設定です。
~/.cargo/envの中身
export PATH="$HOME/.cargo/bin:$PATH"

curl...sh実行時に出る下記メッセージの通り、勝手に~/.bash_profileなどにexport文が書き込まれるようです。

This path will then be added to your PATH environment variable by
modifying the profile files located at:

/home/u1and0/.profile
/home/u1and0/.bash_profile

これで次回shell立ち上げ時にcargo関連のパスが追加され、cargoやrustupを実行できるようになります。

curl...shのインストールスクリプトを使う方法とOSのパッケージマネージャーを使う方法どちらが良いかは運用方法、好みによります。
OSのパッケージマネージャーを使えば、pacman -Syuしたときに自動的にrustupもアップグレードしてくれますし、インストールスクリプトを使えば自分でrustup updateを打つ必要があります。
(OSのパッケージマネージャーを使っても、rustup自体がアップグレードされるだけで、実質rustup updateも打たなければなりませんが。)

どのユーザーがRustを使えるか、という点も異なる点の一つです。グローバルに使いたいのであればOSのパッケージマネージャー、1ユーザーだけ使えれば良いのであれば面倒の少ないcurl...shで良いのではないでしょうか。

Hello world

最初のプログラム、Hello worldを書いていきます。

入門書に従い、下記ディレクトリを作成、移動し、main.rsに書き込みました。

$ mkdir -p ~/Dropbox/Program/rust/hello_world; cd $_
$ nvim main.rs
main.rs
fn main(){
    println!("Hello world");
}

shell上でmain.rsをコンパイルし、生成されたバイナリを実行します。

$ rustc main.rs  # main.rsをコンパイルする
$ ls  # バイナリが生成されたことを確認
main
main.rs
$ ./main # バイナリ実行
Hello world

うまくHello worldが出力されました。

Hello cargo

cargoの使い方を学びます。
cargoのバージョンを確認し、インストールされていることを確認します。

$ cargo --version
cargo 1.45.0 (744bd1fbb 2020-06-15)

Cargoを使用して新しいプロジェクトを作成します。
--bin引数をつけることでバイナリを作成するプロジェクトのテンプレートを使用します。

$ cargo new hello_cargo --bin
     Created binary (application) `hello_cargo` package
$ tree hello_cargo
hello_cargo
├── Cargo.toml
└── src
    └── main.rs

1 directory, 2 files

上記のようなディレクトリとファイルが作成されました。
tomlの中身を覗いてみます。

hello_cargo/Cargo.toml
[package]
name = "hello_cargo"
version = "0.1.0"
authors = ["u1and0 <[email protected]>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

勝手にGitのユーザ名とかメールアドレスとか使われるんですねー。
main.rsの中身を覗いてみます。

hello_cargo/src/main.rs
fn main() {
    println!("Hello, world!");
}

Cargoが勝手にHello worldプログラムを生成してくれています。
入門書の文章を引用します。

Cargoは、ソースファイルがsrcディレクトリにあることを期待します。プロジェクトの最上位のディレクトリは、 READMEファイル、ライセンス情報、設定ファイル、あるいは、他のコードに関連しないもののためのものです。 Cargoを使用すると、プロジェクトを体系化する手助けをしてくれます。

Cargoプロジェクトをビルドし、実行する

コンパイルする

Cargoプロジェクトのディレクトリ上でcargo buildコマンドを打ちます。

$ cargo build
   Compiling hello_cargo v0.1.0 (/home/u1and0/Dropbox/Program/rust/hello_cargo)
    Finished dev [unoptimized + debuginfo] target(s) in 0.50s
$ tree
.
├── Cargo.lock
├── Cargo.toml
├── src
│   └── main.rs
└── target
    └── debug
        ├── build
        ├── deps
        │   ├── hello_cargo-87a9db45987e9851
        │   └── hello_cargo-87a9db45987e9851.d
        ├── examples
        ├── hello_cargo  # コンパイルされた実行ファイル
        ├── hello_cargo.d
        └── incremental
            └── hello_cargo-szy1czdxg7sc
                ├── s-fpk74m1exc-85ppht-1fjb5q50dnnhg
                │   ├── 1gm6s9z6a68yb6gt.o
                │   ├── 24lg2nh8sairvn1p.o
                │   ├── 2i3icgmskvbcs2r6.o
                │   ├── 4tdo6t3jaqdcmc89.o
                │   ├── 4viuo6i1wu42msnb.o
                │   ├── dep-graph.bin
                │   ├── geox6bxp965pvuc.o
                │   ├── query-cache.bin
                │   └── work-products.bin
                └── s-fpk74m1exc-85ppht.lock

9 directories, 17 files

随分ディレクトリやファイルが増えました。
コンパイルされた実行ファイルはtarget/debugの下にあります。

コンパイルしてから実行する

cargo buildはコンパイルまでですが、cargo runを使えばコンパイルから実行までをワンコマンドでできます。

$ cd ..
$ rm -rf hello_cargo
$ cargo new hello_cargo --bin
$ cd hello_cargo
$ # 上記でbuildする前の状態までディレクトリの状態を戻してます。
$ cargo run
   Compiling hello_cargo v0.1.0 (/home/u1and0/Dropbox/Program/rust/hello_cargo)
    Finished dev [unoptimized + debuginfo] target(s) in 0.26s
     Running `target/debug/hello_cargo`
Hello, world!
$ tree
.
├── Cargo.lock
├── Cargo.toml
├── src
│   └── main.rs
└── target
    └── debug
        ├── build
        ├── deps
        │   ├── hello_cargo-87a9db45987e9851
        │   └── hello_cargo-87a9db45987e9851.d
        ├── examples
        ├── hello_cargo
        ├── hello_cargo.d
        └── incremental
            └── hello_cargo-szy1czdxg7sc
                ├── s-fpk7k06p9o-kzim4w-1fjb5q50dnnhg
                │   ├── 1gm6s9z6a68yb6gt.o
                │   ├── 24lg2nh8sairvn1p.o
                │   ├── 2i3icgmskvbcs2r6.o
                │   ├── 4tdo6t3jaqdcmc89.o
                │   ├── 4viuo6i1wu42msnb.o
                │   ├── dep-graph.bin
                │   ├── geox6bxp965pvuc.o
                │   ├── query-cache.bin
                │   └── work-products.bin
                └── s-fpk7k06p9o-kzim4w.lock

9 directories, 17 files

cargo runするとcargo buildのときと同じようにディレクトリとファイルを作成し、Hello worldを実行します。

コンパイル可能か確認する

cargo checkコマンドは迅速にコードを確認しコンパイル出来ることを確かめますが、実行可能ファイルは生成しません。
cargo buildのように実行可能ファイルを生成しないので、cargo buildより高速です。
プログラムが実行可能かどうかを確かめながら組み立てるためにcargo checkを定期的に実行しながらコーディングします。

まとめ

  • rustup: toolchainインストーラー
  • rustup update stable: stable toolchainをアップデートする
  • rustc: コンパイラ
  • rustc main.rs: main.rsをコンパイルする
  • cargo build: cargoでコンパイル
  • cargo run: cargoでコンパイルから実行
  • cargo check: cargoでコンパイルできることを確認する(高速)