릴리즈 프로필 설정
Cargo의 dev·release 프로필과 opt-level 같은 설정을 조정해 컴파일 속도·실행 성능·디버깅 정보의 균형을 선택합니다.
지금까지는 코드를 빌드하고 실행하고 테스트하는 Cargo의 가장 기본적인 기능만 썼지만, Cargo는 훨씬 많은 일을 할 수 있습니다. 이번 장에서는 다음과 같은 일을 하는 Cargo의 고급 기능 몇 가지를 살펴봅니다.
| 글 | 다루는 기능 |
|---|---|
| 이 글 | 릴리스 프로필로 빌드 설정 바꾸기 |
| Crates.io 배포 | crates.io에 라이브러리 배포하기 |
| Cargo 작업공간 | 큰 프로젝트를 작업공간(workspace)으로 정리하기 |
| cargo install로 바이너리 설치 | crates.io의 바이너리 설치하기 |
| Cargo 커스텀 명령어 | 직접 만든 명령으로 Cargo 확장하기 |
Cargo는 이번 장에서 다루는 것보다 더 많은 일을 할 수 있으므로, 모든 기능을 자세히 보려면 Cargo 문서를 참고하세요.
릴리즈 프로필로 빌드 커스터마이징하기
러스트에서 릴리스 프로필(release profile)은 미리 정의되어 있고 설정을 바꿀 수 있는 프로필로, 서로 다른 설정을 담고 있어 프로그래머가 코드를 컴파일하는 여러 옵션을 더 세밀하게 다룰 수 있게 해 줍니다. 각 프로필은 다른 프로필과 독립적으로 설정됩니다.
Cargo에는 주요 프로필이 두 개 있습니다. cargo build를 실행할 때 쓰는 dev 프로필과, cargo build --release를 실행할 때 쓰는 release 프로필입니다. dev 프로필은 개발에 알맞은 기본값으로 정의되어 있고, release 프로필은 릴리스 빌드에 알맞은 기본값을 가집니다. 이 프로필 이름은 빌드 결과에서 본 적이 있을 것입니다.
cargo build
cargo build --release Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
Finished `release` profile [optimized] target(s) in 0.32s결과에 나온 dev와 release가 컴파일러가 쓴 서로 다른 프로필입니다. 걸린 시간은 환경마다 다릅니다. 아래 표는 Cargo.toml에서 덮어쓰지 않았을 때 각 프로필을 어떻게 고르고, 주요 기본값이 무엇인지 정리한 것입니다.
RUST · PROFILE SELECTION
프로필은 빌드 설정을 고르고, 성능은 측정으로 확인한다
아래는 Cargo.toml·설정에서 덮어쓰기 전의 주요 기본값입니다. 본문의 dev 최적화 변경과 release-lto 상속도 같은 선택 규칙을 따릅니다.
| 프로필 | 선택 방식 | 주요 기본값 | 기본 목적 |
|---|---|---|---|
dev |
cargo build, cargo run, cargo check, cargo rustc |
opt-level = 0, debug = true |
일반 개발과 디버깅 |
release |
--release 또는 --profile=release |
opt-level = 3, debug = false |
릴리스·프로덕션용 최적화 산출물 |
| 사용자 정의 | --profile=NAME |
inherits 필수, 필요한 키만 덮어쓰기 |
LTO·디버그·성능 비교처럼 이름 있는 별도 빌드 흐름 |
dev- 선택
cargo build,cargo run,cargo check,cargo rustc - 기본값
opt-level = 0,debug = true - 목적 일반 개발과 디버깅
release- 선택
--release또는--profile=release - 기본값
opt-level = 3,debug = false - 목적 릴리스·프로덕션용 최적화 산출물
- 사용자 정의 프로필
- 선택
--profile=NAME - 설정
inherits를 명시하고 필요한 키만 덮어쓴다. - 목적 LTO나 디버그 설정을 분리해 측정한다.
본문의 dev 변경
[profile.dev]
opt-level = 1cargo build에 적용됩니다. 기본 0을 이 키 하나만 1로 바꿉니다.
본문의 사용자 정의 프로필
[profile.release-lto]
inherits = "release"
lto = "thin"cargo build --profile release-lto로 선택합니다. release 기본값을 상속하고 LTO만 변경합니다.
test는 dev, bench는 release를 상속합니다. workspace의 profile 설정은 루트 manifest에서 정합니다. 높은 opt-level이 항상 더 빠르거나 더 작지는 않으므로 실제 빌드·실행 결과를 비교합니다.
dev는 cargo build, cargo run, cargo check, cargo rustc가 기본으로 쓰며, opt-level = 0과 debug = true로 일반적인 개발과 디버깅에 맞춰져 있습니다. release는 --release나 --profile=release로 고르며, opt-level = 3과 debug = false로 배포할 최적화된 결과물을 만듭니다. --profile=이름으로 고르는 사용자 정의 프로필은 inherits로 바탕이 될 프로필을 꼭 지정하고, 필요한 설정만 덮어씁니다. 이 밖에 test 프로필은 dev를, bench 프로필은 release를 상속합니다.
Cargo에는 프로젝트의 Cargo.toml에 [profile.*] 섹션을 명시적으로 더하지 않았을 때 적용되는 프로필별 기본 설정이 있습니다. 설정을 바꾸고 싶은 프로필에 [profile.*] 섹션을 더하면, 기본 설정 가운데 일부를 덮어쓸 수 있습니다. 예를 들어 dev와 release 프로필의 opt-level 기본값은 다음과 같습니다.
[profile.dev]
opt-level = 0
[profile.release]
opt-level = 3opt-level 설정은 러스트가 코드에 적용할 최적화의 정도를 0부터 3까지로 정합니다. 최적화를 많이 할수록 컴파일 시간이 늘어나므로, 개발 중에 코드를 자주 컴파일한다면 결과 코드가 느리게 실행되더라도 더 적게 최적화해 빨리 컴파일하고 싶을 것입니다. 그래서 dev의 기본 opt-level은 0입니다. 코드를 배포할 준비가 되었다면 컴파일에 시간을 더 쓰는 것이 낫습니다. 릴리스 모드로는 한 번만 컴파일하고 그 프로그램은 여러 번 실행할 것이므로, 릴리스 모드는 컴파일 시간을 더 쓰는 대신 더 빠르게 실행되는 코드를 만듭니다. 그래서 release 프로필의 기본 opt-level은 3입니다.
Cargo.toml에 다른 값을 적어 기본 설정을 덮어쓸 수 있습니다. 예를 들어 개발 프로필에서 최적화 수준 1을 쓰고 싶다면, 프로젝트의 Cargo.toml에 다음 두 줄을 더합니다.
[profile.dev]
opt-level = 1이 코드는 기본 설정 0을 덮어씁니다. 이제 cargo build를 실행하면 Cargo는 dev 프로필의 기본값에 opt-level만 바꾼 설정을 씁니다. opt-level을 1로 정했으므로 Cargo는 기본보다는 더 최적화하지만, 릴리스 빌드만큼 많이 하지는 않습니다.
release의 설정을 바탕으로 일부만 바꾼 빌드를 따로 두고 싶다면 사용자 정의 프로필을 만듭니다. 다음은 release를 상속하고 링크 타임 최적화(link-time optimization, LTO)만 바꾼 release-lto 프로필입니다.
[profile.release-lto]
inherits = "release"
lto = "thin"cargo build --profile release-lto이렇게 하면 release의 기본값은 그대로 쓰고 lto만 바꾼 결과물이 만들어지므로, 일반 release 빌드와 나란히 두고 비교할 수 있습니다. 결과물은 프로필 이름을 딴 target/release-lto 폴더에 들어갑니다.
프로필을 설정할 때 알아 둘 점이 두 가지 있습니다. 작업공간(workspace)에서는 루트 Cargo.toml의 프로필 설정만 쓰이고, 의존하는 패키지에 적힌 프로필 설정은 무시됩니다. 또 opt-level이 높다고 언제나 더 빠르거나 더 작은 결과물이 나오지는 않으므로, 설정을 바꿨다면 실제로 빌드하고 실행해 결과를 비교합니다.
각 프로필의 설정 옵션과 기본값 전체는 Cargo의 프로필 문서에 있습니다.
더 깊이: opt-level 말고도 두 프로필이 다르게 정한 것
두 프로필의 차이는 최적화 수준과 디버그 정보에서 끝나지 않습니다. Cargo의 프로필 문서에 적힌 기본값 가운데 두 프로필이 다르게 정한 것을 모으면 다음과 같습니다.
| 설정 | dev | release |
|---|---|---|
debug-assertions | true | false |
overflow-checks | true | false |
incremental | true | false |
codegen-units | 256 | 16 |
debug-assertions는 cfg(debug_assertions)를 켜고 끄므로, debug_assert!가 릴리스 빌드에서 실행되지 않는 것이 이 설정 때문입니다. overflow-checks는 데이터 타입에서 본, 정수 오버플로가 디버그 빌드에서는 패닉이 되고 릴리스 빌드에서는 감싸기가 되는 차이를 만듭니다. 그래서 릴리스 빌드에서도 오버플로를 잡고 싶다면 [profile.release]에 overflow-checks = true만 더하면 됩니다.
incremental은 다시 컴파일할 때 쓸 정보를 target 폴더에 저장하는 증분 컴파일을 켜며, 작업공간의 멤버와 경로 의존성에만 쓰입니다. codegen-units는 크레이트를 몇 개의 코드 생성 단위로 나눌지 정하는데, 문서는 단위가 많을수록 병렬로 처리해 컴파일이 빨라질 수 있지만 만들어진 코드가 느려질 수 있다고 설명하며, 기본값을 증분 빌드에서는 256, 그렇지 않은 빌드에서는 16으로 둡니다. 또 panic 설정은 두 프로필 모두 'unwind'이며, 테스트와 벤치마크, 빌드 스크립트, 절차적 매크로는 이 설정을 바꿔도 따르지 않습니다. 테스트와 벤치마크가 따르지 않는 것은 러스트의 테스트 하네스가 지금은 되감기 동작을 필요로 하기 때문입니다.
정리
- Cargo는
cargo build에dev프로필을,cargo build --release에release프로필을 쓰며, 빌드 결과의Finished줄에 프로필 이름이 나옵니다. dev의 기본값은opt-level = 0,debug = true이고,release의 기본값은opt-level = 3,debug = false입니다.Cargo.toml에[profile.dev]처럼 섹션을 더해 적은 설정만 덮어쓰고, 나머지는 기본값을 그대로 씁니다.- 사용자 정의 프로필은
inherits로 바탕 프로필을 지정하고--profile 이름으로 고릅니다. - 작업공간에서는 루트
Cargo.toml의 프로필 설정만 적용되며, 설정을 바꾼 효과는 실제로 측정해 확인합니다.
연습 문제
1. 어느 설정이 쓰일까
Cargo.toml에 [profile.dev]와 opt-level = 1만 적었습니다. (가) cargo run, (나) cargo test, (다) cargo build --release는 각각 어떤 opt-level과 debug 설정으로 빌드되나요?
해설 보기
(가)는 dev 프로필을 쓰므로 바꾼 opt-level = 1과 기본값 debug = true로 빌드됩니다. (나)는 test 프로필이 dev를 상속하므로 같은 opt-level = 1, debug = true가 적용됩니다. (다)는 release 프로필을 바꾸지 않았으므로 기본값 opt-level = 3, debug = false로 빌드됩니다.
2. 사용자 정의 프로필 만들기
릴리스 빌드와 같은 최적화를 쓰되 디버깅 정보는 넣은 profiling 프로필을 만들고 싶습니다. Cargo.toml에 무엇을 적고, 어떻게 빌드하나요?
해설 보기
다음처럼 release를 상속하고 debug만 덮어씁니다.
[profile.profiling]
inherits = "release"
debug = true빌드할 때는 cargo build --profile profiling을 실행하며, 결과물은 target/profiling에 들어갑니다. inherits를 빼면 Cargo가 바탕 프로필을 알 수 없어 오류를 냅니다.
다음 글 Crates.io 배포에서는 문서화 주석과 공개 API를 다듬어 라이브러리를 crates.io에 배포하는 방법을 살펴봅니다.