iBetter Books
수정

실행 파일로 컴파일하고 배포하기

dart run으로 실행하면 Dart VM이 필요합니다. 다른 사람에게 배포하려면 Dart가 설치되지 않은 환경에서도 실행되어야 합니다. dart compile exe 명령어가 이를 해결합니다. Dart 코드를 네이티브 실행 파일로 컴파일합니다. Dart VM이 없어도 됩니다.

dart compile exe

dart compile exe bin/file_organizer.dart -o build/file_organizer
  • bin/file_organizer.dart: 컴파일할 엔트리포인트
  • -o build/file_organizer: 출력 파일 경로 (Windows에서는 .exe 자동 추가)
# 빌드 디렉토리 생성 후 컴파일mkdir -p builddart compile exe bin/file_organizer.dart -o build/file_organizer# 실행./build/file_organizer --help./build/file_organizer stats -r

컴파일된 실행 파일은 단일 바이너리입니다. 의존성이 모두 포함되어 있습니다. 배포하려면 이 파일 하나만 전달하면 됩니다.

컴파일 옵션 비교

Dart는 여러 컴파일 타깃을 지원합니다.

명령어 결과 용도
dart run JIT 실행 개발 중 빠른 피드백
dart compile exe 네이티브 바이너리 CLI 배포
dart compile aot-snapshot AOT 스냅샷 Dart 런타임 필요, 파일 작음
dart compile js JavaScript 웹 배포
dart compile jit-snapshot JIT 스냅샷 워밍업 후 빠른 실행

CLI 도구를 배포할 때는 dart compile exe가 가장 좋습니다.

Makefile로 빌드 자동화

매번 긴 명령어를 입력하지 않도록 Makefile을 작성합니다.

# 새 파일: Makefile
APP_NAME := file_organizer
BUILD_DIR := build
ENTRY := bin/file_organizer.dart

.PHONY: build clean test run install

## 네이티브 실행 파일 빌드
build:
	@mkdir -p $(BUILD_DIR)
	dart compile exe $(ENTRY) -o $(BUILD_DIR)/$(APP_NAME)
	@echo "빌드 완료: $(BUILD_DIR)/$(APP_NAME)"

## 테스트 실행
test:
	dart test

## 개발 모드 실행 (JIT)
run:
	dart run $(ENTRY) $(ARGS)

## /usr/local/bin에 설치
install: build
	cp $(BUILD_DIR)/$(APP_NAME) /usr/local/bin/$(APP_NAME)
	@echo "설치 완료: /usr/local/bin/$(APP_NAME)"

## 빌드 아티팩트 삭제
clean:
	rm -rf $(BUILD_DIR)
make build          # 빌드make install        # 빌드 + /usr/local/bin 설치make run ARGS="stats -r"  # 개발 모드 실행

PATH 등록

설치된 실행 파일을 어디서나 실행하려면 PATH에 등록해야 합니다.

macOS / Linux (Bash/Zsh)

# 방법 1: /usr/local/bin에 복사 (권장)sudo cp build/file_organizer /usr/local/bin/# 방법 2: ~/.local/bin에 복사 (root 권한 불필요)mkdir -p ~/.local/bincp build/file_organizer ~/.local/bin/echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrcsource ~/.zshrc

Windows (PowerShell)

# 사용자 bin 디렉토리 생성 후 복사
New-Item -ItemType Directory -Force "$env:USERPROFILE\bin"
Copy-Item "build\file_organizer.exe" "$env:USERPROFILE\bin\"

# PATH에 추가
$userPath = [Environment]::GetEnvironmentVariable("PATH", "User")
[Environment]::SetEnvironmentVariable("PATH", "$userPath;$env:USERPROFILE\bin", "User")

버전 정보 내장

실행 파일에 버전 정보를 포함하는 것이 좋습니다. pubspec.yaml의 버전을 코드에서 읽는 방법입니다.

// 새 파일: lib/src/version.dart

/// 현재 버전. pubspec.yaml과 동기화 필요.
const String version = '1.0.0';

/// 빌드 날짜. 빌드 시점에 자동 생성됩니다.
final String buildDate = DateTime.now().toIso8601String().substring(0, 10);

runner.dart에 버전 플래그를 추가합니다.

// 수정: lib/src/runner.dart
import 'package:args/command_runner.dart';

import 'commands/organize_command.dart';
import 'commands/rename_command.dart';
import 'commands/stats_command.dart';
import 'version.dart';

