Skip to content

Instantly share code, notes, and snippets.

@brostosjoined
Last active August 29, 2024 21:57
Show Gist options
  • Save brostosjoined/df1de02541bb33869431309fd2a74a4b to your computer and use it in GitHub Desktop.
Save brostosjoined/df1de02541bb33869431309fd2a74a4b to your computer and use it in GitHub Desktop.
Automated Installion of Lua (and wlua!),Luarocks and Luasocket on native Windows (not WSL)

Automated Installion of Lua (and wlua!),Luarocks and Luasocket on native Windows (not WSL)

Thanks to Frityet's gist instructions now you can easily install lua,wlua and luarocks easily from this automated powershell script. Added a patch to make Luasocket compile using this PR.

Running the Script

  • To execute the script, open your terminal and run the following command:
powershell -executionpolicy bypass -File .\lua_installer.ps1
  • If you need wlua just add -wLua argument after the command like this.
powershell -executionpolicy bypass -File .\lua_installer.ps1 -wLua

Modification

You can easily modify the script to choose the compiler and lua version by just editing the variables on the top of the script.

$luaVersion = "5.4.7" # Choose your Lua Version 
$luaVersionMajor = "54"  # Major version for Lua library eg lua54.dll
$releaseDate = "20240619" # LLVM release date

