Rust 프로젝트가 커짐에 따라 모듈화와 구조화, 그리고 최종적으로 바이너리 또는 라이브러리로 배포하는 과정이 중요해집니다. 이번에는 Rust 프로젝트를 어떻게 구성하고, 빌드하며, 배포하는지에 대해 알아보겠습니다.
1. Rust 프로젝트 구조
Rust는 기본적으로 cargo를 사용하여 프로젝트를 관리합니다. 일반적인 프로젝트 구조는 다음과 같습니다:
my_project/
├── Cargo.toml
├── Cargo.lock
├── src/
│ ├── main.rs
│ └── lib.rs
├── tests/
│ └── integration_test.rs
├── benches/
│ └── benchmark.rs
└── examples/
└── hello.rs
✅ 주요 구성 요소 설명
- Cargo.toml: 프로젝트의 메타데이터, 의존성 등을 관리하는 설정 파일입니다.
- src/main.rs: 실행 가능한 바이너리 프로그램의 진입점입니다.
- src/lib.rs: 라이브러리 crate의 코드가 들어가는 곳입니다. 모듈화된 코드 작성 시 여기에 구현합니다.
- tests/: 통합 테스트를 위한 디렉터리입니다.
- benches/: 성능 벤치마크용 테스트가 위치합니다.
- examples/: 사용 예제를 담는 폴더로, cargo run –example 예제이름으로 실행할 수 있습니다.
2. 모듈과 라이브러리 구조
기본적인 모듈 구성
my_project/
├── Cargo.toml
└── src/
├── main.rs // 실행 가능한 바이너리 프로그램
├── lib.rs // 라이브러리로 정의된 코드
└── utils.rs // lib.rs에서 공개하는 하위 모듈
프로젝트명은 my_project이고, 그 아래 Cargo.toml과 src 폴더가 있고,
src 폴더에 main.rs, lib.rs, utils.rs가 있습니다.
- main.rs는 fn main()을 통해 프로그램을 실행하는 진입점(entry point)
- lib.rs는 모듈과 함수들을 정의하고 외부에 노출하는 라이브러리
- utils.rs는 lib의 서브 모듈로 기능 분리용
가. utils.rs
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
- add 함수는 두 정수를 더해서 반환하는 간단한 유틸 함수입니다.
- pub으로 선언했기 때문에 이 함수는 외부 모듈 (lib.rs나 main.rs)에서도 사용할 수 있습니다.
나. lib.rs
pub mod utils;
pub fn greet(name: &str) {
println!("Hello, {}!", name);
}
- pub mod utils;
→ src/utils.rs 파일을 모듈로 포함함.
utils 모듈이 공개(pub)되었기 때문에 외부에서 사용 가능. - pub fn greet(name: &str)
→ greet 함수도 공개되어 있어서 외부 crate나 main.rs에서 사용할 수 있음.
다. main.rs
use my_project::greet;
use my_project::utils::add;
fn main() {
greet("Rust");
println!("2 + 3 = {}", add(2, 3));
}
- use my_project::greet;
→ lib.rs에서 정의된 greet 함수를 가져와 사용함. - use my_project::utils::add;
→ lib.rs가 공개한 utils 모듈을 통해 add 함수를 가져옴. - main() 함수에서는
greet(“Rust”)를 호출해서 Hello, Rust!를 출력하고,
add(2, 3)의 결과 5를 출력합니다.
라. Cargo 관점에서
Cargo.toml에는 특별한 설정 없이도 다음이 자동 처리됨:
[package]
name = "my_project"
version = "0.1.0"
edition = "2021"
- lib.rs는 my_project라는 이름의 라이브러리 크레이트로 인식됨
- main.rs는 실행 파일용 바이너리 크레이트로 인식됨
따라서 main.rs에서 my_project::를 통해 lib.rs의 함수와 모듈을 가져올 수 있는 것임.
마. 빌드 및 실행
cargo run
실행하면 아래와 같이 출력됩니다.
Hello, Rust!
2 + 3 = 5
사. 요약
파일 | 역할 | 주요 내용 |
---|---|---|
lib.rs | 라이브러리 크레이트 | greet 함수 정의, utils 모듈 공개 |
utils.rs | 하위 모듈 | add 함수 정의 |
main.rs | 실행 크레이트 | greet와 add 호출하여 메시지 출력 |
이 구조는 라이브러리를 재사용하거나 다른 프로젝트에 공유하고 싶을 때 매우 적합하며, 기능 분리와 모듈화에도 강력한 패턴입니다.
3. 패키지와 워크스페이스
여러 crate를 하나의 프로젝트로 묶고싶다면 workspace 기능을 사용할 수 있습니다.
[workspace]
members = [
"core_lib",
"cli_tool",
]
이 구조에서는 core_lib는 공통 로직을 담고, cli_tool은 실행 바이너리를 담당할 수 있습니다. 모노레포(Monorepo) 방식으로 관리하기에 유리합니다.
Cargo.toml 파일에 [workspace] 섹션을 추가하여 workspace를 정의하는데, members 필드에 각 하위 프로젝트의 경로를 지정합니다.
모노레포는 멀티레포와 대비되는 개념으로, 여러 하위 프로젝트들을 하나의 저장소에서 관리하는 것을 말하며, 이렇게 하면 코드 공유, 재사용, 일관된 빌드 및 테스트 설정 등을 효율적으로 관리할 수 있습니다. 일반적으로 Cargo를 사용하여 모노레포를 구성합니다.
* 레포는 Repository의 약어
4. 빌드 및 최적화
기본 빌드
cargo build
- 기본 빌드 모드에서는 target/debug/에 실행 파일이 생성됩니다.
릴리즈 빌드 (최적화 포함)
cargo build --release
- 릴리즈 모드에서는 최적화가 적용되며, target/release/에 실행 파일이 생성됩니다.
- 실제 배포 시에는 릴리즈 모드를 사용하는 것이 일반적입니다.
5. 바이너리 배포
Rust는 정적 바이너리 생성을 기본으로 하므로, 종속성 없는 실행 파일을 만들 수 있습니다.
가. 윈도우/리눅스/맥용 빌드
# 리눅스용으로 크로스 컴파일
cargo build --release --target x86_64-unknown-linux-gnu
# 윈도우용
cargo build --release --target x86_64-pc-windows-msvc
cargo build –release –target x86_64-unknown-linux-gnu실행 시
note: the x86_64-unknown-linux-gnu target may not be installed
라고 표시되면
rustup target add x86_64-unknown-linux-gnu를 통해 target을 먼저 설치해야 합니다.
나. 크로스 컴파일
- cross 크레이트를 사용하면 플랫폼별 크로스 컴파일을 간편하게 할 수 있습니다.
cargo install cross
cross build –target x86_64-unknown-linux-gnu –release - 위 명령어를 실행하면 docker 또는 podman이 설치되어 있는지 묻습니다. 따라서, docker 등을 설치하고 그 안에서 위 명령을 실행해야 합니다.

