devAlice
← Windows

Windows 開発環境の週次メンテナンス — MSYS2・winget・ツールチェーンを 1 コマンドで

MSYS2 の pacman、winget、Scoop、npm グローバル、rustup、cargo バイナリ、pipx、Flutter を更新する週次 PowerShell スクリプト。

Windows の開発環境は常に依存関係の寄せ集めだ — IDE は winget、gcc/make/git は MSYS2、CLI は scoop、グローバルは npm/pip/cargo。それぞれに異なる更新コマンドがあり、忘れると最終的に ld.exe: cannot find -lcrypt32 のような意味不明なエラーで Tauri ビルドが壊れる。

この記事は、それを防ぐ 8 ステップ統合 PowerShell スクリプトだ。週に 1 回実行すれば完了。

TL;DR

  • MSYS2 pacmanwingetScoopnpm -grustupcargo install-updatepipxflutter
  • MSYS2 がステップ 1:Windows 上のビルド環境の OS に相当する。スキップするとネイティブビルドがドミノ倒しで崩れる
  • ツールがインストールされていない場合、各ステップは自動スキップ;1 つの失敗で残りが止まることはない
  • 約 100 行の PowerShell、update-system.bat をダブルクリックで実行

MSYS2 がステップ 1 の理由

Windows の winget はユーザーアプリ(Chrome、Slack など)と最終的な開発ツールのアーティファクトを扱う。しかし実際にコードをコンパイルする環境は MSYS2 内にある — pacman 経由で gcc、make、autotools、openssl ヘッダー、libsqlite、zlib が提供される。

1 か月スキップすると:

  • Rust + Tauri のクロスコンパイルが OpenSSL ヘッダーのバージョン不一致で壊れる
  • Python C 拡張ビルド(pip install pillow など)が freetype のバージョンずれで失敗する
  • MinGW ベースのビルドが依存ライブラリの ABI 不一致で壊れる

だから pacman -Syuu(ダブル u — ダウングレードも含む同期)が常に最初のステップだ。

前提条件

  • Windows 10 1709 以上 / 11(winget 組み込み)
  • 全 8 ステップに対応:MSYS2、pipx、cargo-update、Flutter が事前インストール済み
  • Scoop はオプション — 未インストールなら自動スキップ

初回準備

管理者 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/windows

MSYS2 インストール後、MSYS2 シェルを一度開いて pacman -Syuu を実行してベースパッケージを同期する。

8 つの更新ステップ

#ステップコマンド備考
1MSYS2pacman -Syuuビルド環境の OS — #1
2wingetwinget upgrade --allシステムパッケージ
3Scoopscoop update *インストール済みの場合のみ
4npm グローバルnpm update -gグローバル npm パッケージ
5Rust ツールチェーンrustup updatestable チャンネル
6Cargo バイナリcargo install-update -acargo-update が必要
7pipxpipx upgrade-allPython グローバルツール
8Flutter SDKflutter 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 "━━━ System update (Windows) ━━━" -ForegroundColor Cyan
 
# 1. MSYS2(最重要 — ビルド環境の OS)
Step-Header "MSYS2 (pacman -Syuu) — critical"
$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 "  → using: $msys2Bash" -ForegroundColor DarkGray
    & $msys2Bash -lc "pacman -Syuu --noconfirm"
    if ($LASTEXITCODE -eq 0) {
        Write-OK "pacman -Syuu done (rerun once if core packages updated)"
    } else {
        Write-Fail "pacman -Syuu (after core updates, restart shell + rerun)"
    }
} else {
    Write-Skip "MSYS2 not installed (checked: C:\msys64, D:\msys64, C:\tools\msys64)"
}
 
# 2. winget
Step-Header "winget (system packages)"
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 (some packages may need admin/interactive)" }
} else {
    Write-Skip "winget not installed"
}
 
# 3. Scoop(オプション)
Step-Header "Scoop (if installed)"
if (Has-Command scoop) {
    scoop update
    scoop update *
    Write-OK "scoop update / update *"
} else {
    Write-Skip "scoop not installed"
}
 
# 4. npm グローバル
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 not installed"
}
 
