Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Hello, Cargo!

Cargo는 러스트의 빌드 시스템이자 패키지 관리자입니다. 대부분의 Rustacean은 Rust 프로젝트를 관리할 때 이 도구를 사용합니다. Cargo가 코드 빌드, 코드가 의존하는 라이브러리 다운로드, 그리고 그 라이브러리들의 빌드 같은 일을 많이 대신 처리해 주기 때문입니다. (코드에 필요한 라이브러리를 의존성(dependencies) 이라고 부릅니다.)

우리가 지금까지 작성한 것 같은 가장 단순한 Rust 프로그램은 의존성이 없습니다. “Hello, world!” 프로젝트를 Cargo로 만들었다면, Cargo의 기능 중 코드 빌드를 담당하는 부분만 사용했을 것입니다. 하지만 더 복잡한 Rust 프로그램을 작성하게 되면 의존성이 추가되기 시작하고, 프로젝트를 Cargo로 시작해 두면 그런 의존성을 훨씬 쉽게 추가할 수 있습니다.

대부분의 Rust 프로젝트가 Cargo를 사용하기 때문에, 이 책의 나머지 부분도 여러분이 Cargo를 사용한다고 가정합니다. Cargo는 “설치” 절에서 설명한 공식 설치 방법으로 Rust를 설치했다면 함께 설치됩니다. 다른 방식으로 Rust를 설치했다면, 터미널에서 다음 명령을 입력해 Cargo가 설치되어 있는지 확인하세요.

$ cargo --version

버전 번호가 보이면 Cargo가 있는 것입니다! command not found 같은 오류가 보이면, 자신이 사용한 설치 방식의 문서를 확인해 Cargo를 따로 설치하는 방법을 찾아보세요.

Cargo로 프로젝트 만들기

Cargo를 사용해 새 프로젝트를 만들고, 그것이 우리가 처음 만든 “Hello, world!” 프로젝트와 어떻게 다른지 살펴봅시다. 다시 projects 디렉터리(혹은 코드를 보관하기로 정한 위치)로 이동한 뒤, 어떤 운영체제에서든 다음을 실행하세요.

$ cargo new hello_cargo
$ cd hello_cargo

첫 번째 명령은 hello_cargo 라는 새 디렉터리와 프로젝트를 만듭니다. 프로젝트 이름을 hello_cargo 로 지었기 때문에 Cargo도 같은 이름의 디렉터리에 파일들을 생성합니다.

hello_cargo 디렉터리로 들어가 파일 목록을 살펴보세요. Cargo가 두 개의 파일과 하나의 디렉터리를 생성해 둔 것을 볼 수 있습니다. 즉 Cargo.toml 파일과, 그 안에 main.rs 파일이 들어 있는 src 디렉터리입니다.

또한 .gitignore 파일과 함께 새 Git 저장소도 초기화합니다. 이미 존재하는 Git 저장소 안에서 cargo new 를 실행하면 Git 관련 파일은 생성되지 않습니다. 이 동작을 바꾸고 싶다면 cargo new --vcs=git 를 사용할 수 있습니다.

Note: Git은 널리 쓰이는 버전 관리 시스템입니다. --vcs 플래그를 사용하면 cargo new 가 다른 버전 관리 시스템을 사용하도록 하거나, 아예 버전 관리 시스템을 사용하지 않도록 바꿀 수 있습니다. 가능한 선택지는 cargo new --help 로 확인하세요.

원하는 텍스트 에디터로 Cargo.toml 을 열어 보세요. 목록 1-2와 비슷한 모습일 것입니다.

Filename: Cargo.toml
[package]
name = "hello_cargo"
version = "0.1.0"
edition = "2024"

[dependencies]
Listing 1-2: cargo new 가 생성한 Cargo.toml 내용

이 파일은 Cargo의 설정 형식인 TOML(Tom’s Obvious, Minimal Language) 형식으로 작성되어 있습니다.

첫 줄의 [package] 는 뒤따르는 항목들이 패키지 설정임을 나타내는 섹션 헤딩입니다. 앞으로 이 파일에 더 많은 정보를 추가하면서 다른 섹션도 늘어나게 됩니다.

다음 세 줄은 Cargo가 프로그램을 컴파일하는 데 필요한 설정, 즉 이름, 버전, 사용할 Rust 에디션을 지정합니다. edition 키는 부록 E에서 다룹니다.

