rem=rem --[[ @setlocal& set luafile="%~f0" & if exist "%~f0.bat" set luafile="%~f0.bat" @lua5.1\bin\lua5.1.exe %luafile% %*& exit /b ]] local vars = {} vars.PREFIX = [[C:\LuaRocks]] vars.VERSION = "2.0" vars.SYSCONFDIR = [[C:\LuaRocks]] vars.ROCKS_TREE = [[C:\LuaRocks]] vars.SCRIPTS_DIR = nil vars.LUA_INTERPRETER = nil vars.LUA_PREFIX = nil vars.LUA_BINDIR = nil vars.LUA_INCDIR = nil vars.LUA_LIBDIR = nil vars.LUA_LIBNAME = nil vars.LUA_VERSION = "5.1" vars.LUA_SHORTV = nil vars.LUA_LIB_NAMES = "lua5.1.lib lua51.dll liblua.dll.a" vars.LUA_RUNTIME = nil local P_SET = false local FORCE = false local FORCE_CONFIG = false local INSTALL_LUA = false local USE_MINGW = false local REGISTRY = false --- -- Some helpers -- local function die(message) if message then print(message) end print() print("Failed installing LuaRocks. Run with /? for help.") os.exit(1) end local function exec(cmd) --print(cmd) local status = os.execute(cmd) return status == 0 end local function exists(filename) local cmd = [[.\bin\test -e "]]..filename..[["]] return exec(cmd) end local function mkdir (dir) return exec([[.\bin\mkdir -p "]]..dir..[[" >NUL]]) end -- interpolate string with values from 'vars' table local function S (tmpl) return (tmpl:gsub('%$([%a_][%w_]*)', vars)) end local function print_help() print(S[[ Installs LuaRocks. /P [dir] (REQUIRED) Where to install. Note that version; $VERSION, will be appended to this path. /CONFIG [dir] Location where the config file should be installed. Default is same place of installation /TREE [dir] Root of the local tree of installed rocks. Default is same place of installation /SCRIPTS [dir] Where to install scripts installed by rocks. Default is TREE/bin. /LV [version] Lua version to use; either 5.1 or 5.2. Default is 5.1 /L Install LuaRocks' own copy of Lua even if detected, this will always be a 5.1 installation. (/LUA, /INC, /LIB, /BIN cannot be used with /L) /LUA [dir] Location where Lua is installed - e.g. c:\lua\5.1\ This is the base directory, the installer will look for subdirectories bin, lib, include. Alternatively these can be specified explicitly using the /INC, /LIB, and /BIN options. /INC [dir] Location of Lua includes - e.g. c:\lua\5.1\include If provided overrides sub directory found using /LUA. /LIB [dir] Location of Lua libraries -e.g. c:\lua\5.1\lib If provided overrides sub directory found using /LUA. /BIN [dir] Location of Lua executables - e.g. c:\lua\5.1\bin If provided overrides sub directory found using /LUA. /MW Use mingw as build system instead of MSVC /FORCECONFIG Use a single config location. Do not use the LUAROCKS_CONFIG variable or the user's home directory. Useful to avoid conflicts when LuaRocks is embedded within an application. /F Remove installation directory if it already exists. /R Load registry information to register '.rockspec' extension with LuaRocks commands (right-click). ]]) end -- *********************************************************** -- Option parser -- *********************************************************** local function parse_options(args) for _, option in ipairs(args) do local name = option.name:upper() if name == "/?" then print_help() os.exit(0) elseif name == "/P" then vars.PREFIX = option.value vars.SYSCONFDIR = option.value vars.ROCKS_TREE = option.value P_SET = true elseif name == "/CONFIG" then vars.SYSCONFDIR = option.value elseif name == "/TREE" then vars.ROCKS_TREE = option.value elseif name == "/SCRIPTS" then vars.SCRIPTS_DIR = option.value elseif name == "/LV" then vars.LUA_VERSION = option.value elseif name == "/L" then INSTALL_LUA = true elseif name == "/MW" then USE_MINGW = true elseif name == "/LUA" then vars.LUA_PREFIX = option.value elseif name == "/LIB" then vars.LUA_LIBDIR = option.value elseif name == "/INC" then vars.LUA_INCDIR = option.value elseif name == "/BIN" then vars.LUA_BINDIR = option.value elseif name == "/FORCECONFIG" then FORCE_CONFIG = true elseif name == "/F" then FORCE = true elseif name == "/R" then REGISTRY = true else die("Unrecognized option: " .. name) end end end -- check for combination/required flags local function check_flags() if not P_SET then die("Missing required parameter /P") end if INSTALL_LUA then if vars.LUA_INCDIR or vars.LUA_BINDIR or vars.LUA_LIBDIR or vars.LUA_PREFIX then die("Cannot combine option /L with any of /LUA /BIN /LIB /INC") end if vars.LUA_VERSION ~= "5.1" then die("Bundled Lua version is 5.1, cannot install 5.2") end end if vars.LUA_VERSION ~= "5.1" then if vars.LUA_VERSION == "5.2" then vars.LUA_LIB_NAMES = vars.LUA_LIB_NAMES:gsub("5([%.]?)1", "5%12") else die("Bad argument: /LV must either be 5.1 or 5.2") end end end -- *********************************************************** -- Detect Lua -- *********************************************************** local function look_for_interpreter (directory) if vars.LUA_BINDIR then if exists( S"$LUA_BINDIR\\lua$LUA_VERSION.exe" ) then vars.LUA_INTERPRETER = S"lua$LUA_VERSION.exe" print(S" Found $LUA_BINDIR\\$LUA_INTERPRETER") return true elseif exists(S"$LUA_BINDIR\\lua.exe") then vars.LUA_INTERPRETER = "lua.exe" print(S" Found $LUA_BINDIR\\$LUA_INTERPRETER") return true elseif exists(S"$LUA_BINDIR\\luajit.exe") then vars.LUA_INTERPRETER = "luajit.exe" print(S" Found $LUA_BINDIR\\$LUA_INTERPRETER") return true end die(S"Lua executable lua.exe, luajit.exe or lua$LUA_VERSION.exe not found in $LUA_BINDIR") end for _, e in ipairs{ [[\]], [[\bin\]] } do if exists(directory..e.."\\lua"..vars.LUA_VERSION..".exe") then vars.LUA_INTERPRETER = S"lua$LUA_VERSION.exe" vars.LUA_BINDIR = directory .. e print(" Found ."..e..vars.LUA_INTERPRETER) return true elseif exists(directory..e.."\\lua.exe") then vars.LUA_INTERPRETER = "lua.exe" vars.LUA_BINDIR = directory..e print(" Found ."..e..vars.LUA_INTERPRETER) return true elseif exists(directory..e.."\\luajit.exe") then vars.LUA_INTERPRETER = "luajit.exe" vars.LUA_BINDIR = directory..e print(" Found ."..e..vars.LUA_INTERPRETER) return true end end print(" No Lua interpreter found") return false end local function look_for_link_libraries (directory) if vars.LUA_LIBDIR then for name in vars.LUA_LIB_NAMES:gmatch("[^%s]+") do print(S" checking for $LUA_LIBDIR\\"..name) if exists(vars.LUA_LIBDIR.."\\"..name) then vars.LUA_LIBNAME = name print(" Found "..name) return true end end die(S"link library (one of; $LUA_LIB_NAMES) not found in $LUA_LIBDIR") end for _, e in ipairs{ [[\]], [[\lib\]], [[\bin\]]} do for name in vars.LUA_LIB_NAMES:gmatch("[^%s]+") do print(" checking for "..directory..e.."\\"..name) if exists(directory..e.."\\"..name) then vars.LUA_LIBDIR = directory .. e vars.LUA_LIBNAME = name print(" Found "..name) return true end end end return false end local function look_for_headers (directory) if vars.LUA_INCDIR then print(S" checking for $LUA_INCDIR\\lua.h") if exists(S"$LUA_INCDIR\\lua.h") then print(" Found lua.h") return true end die(S"lua.h not found in $LUA_INCDIR") end for _, e in ipairs{ [[\]], [[\include\]]} do print(" checking for "..directory..e.."\\lua.h") if exists(directory..e.."\\lua.h") then vars.LUA_INCDIR = directory..e print(" Found lua.h") return true end end return false end -- Checks a binary file for the runtime dll used by it. If nu runtime is found, it returns an -- array of dll's is depends upon. -- result: string = runtime used, table = list of dll's depended upon, nil = nothing found. local function get_file_runtime(p,f) -- path, filename local infile = p.."\\"..f local outfile = "output.txt" local content -- analyze binary if exec([[.\bin\objdump -x "]]..infile..[[" > ]]..outfile..[[ 2<&1]]) then -- read temp file local fh = io.open(outfile) content = fh:read("*a") fh:close() end -- delete temp file os.remove(outfile) if not content then print(" Failed to analyze "..infile.." for the runtime used") return nil end -- lookup content = content:upper() local result = content:match('DLL NAME%: (MSVCR%d*)%.DLL') if not result then result = content:match('DLL NAME%: (MSVCRT)%.DLL') end if result then print(" "..f.." uses "..tostring(result)..".DLL as runtime") else print(" No runtime found for "..f) -- so; create a list of dll's this file is depending upon, next level of the tree result = {} for name in content:gmatch("DLL NAME%: (.-%.DLL)") do --print("found dll:", name) table.insert(result, name) end end return result end local function get_runtime() -- first check interpreter vars.LUA_RUNTIME = get_file_runtime(vars.LUA_BINDIR, vars.LUA_INTERPRETER) if type(vars.LUA_RUNTIME) == "table" then -- a table with dll's depended upon was returned, check this list -- note: we only check 1 level deep for _,dll in ipairs(vars.LUA_RUNTIME) do local t = get_file_runtime(vars.LUA_BINDIR, dll) if type(t) == "string" then -- found it vars.LUA_RUNTIME = t break end end end if type(vars.LUA_RUNTIME) ~= "string" then -- analysis failed, issue a warning vars.LUA_RUNTIME = "MSVCR80" print("*** WARNING ***: could not analyse the runtime used, defaulting to "..vars.LUA_RUNTIME) end return true end local function look_for_lua_install () print("Looking for Lua interpreter") local directories = { [[c:\lua5.1.2]], [[c:\lua]], [[c:\kepler\1.1]] } if vars.LUA_PREFIX then table.insert(directories, 1, vars.LUA_PREFIX) end if vars.LUA_BINDIR and vars.LUA_LIBDIR and vars.LUA_INCDIR then if look_for_interpreter(vars.LUA_BINDIR) and look_for_link_libraries(vars.LUA_LIBDIR) and look_for_headers(vars.LUA_INCDIR) then if exec(S"$LUA_BINDIR\\$LUA_INTERPRETER -v 2>NUL") then print(" Ok") return true end end return false end for _, directory in ipairs(directories) do print(" checking " .. directory) if exists(directory) then if look_for_interpreter(directory) then print("Interpreter found, now looking for link libraries...") if look_for_link_libraries(directory) then print("Link library found, now looking for headers...") if look_for_headers(directory) then print("Headers found, checking runtime to use...") if get_runtime() then print("Runtime check completed, now testing interpreter...") if exec(S[[$LUA_BINDIR\$LUA_INTERPRETER -v 2>NUL]]) then print(" Ok") return true end print(" Interpreter returned an error, not ok") end end end end end end return false end --- -- Poor man's command-line parsing local config = {} local with_arg = { -- options followed by an argument, others are flags ["/P"] = true, ["/CONFIG"] = true, ["/TREE"] = true, ["/SCRIPTS"] = true, ["/LV"] = true, ["/LUA"] = true, ["/INC"] = true, ["/BIN"] = true, ["/LIB"] = true, } local i = 1 while i <= #arg do local opt = arg[i] if with_arg[opt] then local value = arg[i + 1] if not value then die("Missing value for option "..opt) end config[#config + 1] = { name = opt, value = value } i = i + 1 else config[#config + 1] = { name = opt } end i = i + 1 end print(S"LuaRocks $VERSION.x installer.\n") parse_options(config) check_flags() vars.FULL_PREFIX = S"$PREFIX\\$VERSION" vars.BINDIR = vars.FULL_PREFIX vars.LIBDIR = vars.FULL_PREFIX vars.LUADIR = S"$FULL_PREFIX\\lua" vars.INCDIR = S"$FULL_PREFIX\\include" vars.LUA_SHORTV = vars.LUA_VERSION:gsub("%.", "") if not look_for_lua_install() then print("Could not find Lua. Will install its own copy.") print("See /? for options for specifying the location of Lua.") if vars.LUA_VERSION ~= "5.1" then die("Cannot install own copy because no 5.2 version is bundled") end INSTALL_LUA = true vars.LUA_INTERPRETER = "lua5.1" vars.LUA_BINDIR = vars.BINDIR vars.LUA_LIBDIR = vars.LIBDIR vars.LUA_INCDIR = vars.INCDIR vars.LUA_LIBNAME = "lua5.1.lib" vars.LUA_RUNTIME = "MSVCR80" else print(S[[ Will configure LuaRocks with the following paths: LuaRocks : $FULL_PREFIX Lua interpreter: $LUA_BINDIR\$LUA_INTERPRETER Lua binaries : $LUA_BINDIR Lua libraries : $LUA_LIBDIR Lua includes : $LUA_INCDIR Binaries will be linked against: $LUA_LIBNAME with runtime $LUA_RUNTIME ]]) end -- *********************************************************** -- Install LuaRocks files -- *********************************************************** if FORCE then print(S"Removing $FULL_PREFIX...") exec(S[[RD /S /Q "$FULL_PREFIX"]]) print() end if exists(vars.FULL_PREFIX) then die(S"$FULL_PREFIX exists. Use /F to force removal and reinstallation.") end print(S"Installing LuaRocks in $FULL_PREFIX...") if not exists(vars.BINDIR) then if not mkdir(vars.BINDIR) then die() end end if INSTALL_LUA then -- Copy the included Lua interpreter binaries if not exists(vars.LUA_BINDIR) then mkdir(vars.LUA_BINDIR) end if not exists(vars.LUA_INCDIR) then mkdir(vars.LUA_INCDIR) end exec(S[[COPY lua5.1\bin\*.* "$LUA_BINDIR" >NUL]]) exec(S[[COPY lua5.1\include\*.* "$LUA_INCDIR" >NUL]]) print(S"Installed the LuaRocks bundled Lua interpreter in $LUA_BINDIR") end -- Copy the LuaRocks binaries if not exec(S[[COPY bin\*.* "$BINDIR" >NUL]]) then die() end -- Copy the LuaRocks lua source files if not exists(S[[$LUADIR\luarocks]]) then if not mkdir(S[[$LUADIR\luarocks]]) then die() end end if not exec(S[[XCOPY /S src\luarocks\*.* "$LUADIR\luarocks" >NUL]]) then die() end -- Create start scripts if not exec(S[[COPY src\bin\*.* "$BINDIR" >NUL]]) then die() end for _, c in ipairs{"luarocks", "luarocks-admin"} do -- rename unix-lua scripts to .lua files if not exec( (S[[RENAME "$BINDIR\%s" %s.lua]]):format(c, c) ) then die() end -- create a bootstrap batch file for the lua file, to start them exec(S[[DEL /F /Q "$BINDIR\]]..c..[[.bat" 2>NUL]]) local f = io.open(vars.BINDIR.."\\"..c..".bat", "w") f:write(S[[ @ECHO OFF SETLOCAL SET LUA_PATH=$LUADIR\?.lua;$LUADIR\?\init.lua;%LUA_PATH% SET PATH=$BINDIR\;%PATH% "$LUA_INTERPRETER" "$BINDIR\]]..c..[[.lua" %* ENDLOCAL ]]) f:close() print(S"Created LuaRocks command: $BINDIR\\"..c..".bat") end -- configure 'scripts' directory if vars.SCRIPTS_DIR then mkdir(vars.SCRIPTS_DIR) if not USE_MINGW then -- definitly not for MinGW because of conflicting runtimes -- but is it ok to do it for others??? exec(S[[COPY lua5.1\bin\*.dll "$SCRIPTS_DIR" >NUL]]) end else if not USE_MINGW then mkdir(S[[$ROCKS_TREE\bin]]) -- definitly not for MinGW because of conflicting runtimes -- but is it ok to do it for others??? exec(S[[COPY lua5.1\bin\*.dll "$ROCKS_TREE"\bin >NUL]]) end end print() print("Configuring LuaRocks...") -- Create a site-config file if exists(S[[$LUADIR\luarocks\site_config.lua]]) then exec(S[[RENAME "$LUADIR\luarocks\site_config.lua" site_config.lua.bak]]) end local f = io.open(vars.LUADIR.."\\luarocks\\site_config.lua", "w") f:write(S[=[ module("luarocks.site_config") LUA_INCDIR=[[$LUA_INCDIR]] LUA_LIBDIR=[[$LUA_LIBDIR]] LUA_BINDIR=[[$LUA_BINDIR]] LUA_INTERPRETER=[[$LUA_INTERPRETER]] ]=]) if USE_MINGW then f:write("LUAROCKS_UNAME_S=[[MINGW]]\n") else f:write("LUAROCKS_UNAME_S=[[WindowsNT]]\n") end f:write(S[=[ LUAROCKS_UNAME_M=[[x86]] LUAROCKS_SYSCONFIG=[[$SYSCONFDIR\config.lua]] LUAROCKS_ROCKS_TREE=[[$ROCKS_TREE]] LUAROCKS_PREFIX=[[$PREFIX]] LUAROCKS_DOWNLOADER=[[wget]] LUAROCKS_MD5CHECKER=[[md5sum]] ]=]) if FORCE_CONFIG then f:write("local LUAROCKS_FORCE_CONFIG=true\n") end if exists(vars.LUADIR.."\\luarocks\\site_config.lua.bak") then for line in io.lines(vars.LUADIR.."\\luarocks\\site_config.lua.bak", "r") do f:write(line) f:write("\n") end exec(S[[DEL /F /Q "$LUADIR\luarocks\site_config.lua.bak"]]) end f:close() print(S[[Created LuaRocks site-config file: $LUADIR\luarocks\site_config.lua]]) -- create config file vars.CONFIG_FILE = vars.SYSCONFDIR.."\\config.lua" if not exists(vars.SYSCONFDIR) then mkdir(vars.SYSCONFDIR) end if not exists(vars.CONFIG_FILE) then local f = io.open(vars.CONFIG_FILE, "w") f:write([=[ rocks_servers = { [[http://luarocks.org/repositories/rocks]] } rocks_trees = { ]=]) if FORCE_CONFIG then f:write(" home..[[/luarocks]],\n") end f:write(S" [[$ROCKS_TREE]]\n") f:write("}\n") if vars.SCRIPTS_DIR then f:write(S"scripts_dir=[[$SCRIPTS_DIR]]\n") end f:write("variables = {\n") if USE_MINGW and vars.LUA_RUNTIME == "MSVCRT" then f:write(" MSVCRT = 'm', -- make MinGW use MSVCRT.DLL as runtime\n") else f:write(" MSVCRT = '"..vars.LUA_RUNTIME.."',\n") end f:write(S" LUALIB = '$LUA_LIBNAME'\n") f:write("}\n") f:close() print(S"Created LuaRocks config file: $CONFIG_FILE") else print(S"LuaRocks config file already exists: $CONFIG_FILE") end print() print("Creating rocktrees...") if not exists(vars.ROCKS_TREE) then mkdir(vars.ROCKS_TREE) print(S[[Created rocktree: "$ROCKS_TREE"]]) else print(S[[Rocktree exists: "$ROCKS_TREE"]]) end local APPDATA = os.getenv("APPDATA") if not exists(APPDATA.."\\luarocks") then mkdir(APPDATA.."\\luarocks") print([[Created rocktree: "]]..APPDATA..[[\luarocks"]]) else print([[Rocktree exists: "]]..APPDATA..[[\luarocks"]]) end -- Load registry information if REGISTRY then -- expand template with correct path information print() print([[Loading registry information for ".rockspec" files]]) exec( S[[lua5.1\bin\lua5.1.exe "$FULL_PREFIX\create_reg_file.lua" "$FULL_PREFIX\LuaRocks.reg.template"]] ) exec( S"$FULL_PREFIX\\LuaRocks.reg" ) end -- *********************************************************** -- Exit handlers -- *********************************************************** print(S[[ *** LuaRocks is installed! *** You may want to add the following elements to your paths; PATH : $LUA_BINDIR;$FULL_PREFIX LUA_PATH : $ROCKS_TREE\share\lua\$LUA_VERSION\?.lua;$ROCKS_TREE\share\lua\$LUA_VERSION\?\init.lua LUA_CPATH: $LUA_LIBDIR\lua\$LUA_VERSION\?.dll ]]) os.exit(0)