# 5. Rust ツールチェーン
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 not installed"
}
 
# 6. Cargo バイナリ
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 missing (install: cargo install cargo-update)"
    }
} else {
    Write-Skip "cargo not installed"
}
 
# 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 not installed"
}
 
# 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 not installed"
}
 
Write-Host ""
Write-Host "━━━ Done ━━━" -ForegroundColor Cyan
Write-Host "Checks: winget upgrade  /  npm outdated -g  /  pacman -Qu (MSYS2)" -ForegroundColor DarkGray

update-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.
)
 
pause

**.ps1 ファイルは BOM 付き UTF-8 で保存すること。**BOM がないと Windows PowerShell 5.1 で非 ASCII 出力が文字化けする。VS Code では右下のエンコーディング表示をクリック → 「Save with Encoding」→「UTF-8 with BOM」。

実行例

update-system.bat をダブルクリック(UAC に同意)。初回は 5〜10 分(MSYS2 + winget)。以降は 1〜3 分。

━━━ System update (Windows) ━━━

[1/8] MSYS2 (pacman -Syuu) — critical
  → using: C:\msys64\usr\bin\bash.exe
:: Synchronizing package databases...
:: Starting core system upgrade...
...
  OK pacman -Syuu done (rerun once if core packages updated)

[2/8] winget (system packages)
  Microsoft.VisualStudioCode 1.99.2 → 1.100.0
  GitHub.cli 2.65.0 → 2.66.1
  ...
  OK winget upgrade --all

[3/8] Scoop (if installed)
  SKIP scoop not installed

[4/8] npm globals
  OK npm update -g

...

━━━ Done ━━━
Checks: winget upgrade  /  npm outdated -g  /  pacman -Qu (MSYS2)

自動化 — Task Scheduler でリマインダーのみ

完全な自動化は推奨しない。winget は時々 EULA ダイアログを表示し、MSYS2 のコア更新はシェルの再起動が必要で無人実行を妨げる。実行ではなくリマインダーとして:

PowerShell から Task Scheduler を設定:

$action = New-ScheduledTaskAction -Execute "powershell.exe" `
    -Argument '-NoProfile -Command "[System.Reflection.Assembly]::LoadWithPartialName(\"System.Windows.Forms\"); [System.Windows.Forms.MessageBox]::Show(\"Weekly update-system reminder\", \"Dev Maintenance\")"'
 
$trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Friday -At 10:00am
 
Register-ScheduledTask -TaskName "Dev Update Reminder" `
    -Action $action -Trigger $trigger `
    -Description "Weekly reminder to run update-system"

毎週金曜 10:00 にメッセージボックスが 1 つ表示される。実行するかどうかは自分で決める。

注意点

  • MSYS2 のコア更新はシェルの再起動 + 再実行が必要:pacman が自身またはコアライブラリ(libcurl、openssl)を更新すると、トランザクションを停止して再実行を求める。最初の実行が完了したら update-system.bat をもう一度実行する。
  • 一部の winget パッケージはインタラクティブな入力が必要--silent でほとんどはサイレントになるが、新しい EULA がブロックすることがある。該当パッケージは手動でインストールする。
  • Flutter が winget リポジトリにない場合があるFlutter.Flutter がリストにない場合は docs.flutter.dev から zip を取得して PATH に追加する。
  • Scoop はオプション:winget のみまたは scoop のみを意図的に使う場合、もう一方のステップはクリーンにスキップされる。競合リスクはない。
  • -Syuu の 2 つめの u:ダウングレードも同期する。MSYS2 は意図的にパッケージをダウングレードすることがあり、-Syu だけでは競合が蓄積する。

Mac ユーザーは?

brew + 言語ツールチェーン + Flutter + CocoaPods をカバーする同様のガイド → Mac 開発環境の週次メンテナンス

まとめ

  • Windows では MSYS2 の更新が最優先
  • ツールを 1 つずつ更新 → 忘れる
  • 統合スクリプト 1 本 → 何も気にせず実行するだけ
  • リマインダーとしてのみ自動化し、実行自体は自動化しない
  • 週 1 回でビルドの崩壊・証明書切れ・SDK のずれを防止できる