마지막 줄인 [dependencies] 는 프로젝트의 의존성을 나열하는 섹션의 시작입니다. Rust에서는 코드 패키지를 crate 라고 부릅니다. 이 프로젝트에서는 다른 crate가 필요 없지만, 2장의 첫 번째 프로젝트에서는 필요하므로 그때 이 의존성 섹션을 사용하게 됩니다.

이제 src/main.rs 를 열어 봅시다.

Filename: src/main.rs

fn main() {
    println!("Hello, world!");
}

Cargo는 목록 1-1에서 우리가 직접 쓴 것과 똑같은 “Hello, world!” 프로그램을 자동으로 만들어 주었습니다! 지금까지 우리가 만든 프로젝트와 Cargo가 생성한 프로젝트의 차이는, Cargo는 코드를 src 디렉터리에 넣고 최상위 디렉터리에 Cargo.toml 설정 파일을 만든다는 점입니다.

Cargo는 소스 파일이 src 디렉터리 안에 있기를 기대합니다. 프로젝트 최상위 디렉터리는 README 파일, 라이선스 정보, 설정 파일, 그리고 코드와 직접 관련 없는 다른 것들을 두는 곳입니다. Cargo를 사용하면 프로젝트를 체계적으로 정리할 수 있습니다. 모든 것에는 자리가 있고, 모든 것이 제자리에 있게 됩니다.

“Hello, world!” 프로젝트처럼 Cargo를 사용하지 않고 시작한 프로젝트라도, 나중에 Cargo를 사용하는 프로젝트로 바꿀 수 있습니다. 프로젝트 코드를 src 디렉터리 안으로 옮기고 적절한 Cargo.toml 파일을 만들면 됩니다. 그 파일을 쉽게 만드는 방법 중 하나는 cargo init 을 실행하는 것입니다. 그러면 자동으로 생성해 줍니다.

Cargo 프로젝트 빌드하고 실행하기

이제 “Hello, world!” 프로그램을 Cargo로 빌드하고 실행할 때 무엇이 다른지 살펴봅시다! hello_cargo 디렉터리에서 다음 명령으로 프로젝트를 빌드하세요.

$ cargo build
   Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo)
    Finished dev [unoptimized + debuginfo] target(s) in 2.85 secs

이 명령은 실행 파일을 현재 디렉터리가 아니라 target/debug/hello_cargo (Windows에서는 target\debug\hello_cargo.exe) 에 만듭니다. 기본 빌드는 디버그 빌드이기 때문에, Cargo는 바이너리를 debug 라는 디렉터리에 넣습니다. 실행 파일은 다음 명령으로 실행할 수 있습니다.

$ ./target/debug/hello_cargo # or .\target\debug\hello_cargo.exe on Windows
Hello, world!

모든 것이 잘 되었다면 터미널에 Hello, world! 가 출력됩니다. cargo build 를 처음 실행하면 Cargo는 최상위 디렉터리에 Cargo.lock 이라는 새 파일도 만듭니다. 이 파일은 프로젝트의 의존성 정확한 버전을 추적합니다. 이 프로젝트에는 의존성이 없기 때문에 내용이 많지 않습니다. 이 파일은 손으로 수정할 일이 없고, Cargo가 내용을 대신 관리해 줍니다.

방금은 cargo build 로 프로젝트를 빌드하고 ./target/debug/hello_cargo 로 실행했지만, cargo run 을 쓰면 코드 컴파일과 생성된 실행 파일 실행을 한 번에 할 수 있습니다.

