대규모 Rust 프로젝트 효과적으로 구성하는 방법
Wenhao Wang
Dev Intern · Leapcell

Rust 프로젝트 구조
많은 학습자들이 Rust를 공부하면서 자신의 프로젝트 파일 구조가 올바르고 표준인지 궁금해합니다. 이 글에서는 기본적인 main.rs
와 lib.rs
부터 시작하여 대규모 Rust 프로젝트가 코드를 어떻게 구성하는지 살펴보겠습니다.
Crate
- crate는 Rust의 기본 컴파일 단위입니다. 각 crate는 독립적인 컴파일 대상이며 라이브러리 (lib crate) 또는 실행 파일 (binary crate)이 될 수 있습니다.
- crate는 루트 파일이 있습니다. 라이브러리 crate의 경우
src/lib.rs
이고, 바이너리 crate의 경우src/main.rs
입니다.
Package
그러나 기본적인 Rust 프로젝트는 이 두 파일만으로 구성될 수 없습니다.
패키지는 하나 이상의 crate 모음입니다. 패키지에는 패키지의 메타데이터 및 종속성을 정의하는 Cargo.toml
및 Cargo.lock
파일이 포함되어 있습니다.
실제 프로젝트에서 crate는 코드와 모듈만 포함하고, Cargo.toml
및 Cargo.lock
파일은 전체 패키지를 관리하고 빌드하는 역할을 하는 패키지의 일부입니다.
예를 들어 cargo new sdk
를 사용하여 라이브러리를 만들면 결과 구조는 다음과 같습니다.
예시 파일 구조
// Library crate
sdk/
├── Cargo.toml
├── Cargo.lock
└── src
└── lib.rs
or
// Binary crate
sdk/
├── Cargo.toml
├── Cargo.lock
└── src
└── main.rs
TOML 파일
TOML
파일은 종속성 및 버전 정보를 관리하는 데 사용됩니다. 예를 들어:
[package] name = "sdk" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies]
일반적으로 사용되는 오류 처리 단순화 패키지인 thiserror
를 추가합니다. cargo add thiserror
명령을 사용할 수 있습니다.
[package] name = "sdk" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] thiserror = "1.0.61"
테스트 코드 및 성능 테스트
이 시점에서 우리는 이미 완전한 프로젝트를 작성하고 있습니다. 그러나 모든 프로젝트의 필수적인 부분은 단위 테스트와 성능 테스트를 포함한 테스트입니다. 그렇다면 이러한 테스트 파일은 어디에 배치해야 할까요? sdk
프로젝트를 예시로 계속 사용해 보겠습니다.
커뮤니티 및 공식 표준에 따르면 테스트 및 벤치마크 파일은 아래와 같이 src
와 동일한 수준의 tests
및 benches
디렉터리에 배치해야 합니다.
sdk/
├── Cargo.toml
├── src/
│ └── lib.rs
├── tests/
│ ├── some-integration-tests.rs
│ └── multi-file-test/
│ ├── main.rs
│ └── test_module.rs
└── benches/
├── large-input.rs
└── multi-file-bench/
├── main.rs
└── bench_module.rs
프로젝트를 처음 작성할 때 단위 테스트는 관련 코드 파일 바로 아래에 배치할 수 있으므로 multi-file-test
디렉터리 및 파일을 만들 필요가 없습니다. 그러나 개발이 진행되고 테스트 코드가 상당한 공간을 차지하기 시작하면 주요 코드를 정리하기 위해 tests
폴더로 옮기는 것이 좋습니다.
tests/
에는 기능 구현을 검증하기위한 기능 테스트 코드가 포함되어 있습니다.benches/
에는 성능 측정을 위한 성능 테스트 코드가 포함되어 있습니다 (예 : 서비스 API 성능 테스트).
Workspace
대규모 프로젝트가 여러 Rust 프로젝트로 구성된 경우 어떻게 해야 할까요? 예를 들어 sdk
crate는 한 명의 개발자가 유지 관리하고 CLI 프로젝트와 서버 프로젝트를 기반으로 빌드해야 한다고 가정합니다. 코드를 세 개의 개별 프로젝트로 분할해야 할까요? 그러면 상황이 복잡해질 수 있습니다. 이를 관리하는 통합된 방법이 있을까요? 네, Workspaces를 사용하면 됩니다.
Rust에서 workspace는 단일 프로젝트 내에서 여러 패키지를 구성하고 관리하는 방법입니다. Workspace는 여러 관련 패키지에서 종속성 관리, 빌드 및 테스트를 간소화하는 도구와 메커니즘을 제공합니다.
Workspace 사용의 이점
- 여러 패키지 구성: Workspace를 사용하면 라이브러리 crate, CLI 도구 또는 기타 유형의 패키지를 포함할 수 있는 여러 패키지를 그룹화할 수 있습니다.
- 공유 종속성: Workspace의 모든 패키지는 단일
Cargo.lock
파일을 공유하여 일관된 종속성 버전을 보장하고 충돌을 방지합니다. - 간소화된 빌드 프로세스: 루트 workspace 디렉터리에서
cargo build
또는cargo test
를 실행하면 workspace의 모든 패키지를 재귀적으로 빌드하고 테스트합니다. - 일관성: 공유
Cargo.lock
파일과 통합된 빌드 명령은 모든 패키지가 일관성을 유지하고 원활하게 조정되도록 합니다.
Workspace 구조
sdk
, cli
및 server
를 동일한 workspace 내에 배치한다고 가정합니다. 디렉터리 구조는 다음과 같습니다.
일반적인 workspace는 루트 Cargo.toml
파일이 포함된 최상위 디렉터리와 자체 Cargo.toml
파일 및 소스 디렉터리가 있는 여러 하위 패키지로 구성됩니다.
my_workspace /
├── Cargo.lock
├── Cargo.toml
├── crates/
│ ├── sdk/
│ │ ├── Cargo.toml
│ │ ├── src/
│ │ │ └── lib.rs
│ │ └──── tests/
│ │ ├── some-integration-tests.rs
│ │ └── multi-file-test/
│ │ ├── main.rs
│ │ └── test_module.rs
│ ├── cli/
│ │ ├── Cargo.toml
│ │ ├── src/
│ │ │ └── main.rs
│ │ ├── bin/
│ │ │ ├── named-executable.rs
│ │ │ ├── another-executable.rs
│ │ │ └── multi-file-executable/
│ │ │ ├── main.rs
│ │ │ └── some_module.rs
│ │ └──── tests/
│ │ ├── some-integration-tests.rs
│ │ └── multi-file-test/
│ │ ├── main.rs
│ │ └── test_module.rs
│ └── server/
│ ├── Cargo.toml
│ ├── src/
│ │ └── main.rs
│ ├── bin/
│ │ ├── named-executable.rs
│ │ ├── another-executable.rs
│ │ └── multi-file-executable/
│ │ ├── main.rs
│ │ └── some_module.rs
│ ├── tests/
│ │ ├── some-integration-tests.rs
│ │ └── multi-file-test/
│ │ ├── main.rs
│ │ └── test_module.rs
│ └── benches/
│ ├── large-input.rs
│ └── multi-file-bench/
│ ├── main.rs
│ └── bench_module.rs
Workspace TOML 파일
Cargo의 2세대 리졸버를 사용하려면 resolver = "2"
를 지정합니다. 이 리졸버는 더 효율적입니다.
[workspace] resolver = "2"
workspace 패키지 정보를 정의합니다.
[workspace.package] name = "my-workspace" version = "0.1.0" edition = "2021"
workspace 멤버를 추가합니다.
[workspace] members = [ "crates/sdk", "crates/cli", "crates/server", ]
workspace 멤버 간에 공유되는 종속성을 지정합니다.
[workspace.dependencies] thiserror = "1.0.61"
"하지만 이미 sdk
의 Cargo.toml
에 정의되어 있습니다. 왜 workspace에 다시 정의해야 할까요?"라는 의문이 들 수 있습니다.
이는 workspace를 통해 종속성 관리를 중앙 집중화할 수 있기 때문입니다. cli
와 server
모두 thiserror
가 필요한 경우 각각의 Cargo.toml
파일에 thiserror = "1.0.61"
을 별도로 정의해야 할까요? 그렇게 할 수도 있지만 잠재적인 문제가 발생할 수 있습니다. 프로젝트마다 다른 버전을 사용하면 컴파일 속도가 느려지고 컴파일된 바이너리에 thiserror
의 중복 복사본이 포함될 수 있습니다.
컴파일 시간과 바이너리 크기를 최적화하기 위해 workspace에서 통합된 종속성 버전을 설정합니다.
# In the workspace `Cargo.toml` [workspace.dependencies] thiserror = "1.0.61"
# In the `cli` and `server` packages [dependencies] thiserror.workspace = true
패키지 간 종속성
cli
와 server
가 sdk
의 메서드를 사용하도록 하려면 workspace에서 종속성을 선언해야 합니다.
[workspace.dependencies] sdk = { path = "crates/sdk" } cli = { path = "crates/cli" } server = { path = "crates/server" }
그런 다음 패키지별 Cargo.toml
파일에서:
[dependencies] sdk.workspace = true thiserror.workspace = true
이렇게 하면 workspace의 모든 프로젝트가 중복된 종속성 버전 없이 sdk
를 참조할 수 있습니다.
Leapcell은 Rust 프로젝트 호스팅을 위한 최고의 선택입니다.
Leapcell은 웹 호스팅, 비동기 작업 및 Redis를 위한 차세대 서버리스 플랫폼입니다.
다국어 지원
- Node.js, Python, Go 또는 Rust로 개발하십시오.
무제한 프로젝트를 무료로 배포
- 사용량에 대해서만 지불하십시오. 요청이나 요금이 부과되지 않습니다.
탁월한 비용 효율성
- 유휴 요금 없이 사용한 만큼만 지불하십시오.
- 예: $25는 평균 응답 시간 60ms에서 694만 건의 요청을 지원합니다.
능률적인 개발자 경험
- 간편한 설정을 위한 직관적인 UI。
- 완전 자동화된 CI/CD 파이프라인 및 GitOps 통합。
- 실행 가능한 통찰력을 위한 실시간 메트릭 및 로깅。
간편한 확장성 및 고성능
- 고도의 동시성을 쉽게 처리할 수 있도록 자동 확장。
- 운영 오버헤드가 없어 구축에만 집중하십시오.
설명서 더보기!
X에서 우리를 팔로우하십시오: @LeapcellHQ