#21 Cargo와 crates.io

Pt J·2020년 9월 9일
1

[完] Rust Programming

목록 보기
24/41
post-thumbnail

이 시리즈는 Rust 공식문서를 통해 공부한 흔적임을 밝힙니다.

우리는 지금까지 build, run, test를 하는 데 Cargo를 사용해왔다.
하지만 Cargo는 이것보다 훨씬 다양한 기능을 제공한다.
이번 시간에는 그 다양한 기능들 중 일부를 소개하는 시간을 갖도록 하겠다.

배포 프로필 Release Profile

배포 프로필은 빌드를 제어하기 위한 옵션을 미리 정의해놓은 것으로
빌드를 실행하면 어떤 배포 프로필로 빌드되었는지가 실행 결과에 출력된다.
Rust는 두 개의 메인 프로필을 제공하는데
별 다른 옵션을 주지 않고 빌드하면 dev 프로필이 사용되며
--release 옵션을 통해 release 프로필을 사용하겠다고 명시할 수 있다.

이들에 대한 설정을 Cargo.toml에 작성하지 않으면 default값으로 설정되며
default값은 다음과 같다.

[profile.dev]
opt-level = 0

[profile.release]
opt-level = 3

배포 프롷필을 설정할 때는 profile.프로필이름 형태의 이름을 가진 세션을 사용한다.
opt-level은 최적화 수준을 결정하는 설정이며 0부터 3까지 값을 지정할 수 있고
숫자가 클수록 더 많은 최적화가 이루어진다.
빌드 시간에 최적화를 높은 수준으로 할수록 빌드는 오래 걸리지만 결과 코드는 빠르다.

opt-level 외의 다른 설정은 공식문서에서 확인할 수 있다.

crates.io

Rust로 구현한 패키지는 다른 Rustacean이 사용할 수 있도록 오픈소스로 공유할 수 있는데
그러한 패키지는 crates.io에 공유된다.
패키지를 공유할 땐 그것을 언제 어떻게 사용할 수 있는지에 대한 설명을 포함해야 한다.

문서화 주석 Documentation Comment

패키지에 대한 설명은 문서화 주석을 통해 작성할 수 있다.
설명하고자 하는 아이템 바로 위에 슬래시 세 개 ///로 작성하며
markdown 문법을 지원한다.
이렇게 작성한 문서화 주석은 cargo doc 명령어를 통해 HTML 문서를 생성하는데
내부적으로는 rustdoc 도구를 통해 target/doc 디렉토리에 HTML 문서를 생성한다.

cargo doc --open 명령어를 사용하면 현재 크레이트의 HTML 문서를 생성하고
운영체제에 기본 브라우저로 등록되어 있는 웹 브라우저를 통해 그것을 보여준다.

간단한 문서화 주석을 작성하여 그것을 확인해보자.

peter@hp-laptop:~/rust-practice$ mkdir chapter14
peter@hp-laptop:~/rust-practice$ cd chapter14
peter@hp-laptop:~/rust-practice/chapter14$ cargo new my_crate --lib
     Created library `my_crate` package
peter@hp-laptop:~/rust-practice/chapter14$ cd my_crate/
peter@hp-laptop:~/rust-practice/chapter14/my_crate$ vi src/lib.rs

src/lib.rs

/// Adds one to the number given.
/// 
/// # Examples
/// 
/// ```
/// let arg = 5;
/// let answer = my_crate::add_one(arg);
/// 
/// assert_eq!(6, answer);
/// ```
pub fn add_one(x: i32) -> i32 {
    x + 1
}
peter@hp-laptop:~/rust-practice/chapter14/my_crate$ cargo doc --open
 Documenting my_crate v0.1.0 (/home/peter/rust-practice/chapter14/my_crate)
    Finished dev [unoptimized + debuginfo] target(s) in 0.54s
     Opening /home/peter/rust-practice/chapter14/my_crate/target/doc/my_crate/index.html
peter@hp-laptop:~/rust-practice/chapter14/my_crate$ 


현재 크레이트의 문서를 보여주는 화면에서 확인하고자 하는 아이템을 선택하여 클릭하면
우리가 그것에 대해 작성한 문서를 확인할 수 있다.

섹션 Section

문서는 몇 가지 섹션으로 구성될 수 있는데 섹션은 #를 통해 구분된다.
우리는 이미 예제 코드를 작성하기 위한 # Examples 섹션을 작성해보았다.
그 외에도 패닉을 일으키는 경우를 설명하여 사용자에게 주의를 주는 # Panics,
Result를 반환하는 경우 어떤 상황에서 어떤 오류를 반환하는지 알려주는 # Errors,
함수의 호출이 안전하지 않을 경우 그 이유와 주의할 점을 알려주는 # Safety 등이 있는데
필요에 따라 선택적으로 작성하면 된다.

문서에 작성한 예제 코드는 cargo test 명령어를 통해 동작을 확인할 수 있다.
이와 같이 문서의 예제 코드를 테스트하는 것을 문서 테스트라고 한다.

