看過來

初來乍到者,請參閱這篇「緣起」。它是總索引!

2017年3月30日 星期四

[Rust] Rust 預設堆疊大小

本文討論到 Rust 程式的預設堆疊大小,那這裡的堆疊是指什麼?

Rust 和 C 語言一樣,若是宣告了自動變數(區域變數),那麼區域變數本身的空間必須由堆疊來供應。此外,進行函數呼叫的時候,為了保存返回位置,也需要使用堆疊。

(附帶一提,在 Rust 中,若想要進行動態分配,則必須使用 Box<T>; C 裡面則要使用 malloc。Rust 的 Vec<T> 內部使用了 Box<T>,所以可以達成動態大小。)

所以說,若您的程式需要很大的陣列空間,或者是會進行遞迴呼叫,那您可能會遇到堆疊空間不足的問題。所以了解堆疊空間限制,以及調整的方法就變成了重要的課題。

實務上來說,若能夠在編譯時調整堆疊空間(像是 C 語言),或者最起碼可以在啟動時調整(像是 JVM),則可以不用了解堆疊空間限制在哪裡,不夠的時候直接調整便可。然而,對 Rust 來說,目前似乎仍然沒有可以調整主執行緒(main thread)堆疊大小的方法:
雖然沒辦法調整主執行緒的堆疊大小,但是在 Rust 裡面,我們可以調整新生成執行緒的大小。利用這樣的原則,我們不只可以在發覺主執行緒堆疊不足時迴避此問題,還可以藉著比較已知堆疊大小的新執行緒以及主執行緒會發生堆疊溢滿(Stack overflow)的函數呼叫次數來推得一個系統的預設堆疊大小。

利用上面的概念,千秋設計了一支程式,它可以:
  • 示範如何調整新執行緒的堆疊大小
  • 利用 command-line switch ,您可以選擇測試主執行緒的堆疊大小,或是新生執行緒的堆疊大小,並且可以指定新生執行緒的堆疊大小
此程式所測試的堆疊大小,不是以具體大小來呈現,而是以「可以遞迴呼叫某函數幾次」來呈現。

此程式之程式碼倉庫位在 https://gitlab.com/chiakikame/rust_stack_size

2017年3月19日 星期日

[Rust] 在 GNU/Linux 的機器上產生 Windows 64-bit 執行檔

若是可以在 GNU/Linux 下面產生 Windows 的執行檔該有多好...

前置作業

  • 安裝 mingw64
    如果您也是 OpenSUSE 的使用者,您可以參考此文
  • rustup target add x86_64-pc-windows-gnu

設定

在 Linux 下面預設的 linker 是 gcc,但是編譯成 x86_64-pc-windows-gnu 執行檔時 linker 也是,怎麼辦呢?

請把如下的內容放到 ~/.cargo/config 中

[target.x86_64-pc-windows-gnu]
linker = "x86_64-w64-mingw32-gcc"

接著就可以開始編譯了:

cargo build --target=x86_64-pc-windows-gnu


參考資料

https://github.com/rust-lang/rust/issues/32859

[OpenSUSE] 安裝 MinGW 工具

若想要在 OpenSUSE 上安裝 cross compile 到 Windows 的必需品 mingw64,則可以照著如下設定進行
  • 前往 https://build.opensuse.org/repositories/windows:mingw:win64
  • 找到您的 OpenSUSE 版本,複製 Go to download repository 字樣上頭的連結
  • 打開 YaST2 的 Software Management 模組
  • 在目錄上找到 Configuration -> Repositories
  • 在彈出的視窗上選擇 Add
  • 在新出現的視窗上選擇 Specify URL,按下 Next,接著貼上剛才複製的 URL,選擇 Ok
  • 等 YaST 完工後便可以尋找並且安裝 mingw64 的軟體包了

[Rust] cargo.lock 究竟該不該放入 git 倉庫?

撰寫 rust 程式時,使用 cargo init 或是 cargo new 來初始化一個新的專案。新初始化的專案中已經設定好本地 git 程式倉庫,並且附帶了 .gitignore 檔案,省去了不少設定上的麻煩。

然而,執行檔專案(cargo init --bin)以及程式庫專案的 .gitignore 內容卻不一樣:程式庫專案的 .gitignore 指出,Cargo.lock 不會被放入 git 程式倉庫中;執行檔專案則相反。這是為何呢?

依據 Cargo guide 所述,cargo.lock 是描述一個專案建置時所使用的所有完整相依條件。(跟 yarn.lock 很像。)這也就是說,cargo.lock 裡面紀錄了你的相依元件的版本(cargo.toml 只有版本要求,例如某個版本以上,或是範圍內),以及你相依元件的相依元件的版本。

總之您可以利用 cargo.lock 裡面的資訊來說明您開發時所使用的所有相依元件的版本恰為多少多少。若使用和 cargo.lock 內相同版本的元件就可以成功進行編譯。

上面所描述的「版本鎖定」可以對執行檔的所有相依元件進行版本鎖定,確保在別台機器上面可以重現建置,甚至執行結果。因此我們在撰寫執行檔專案時,必須把 cargo.lock 放入 git 程式倉庫中。