다. 실행 파일 위치
- 기본 빌드: target/debug/프로젝트명
- 릴리즈 빌드: target/release/프로젝트명
이 파일을 원하는 디렉토리나 서버로 옮기면 됩니다.
6. Crates.io에 라이브러리 배포
만약 자신이 만든 라이브러리를 다른 사람들과 공유하고 싶다면, crates.io에 등록할 수 있습니다.
가. 준비 단계
- https://crates.io에 계정을 만들고 API Token을 생성합니다.
- ~/.cargo/credentials에 토큰을 저장합니다.
- Cargo.toml에 필수 정보를 입력합니다:
[package]
name = "my_crate"
version = "0.1.0"
authors = ["홍길동 <email@example.com>"]
edition = "2021"
license = "MIT OR Apache-2.0"
description = "간단한 수학 라이브러리"
repository = "https://github.com/username/my_crate"
나. 배포 명령
cargo publish
- 첫 배포 전에는 cargo package로 정상 패키징이 되는지 테스트해보는 것이 좋습니다.
7. CI/CD 통합
CI/CD는 지속적인 통합(Continuous Integration)과 지속적인 제공/배포(Continuous Delivery/Deployment)를 의미하며, 소프트웨어 개발 및 배포 과정을 자동화하여 효율성과 속도를 높이는 방법론입니다. CI/CD는 개발자가 코드 변경 사항을 주기적으로 메인 저장소에 통합하고, 테스트를 거쳐 자동으로 배포될 수 있도록 합니다.
프로젝트가 커지면 GitHub Actions나 GitLab CI와 같은 CI 도구를 통해 자동으로 테스트와 빌드, 배포까지 설정할 수 있습니다.
예: .github/workflows/rust.yml
name: Rust
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
- run: cargo build --release
- run: cargo test
8. 마무리
Rust 프로젝트는 명확한 구조와 cargo의 강력한 관리 도구 덕분에 규모가 커져도 효율적으로 관리할 수 있습니다. 프로젝트 구조를 잘 나누고, 최적화된 빌드를 통해 빠르고 안정적인 배포 환경을 만드는 것이 중요합니다.