$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target/debug/hello_cargo`
Hello, world!

cargo run 은 먼저 cargo build 를 실행하고 다시 바이너리 전체 경로를 입력해야 하는 방식보다 훨씬 편리합니다. 그래서 대부분의 개발자는 cargo run 을 사용합니다.

이번에는 Cargo가 hello_cargo 를 컴파일하고 있다는 출력이 보이지 않았다는 점에 주목하세요. Cargo가 파일이 바뀌지 않았다고 판단했기 때문에 다시 빌드하지 않고 그냥 바이너리만 실행한 것입니다. 소스 코드를 수정했다면 실행 전에 프로젝트를 다시 빌드했을 것이고, 다음과 같은 출력이 보였을 것입니다.

$ cargo run
   Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo)
    Finished dev [unoptimized + debuginfo] target(s) in 0.33 secs
     Running `target/debug/hello_cargo`
Hello, world!

Cargo는 cargo check 라는 명령도 제공합니다. 이 명령은 코드가 컴파일되는지만 빠르게 확인하고, 실행 파일은 만들지 않습니다.

$ cargo check
   Checking hello_cargo v0.1.0 (file:///projects/hello_cargo)
    Finished dev [unoptimized + debuginfo] target(s) in 0.32 secs

왜 실행 파일을 만들지 않으려 할까요? cargo check 는 실행 파일 생성 단계를 건너뛰기 때문에 cargo build 보다 훨씬 빠른 경우가 많습니다. 코드를 작성하면서 계속 중간 점검을 하고 있다면, cargo check 는 프로젝트가 아직 잘 컴파일되는지를 더 빨리 알려 줍니다. 그래서 많은 Rustacean이 프로그램을 작성하는 동안 주기적으로 cargo check 를 실행해 컴파일 상태를 확인하고, 실행 파일이 필요해졌을 때 cargo build 를 실행합니다.

지금까지 Cargo에 대해 배운 내용을 정리해 봅시다.

  • cargo new 로 프로젝트를 만들 수 있습니다.
  • cargo build 로 프로젝트를 빌드할 수 있습니다.
  • cargo run 으로 빌드와 실행을 한 번에 할 수 있습니다.
  • cargo check 로 바이너리를 만들지 않고 오류만 확인할 수 있습니다.
  • Cargo는 빌드 결과를 코드와 같은 디렉터리가 아니라 target/debug 디렉터리에 저장합니다.

Cargo를 사용할 때의 또 다른 장점은, 어떤 운영체제에서 작업하든 명령이 같다는 것입니다. 따라서 이 시점부터는 Linux·macOS와 Windows를 따로 나눠 설명하지 않겠습니다.

릴리스용 빌드

프로젝트가 마침내 배포할 준비가 되었다면, cargo build --release 로 최적화를 켜고 컴파일할 수 있습니다. 이 명령은 실행 파일을 target/debug 대신 target/release 에 만듭니다. 최적화를 켜면 Rust 코드 실행 속도는 빨라지지만, 컴파일 시간은 더 길어집니다. 그래서 프로필이 두 가지 존재합니다. 자주 빠르게 다시 빌드하고 싶은 개발용 프로필 하나, 사용자에게 전달할 최종 프로그램을 가능한 빠르게 실행되도록 빌드하는 용도의 프로필 하나입니다. 코드 실행 시간을 벤치마크할 때는 반드시 cargo build --release 로 빌드하고 target/release 안의 실행 파일로 측정하세요.

Cargo의 관례 활용하기

단순한 프로젝트에서는 Cargo가 rustc 를 직접 쓰는 것에 비해 큰 차이를 주지 않을 수 있습니다. 하지만 프로그램이 복잡해질수록 Cargo의 진가가 드러납니다. 프로그램이 여러 파일로 커지거나 의존성이 필요해지면, 빌드 조율을 Cargo에 맡기는 편이 훨씬 쉽습니다.

hello_cargo 프로젝트는 단순하지만, 앞으로 러스트를 사용하는 동안 계속 쓰게 될 실제 도구의 상당 부분을 이미 사용하고 있습니다. 실제로 이미 존재하는 프로젝트에서 작업할 때도, 다음처럼 Git으로 코드를 받아오고 해당 프로젝트 디렉터리로 이동한 뒤 빌드하면 됩니다.

$ git clone example.org/someproject
$ cd someproject
$ cargo build

Cargo에 대해 더 알고 싶다면 공식 문서를 확인하세요.

정리

여러분은 이미 러스트 여정을 훌륭하게 시작했습니다! 이 장에서는 다음 내용을 배웠습니다.

  • rustup 으로 Rust의 최신 안정 버전을 설치하는 방법
  • 더 새로운 Rust 버전으로 업데이트하는 방법
  • 로컬에 설치된 문서를 여는 방법
  • rustc 를 직접 사용해 “Hello, world!” 프로그램을 작성하고 실행하는 방법
  • Cargo의 관례를 사용해 새 프로젝트를 만들고 실행하는 방법

이제 좀 더 실질적인 프로그램을 만들어 보면서 Rust 코드를 읽고 쓰는 감각을 익히기 좋은 시점입니다. 그래서 2장에서는 숫자 맞히기 게임 프로그램을 만들어 봅니다. 만약 일반적인 프로그래밍 개념이 Rust에서 어떻게 동작하는지부터 배우고 싶다면 3장을 먼저 읽은 뒤 다시 2장으로 돌아오면 됩니다.