但如果是程式庫呢?若是使用 cargo.lock 來限制程式庫的相依元件版本,則本身作為其他程式(下稱主專案)相依元件的程式庫本身的相依元件可能會和主專案的其他相依元件,或是其他相依元件的相依元件有版本衝突。所以在撰寫程式庫專案時,不能把 cargo.lock 放入 git 程式倉庫中。

參考資料

http://doc.crates.io/guide.html#cargo.toml-vs-cargo.lock
http://doc.crates.io/faq.html#why-do-binaries-have-cargolock-in-version-control-but-not-libraries

Rust


超簡單介紹

 Rust 是 Mozilla Research 設計出來的程式語言。(千秋覺得)它最主要的特性是
  • 以安全為主要訴求
    藉著型別系統,實現資料所有權以及借用(Ownership & borrowing)的概念,在編譯的階段便可以確認資源的使用情況,讓開發者不需要介入資源的管理。
  • 強大的靜態型別系統
    利用 trait 達成多型,可以建造 algebraic data type
    Rust 利用此型別系統達成了資源管理安全,以及並行處理安全
  • 表達力強
    有 functional programming 等高階語言中可見的表達模式
  • 執行效率好
    利用 LLVM 直接編譯到機器碼
  • 可用於嵌入式系統開發
    您甚至可以利用 #[deny(box-pointers)] 來檢查您的程式是否使用了 heap;C語言的話,不要使用 malloc / free 就保證不會用到 heap,但是沒人替您檢查這個...
千秋覺得 Rust 有許多和 Haskell 相似的地方(但是記得它們兩者事實上有非常大的差異)
  • 強大的靜態型別系統(algebraic data type 以及 trait / typeclass)
    帶來了 Option (Rust)以及 Maybe (Haskell),不需要使用 null 了。
  • Pattern matching
  • 資料預設為不可變(immutable)
    在 Rust 您必須明確指出某個資料為可變,方可改變其內容;而在 haskell 裡面,如果沒使用奇怪的招數(像是利用 FFI 來修改資料),那資料都是不可變。
  • Operator overloading
    在 Rust 裡,藉著實作 trait 來賦予資料使用運算子的能力;在 haskell ,運算子被視為函數。此外,使用 haskell 時,您可以定義新的運算子(<_._>, >=> 等稀奇古怪的),也可以把一般函數當成運算子(add a b 等同 a `add` b)
  • 簡易的 FFI (foreign function interface)界面
您可前往其官方網站 https://www.rust-lang.org/ 一探究竟

開發工具

若透過官方的安裝方式來安裝,則已經取得建置系統 cargo 以及開發工具版本管理系統 rustup,加上編譯器 rustc。此時只要挑選順手的編輯器即可
  1. 建置及包裹管理系統
    官方有 cargo (使用官方的安裝方式會一併取得)
  2. 開發工具版本管理
    官方有 rustup (使用官方的安裝方式會一併取得)
  3. 文字編輯器
    1. IntelliJ IDEA + rust plugin
    2. Atom
      language-rust + racer + linter-rust
    3. Visual Studio Code
    4. Emacs
    5. Vim
  4. 除錯器
  5. 測試工具
    cargo test 即應可滿足大多數需求。值得注意的是,cargo test 會一併測試註解說明(//! 以及 ///)內的範例程式碼有沒有錯誤

學習資源

Rust 的學習資源(相對於甚至已有互動式做中學的 JavaScript 以及 Python 來說)似乎不多。您可以參考 https://github.com/ctjhoa/rust-learning 來了解現有的學習資源。

想學習 Rust 的人可以先用 The Rust Programming Language 來:
  • 能夠弄一個 hello world 程式
  • 弄懂大略的語法
    函數宣告、資料結構、方法宣告、trait 的概念、型別系統的概念
    您可以利用位在 https://github.com/carols10cents/rustlings 的小練習來熟悉語法
  • 稍加了解 ownership, borrowing 以及 lifetime 的概念
接著,利用 exercism 來做練習,讓自己更加熟悉 Rust 的語法以及設計哲學。把 exercism 內的練習做個九成之後,就可以考慮看看要不要弄個中小型專案啦!

程式庫

您亦可參考 https://github.com/kud1ing/awesome-rust 來取得更多最新的程式庫資訊
  • 基礎輔助
    • 編譯系統
      • libc
        提供比較適用於 FFI 的型別,以及 C runtime 中的某些服務
      • gcc
    • 數學與計算
      • rand
        產生隨機數
    • 安全
      • ring
        在 Windows 以及 macOS 使用作業系統服務;其他作業系統使用 OpenSSL
    • 資料序列化(serialization)
      • serde
        可以處理 json, xml 等諸多格式
    • 資料格式剖析
    • 日期與時間
      • chrono
    • 剖析器製作
      • nom
    • 其他
      • byteorder
        位元順序轉換、自位元陣列 (&[u8]) 讀取資料
  • 框架
    • 本機遊戲
    • 伺服器以及服務設計
      • hyper
        • reroute
          利用 regular expression 提供 routing 的功能
      • pencil
      • iron
      • nickel
      • rocket
        目前(2017/3/23)需要使用 nightly 的編譯器方可使用 
      • Gotham
  • 網路通訊
    • HTTP
      • hyper
      • reqwest
    • FTP
      • ftp
  • (探索中)

自行撰寫之文章

其他高手的文章