WindowsにLua 5.1をインストールしてLuarocksする。

NeovimにはLuaJITが組み込まれています。これはLua 5.1がベースになったLuaJIT 2.1.0-beta3とのこと。ちなみにLua 5.1系自体は2012年2月17日にbug-fixリリースの5.1.5が最後です。その前年の12月に5.2.0がリリースされ、その後現在のバージョンは5.4.3になっています。

Pythonはちょろっといじってきたのですが、せっかくNeovimにLuaが組み込まれているのだし、VimScriptも難しいし、テキスト加工の自動化とかもLuaでできたら楽なのかな、と思ったのでLuaに手を出してみることにしました。

ということでちょっと調べてみると、Lua 5.1では文字列はbyte列として扱う、ということで、たとえばコマンドプロンプトでLuaインタプリタを起動し、string.len("あいうえお")とすると、
  • CP932環境では 10
  • CP65001環境では 5
です。一方Neovim(encoding=utf-8)で:lua print(string.len('あいうえお'))すると15が返ってきます。

ちょっとやってみただけなので間違ってたり環境依存だったり勘違いだったりするのかもしれませんが、まあそんな感じで一筋縄では行かなそうだし、本当に文字エンコーディングの問題は魂に刻み込まれた呪いのようです。

Windows 11が出るよ、と言われて、全部Unicodeになるの?と思ったらやっぱりならないみたいだし、この呪いはもはや「with 文字エンコーディング」として付き合っていかないとなのでしょうか。

閑話休題 それはさておき

調べてみると、Lua 5.1でも使えるutf8ライブラリがあるようです。starwindg/luautf8は、5.3のビルトインのものと互換性があるようで、これを使うのが一番良さそうです。ところがこれは LuaRocks を利用してインストールする形になっているので、Lua + LuaRocks が必要です。
 

Lua 5.1のインストール

ともかく、Luaをインストールしてしまいましょう。といっても、最新の5.4系ではなく、Neovimと同じ5.1系を選びます。具体的には最終版の5.1.5。

Lua DownloadページのToolsのところに、LuaBinariesというリンクがあるのでそこに飛びます。すると、[05/May/2014]のところに Lua 5.1.5 - Release 1 というリンクがあるのでそこをクリックします。
そこにある Tools Executables に実行形式が、Windows Libraries にDLLがあります。

使用しているNeovimは64bitビルドなので、ここでは lua-5.1.5_Win64_bin.zip を選びます。が!ここで注意なのですが、bin.zipのほうはVC+2005でコンパイルされています。そのためランタイムも必要になり、ちょっとめんどくさいです。

また、LuaRocks を動作させるためにはヘッダーファイルが必要となるため、上記 Windows Libraries から lua-5.1.5_Win64_dll16_lib.zip もダウンロードします。
bin.zipのほうはVC+2005でコンパイルされていますが、dll16_lib.zipはVS2019でコンパイルされています。

なので、余計なランタイムをなくすためにも、ここではソースもダウンロードして、Lua 5.1.5もVS2019でコンパイルし直します。ソースはtar ballになっていて、lua-5.1.5.tar.gz からダウンロードできます。

Lua 5.1のコンパイル

ダウンロードしたtar ballをほどいたら、VS2019のNative x64 コマンドプロンプトを開き、lua-5.1.5ディレクトリに移動します。INSTALLファイルを見るとプロジェクトを自分で作ってコンパイルしなさい、とありますが、ここでは簡単に etc\luavs.bat を起動します。必要に応じて src\luaconf.h を編集しなさいともありますが、特に希望はないのでそのままで。

コンパイルが無事に終われば、lua.exe、luac.exe、lua51.dll、lua51.libができています。ここではlua51.libを c:\Apps\Lua\lib に、その他を c:\Apps\Lua\bin にコピーします。
また、lua.h、lua.hpp、luaconf.h、lualib.h、luaxlib.hを c:\Apps\Lua\include にコピーします。lua.hppは etcディレクトリにあるのでご注意。
コピーしたら c:\Apps\Lua\bin にPATHを通して動作チェックです。

LuaRocksのインストール

次にLuaRocksをインストールします。といっても、Installation instructions for Windowsに従って実行形式ファイルをコピーするだけですが。
LuaRocksのダウンロードページから、Windows all-in-one executable (64-bit)をダウンロードします。このzipファイルを開くとluarocks.exeとluarocks-admin.exeがあるので、これを先程の  c:\Apps\Lua\bin コピーします。

コピーしたら、環境変数を設定します。
  • LUA_DIR : c:\Apps\Lua
  • LUA_BINDIR : c:\Apps\Lua\bin
  • LUA_INCDIR : c:\Apps\Lua\include
  • LUA_LIBDIR : c:\Apps\Lua\lib
あるいは、以下のようにしてconfigファイルを作成しておきます。
$ luarocks --lua-version 5.1 config --global variables.LUA_DIR c:\Apps\Lua
$ luarocks --lua-version 5.1 config --global variables.LUA_BINDIR c:\Apps\Lua\bin
$ luarocks --lua-version 5.1 config --global variables.LUA_INCDIR c:\Apps\Lua\include
$ luarocks --lua-version 5.1 config --global variables.LUA_LIBDIR c:\Apps\Lua\lib

します。Luaのデフォルトのバージョンは5.3になっているようで、5.1を利用する場合には --lua-version オプションが必要です。見落としているかもしれませんが、どうもデフォルトで5.1に固定するような設定はなさそうです。

luautf8のコンパイル

次はluautf8のコンパイルです。
これは、VS2019のx64 コマンドプロンプトを開いて、
$ luarocks --lua-version 5.1 --global install luautf8
とします。
$ luarocks --lua-version 5.1 --global install luautf8
Installing https://luarocks.org/luautf8-0.1.3-1.src.rock

luautf8 0.1.3-1 depends on lua >= 5.1 (5.1-1 provided by VM)
cl /nologo /MD /O2 -c -Folutf8lib.obj -Ic:\Apps\Lua\include lutf8lib.c
lutf8lib.c
link -dll -def:lua-utf8.def -out:lua-utf8.dll c:\Apps\Lua\lib/lua51.lib lutf8lib.obj
Microsoft (R) Incremental Linker Version 14.29.30133.0
Copyright (C) Microsoft Corporation.  All rights reserved.

   ライブラリ lua-utf8.lib とオブジェクト lua-utf8.exp を作成中
luautf8 0.1.3-1 is now installed in C:\Users\kats\AppData\Roaming/luarocks (license: MIT)
ちょっと深い場所に出力されていますが、ここでできた lua-utf8.dll をc:\Apps\Lua\bin にコピー、また Neovim から使うには c:\Apps\Neovim\bin にコピーすれば require で参照できます。

Lua 5.3の標準ライブラリと同様に使うために、lua-utf8 を utf8 として参照できるようにします。
> utf8 = require 'lua-utf8'
> print(utf8.reverse('あいうえお'))
おいうえあ
ただ、コマンドプロンプトとかCP932な環境なので今ひとつな感じ。Neovimだけならなんとかなるかしら。

Windowsでシンボリックリンクを試してみる。

きっかけは、1つのファイルを別の名前で起動したら違う動きになるようなスクリプトを書く、でした。  busybox なんかでは、同じ実行形式ファイルの名前を、lsにすればlsと同じ、cpとすればcpと同じ動作をするようにしてますが、Pythonスクリプトでそれと同じように argv...