/// CLI 애플리케이션의 진입점 역할을 하는 러너.
class FileOrganizerRunner {
  FileOrganizerRunner() {
    _runner = CommandRunner<void>(
      'file_organizer',
      '파일 정리 및 변환 CLI 도구.',
    )
      ..addCommand(OrganizeCommand())
      ..addCommand(StatsCommand())
      ..addCommand(RenameCommand());

    _runner.argParser
      ..addFlag(
        'verbose',
        abbr: 'v',
        negatable: false,
        help: '상세 출력을 활성화합니다.',
      )
      ..addFlag(
        'version',
        negatable: false,
        help: '버전 정보를 출력합니다.',
      );
  }

  late final CommandRunner<void> _runner;

  Future<void> run(List<String> arguments) async {
    // --version 처리 (run() 전에 먼저 확인)
    if (arguments.contains('--version') || arguments.contains('-V')) {
      print('file_organizer $version (built $buildDate)');
      return;
    }

    await _runner.run(arguments);
  }
}

크로스 플랫폼 빌드

dart compile exe는 현재 플랫폼의 실행 파일만 생성합니다. macOS에서 Windows용 바이너리를 만들 수 없습니다. 크로스 플랫폼 배포가 필요하면 GitHub Actions를 사용합니다.

# 새 파일: .github/workflows/build.ymlname: Buildon:  push:    tags:      - 'v*'jobs:  build:    strategy:      matrix:        include:          - os: ubuntu-latest            output: file_organizer-linux          - os: macos-latest            output: file_organizer-macos          - os: windows-latest            output: file_organizer-windows.exe    runs-on: ${{ matrix.os }}    steps:      - uses: actions/checkout@v4      - uses: dart-lang/setup-dart@v1        with:          sdk: stable      - name: 의존성 설치        run: dart pub get      - name: 테스트 실행        run: dart test      - name: 실행 파일 빌드        run: |          mkdir -p build          dart compile exe bin/file_organizer.dart -o build/${{ matrix.output }}      - name: GitHub Release에 업로드        uses: actions/upload-artifact@v4        with:          name: ${{ matrix.output }}          path: build/${{ matrix.output }}

태그를 푸시하면 세 플랫폼에서 동시에 빌드가 실행됩니다.

git tag v1.0.0git push origin v1.0.0

dart pub global — 전역 도구 설치

pub.dev에 패키지를 배포하면 dart pub global activate로 설치할 수 있습니다.

# pub.dev에서 전역 설치dart pub global activate file_organizer# 로컬 경로에서 전역 설치 (개발 중)dart pub global activate --source path .# 실행file_organizer stats

dart pub global activate~/.pub-cache/bin/에 래퍼 스크립트를 생성합니다. 이 디렉토리가 PATH에 있으면 어디서나 실행할 수 있습니다.

# PATH에 추가 (한 번만)export PATH="$PATH":"$HOME/.pub-cache/bin"

빌드 성능 확인

# JIT vs AOT 실행 시간 비교time dart run bin/file_organizer.dart stats -rtime ./build/file_organizer stats -r

일반적으로 AOT 컴파일된 실행 파일이 JIT보다 시작 시간이 빠릅니다. 특히 단순 실행이 많은 CLI 도구에서는 체감 차이가 큽니다.

최종 프로젝트 구조

완성된 file_organizer 프로젝트 구조입니다.

file_organizer/
├── .github/
│   └── workflows/
│       └── build.yml
├── bin/
│   └── file_organizer.dart
├── build/
│   └── file_organizer          ← 컴파일된 실행 파일
├── lib/
│   ├── src/
│   │   ├── commands/
│   │   │   ├── organize_command.dart
│   │   │   ├── rename_command.dart
│   │   │   └── stats_command.dart
│   │   ├── models/
│   │   │   ├── file_info.dart
│   │   │   └── rename_rule.dart
│   │   ├── utils/
│   │   │   ├── csv_utils.dart
│   │   │   ├── file_utils.dart
│   │   │   ├── json_utils.dart
│   │   │   ├── progress_bar.dart
│   │   │   ├── prompt.dart
│   │   │   └── terminal.dart
│   │   ├── exceptions.dart
│   │   ├── runner.dart
│   │   └── version.dart
│   └── file_organizer.dart
├── test/
├── Makefile
├── pubspec.yaml
└── README.md

정리

이번 챕터에서 PART 04의 file_organizer 프로젝트를 완성했습니다.

  • dart compile exe로 Dart VM 없이 실행 가능한 단일 바이너리를 생성했습니다.
  • Makefile로 빌드 과정을 자동화했습니다.
  • GitHub Actions로 세 플랫폼(Linux, macOS, Windows)용 바이너리를 동시에 빌드합니다.
  • dart pub global activate로 전역 도구로 설치할 수 있습니다.

다음 PART에서는 이 file_organizer 코드를 대상으로 테스트를 작성합니다.