peter@hp-laptop:~/rust-practice/chapter14/my_crate$ cargo test
   Compiling my_crate v0.1.0 (/home/peter/rust-practice/chapter14/my_crate)
    Finished test [unoptimized + debuginfo] target(s) in 0.21s
     Running target/debug/deps/my_crate-7c36cd5710f21cb7

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

   Doc-tests my_crate

running 1 test
test src/lib.rs - add_one (line 5) ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

peter@hp-laptop:~/rust-practice/chapter14/my_crate$ 

크레이트에 대한 문서화 주석

///를 통한 문서화 주석은 크레이트 내 어떤 아이템에 대한 문서를 나타낸다.
그런데 때로는 크레이트 자체, 혹은 어떤 모듈에 대한 문서가 필요하다.
이 경우에는 //! 문서화 주석을 사용한다.

예를 들어, 앞서 작성한 my_crate 예제에
my_crate 크레이트 자체에 대한 설명을 위해 맨 위에 문서화 주석을 추가해보자.

peter@hp-laptop:~/rust-practice/chapter14/my_crate$ vi src/lib.rs

src/lib.rs

//! # My Crate
//! `my_crate` is a collection of utilites to make performing certain
//! calculations more convenient.

/// Adds one to the number given.

이제 문서를 다시 열어보면 해당 내용이 추가되어 있는 것을 확인할 수 있다.

peter@hp-laptop:~/rust-practice/chapter14/my_crate$ cargo doc --open
 Documenting my_crate v0.1.0 (/home/peter/rust-practice/chapter14/my_crate)
    Finished dev [unoptimized + debuginfo] target(s) in 0.53s
     Opening /home/peter/rust-practice/chapter14/my_crate/target/doc/my_crate/index.html
peter@hp-laptop:~/rust-practice/chapter14/my_crate$


//! 문서화 주석은 크레이트나 모듈의 전반적인 목적을 설명하는데 사용된다.

공개 API

계층적인 모듈은 패키지를 관리할 때는 용이하지만 사용자 입장에서는
깊은 곳에 있는 아이템을 사용하고자 할 때 그 경로를 다 적어주는 것은 번거로운 일이다.
따라서 우리는 pub use 키워드를 통해 내부 구조와는 다른 경로로 공개 API를 제시할 수 있다.
이로서 사용자가 보다 쉽고 편하게 내부 아이템에 접근할 수 있도록 할 수 있다.

pub use의 이점을 알아보기 위해 그것을 사용하지 않은 예제와 사용한 예제를 비교해보자.
내부적인 기능보다는 그 구조에 집중하기 위해 함수의 본문은 작성하지 않았다.

peter@hp-laptop:~/rust-practice/chapter14/my_crate$ cd ..
peter@hp-laptop:~/rust-practice/chapter14$ cargo new art --lib
     Created library `art` package
peter@hp-laptop:~/rust-practice/chapter14$ cd art/
peter@hp-laptop:~/rust-practice/chapter14/art$ vi src/lib.rs

src/lib.rs

//! # Art
//! 
//! A library for modeling artistic concepts.

pub mod kinds {
    /// The primary colors according to the RYB color model
    pub enum PrimaryColor {
        Red,
        Yellow,
        Blue,
    }

    /// The secondary colors according to the RYB color model
    pub enum SecondaryColor {
        Orange,
        Green,
        Purple,
    }
}

pub mod utils {
    use crate::kinds::*;

    /// Combines two primary colors in equal amount to create
    /// a secondary color.
    pub fn mix(c1: PrimaryColor, c2: PrimaryColor) -> SecondaryColor {
        // snip
    }
}

이렇게 작성한 패키지의 문서는 다음과 같다.

peter@hp-laptop:~/rust-practice/chapter14/art$ cargo doc --open
 Documenting art v0.1.0 (/home/peter/rust-practice/chapter14/art)
    Finished dev [unoptimized + debuginfo] target(s) in 0.51s
     Opening /home/peter/rust-practice/chapter14/art/target/doc/art/index.html
peter@hp-laptop:~/rust-practice/chapter14/art$ 


우리가 작성한 내용은 각 모듈 내부로 들어가야 볼 수 있고
global하게 공개되어 있는 것 없이 모듈 내부 경로를 통해 각 아이템을 사용할 수 있다.

이 상태에서 main.rs를 작성하면 다음과 같이 작성할 수 있다.

peter@hp-laptop:~/rust-practice/chapter14/art$ vi src/main.rs

src/main.rs

use art::kinds::PrimaryColor;
use art::utils::mix;

fn main() {
    let red = PrimaryColor::Red;
    let yellow = PrimaryColor::Yellow;
    mix(red, yellow);
}

이와 같은 코드를 작성하기 위해서는 PrimaryColorkinds 모듈에 있고
mixutils 모듈에 있다는 것을 알아야 한다.
하지만 그것은 정말 번거로운 일이다.
따라서 사용자들이 이것을 art::PrimaryColor와 같이 바로 접근할 수 있도록 하기 위해
pub use 키워드를 사용한다.

