Rust 크로스 컴파일 — Windows/macOS/Linux 한 번에 빌드하기

게시일: 2025년 10월 3일 · 14분 읽기

Rust의 크로스 컴파일은 C++에 비하면 천국이다. 하지만 함정은 있다

실무 개발 경력 중 10년을 C++로 보냈다. 크로스 플랫폼 빌드는 악몽이었다. DLL vs SO, 아키텍처 차이, 컴파일러 호환성... 하루 종일 빌드만 했던 날도 있다.

Rust로 옮기고 나니 정말 쉽다. 같은 명령어로 Windows, macOS, Linux 바이너리가 나온다. 하지만 세부 사항을 모르면 함정에 빠진다.

기본: Rust 크로스 컴파일

설치:

cargo install cross

사용:

# Linux에서 Windows용 빌드
cross build --release --target x86_64-pc-windows-gnu

# macOS에서 Linux용 빌드
cross build --release --target x86_64-unknown-linux-gnu

# Linux에서 ARM 기기용 빌드 (라즈베리파이)
cross build --release --target armv7-unknown-linux-gnueabihf

끝이다. 정말로.

Target Triple 이해하기

Target triple은 빌드 대상을 정의한다: <cpu>-<vendor>-<os>-<env>

예:

전체 목록 확인:

rustc --print target-list | grep -i linux
rustc --print target-list | grep -i windows

GitHub Actions로 자동 빌드

모든 플랫폼을 자동으로 빌드하려면 GitHub Actions를 사용한다:

name: Cross-Platform Build

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        include:
          # Windows
          - os: windows-latest
            target: x86_64-pc-windows-msvc
            artifact_name: myapp.exe

          # macOS Intel
          - os: macos-latest
            target: x86_64-apple-darwin
            artifact_name: myapp

          # macOS Apple Silicon
          - os: macos-latest
            target: aarch64-apple-darwin
            artifact_name: myapp

          # Linux
          - os: ubuntu-latest
            target: x86_64-unknown-linux-gnu
            artifact_name: myapp

    steps:
      - uses: actions/checkout@v3

      - uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.target }}

      - name: Install cross
        run: cargo install cross

      - name: Build
        run: cross build --release --target ${{ matrix.target }}

      - name: Upload artifact
        uses: actions/upload-artifact@v3
        with:
          name: myapp-${{ matrix.target }}
          path: target/${{ matrix.target }}/release/${{ matrix.artifact_name }}

조건부 컴파일

플랫폼별로 다른 코드를 실행해야 할 때:

#[cfg(target_os = "windows")]
fn get_config_path() -> PathBuf {
    PathBuf::from(format!("{}\AppData\Local\myapp",
                          std::env::var("USERPROFILE").unwrap()))
}

#[cfg(target_os = "unix")]
fn get_config_path() -> PathBuf {
    PathBuf::from(format!("{}/.config/myapp",
                          std::env::var("HOME").unwrap()))
}

#[cfg(target_arch = "x86_64")]
fn get_num_threads() -> usize {
    8
}

#[cfg(target_arch = "arm")]
fn get_num_threads() -> usize {
    4
}

의존성의 함정

모든 라이브러리가 크로스 플랫폼을 지원하는 건 아니다.

문제가 생기는 경우:

해결책:

[dependencies]
winapi = { version = "0.3", features = ["winuser"] }

[target.'cfg(windows)'.dependencies]
windows = "0.37"

[target.'cfg(unix)'.dependencies]
libc = "0.2"

테스트 전략

모든 플랫폼에서 테스트를 해야 한다:

# 로컬에서 특정 플랫폼으로 테스트
cross test --target x86_64-unknown-linux-gnu

# GitHub Actions에서 모든 플랫폼 테스트
- name: Test
  run: cross test --release --target ${{ matrix.target }}

# 커버리지 (선택사항)
- name: Generate coverage
  run: |
    cargo install tarpaulin
    cargo tarpaulin --out Xml --target ${{ matrix.target }}

실제 예제: 간단한 CLI 도구

// main.rs
use std::env;

#[cfg(target_os = "windows")]
const SEPARATOR: &str = "\";

#[cfg(target_os = "unix")]
const SEPARATOR: &str = "/";

fn main() {
    let args: Vec<String> = env::args().collect();

    println!("OS: {}", std::env::consts::OS);
    println!("Arch: {}", std::env::consts::ARCH);
    println!("Path separator: {}", SEPARATOR);

    for arg in &args[1..] {
        println!("Argument: {}", arg);
    }
}

빌드 시간 최적화

크로스 컴파일은 느릴 수 있다. 최적화하려면:

# .cargo/config.toml
[profile.release]
opt-level = 3
lto = true
codegen-units = 1

# GitHub Actions 캐시
- uses: Swatinem/rust-cache@v2
  with:
    cache-targets: "true"

배포 자동화

빌드된 바이너리를 자동으로 릴리스하려면:

# Cargo.toml
[package]
name = "myapp"
version = "0.1.0"

# GitHub Actions
- name: Create Release
  if: startsWith(github.ref, 'refs/tags/')
  uses: softprops/action-gh-release@v1
  with:
    files: |
      target/*/release/myapp
      target/*/release/myapp.exe

실제 경험: 문제 해결

문제 1: Windows에서 OpenSSL 컴파일 실패

해결:
1. vcpkg 설치
2. VCPKG_ROOT 설정
3. OpenSSL 설치: vcpkg install openssl:x64-windows

문제 2: ARM 아키텍처에서 느린 빌드

해결:
1. 로컬 ARM 기기에서 빌드 (라즈베리파이)
2. Docker 사용
3. cargo-cross 사용 (권장)

결론

Rust의 크로스 컴파일은 정말 강력하다. C++과 비교하면 차원이 다르다.

하지만 주의할 점:

오랜 개발 경험에서 느낀 점: 이렇게 쉬운 크로스 컴파일이 C++에는 없었다. Rust가 정말 잘 설계되었다.

iL
ian.lab

실무 개발자입니다. 현장에서 겪은 문제와 해결 과정을 기록합니다. 오류 제보는 연락처로 보내주세요.