# Define URL variables for downloading
$llvmUrl = "https://github.com/mstorsjo/llvm-mingw/releases/download/$releaseDate/llvm-mingw-$releaseDate-ucrt-$targetArch.zip"
$luaUrl = "https://www.lua.org/ftp/lua-$luaVersion.tar.gz"
$luarocksUrl = "https://github.com/luarocks/luarocks/archive/refs/heads/master.zip" # Source code
# powershell -executionpolicy bypass -File .\test.ps1 #add -wLua argument if you need to install it
# Did some monkey patching to make luasocket work by downloading latest and changing version number
# Check if wlua arugument is passed
param (
[switch]$wLua
)
# Define variables for version numbers and directories
$luaVersion = "5.4.7"
$luaVersionMajor = "54" # Major version for Lua library
$luarocksVersion = "3.11.1"
$luasocketVersion = "3.1.0"
$releaseDate = "20240619" # LLVM release date
$programFilesDir = "C:\Program Files"
# Retrieve the processor architecture
$processorArch = (Get-CimInstance Win32_Processor).Architecture
# Map the architecture number to a string
switch ($processorArch) {
0 { $targetArch = "i686" } # x86
9 { $targetArch = "x86_64" } # x86_64 (AMD64)
12 { $targetArch = "armv7" } # ARM
14 { $targetArch = "aarch64" } # ARM64
default {
Write-Output "Unsupported architecture number: $processorArch"
exit 1
}
}
if ($targetArch -eq "x86_64") {
$targetArchBit = "64"}
else {
$targetArchBit = "32" <# Action when all if and elseif conditions are false #>
}
# Define URL variables for downloading
$llvmUrl = "https://github.com/mstorsjo/llvm-mingw/releases/download/$releaseDate/llvm-mingw-$releaseDate-ucrt-$targetArch.zip"
$luaUrl = "https://www.lua.org/ftp/lua-$luaVersion.tar.gz"
$luarocksUrl = "https://luarocks.github.io/luarocks/releases/luarocks-$luarocksVersion-windows-$targetArchBit.zip"
$luasocketUrl = "https://github.com/lunarmodules/luasocket/archive/refs/tags/v$luasocketVersion.zip"
# Define output folder
$outputFolder = "$env:TEMP\luainstaller"
if (-not (Test-Path -Path $outputFolder)) {
New-Item -ItemType Directory -Path $outputFolder
}
# Define file names
$llvmFileName = [System.IO.Path]::GetFileName($llvmUrl)
$luaFileName = [System.IO.Path]::GetFileName($luaUrl)
$luarocksFileName = [System.IO.Path]::GetFileName($luarocksUrl)
$luasocketFileName = [System.IO.Path]::GetFileName($luasocketUrl)
# Download files
$wc = New-Object System.Net.WebClient
$files = @{
$llvmFileName = $llvmUrl
$luaFileName = $luaUrl
$luarocksFileName = $luarocksUrl
$luasocketFileName = $luasocketUrl
}
foreach ($file in $files.GetEnumerator()) {
$fileName = $file.Key
$url = $file.Value
$outputPath = Join-Path -Path $outputFolder -ChildPath $fileName
Write-Output "Downloading $fileName"
$wc.DownloadFile($url, $outputPath)
Write-Output "Completed $fileName"
}
# Install 7-Zip module for extraction
Write-Output "Downloading 7zip to extract tar files"
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
Install-Module -Name 7Zip4Powershell -RequiredVersion 2.0.0 -Force
Import-Module 7Zip4Powershell
# Define file paths for extraction
$luaSource = Join-Path -Path $outputFolder -ChildPath $luaFileName
$llvmSource = Join-Path -Path $outputFolder -ChildPath $llvmFileName
$luarocksSource = Join-Path -Path $outputFolder -ChildPath $luarocksFileName
$luasocketSource = Join-Path -Path $outputFolder -ChildPath $luasocketFileName
# Define destination paths
$llvmDestination = "$programFilesDir\LLVM"
# Extract Lua
Write-Output "Extracting Lua"
$tarFile = Join-Path -Path $outputFolder -ChildPath "lua-$luaVersion.tar"
Expand-7Zip -ArchiveFileName $luaSource -TargetPath $outputFolder
Expand-7Zip -ArchiveFileName $tarFile -TargetPath $outputFolder
# Extract LLVM
Write-Output "Extracting LLVM"
Expand-7Zip -ArchiveFileName $llvmSource -TargetPath $llvmDestination
# Extract Luarocks
Write-Output "Extracting Luarocks"
Expand-7Zip -ArchiveFileName $luarocksSource -TargetPath $outputFolder
# Extract Luasocket
Write-Output "Extracting Luasocket"
Expand-7Zip -ArchiveFileName $luasocketSource -TargetPath $outputFolder
# Create symbolic link for make
Write-Output "Creating symbolic link for make"
$llvmFolderName = [System.IO.Path]::GetFileNameWithoutExtension($llvmFileName)
$makePath = "$llvmDestination\$llvmFolderName\bin\make.exe"
$mingw32MakePath = "$llvmDestination\$llvmFolderName\bin\mingw32-make.exe"
if (-Not (Test-Path -Path $makePath)) {
# Create the symbolic link if it does not exist
New-Item -ItemType SymbolicLink -Path $makePath -Target $mingw32MakePath
Write-Output "Symbolic link created."
} else {
Write-Output "Symbolic link already exists."
}
# Add paths to system PATH variable
Write-Output "Adding paths to system PATH variable"
$newPaths = @(
"$llvmDestination\$llvmFolderName\bin",
"$programFilesDir\Lua\bin",
"$programFilesDir\Lua\lib",
"$programFilesDir\Luarocks"
)
# Retrieve the current Path environment variable
$originalPath = [System.Environment]::GetEnvironmentVariable("Path", "Machine")
# Split the original Path into an array of individual paths
$existingPaths = $originalPath -split ";"
# Filter out paths that are already in the existing Path
$pathsToAdd = $newPaths | Where-Object { $_ -notin $existingPaths }
if ($pathsToAdd.Count -gt 0) {
# If there are paths to add, update the Path environment variable
$updatedPath = "$originalPath;" + ($pathsToAdd -join ";")
[System.Environment]::SetEnvironmentVariable("Path", $updatedPath, "Machine")
# Refresh the current session's environment variables
$env:Path = $updatedPath
Write-Output "Paths added successfully."
} else {
Write-Output "No new paths to add."
}
# Compile Lua
$luaSourceDir = Join-Path -Path $outputFolder -ChildPath "lua-$luaVersion"
$makefilePath = Join-Path -Path $luaSourceDir -ChildPath "Makefile"
$content = Get-Content -Path $makefilePath
# Define paths for the executables
$makePath = "C:\Program Files\LLVM\llvm-mingw-20240619-ucrt-$targetArch\bin\make.exe"
$windresPath = "C:\Program Files\LLVM\llvm-mingw-20240619-ucrt-$targetArch\bin\windres.exe"
$gccPath = "C:\Program Files\LLVM\llvm-mingw-20240619-ucrt-$targetArch\bin\gcc.exe"
# Define commands
$makeCommand = "& '$makePath' mingw"
$windresCommand = "& '$windresPath' wlua.rc -O coff -o resources.o"
$gccCommand = "& '$gccPath' resources.o lua.o -o wlua.exe lua$luaVersionMajor.dll -mwindows"
# Perform the replacements
Write-Output "Modifying Makefile to Work with windows"
$updatedContent = $content `
-replace '\$\(\s*MAKE\s*\)', '"$(MAKE)"' `
-replace '\$\s*V\s*', '$(V)' `
-replace '\$\s*R\s*', '$(R)' `
-replace '\$\(\s*INSTALL_BIN\s*\)', '"$(INSTALL_BIN)"' `
-replace '\$\(\s*INSTALL_INC\s*\)', '"$(INSTALL_INC)"' `
-replace '\$\(\s*INSTALL_LIB\s*\)', '"$(INSTALL_LIB)"' `
-replace '\$\(\s*INSTALL_MAN\s*\)', '"$(INSTALL_MAN)"' `
-replace '\$\(\s*INSTALL_LMOD\s*\)', '"$(INSTALL_LMOD)"' `
-replace '\$\(\s*INSTALL_CMOD\s*\)', '"$(INSTALL_CMOD)"' `
-replace '\$\(\s*INSTALL_EXEC\s*\)', '"$(INSTALL_EXEC)"' `
-replace '\$\(\s*INSTALL_DATA\s*\)', '"$(INSTALL_DATA)"'
Set-Content -Path $makefilePath -Value $updatedContent
# Build Lua
Write-Output "Compiling Lua"
Start-Process powershell -ArgumentList @(
"-Command", # Specify the command to run
"cd '$luaSourceDir'; $makeCommand" # Navigate to the directory and run the command
) -Wait
# Setup Lua installation directory
Write-Output "Setting up Lua installation directory"
$luaOutputFolder = "$programFilesDir\Lua"
New-Item -ItemType Directory -Path $luaOutputFolder -Force
New-Item -ItemType Directory -Path "$luaOutputFolder\bin" -Force
New-Item -ItemType Directory -Path "$luaOutputFolder\lib" -Force
New-Item -ItemType Directory -Path "$luaOutputFolder\include" -Force
# Copy Lua files to the installation directory
Write-Output "Copying Lua files to the installation directory"
Copy-Item -Path (Join-Path -Path $luaSourceDir -ChildPath "src\lua.exe") -Destination "$luaOutputFolder\bin"
Copy-Item -Path (Join-Path -Path $luaSourceDir -ChildPath "src\luac.exe") -Destination "$luaOutputFolder\bin"
Copy-Item -Path (Join-Path -Path $luaSourceDir -ChildPath "src\lua$luaVersionMajor.dll") -Destination "$luaOutputFolder\lib"
Copy-Item -Path (Join-Path -Path $luaSourceDir -ChildPath "src\liblua.a") -Destination "$luaOutputFolder\lib"
Copy-Item -Path (Join-Path -Path $luaSourceDir -ChildPath "src\lua.h") -Destination "$luaOutputFolder\include"
Copy-Item -Path (Join-Path -Path $luaSourceDir -ChildPath "src\lualib.h") -Destination "$luaOutputFolder\include"
Copy-Item -Path (Join-Path -Path $luaSourceDir -ChildPath "src\lauxlib.h") -Destination "$luaOutputFolder\include"
Copy-Item -Path (Join-Path -Path $luaSourceDir -ChildPath "src\luaconf.h") -Destination "$luaOutputFolder\include"
Copy-Item -Path (Join-Path -Path $luaSourceDir -ChildPath "src\lua.hpp") -Destination "$luaOutputFolder\include"
# Compile Wlua
# Function to handle wLua installation and configuration
function Install-wLua {
$manifestFilePath = Join-Path -Path $luaSourceDir -ChildPath "src\wlua.manifest"
$luaCFilePath = Join-Path -Path $luaSourceDir -ChildPath "src\lua.c"
# Modify lua.c file
$fileContent = Get-Content -Path $luaCFilePath
$insertLines = @"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
"@
$index = $fileContent.IndexOf("#include <signal.h>")
if ($index -ne -1) {
$fileContent = $fileContent[0..($index)] + $insertLines + $fileContent[($index + 1)..($fileContent.Length - 1)]
Set-Content -Path $luaCFilePath -Value $fileContent
} else {
Write-Output "Line '#include <signal.h>' not found in the file."
}
$fileContent = Get-Content -Path $luaCFilePath -Raw
$newLMessage = @"
static void l_message (const char *pname, const char *msg) {
char buffer[1024] = {0};
strncpy(buffer, msg, 1024);
pname = pname ? pname : "Error";
MessageBox(NULL, buffer, pname, MB_OK | MB_ICONERROR);
}
"@
$fileContent = $fileContent -replace "(?s)static void l_message \(const char \*pname, const char \*msg\) \{.*?\}", $newLMessage
Set-Content -Path $luaCFilePath -Value $fileContent
Write-Output "l_message function replaced successfully!"
$codeSnippet = @"
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
return main(__argc, __argv);
}
"@
$fileContent += $codeSnippet
Set-Content -Path $luaCFilePath -Value $fileContent
Write-Output "Code snippet added successfully!"
$manifestContent = @"
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
</application>
</compatibility>
<dependency>
<dependentAssembly>
<!-- Visual styles -->
<assemblyIdentity type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"/>
</dependentAssembly>
</dependency>
</assembly>
"@
Set-Content -Path $manifestFilePath -Value $manifestContent
$resourceFilePath = Join-Path -Path $luaSourceDir -ChildPath "src\wlua.rc"
$rcContent = @"
// this is a UTF-8 file
#pragma code_page(65001)
1 24 "wlua.manifest"
"@
Set-Content -Path $resourceFilePath -Value $rcContent
$srcFilePath = Join-Path -Path $luaSourceDir -ChildPath "src"
Start-Process powershell -ArgumentList @(
"-Command",
"cd '$srcFilePath'; $windresCommand"
) -Wait
Start-Process powershell -ArgumentList @(
"-Command",
"cd '$srcFilePath'; $makeCommand"
) -Wait
Remove-Item -Path "$luaSourceDir\src\lua.exe"
Start-Process powershell -ArgumentList @(
"-Command",
"cd '$srcFilePath'; $gccCommand"
) -Wait
Copy-Item -Path (Join-Path -Path $luaSourceDir -ChildPath "src\wlua.exe") -Destination "$luaOutputFolder\bin"
Write-Output "Wlua installed."
}
# Check if the -wLua argument is passed
if ($wLua) {
Install-Wlua
}
# Copy Luarocks
Write-Output "Copying Luarocks"
$luarocksInstallPath = Join-Path -Path $programFilesDir -ChildPath "Luarocks"
$luarocksFolderName = [System.IO.Path]::GetFileNameWithoutExtension($luarocksFileName)
$luarocksFolderPath = Join-Path -Path $outputFolder -ChildPath $luarocksFolderName
# Get all .exe files from the source directory and its subdirectories
$exeFiles = Get-ChildItem -Path $luarocksFolderPath -Filter *.exe -Recurse
# Copy each .exe file to the destination directory
foreach ($file in $exeFiles) {
$destinationPath = Join-Path -Path $luarocksInstallPath -ChildPath $file.Name
New-Item -ItemType Directory -Path $luarocksInstallPath -Force
Copy-Item -Path $file.FullName -Destination $destinationPath -Force
Write-Host "Copied $($file.FullName) to $destinationPath"
}
Write-Host "Luarocks copying completed."
# Configure Luarocks
# Define the path to the Lua configuration file
$luaVersionShort = "$($luaVersionMajor.Substring(0,1)).$($luaVersionMajor.Substring(1,1))"
$configFilePath = "$env:APPDATA\luarocks\config-$luaVersionShort.lua"
# Create the file if it does not exist
if (-not (Test-Path -Path $configFilePath)) {
# Create the file
New-Item -Path $configFilePath -ItemType File -Force
Write-Output "Configuration file created at $configFilePath"
} else {
Write-Output "Configuration file already exists at $configFilePath"
}
# Define the content for the Lua config file
$luaConfigContent = @"
local function q(x) return '"'..x..'"' end
variables = {
ucrt = q[[UCRTBASE]],
CC = q[[C:\Program Files\LLVM\llvm-mingw-20240619-ucrt-$targetArch\bin\$targetArch-w64-mingw32-gcc.exe]],
MAKE = q[[C:\Program Files\LLVM\llvm-mingw-20240619-ucrt-$targetArch\bin\make.exe]],
RC = q[[C:\Program Files\LLVM\llvm-mingw-20240619-ucrt-$targetArch\bin\windres.exe]],
LD = q[[C:\Program Files\LLVM\llvm-mingw-20240619-ucrt-$targetArch\bin\$targetArch-w64-mingw32-gcc.exe]],
AR = q[[C:\Program Files\LLVM\llvm-mingw-20240619-ucrt-$targetArch\bin\ar.exe]],
RANLIB = q[[C:\Program Files\LLVM\llvm-mingw-20240619-ucrt-$targetArch\bin\ranlib.exe]]
}
"@
# Write the configuration content to the file without BOM
$luaConfigContent | Out-File -FilePath $configFilePath -Encoding ascii
# Compiling Luasoscket with modifications
Write-Output "Modifying rockspec to fix compilation errors"
# Find the .rockspec file in the directory
$luasocketFolderName = "luasocket-$luasocketVersion"
$luasocketFolderPath = Join-Path -Path $outputFolder -ChildPath $luasocketFolderName
$rockspecFile = Get-ChildItem -Path "$luasocketFolderPath\rockspecs\luasocket-$luasocketVersion-1.rockspec"
# Check if the .rockspec file exists
if ($rockspecFile) {
# Read the contents of the file
$fileContent = Get-Content $rockspecFile.FullName -Raw
# Define the new version strings
# New version is just a decoy of 3.1.0
$newVersion = '2.9.0'
# Replace occurrences of the old version with the new version
$updatedContent = $fileContent -replace $luasocketVersion, $newVersion
# Define the new filename
$newFileName = $rockspecFile.Name -replace "$luasocketVersion", "$newVersion"
# Define the line to add and regex pattern to match
$lineToAdd = 'modules["mime.core"].libdirs = {}'
$pattern = '(?<whitespace>\s*)modules\["socket.core"\]\.libdirs\s*=\s*\{\}'
# Check if the pattern is present in the updated content
if ($updatedContent -match $pattern) {
# Extract the leading whitespace
$leadingWhitespace = $matches['whitespace']
# Prepare the new line with the same leading whitespace
$newLine = "$leadingWhitespace$lineToAdd"
# Insert the new line after the matched line
$updatedContent = $updatedContent -replace ($pattern + '(?=\r?\n)'), "$&`r`n$newLine"
} else {
Write-Output "Text to append after not found in file: $($rockspecFile.FullName)"
}
# Write the updated content back to the new file
$newFilePath = Join-Path $rockspecFile.DirectoryName $newFileName
Set-Content -Path $newFilePath -Value $updatedContent
Write-Output "File updated and renamed successfully: $newFilePath"
} else {
Write-Output "No .rockspec file found in directory."
}
# Navigate to the directory containing the .rockspec file
$command = "luarocks make .\rockspecs\luasocket-$newVersion-1.rockspec"
Start-Process powershell -ArgumentList @(
"-Command", # Specify the command to run
"cd '$luasocketFolderPath'; $command" # Navigate to the directory and run the command
) -Wait
# Define a list of architectures to keep (based on target architecture)
$architecturesToKeep = @($targetArch)
# Function to delete directories not matching target architectures executables
function Remove-NonTargetDirectories {
param (
[string]$baseDir,
[string[]]$archToKeep
)
# Get all directories in the base directory
$directories = Get-ChildItem -Path $baseDir -Directory
foreach ($dir in $directories) {
# Extract the architecture from the directory name
$dirName = $dir.Name
$archmatches = $dirName -match '^(aarch64|armv7|i686|x86_64)-w64-mingw32$'
if ($archmatches) {
$arch = $dirName -replace '-w64-mingw32$', ''
if ($arch -notin $archToKeep) {
# Remove the directory and its contents
Remove-Item -Path $dir.FullName -Recurse -Force
Write-Output "Removed directory '$($dir.FullName)'"
}
}
}
}
# Function to delete files not matching target architectures in the bin directory
function Remove-NonTargetFiles {
param (
[string]$binDir,
[string[]]$archToKeep
)
# Get all files in the bin directory
$archPrefixes = @("aarch64", "armv7", "i686", "x86_64")
$files = Get-ChildItem -Path $binDir -File
foreach ($file in $files) {
# Check if the file name starts with one of the known architecture prefixes
$startsWithArchPrefix = $archPrefixes | Where-Object { $file.Name.StartsWith($_ + "-w64-mingw32") }
if ($startsWithArchPrefix) {
# Check if the file name starts with the target architecture prefix
if (-not $file.Name.StartsWith($targetArch + "-w64-mingw32")) {
# Remove the file if it starts with an architecture prefix but is not the target architecture
Remove-Item -Path $file.FullName -Force
Write-Output "Removed file '$($file.FullName)'"
}
}
}
}
# Remove non-target architecture directories
Remove-NonTargetDirectories -baseDir "$llvmDestination\$llvmFolderName" -archToKeep $architecturesToKeep
# Remove non-target architecture files in the bin directory
$binDirectory = Join-Path -Path $llvmDestination -ChildPath "$llvmFolderName\bin"
if (Test-Path $binDirectory) {
Remove-NonTargetFiles -binDir $binDirectory -archToKeep $architecturesToKeep
} else {
Write-Output "Bin directory '$binDirectory' does not exist."
}
# Define the commands to test
$luaCommand = "lua -v"
$luarocksCommand = "luarocks --version"
# Function to test command execution
function Test-Command {
param (
[string]$Command
)
try {
# Execute the command and capture output
$output = & $Command 2>&1
if ($LASTEXITCODE -eq 0) {
return $true
} else {
Write-Output "Command failed: $Command"
Write-Output "Error output: $output"
return $false
}
} catch {
Write-Output "Command exception: $Command"
Write-Output "Exception: $_"
return $false
}
}
# Check if Lua is working
$luaWorking = Test-Command -Command $luaCommand
# Check if LuaRocks is working
$luarocksWorking = Test-Command -Command $luarocksCommand
# Delete the output folder if both Lua and LuaRocks are working
if ($luaWorking -and $luarocksWorking) {
if (Test-Path $outputFolder) {
Remove-Item -Path $outputFolder -Recurse -Force
Write-Output "Output folder deleted."
} else {
Write-Output "Output folder does not exist."
}
} else {
Write-Output "Either Lua or LuaRocks is not working. Output folder not deleted."
}
# Define the Unicode emoji for the star (U+2B50)
$EmojiIcon = [System.Convert]::ToInt32("2B50", 16)
# Convert the Unicode code point to the actual character
$StarEmoji = [System.Char]::ConvertFromUtf32($EmojiIcon)
# Display the message with the star emoji
Write-Output "Installation complete. Open a new window and consider leaving a star$StarEmoji on https://github.com/luarocks/luarocks"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment