nptclのブログ

Common Lisp処理系nptの開発メモです。https://github.com/nptcl/npt

sbcl Windows版のmsiファイルから内容を直接展開する

Windows環境にsbclを導入するには、公式サイトからmsiファイルをダウンロードして実行する必要があります。 するとインストーラーが起動し、わざわざ管理者モードになって親切に色んなことをやってくれます。

例えば次の通り。

  • Program File上へファイルの展開
  • スタートメニューの登録
  • アプリケーション削除の登録
  • 環境変数の登録

でも、そういうの全然いらないから、ただファイル展開だけして欲しいんです。 あと管理者モードの移行もやめて欲しい。 zipファイルで配布されていればいいんですが、msiファイルしかない。 どうしたらいいのか。

sbclに限らずmsiファイルに困っている人は結構いるようで、検索するとすぐに解決します。 msiexecという実行ファイルで行けそうです。

msiexec /a [msiファイル] targetdir=[出力先] /qn

つまり下記のようになります。

C:\> msiexec /a sbcl-1.4.14-x86-64-windows-binary.msi targetdir=C:\temp\ /qn

うまく行くとC:\temp\上に展開されます。 targetdirはフルパスでちゃんと記載しないとダメでした。

何が展開されるかというと、

C:\temp\PFiles\Steel Bank Common Lisp\1.4.14\
  controb\
  sbcl.exec
  sbcl.core

となります。

コマンドプロンプトを起動するのが面倒なので、 バッチファイルを作成してみました。 sbcl-extract.batmsiファイルをドラッグしてドロップすると起動し、 バッチファイルと同じディレクトリに、 例えば1.4.14みたいなディレクトリが作成されます。

ファイルsbcl-extract.bat

@echo off
set inst=%~1
set base=%~dp0
set temp=%base%\__temp
cd /d "%base%"

REM -- File check --
if not exist "%inst%" (
  echo Argument error
  goto error
)

REM --- Remove directory ---
if exist "%temp%" (
  rmdir /S /Q "%temp%"
  if errorlevel 1 (
    echo rmdir error
    goto error
  )
)

REM -- Base directory check --
mkdir "%temp%"
if errorlevel 1 (
  echo mkdir error
  goto error
)

REM -- Extract --
msiexec /a "%inst%" targetdir="%temp%\" /qn
if errorlevel 1 (
  echo msiexec error
  goto error
)

REM -- Move --
set version=
set vername=
for /D %%i in ("%temp%\PFiles\Steel Bank Common Lisp\*.*.*") do (
  set version=%%~i
  set vername=%%~ni%%~xi
)

if not exist "%version%" (
  echo Version path error
  goto error
)

if "%vername%" == "" (
  echo Version name error
  goto error
)

set dest=%base%\%vername%
if exist "%dest%" (
  echo Version %version% already exists.
  goto error
)

move "%version%" "%dest%"
if errorlevel 1 (
  echo move error
  goto error
)

REM --- Success ---
rmdir /S /Q "%temp%"
if errorlevel 1 (
  echo rmdir error
  goto error
)
echo OK
pause
exit /b 0

REM --- Error ---
:error
echo Error
if exist "%temp%" (
  rmdir /S /Q "%temp%"
)
pause
exit /b 1

バッチファイルは便利だけど、書き方が難しくて合っているのかよくわからん。