Luarocks в Windows

Всё началось с Moonscript и Haxe: мне захотелось поразвлечься с этими новыми для меня языками. Оба позволяют транспилировать свои программы в Lua, а Lua, на мой взгляд, это один из наиболее актуальных языков, поскольку много какое используемое мною ПО позволяет на нём писать внутренние скрипты.

В Lua .hx (Haxe) транспилировался, но выполняться отказался, требуя модуль lua-utf8. Его необходимо было поставить через luarocks.

На мой взгляд, luarocks документирован плохо и совершенно не очевидно, как оно работает. А работает он так.

luarocks при запуске ищет в директориях по умолчанию (c:\users\user\appdata\luarocks) конфигурационный файл, имя которого зависит от версии Lua. В моём случае это config-5.3.lua.

В этом файле много чего требуется написать. У меня конфиг сейчас выглядит вот так:

arch = "win32-x86_64"
cmake_generator = "MinGW Makefiles"
deploy_bin_dir = "c:/users/user/.luarocks/bin"
deploy_lib_dir = "c:/users/user/.luarocks/lib/lua/5.3"
deploy_lua_dir = "c:/users/user/.luarocks/share/lua/5.3"
export_path_separator = ";"
external_deps_dirs = {
   "c:/mingw",
   "c:/windows/SysWOW64",
   "c:/windows/System32"
}
external_deps_patterns = {
   bin = {
      "?.exe",
      "?.bat"
   },
   include = {
      "?.h"
   },
   lib = {
      "lib?.dll.a",
      "?.dll.a",
      "lib?.a",
      "cyg?.dll",
      "lib?.dll",
      "?.dll",
      "?.lib"
   }
}
external_deps_subdirs = {
   bin = "bin",
   include = "include",
   lib = {
      "",
      "lib",
      "bin"
   }
}
external_lib_extension = "dll"
home = "C:\\Users\\user\\AppData\\Roaming"
home_tree = "C:\\Users\\user\\AppData\\Roaming/luarocks"
homeconfdir = "C:\\Users\\user\\AppData\\Roaming/luarocks"
lib_extension = "dll"
link_lua_explicitly = true
local_by_default = false
local_cache = "C:\\Users\\user\\AppData\\Local/LuaRocks/Cache"
lua_extension = "lua"
lua_interpreter = "lua.exe"
lua_version = "5.3"
makefile = "Makefile"
no_manifest = false
obj_extension = "o"
processor = "x86_64"
rocks_trees = {
   {
      name = "user",
      root = "C:\\Users\\user\\AppData\\Roaming/luarocks"
   }
}
rocks_dir = "c:/users/user/.luarocks/lib/luarocks/rocks-5.3"
rocks_servers = {
   {
      "https://luarocks.org",
      "https://raw.githubusercontent.com/rocks-moonscript-org/moonrocks-mirror/master/",
      "http://luafr.org/moonrocks/",
      "http://luarocks.logiceditor.com/rocks"
   }
}
runtime_external_deps_patterns = {
   bin = {
      "?.exe",
      "?.bat"
   },
   include = {
      "?.h"
   },
   lib = {
      "?.dll",
      "cyg?.dll",
      "lib?.dll"
   }
}
runtime_external_deps_subdirs = {
   bin = "bin",
   include = "include",
   lib = {
      "",
      "lib",
      "bin"
   }
}
static_lib_extension = "a"
target_cpu = "x86_64"
variables = {
   AR = "C:\\MinGW\\bin\\ar.exe",
   CC = "C:\\MinGW\\bin\\gcc.exe",
   CFLAGS = "-O2",
   CMAKE = "cmake",
   LD = "C:\\MinGW\\bin\\gcc.exe",
   LIBFLAG = "-shared",
   LIB_EXTENSION = "dll",
   LUALIB = "lua53.dll",
   LUA_LIBDIR_FILE = "lua53.dll",
   LUA_DIR = "C:/ProgramData/chocolatey/lib/lua53/tools",
   LUA_BINDIR = "C:/ProgramData/chocolatey/lib/lua53/tools",
   LUA_INCDIR = "C:/Lua/include",
   LUA_LIBDIR = "C:/Lua/lib",
   MSVCRT = "msvcrt",
   ROCKS_TREE = "c:/users/user/.luarocks/lib/luarocks/rocks-5.3"
}
verbose = true

При таких настройках библиотеки нормально собираются (за исключением тех, которые имеют типично линуксовые зависимости) в dll и кладутся в папку C:\Users\user\AppData\Roaming\LuaRocks\lib\lua\5.3 (см. deploy_lib_dir).

Lua 5.3 — x64; его можно установить при помощи Chocolatey, а можно просто взять бинарники на SourceForge, взяв заодно и lua-5.3.6_win64_dllw6_lib.zip. MinGW x64 можно взять на nuwen.net и распаковать его в C:\MinGW.

После этого создадим C:\Lua\includes и положим туда файлы заголовков из lua-5.3.6_win64_dllw6_lib.zip, а .dll и .a положим в C:\Lua\lib.

Необходимо добавить к окружению переменную LUA_CPATH=C:\Users\user\AppData\Roaming\LuaRocks\lib\lua\5.3\?.dll, которая означает, что Lua будет искать C-библиотеки в этой папке с именем библиотека.dll. Если собрать luafilesystem (luarocks install luafilesystem), то в этой папке появится lfs.dll. Эту библиотеку можно подгрузить к интерпретатору командой lua -l lfs, и если всё нормально, то интерпретатор загрузится без сообщений.

Для точности хорошо бы ещё добавить к LUA_CPATH строки C:\Users\user\AppData\Roaming\LuaRocks\lib\lua\5.3\?\core.dll и .\?.dll.

На будущее сразу стоит добавить переменную окружения LUA_PATH: LUA_PATH=C:\Users\user\AppData\Roaming\LuaRocks\share\lua\5.3\?.lua;C:\Users\user\AppData\Roaming\LuaRocks\share\lua\5.3\?\init.lua.

Людям, не понимающим, как работает вызов функций в сишных библиотеках, возможно придётся помучаться, потому что правильно собрать эти библиотеки тоже надо уметь (немаловажно, чем собирать и под какую архитектуру). Самый важный параметр в этом — MSVCRT в конфиге, потому что содержимое этого параметра передаётся компилятору при сборке (для gcc, которым я собираю, получается -lmsvcrt).

Теперь заголовки лежат на своём месте, компилятор найден, нужная библиотека функций Windows линкована динамически.

Командой luarocks install luautf8 скачиваем и собираем библиотеку. После того, как она установится, можно попробовать запустить интерпретатор, набрав в строке lua -l lua-utf8.

Теперь Lua-код, транспилированный из Haxe, исполняется и показывает юникод (проверено).