Windows 개발 환경 정기 유지관리 — MSYS2·winget·언어 툴체인을 한 명령으로
주 1회 한 번의 실행으로 MSYS2 pacman, winget, Scoop, npm globals, rustup, cargo binaries, pipx, Flutter를 모두 갱신하는 PowerShell 스크립트.
Windows에서 개발 환경을 굴리는 건 늘 의존성이 흩어져 있다. winget으로 받은 IDE, MSYS2로 깐 gcc·make·git, scoop으로 받은 CLI, npm/pip/cargo로 깐 글로벌 도구. 각각 갱신 명령이 다르고, 잊으면 어느 날 Tauri 빌드가 ld.exe: cannot find -lcrypt32 같은 헛소리로 죽는다.
이 글은 그걸 막는 8단계 통합 PowerShell 스크립트다. 주 1회 한 번이면 끝.
TL;DR
MSYS2 pacman→winget→Scoop→npm -g→rustup→cargo install-update→pipx→flutter8개 순서- MSYS2가 1번: Windows에서 빌드 환경의 OS다. 여기 묵으면 네이티브 빌드 줄줄이 깨진다
- 각 단계는 도구가 없으면 자동 SKIP, 한 단계 실패해도 나머지는 진행
- 약 100줄짜리 단일 PowerShell 스크립트,
update-system.bat으로 더블클릭 실행
왜 MSYS2가 1번인가
Windows의 winget은 사용자 앱(Chrome, Slack 등)이나 개발 도구 최종 산출물을 다룬다. 하지만 실제로 코드를 컴파일하는 환경은 MSYS2 안에 있다 — pacman으로 깐 gcc, make, autotools, openssl 헤더, libsqlite, zlib 등.
이걸 한 달만 묵히면:
- Rust + Tauri 크로스 컴파일이 OpenSSL 헤더 미스매치로 깨짐
- Python C extension 빌드 (
pip install pillow등)이 freetype 버전 어긋남으로 실패 - MinGW 기반 어떤 빌드든 의존 라이브러리 ABI 깨짐
그래서 pacman -Syuu (double u — 다운그레이드까지 동기화)가 항상 첫 단계여야 한다.
사전 조건
- Windows 10 1709+ / 11 (winget 기본 포함)
- 8단계 전부 채우려면: MSYS2, pipx, cargo-update, Flutter 미리 설치
- Scoop은 선택 — 없으면 단계 자동 SKIP
사전 설치 (한 번만)
PowerShell 관리자 권한:
# MSYS2 (~700MB) — 빌드 환경의 OS
winget install MSYS2.MSYS2
# pipx (Python 글로벌 패키지 매니저)
python -m pip install --user pipx
python -m pipx ensurepath
# cargo-update 확장
cargo install cargo-update
# Flutter (~1GB)
winget install Flutter.Flutter
# winget에 없으면 https://docs.flutter.dev/get-started/install/windowsMSYS2 설치 후엔 한 번 MSYS2 셸을 열어서 pacman -Syuu로 베이스 패키지 동기화 권장.
8단계 갱신 대상
| # | 단계 | 명령 | 비고 |
|---|---|---|---|
| 1 | MSYS2 | pacman -Syuu | 빌드 환경의 OS — 1순위 |
| 2 | winget | winget upgrade --all | 시스템 패키지 |
| 3 | Scoop | scoop update * | 있을 때만 |
| 4 | npm globals | npm update -g | 글로벌 npm 패키지 |
| 5 | Rust toolchain | rustup update | stable channel |
| 6 | Cargo binaries | cargo install-update -a | cargo-update 확장 필요 |
| 7 | pipx | pipx upgrade-all | Python global tools |
| 8 | Flutter SDK | flutter upgrade | 현재 채널의 최신 |
통합 스크립트
저장 2개:
update-system.ps1 (실제 로직):
<#
.SYNOPSIS
시스템 도구 일괄 업데이트 — Windows
.DESCRIPTION
빌드 환경 / 패키지 매니저 / 언어 툴체인을 한 번에 갱신.
.NOTES
실행: update-system.bat (관리자 권한 권장)
대상: Windows 10/11
#>
$ErrorActionPreference = "Continue"
$script:Total = 8
$script:Step = 0
function Step-Header {
param([string]$Message)
$script:Step++
Write-Host ""
Write-Host ("[{0}/{1}] {2}" -f $script:Step, $script:Total, $Message) -ForegroundColor Cyan
}
function Has-Command {
param([string]$Cmd)
$null = Get-Command $Cmd -ErrorAction SilentlyContinue
return $?
}
function Write-OK { param([string]$m) Write-Host " OK $m" -ForegroundColor Green }
function Write-Skip { param([string]$m) Write-Host " SKIP $m" -ForegroundColor DarkGray }
function Write-Warn { param([string]$m) Write-Host " WARN $m" -ForegroundColor Yellow }
function Write-Fail { param([string]$m) Write-Host " FAIL $m" -ForegroundColor Red }
Write-Host "━━━ 시스템 업데이트 (Windows) ━━━" -ForegroundColor Cyan
# 1. MSYS2 (가장 중요 — 빌드 환경의 OS)
Step-Header "MSYS2 (pacman -Syuu) — 핵심"
$msys2Candidates = @(
"C:\msys64\usr\bin\bash.exe",
"D:\msys64\usr\bin\bash.exe",
"C:\tools\msys64\usr\bin\bash.exe"
)
$msys2Bash = $msys2Candidates | Where-Object { Test-Path $_ } | Select-Object -First 1
if ($msys2Bash) {
Write-Host " → 사용 경로: $msys2Bash" -ForegroundColor DarkGray
& $msys2Bash -lc "pacman -Syuu --noconfirm"
if ($LASTEXITCODE -eq 0) {
Write-OK "pacman -Syuu 완료 (core 업데이트가 있었다면 한 번 더 권장)"
} else {
Write-Fail "pacman -Syuu (core 패키지 갱신 후엔 셸 재시작 후 재실행 필요할 수 있음)"
}
} else {
Write-Skip "MSYS2 미설치 (확인: C:\msys64, D:\msys64, C:\tools\msys64)"
}
# 2. winget
Step-Header "winget (시스템 패키지)"
if (Has-Command winget) {
winget upgrade --all --silent --accept-package-agreements --accept-source-agreements
if ($LASTEXITCODE -eq 0) { Write-OK "winget upgrade --all" }
else { Write-Fail "winget upgrade --all (일부 패키지가 관리자 권한/대화형 입력 필요)" }
} else {
Write-Skip "winget 미설치"
}
# 3. Scoop (선택)
Step-Header "Scoop (있을 때만)"
if (Has-Command scoop) {
scoop update
scoop update *
Write-OK "scoop update / update *"
} else {
Write-Skip "scoop 미설치"
}
# 4. npm globals
Step-Header "npm globals"
if (Has-Command npm) {
npm update -g
if ($LASTEXITCODE -eq 0) { Write-OK "npm update -g" } else { Write-Fail "npm update -g" }
} else {
Write-Skip "npm 미설치"
}
# 5. Rust toolchain
Step-Header "Rust toolchain (rustup)"
if (Has-Command rustup) {
rustup update
if ($LASTEXITCODE -eq 0) { Write-OK "rustup update" } else { Write-Fail "rustup update" }
} else {
Write-Skip "rustup 미설치"
}
# 6. Cargo binaries
Step-Header "Cargo binaries (cargo install-update -a)"
if (Has-Command cargo) {
cargo install-update --version 2>$null | Out-Null
if ($LASTEXITCODE -eq 0) {
cargo install-update -a
if ($LASTEXITCODE -eq 0) { Write-OK "cargo install-update -a" }
else { Write-Fail "cargo install-update -a" }
} else {
Write-Warn "cargo-update 미설치 (설치: cargo install cargo-update)"
}
} else {
Write-Skip "cargo 미설치"
}
# 7. pipx
Step-Header "pipx (Python global tools)"
if (Has-Command pipx) {
pipx upgrade-all
if ($LASTEXITCODE -eq 0) { Write-OK "pipx upgrade-all" } else { Write-Fail "pipx upgrade-all" }
} else {
Write-Skip "pipx 미설치"
}
# 8. Flutter SDK
Step-Header "Flutter SDK (flutter upgrade)"
if (Has-Command flutter) {
flutter upgrade
if ($LASTEXITCODE -eq 0) { Write-OK "flutter upgrade" } else { Write-Fail "flutter upgrade" }
} else {
Write-Skip "flutter 미설치"
}
Write-Host ""
Write-Host "━━━ 완료 ━━━" -ForegroundColor Cyan
Write-Host "점검: winget upgrade / npm outdated -g / pacman -Qu (MSYS2)" -ForegroundColor DarkGrayupdate-system.bat (더블클릭 진입점):
@echo off
title System Update
echo ============================================
echo System Update (Windows)
echo MSYS2 + winget + npm + rustup + cargo + pipx
echo ============================================
echo.
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dp0update-system.ps1" %*
if %errorlevel% neq 0 (
echo.
echo [ERROR] Update failed. Check log above.
) else (
echo.
echo [DONE] System update complete.
)
pausePS1 파일은 UTF-8 with BOM으로 저장하세요. Windows PowerShell 5.1에서 한글 출력이 깨지지 않으려면 BOM 필요. VS Code는 우하단 인코딩 클릭 → "Save with Encoding" → "UTF-8 with BOM".
실행 결과 예시
update-system.bat 더블클릭 (UAC 승인) → 첫 실행은 MSYS2 + winget 갱신이 5-10분, 두 번째부터는 1-3분.
━━━ 시스템 업데이트 (Windows) ━━━
[1/8] MSYS2 (pacman -Syuu) — 핵심
→ 사용 경로: C:\msys64\usr\bin\bash.exe
:: Synchronizing package databases...
:: Starting core system upgrade...
...
OK pacman -Syuu 완료 (core 업데이트가 있었다면 한 번 더 권장)
[2/8] winget (시스템 패키지)
Microsoft.VisualStudioCode 1.99.2 → 1.100.0
GitHub.cli 2.65.0 → 2.66.1
...
OK winget upgrade --all
[3/8] Scoop (있을 때만)
SKIP scoop 미설치
[4/8] npm globals
OK npm update -g
...
━━━ 완료 ━━━
점검: winget upgrade / npm outdated -g / pacman -Qu (MSYS2)
자동화 — 작업 스케줄러로 알림만
전체 자동 실행은 비추한다. winget이 가끔 대화형 EULA를 띄우거나, MSYS2 core 업데이트는 셸 재시작이 필요한데 무인 실행 시 멎는다. "잊지 않게 알림만".
작업 스케줄러 PowerShell:
$action = New-ScheduledTaskAction -Execute "powershell.exe" `
-Argument '-NoProfile -Command "[System.Reflection.Assembly]::LoadWithPartialName(\"System.Windows.Forms\"); [System.Windows.Forms.MessageBox]::Show(\"주간 update-system 점검 시간\", \"Dev Maintenance\")"'
$trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Friday -At 10:00am
Register-ScheduledTask -TaskName "Dev Update Reminder" `
-Action $action -Trigger $trigger `
-Description "주 1회 update-system 실행 알림"매주 금요일 오전 10시 메시지박스 한 번. 실행은 사람이 결정.
함정
- MSYS2 core 패키지 갱신 후엔 셸 재시작 + 재실행 필요: pacman이 자기 자신이나 핵심 라이브러리(libcurl, openssl)를 갱신하면 진행 중인 트랜잭션을 중단하고 재실행을 요구한다. 첫 실행이 끝난 뒤 한 번 더
update-system.bat을 돌리는 게 안전. - winget 일부 패키지는 대화형 입력 필요:
--silent로 대부분 무인 처리되지만 EULA가 새로 들어간 패키지는 멎는다. 그땐 해당 패키지만 수동. - Flutter winget 패키지가 없을 수 있음: winget 리포지토리에
Flutter.Flutter가 등록 안 된 시기에는 docs.flutter.dev에서 zip 받아 PATH 추가. - Scoop은 선택: 일부러
winget또는scoop한쪽만 쓰는 정책이라면 다른 쪽은 단계가 SKIP된다. 충돌 위험 없음. -Syuu의 두 번째u: 다운그레이드까지 동기화. MSYS2 리포가 가끔 패키지를 의도적으로 다운그레이드하는데-Syu만 쓰면 충돌이 누적된다.
Mac 사용자도?
같은 발상으로 brew·언어 툴체인·Flutter·CocoaPods를 한 번에 갱신하는 셸 스크립트 → Mac 개발 환경 정기 유지관리.
정리
- Windows 빌드 환경은 MSYS2 갱신이 1순위
- 도구 1개씩 손으로 갱신 → 잊는다
- 통합 스크립트 1개 → 잊어도 한 번 돌리면 끝
- 자동화는 알림까지만, 실행은 사람이
- 매주 1회면 빌드 깨짐·인증서 만료·SDK drift 모두 막을 수 있다