peter@hp-laptop:~/rust-practice/chapter14/art$ vi src/lib.rs

src/lib.rs

//! # Art
//! 
//! A library for modeling artistic concepts.

pub use self::kinds::PrimaryColor;
pub use self::kinds::SecondaryColor;
pub use self::utils::mix;

// snip

이제 사용자는 이 녀석들에 쉽게 접근할 수 있다.

peter@hp-laptop:~/rust-practice/chapter14/art$ vi src/main.rs

src/main.rs

use art::PrimaryColor;
use art::mix;

fn main() {
    let red = PrimaryColor::Red;
    let yellow = PrimaryColor::Yellow;
    mix(red, yellow);
}

그리고 이것들이 실제 구현되어 있는 위치는 문서를 통해 확인할 수 있다.

peter@hp-laptop:~/rust-practice/chapter14/art$ cargo doc --open
 Documenting art v0.1.0 (/home/peter/rust-practice/chapter14/art)
    Finished dev [unoptimized + debuginfo] target(s) in 0.53s
     Opening /home/peter/rust-practice/chapter14/art/target/doc/art/index.html
peter@hp-laptop:~/rust-practice/chapter14/art$ 

이와 같이 pub use 키워드를 통해 사용자 편의성을 높여줄 수 있다.

발행하기 Publish

crates.io에 크레이트를 발행하기 위해서는 crates.io의 계정이 필요하다.
github 계정을 통해 crates.io에 로그인할 수 있다.
로그인 후 Account Settings 페이지로 이동하면 여기서 API token을 조회할 수 있다.
그리고 터미널에서 다음과 같은 명령어로 로그인할 수 있다.

$ cargo login 토큰

명령어가 실행되면 API token은 ~/.cargo/credentials 파일에 저장되며
이를 통해 사용자를 확인한다.

모든 크레이트는 고유한 이름이 필요하다.
로컬에서 작업할 때는 어떤 이름이든 상관 없지만
crates.io에 크레이트를 발행하기 위해서는 기존의 것과 중복되지 않는 이름이 필요하다.
크레이트의 이름은 Cargo.toml[package] 섹션에 있는 name에 설정한다.
그 외에도 간단한 설명 description과 라이선스 license가 필요하다.
나머지 정보는 선택 사항이지만 name, description, license는 필수적이다.

리눅스 재단의 SPDX 페이지에 존재하는 라이선스라면 그 식별자를 전달할 수 있지만
그렇지 않은 라이선스의 경우 그 내용을 별도의 파일에 작성하고 그 파일의 이름을 전달해야 한다.
듀얼 라이선스가 적용될 경우 license = "MIT OR Apache-2.0"와 같이 OR을 사용한다.
Rust가 MIT와 Apache-2.0의 듀얼 라이선스임에 따라
Rust 커뮤니티의 많은 개발자들이 자신의 프로젝트에 이 라이선스를 적용한다는 건 여담.

이제 다음 명령어를 통해 크레이트를 발행할 수 있게 되었다.

$ cargo publish

여기서 유의해야 할 점은, 크레이트 발행은 영구적이며 절대 덮어쓰거나 삭제할 수 없다는 것이다.
만약 어떤 프로젝트가 의존성을 가지고 있는 크레이트가 삭제된다면
그것은 큰 문제를 야기할 수 있기 때문에 이를 방지하기 위함이다.
크레이트의 새 버전을 배포하고자 한다면 Cargo.toml의 버전 정보를 수정하여 다시 발행하면 된다.
버전값은 Sementic Versioning 규칙을 통해 결정된다.
이전 버전을 삭제하는 것은 허용하지 않지만 이전 버전에 대한 지원 중단은 할 수 있다.
지원 중단된 크레이트는 그것이 Cargo.lock 되어 있는 프로젝트에서는 사용 가능하지만
지원 중단 이후에 생성되는 Cargo.lock에는 포함시킬 수 없다.
특정 버전의 크레이트를 지원 중단하기 위해서는 다음과 같은 명령어를 사용할 수 있다.

$ cargo yank --vers 버전

지원 중단을 취소하면 그것을 다시 사용할 수 있게 된다.

$ cargo yank --vers 버전 --undo

설치

다른 누군가 올려 놓은 크레이트를 내려 받아 로컬에 설치할 수도 있는데
다음과 같은 명령어를 실행하면 $HOME/.cargo/bin에 설치된다.

$ cargo install 크레이트이름

설치된 실행파일의 이름은 크레이트의 이름과 다를 수 있는데
크레이트를 설치할 때 Installing ~/.cargo/bin/rg와 같이 그 경로와 이름이 출력된다.

이 디렉토리에 있는 실행 파일 중 cargo로 시작하는 녀석들은
cargo-example 대신 cargo example로 실행할 수 있으며
cargo --list를 통해 Cargo 명령어를 출력해보아도 확인할 수 있다.

이 포스트의 내용은 공식문서의 14장 1절 Customizing Builds with Release Profiles & 14장 2절 Publishing a Crate to Crates.io에 해당합니다.

profile
Peter J Online Space - since July 2020

0개의 댓글