diff --git a/scripts/build.ps1 b/scripts/build.ps1 new file mode 100644 index 0000000..8c2b955 --- /dev/null +++ b/scripts/build.ps1 @@ -0,0 +1,511 @@ +# PowerShell script to build ReclassX +# Automatically detects Qt installation and configures build environment + +#Requires -Version 5.1 + +[CmdletBinding()] +param( + [Parameter(Mandatory=$false)] + [string]$QtDir, + + [Parameter(Mandatory=$false)] + [ValidateSet('Release', 'Debug', 'RelWithDebInfo', 'MinSizeRel')] + [string]$BuildType = 'Release', + + [Parameter(Mandatory=$false)] + [switch]$Clean, + + [Parameter(Mandatory=$false)] + [switch]$Rebuild +) + +$ErrorActionPreference = "Stop" + +# ────────────────────────────────────────────────────────────────────────────── +# Functions +# ────────────────────────────────────────────────────────────────────────────── + +function Write-ColorOutput { + param([string]$Message, [ConsoleColor]$Color = [ConsoleColor]::White) + Write-Host $Message -ForegroundColor $Color +} + +function Find-QtInstallation { + $found = @() + + # Query registry for Qt installations + $registryPaths = @( + "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", + "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" + ) + + foreach ($regPath in $registryPaths) { + if (Test-Path $regPath) { + Get-ChildItem -Path $regPath -ErrorAction SilentlyContinue | ForEach-Object { + $displayName = (Get-ItemProperty -Path $_.PSPath -Name DisplayName -ErrorAction SilentlyContinue).DisplayName + if ($displayName -and $displayName -match 'Qt') { + $installLocation = (Get-ItemProperty -Path $_.PSPath -Name InstallLocation -ErrorAction SilentlyContinue).InstallLocation + if ($installLocation -and (Test-Path $installLocation)) { + # Check if this is a Qt root directory, scan for MinGW installations + Get-ChildItem -Path $installLocation -Directory -ErrorAction SilentlyContinue | Where-Object { + $_.Name -match '^\d+\.\d+\.\d+$' + } | ForEach-Object { + Get-ChildItem -Path $_.FullName -Directory -ErrorAction SilentlyContinue | Where-Object { + $_.Name -match 'mingw' + } | ForEach-Object { + $qmakePath = Join-Path $_.FullName "bin\qmake.exe" + if (Test-Path $qmakePath) { + $found += $_.FullName + } + } + } + } + } + } + } + } + + # Fallback: scan common paths if registry search found nothing + if ($found.Count -eq 0) { + $commonPaths = @( + "C:\Qt", + "D:\Qt", + "E:\Qt", + "F:\Qt", + "$env:USERPROFILE\Qt", + "$env:ProgramFiles\Qt", + "${env:ProgramFiles(x86)}\Qt" + ) + + foreach ($basePath in $commonPaths) { + if (Test-Path $basePath) { + Get-ChildItem -Path $basePath -Directory -ErrorAction SilentlyContinue | Where-Object { + $_.Name -match '^\d+\.\d+\.\d+$' + } | ForEach-Object { + Get-ChildItem -Path $_.FullName -Directory -ErrorAction SilentlyContinue | Where-Object { + $_.Name -match 'mingw' + } | ForEach-Object { + $qmakePath = Join-Path $_.FullName "bin\qmake.exe" + if (Test-Path $qmakePath) { + $found += $_.FullName + } + } + } + } + } + } + + return $found | Select-Object -Unique +} + +function Select-QtDirectory { + Add-Type -AssemblyName System.Windows.Forms + $folderBrowser = New-Object System.Windows.Forms.FolderBrowserDialog + $folderBrowser.Description = "Select Qt MinGW installation directory (e.g., C:\Qt\6.10.2\mingw_64)" + $folderBrowser.RootFolder = [System.Environment+SpecialFolder]::MyComputer + $folderBrowser.ShowNewFolderButton = $false + + if ($folderBrowser.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { + return $folderBrowser.SelectedPath + } + return $null +} + +function Get-QtDirectory { + # 1. Check if provided as parameter + if ($QtDir) { + Write-ColorOutput "Using Qt directory from parameter: $QtDir" Cyan + return $QtDir + } + + # 2. Check environment variable and try to find MinGW under it + if ($env:QTDIR) { + $qtdirPath = $env:QTDIR + Write-ColorOutput "Found QTDIR environment variable: $qtdirPath" Cyan + + # Check if QTDIR directly points to a valid MinGW installation + $qmake = Join-Path $qtdirPath "bin\qmake.exe" + if ((Test-Path $qmake) -and ($qtdirPath.ToLower() -match 'mingw')) { + Write-ColorOutput "QTDIR points to valid MinGW installation." Green + return $qtdirPath + } + + # QTDIR might point to Qt root, search for MinGW subdirectories + Write-ColorOutput "QTDIR appears to be Qt root directory. Searching for MinGW installations..." Yellow + $foundMinGW = @() + + Get-ChildItem -Path $qtdirPath -Directory -ErrorAction SilentlyContinue | Where-Object { + $_.Name -match '^\d+\.\d+\.\d+$' + } | ForEach-Object { + Get-ChildItem -Path $_.FullName -Directory -ErrorAction SilentlyContinue | Where-Object { + $_.Name -match 'mingw' + } | ForEach-Object { + $qmakePath = Join-Path $_.FullName "bin\qmake.exe" + if (Test-Path $qmakePath) { + $foundMinGW += $_.FullName + } + } + } + + if ($foundMinGW.Count -eq 1) { + Write-ColorOutput "Found MinGW installation under QTDIR: $($foundMinGW[0])" Green + $response = Read-Host "Use this installation? (Y/n)" + if ($response -match '^(y|yes|)$' -or [string]::IsNullOrWhiteSpace($response)) { + return $foundMinGW[0] + } + } elseif ($foundMinGW.Count -gt 1) { + Write-ColorOutput "Found multiple MinGW installations under QTDIR:" Green + for ($i = 0; $i -lt $foundMinGW.Count; $i++) { + Write-Host " [$($i+1)] $($foundMinGW[$i])" + } + + do { + $choice = Read-Host "Select Qt installation (1-$($foundMinGW.Count))" + $choiceNum = 0 + $valid = [int]::TryParse($choice, [ref]$choiceNum) -and $choiceNum -ge 1 -and $choiceNum -le $foundMinGW.Count + } until ($valid) + + return $foundMinGW[$choiceNum - 1] + } + + Write-ColorOutput "No MinGW installations found under QTDIR." Yellow + } + + # 3. Try to auto-detect + Write-ColorOutput "Searching for Qt installations..." Yellow + $detected = Find-QtInstallation + + if ($detected.Count -eq 1) { + Write-ColorOutput "Found Qt installation: $($detected[0])" Green + $response = Read-Host "Use this installation? (Y/n)" + if ($response -match '^(y|yes|)$' -or [string]::IsNullOrWhiteSpace($response)) { + return $detected[0] + } + } elseif ($detected.Count -gt 1) { + Write-ColorOutput "Found multiple Qt installations:" Green + for ($i = 0; $i -lt $detected.Count; $i++) { + Write-Host " [$($i+1)] $($detected[$i])" + } + Write-Host " [0] Browse for directory manually" + + do { + $choice = Read-Host "Select Qt installation (1-$($detected.Count), or 0 to browse)" + $choiceNum = 0 + $valid = [int]::TryParse($choice, [ref]$choiceNum) -and $choiceNum -ge 0 -and $choiceNum -le $detected.Count + } until ($valid) + + if ($choiceNum -gt 0) { + return $detected[$choiceNum - 1] + } + } + + # 4. Manual input or browse + Write-ColorOutput "No Qt MinGW installation auto-detected." Yellow + Write-Host "" + Write-Host "Options:" + Write-Host " [1] Browse for Qt MinGW directory" + Write-Host " [2] Enter path manually" + Write-Host " [3] Exit" + + do { + $choice = Read-Host "Select option (1-3)" + } until ($choice -match '^[123]$') + + switch ($choice) { + "1" { + $dir = Select-QtDirectory + if ($dir) { return $dir } + Write-ColorOutput "No directory selected. Exiting." Red + exit 1 + } + "2" { + $dir = Read-Host "Enter Qt MinGW directory path (e.g., C:\Qt\6.10.2\mingw_64)" + if ($dir) { return $dir } + Write-ColorOutput "No path entered. Exiting." Red + exit 1 + } + "3" { + Write-ColorOutput "Exiting." Yellow + exit 0 + } + } +} + +function Validate-QtDirectory { + param([string]$Dir) + + $qmake = Join-Path $Dir "bin\qmake.exe" + if (-not (Test-Path $qmake)) { + Write-ColorOutput "ERROR: qmake.exe not found in $Dir\bin\" Red + Write-ColorOutput "Please ensure you selected a valid Qt installation directory (e.g., C:\Qt\6.10.2\mingw_64)" Red + return $false + } + + # Validate it's a MinGW build + $dirLower = $Dir.ToLower() + if ($dirLower -notmatch 'mingw') { + Write-ColorOutput "ERROR: Selected Qt installation is not MinGW-based." Red + Write-ColorOutput "This project requires Qt with MinGW compiler (e.g., C:\Qt\6.10.2\mingw_64)" Red + Write-ColorOutput "Selected path: $Dir" Red + return $false + } + + return $true +} + +function Find-BuildTool { + param([string]$QtDir, [string]$ToolName) + + $qtRoot = Split-Path (Split-Path $QtDir -Parent) -Parent + $toolsDir = Join-Path $qtRoot "Tools" + + if (Test-Path $toolsDir) { + # Search for tool in Qt Tools directory + $toolExe = Get-ChildItem -Path $toolsDir -Recurse -Filter "$ToolName.exe" -ErrorAction SilentlyContinue | Select-Object -First 1 + if ($toolExe) { + return $toolExe.DirectoryName + } + } + + # Check system PATH + $cmd = Get-Command "$ToolName.exe" -ErrorAction SilentlyContinue + if ($cmd) { + return Split-Path $cmd.Source -Parent + } + + return $null +} + +function Find-MinGWDirectory { + param([string]$QtDir) + + $qtRoot = Split-Path (Split-Path $QtDir -Parent) -Parent + $toolsDir = Join-Path $qtRoot "Tools" + + if (Test-Path $toolsDir) { + $mingwToolDirs = Get-ChildItem -Path $toolsDir -Directory -ErrorAction SilentlyContinue | Where-Object { + $_.Name -match 'mingw' + } + + foreach ($dir in $mingwToolDirs) { + $testBin = Join-Path $dir.FullName "bin\g++.exe" + if (Test-Path $testBin) { + return Join-Path $dir.FullName "bin" + } + } + } + + return $null +} + +# ────────────────────────────────────────────────────────────────────────────── +# Main Script +# ────────────────────────────────────────────────────────────────────────────── + +Write-ColorOutput "`n========================================" Cyan +Write-ColorOutput "ReclassX Build Script" Cyan +Write-ColorOutput "========================================`n" Cyan + +# Get script directory and project root +$scriptDir = Split-Path -Parent $PSCommandPath +$projectRoot = Split-Path -Parent $scriptDir +$buildDir = Join-Path $projectRoot "build" + +# Get Qt directory +$selectedQtDir = Get-QtDirectory +if (-not $selectedQtDir) { + Write-ColorOutput "ERROR: No Qt directory provided." Red + exit 1 +} + +# Validate Qt directory +if (-not (Validate-QtDirectory $selectedQtDir)) { + exit 1 +} + +Write-ColorOutput "`nQt Directory: $selectedQtDir" Green +Write-ColorOutput "Build Type: $BuildType" Green + +# Find build tools +Write-ColorOutput "`nSearching for build tools..." Cyan + +$cmakeDir = Find-BuildTool $selectedQtDir "cmake" +$ninjaDir = Find-BuildTool $selectedQtDir "ninja" +$mingwDir = Find-MinGWDirectory $selectedQtDir + +$missingTools = @() + +if (-not $cmakeDir) { + $missingTools += "CMake" + Write-ColorOutput " CMake: NOT FOUND" Red +} else { + Write-ColorOutput " CMake: $cmakeDir" Green +} + +if (-not $ninjaDir) { + $missingTools += "Ninja" + Write-ColorOutput " Ninja: NOT FOUND" Yellow + Write-ColorOutput " (Will try default CMake generator)" Gray +} else { + Write-ColorOutput " Ninja: $ninjaDir" Green +} + +if (-not $mingwDir) { + Write-ColorOutput " MinGW: NOT FOUND (may cause build issues)" Yellow +} else { + Write-ColorOutput " MinGW: $mingwDir" Green +} + +if ($missingTools.Count -gt 0 -and $missingTools -contains "CMake") { + Write-ColorOutput "`nERROR: CMake is required but not found." Red + Write-ColorOutput "Please install CMake or ensure it's in your PATH." Red + Write-ColorOutput "You can download it from: https://cmake.org/download/" Red + exit 1 +} + +# Build PATH environment +$pathDirs = @() +if ($cmakeDir) { $pathDirs += $cmakeDir } +if ($ninjaDir) { $pathDirs += $ninjaDir } +if ($mingwDir) { $pathDirs += $mingwDir } +$pathDirs += (Join-Path $selectedQtDir "bin") +$pathDirs += $env:Path + +$env:Path = ($pathDirs -join ";") + +Write-ColorOutput "`nEnvironment configured." Green + +# Handle clean/rebuild +if ($Rebuild) { + $Clean = $true +} + +if ($Clean -and (Test-Path $buildDir)) { + Write-ColorOutput "`nCleaning build directory..." Yellow + try { + Remove-Item -Path $buildDir -Recurse -Force -ErrorAction Stop + Write-ColorOutput "Build directory cleaned." Green + } catch { + Write-ColorOutput "ERROR: Failed to clean build directory: $_" Red + exit 1 + } +} + +# Create build directory +if (-not (Test-Path $buildDir)) { + Write-ColorOutput "`nCreating build directory..." Cyan + New-Item -ItemType Directory -Path $buildDir -Force | Out-Null +} + +# Change to build directory +Push-Location $buildDir + +try { + Write-ColorOutput "`nConfiguring CMake..." Cyan + + # Prepare CMake command + $cmakeArgs = @( + ".." + "-DCMAKE_BUILD_TYPE=$BuildType" + "-DCMAKE_PREFIX_PATH=$($selectedQtDir -replace '\\', '/')" + ) + + # Add generator if Ninja is available + if ($ninjaDir) { + $cmakeArgs = @("-G", "Ninja") + $cmakeArgs + Write-ColorOutput "Using Ninja generator" Gray + } + + Write-ColorOutput "Command: cmake $($cmakeArgs -join ' ')`n" Gray + + & cmake $cmakeArgs + if ($LASTEXITCODE -ne 0) { + Write-ColorOutput "`nERROR: CMake configuration failed with exit code $LASTEXITCODE" Red + exit 1 + } + Write-ColorOutput "`nCMake configuration completed successfully.`n" Green + + # Build + Write-ColorOutput "Building ReclassX..." Cyan + + $cores = (Get-CimInstance -ClassName Win32_Processor).NumberOfLogicalProcessors + if (-not $cores -or $cores -lt 1) { + $cores = 4 + } + + Write-ColorOutput "Command: cmake --build . --config $BuildType -j$cores`n" Gray + + & cmake --build . --config $BuildType "-j$cores" + if ($LASTEXITCODE -ne 0) { + Write-ColorOutput "`nERROR: Build failed with exit code $LASTEXITCODE" Red + exit 1 + } + Write-ColorOutput "`nBuild completed successfully!`n" Green + + # Find executable + Write-ColorOutput "Locating executable..." Cyan + $exePaths = @( + (Join-Path $buildDir "ReclassX.exe"), + (Join-Path $buildDir "$BuildType\ReclassX.exe") + ) + + $exePath = $null + foreach ($path in $exePaths) { + if (Test-Path $path) { + $exePath = $path + break + } + } + + if ($exePath) { + $fileInfo = Get-Item $exePath + $sizeMB = [math]::Round($fileInfo.Length / 1MB, 2) + Write-ColorOutput "Executable: $exePath" Green + Write-ColorOutput "Size: $sizeMB MB" Gray + + # Run windeployqt to copy Qt dependencies + Write-ColorOutput "`nRunning windeployqt..." Cyan + $windeployqt = Join-Path $selectedQtDir "bin\windeployqt.exe" + + if (Test-Path $windeployqt) { + $exeDir = Split-Path $exePath -Parent + Write-ColorOutput "Command: `"$windeployqt`" `"$exePath`"`n" Gray + + & $windeployqt $exePath + if ($LASTEXITCODE -eq 0) { + Write-ColorOutput "windeployqt completed successfully." Green + + # Count deployed files + $deployedFiles = Get-ChildItem -Path $exeDir -Recurse -File | Where-Object { + $_.Name -ne "ReclassX.exe" -and $_.Extension -match '\.(dll|qm)$' + } + if ($deployedFiles) { + Write-ColorOutput "Deployed $($deployedFiles.Count) Qt dependency files." Gray + } + } else { + Write-ColorOutput "WARNING: windeployqt failed with exit code $LASTEXITCODE" Yellow + Write-ColorOutput "Application may not run without Qt DLLs in PATH" Yellow + } + } else { + Write-ColorOutput "WARNING: windeployqt.exe not found at $windeployqt" Yellow + Write-ColorOutput "Application may not run without Qt DLLs in PATH" Yellow + } + } else { + Write-ColorOutput "WARNING: Could not locate ReclassX.exe" Yellow + } + +} catch { + Write-ColorOutput "`nERROR: Build failed with exception: $_" Red + exit 1 +} finally { + Pop-Location +} + +Write-ColorOutput "`n========================================" Cyan +Write-ColorOutput "Build completed successfully!" Cyan +Write-ColorOutput "========================================`n" Cyan + +if ($exePath) { + Write-ColorOutput "Run the application with:" White + Write-ColorOutput " .\build\ReclassX.exe`n" Cyan +} diff --git a/scripts/build_qscintilla.bat b/scripts/build_qscintilla.bat deleted file mode 100644 index a008742..0000000 --- a/scripts/build_qscintilla.bat +++ /dev/null @@ -1,13 +0,0 @@ -@echo off -set "PATH=C:\Qt\Tools\mingw1120_64\bin;C:\Qt\6.5.2\mingw_64\bin;%PATH%" -cd /d "E:\game_dev\util\reclass2027-main\third_party\qscintilla\src" -echo Current dir: %cd% -echo Running qmake... -"C:\Qt\6.5.2\mingw_64\bin\qmake.exe" qscintilla.pro "CONFIG+=staticlib" -echo qmake exit code: %errorlevel% -echo Running mingw32-make... -"C:\Qt\Tools\mingw1120_64\bin\mingw32-make.exe" -j8 -echo make exit code: %errorlevel% -echo Done. Checking for .a files: -dir /b *.a 2>nul -dir /b release\*.a 2>nul diff --git a/scripts/build_qscintilla.ps1 b/scripts/build_qscintilla.ps1 new file mode 100644 index 0000000..89fe0d4 --- /dev/null +++ b/scripts/build_qscintilla.ps1 @@ -0,0 +1,441 @@ +# PowerShell script to build QScintilla static library for ReclassX +# This script checks for Qt installation, prompts if missing, and builds QScintilla + +#Requires -Version 5.1 + +[CmdletBinding()] +param( + [Parameter(Mandatory=$false)] + [string]$QtDir, + + [Parameter(Mandatory=$false)] + [switch]$Clean +) + +$ErrorActionPreference = "Stop" + +# ────────────────────────────────────────────────────────────────────────────── +# Functions +# ────────────────────────────────────────────────────────────────────────────── + +function Write-ColorOutput { + param([string]$Message, [ConsoleColor]$Color = [ConsoleColor]::White) + Write-Host $Message -ForegroundColor $Color +} + +function Find-QtInstallation { + $found = @() + + # Query registry for Qt installations + $registryPaths = @( + "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", + "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" + ) + + foreach ($regPath in $registryPaths) { + if (Test-Path $regPath) { + Get-ChildItem -Path $regPath -ErrorAction SilentlyContinue | ForEach-Object { + $displayName = (Get-ItemProperty -Path $_.PSPath -Name DisplayName -ErrorAction SilentlyContinue).DisplayName + if ($displayName -and $displayName -match 'Qt') { + $installLocation = (Get-ItemProperty -Path $_.PSPath -Name InstallLocation -ErrorAction SilentlyContinue).InstallLocation + if ($installLocation -and (Test-Path $installLocation)) { + # Check if this is a Qt root directory, scan for MinGW installations + Get-ChildItem -Path $installLocation -Directory -ErrorAction SilentlyContinue | Where-Object { + $_.Name -match '^\d+\.\d+\.\d+$' + } | ForEach-Object { + Get-ChildItem -Path $_.FullName -Directory -ErrorAction SilentlyContinue | Where-Object { + $_.Name -match 'mingw' + } | ForEach-Object { + $qmakePath = Join-Path $_.FullName "bin\qmake.exe" + if (Test-Path $qmakePath) { + $found += $_.FullName + } + } + } + } + } + } + } + } + + # Fallback: scan common paths if registry search found nothing + if ($found.Count -eq 0) { + $commonPaths = @( + "C:\Qt", + "D:\Qt", + "E:\Qt", + "F:\Qt" + ) + + foreach ($basePath in $commonPaths) { + if (Test-Path $basePath) { + Get-ChildItem -Path $basePath -Directory -ErrorAction SilentlyContinue | Where-Object { + $_.Name -match '^\d+\.\d+\.\d+$' + } | ForEach-Object { + Get-ChildItem -Path $_.FullName -Directory -ErrorAction SilentlyContinue | Where-Object { + $_.Name -match 'mingw' + } | ForEach-Object { + $qmakePath = Join-Path $_.FullName "bin\qmake.exe" + if (Test-Path $qmakePath) { + $found += $_.FullName + } + } + } + } + } + } + + return $found | Select-Object -Unique +} + +function Select-QtDirectory { + Add-Type -AssemblyName System.Windows.Forms + $folderBrowser = New-Object System.Windows.Forms.FolderBrowserDialog + $folderBrowser.Description = "Select Qt MinGW installation directory (e.g., C:\Qt\6.10.2\mingw_64)" + $folderBrowser.RootFolder = [System.Environment+SpecialFolder]::MyComputer + $folderBrowser.ShowNewFolderButton = $false + + if ($folderBrowser.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { + return $folderBrowser.SelectedPath + } + return $null +} + +function Get-QtDirectory { + # 1. Check if provided as parameter + if ($QtDir) { + Write-ColorOutput "Using Qt directory from parameter: $QtDir" Cyan + return $QtDir + } + + # 2. Check environment variable and try to find MinGW under it + if ($env:QTDIR) { + $qtdirPath = $env:QTDIR + Write-ColorOutput "Found QTDIR environment variable: $qtdirPath" Cyan + + # Check if QTDIR directly points to a valid MinGW installation + $qmake = Join-Path $qtdirPath "bin\qmake.exe" + if ((Test-Path $qmake) -and ($qtdirPath.ToLower() -match 'mingw')) { + Write-ColorOutput "QTDIR points to valid MinGW installation." Green + return $qtdirPath + } + + # QTDIR might point to Qt root, search for MinGW subdirectories + Write-ColorOutput "QTDIR appears to be Qt root directory. Searching for MinGW installations..." Yellow + $foundMinGW = @() + + Get-ChildItem -Path $qtdirPath -Directory -ErrorAction SilentlyContinue | Where-Object { + $_.Name -match '^\d+\.\d+\.\d+$' + } | ForEach-Object { + Get-ChildItem -Path $_.FullName -Directory -ErrorAction SilentlyContinue | Where-Object { + $_.Name -match 'mingw' + } | ForEach-Object { + $qmakePath = Join-Path $_.FullName "bin\qmake.exe" + if (Test-Path $qmakePath) { + $foundMinGW += $_.FullName + } + } + } + + if ($foundMinGW.Count -eq 1) { + Write-ColorOutput "Found MinGW installation under QTDIR: $($foundMinGW[0])" Green + $response = Read-Host "Use this installation? (Y/n)" + if ($response -match '^(y|yes|)$' -or [string]::IsNullOrWhiteSpace($response)) { + return $foundMinGW[0] + } + } elseif ($foundMinGW.Count -gt 1) { + Write-ColorOutput "Found multiple MinGW installations under QTDIR:" Green + for ($i = 0; $i -lt $foundMinGW.Count; $i++) { + Write-Host " [$($i+1)] $($foundMinGW[$i])" + } + + do { + $choice = Read-Host "Select Qt installation (1-$($foundMinGW.Count))" + $choiceNum = 0 + $valid = [int]::TryParse($choice, [ref]$choiceNum) -and $choiceNum -ge 1 -and $choiceNum -le $foundMinGW.Count + } until ($valid) + + return $foundMinGW[$choiceNum - 1] + } + + Write-ColorOutput "No MinGW installations found under QTDIR." Yellow + } + + # 3. Try to auto-detect + Write-ColorOutput "Searching for Qt installations..." Yellow + $detected = Find-QtInstallation + + if ($detected.Count -eq 1) { + Write-ColorOutput "Found Qt installation: $($detected[0])" Green + $response = Read-Host "Use this installation? (Y/n)" + if ($response -match '^(y|yes|)$' -or [string]::IsNullOrWhiteSpace($response)) { + return $detected[0] + } + } elseif ($detected.Count -gt 1) { + Write-ColorOutput "Found multiple Qt installations:" Green + for ($i = 0; $i -lt $detected.Count; $i++) { + Write-Host " [$($i+1)] $($detected[$i])" + } + Write-Host " [0] Browse for directory manually" + + do { + $choice = Read-Host "Select Qt installation (1-$($detected.Count), or 0 to browse)" + $choiceNum = 0 + $valid = [int]::TryParse($choice, [ref]$choiceNum) -and $choiceNum -ge 0 -and $choiceNum -le $detected.Count + } until ($valid) + + if ($choiceNum -gt 0) { + return $detected[$choiceNum - 1] + } + } + + # 4. Manual input or browse + Write-ColorOutput "No Qt MinGW installation auto-detected." Yellow + Write-Host "" + Write-Host "Options:" + Write-Host " [1] Browse for Qt MinGW directory" + Write-Host " [2] Enter path manually" + Write-Host " [3] Exit" + + do { + $choice = Read-Host "Select option (1-3)" + } until ($choice -match '^[123]$') + + switch ($choice) { + "1" { + $dir = Select-QtDirectory + if ($dir) { return $dir } + Write-ColorOutput "No directory selected. Exiting." Red + exit 1 + } + "2" { + $dir = Read-Host "Enter Qt MinGW directory path (e.g., C:\Qt\6.10.2\mingw_64)" + if ($dir) { return $dir } + Write-ColorOutput "No path entered. Exiting." Red + exit 1 + } + "3" { + Write-ColorOutput "Exiting." Yellow + exit 0 + } + } +} + +function Validate-QtDirectory { + param([string]$Dir) + + $qmake = Join-Path $Dir "bin\qmake.exe" + if (-not (Test-Path $qmake)) { + Write-ColorOutput "ERROR: qmake.exe not found in $Dir\bin\" Red + Write-ColorOutput "Please ensure you selected a valid Qt installation directory (e.g., C:\Qt\6.10.2\mingw_64)" Red + return $false + } + + # Validate it's a MinGW build + $dirLower = $Dir.ToLower() + if ($dirLower -notmatch 'mingw') { + Write-ColorOutput "ERROR: Selected Qt installation is not MinGW-based." Red + Write-ColorOutput "This project requires Qt with MinGW compiler (e.g., C:\Qt\6.10.2\mingw_64)" Red + Write-ColorOutput "Selected path: $Dir" Red + return $false + } + + return $true +} + +function Find-MakeCommand { + param([string]$QtDir) + + # Look for mingw32-make in Qt Tools directory + $qtRoot = Split-Path (Split-Path $QtDir -Parent) -Parent + $toolsDir = Join-Path $qtRoot "Tools" + + if (Test-Path $toolsDir) { + $mingwMake = Get-ChildItem -Path $toolsDir -Recurse -Filter "mingw32-make.exe" -ErrorAction SilentlyContinue | Select-Object -First 1 + if ($mingwMake) { + return $mingwMake.FullName + } + } + + # Check system PATH + $makeCmd = Get-Command mingw32-make.exe -ErrorAction SilentlyContinue + if ($makeCmd) { + return $makeCmd.Source + } + + Write-ColorOutput "WARNING: mingw32-make.exe not found. Please ensure MinGW is in PATH." Yellow + return "mingw32-make.exe" +} + +# ────────────────────────────────────────────────────────────────────────────── +# Main Script +# ────────────────────────────────────────────────────────────────────────────── + +Write-ColorOutput "`n========================================" Cyan +Write-ColorOutput "QScintilla Build Script for ReclassX" Cyan +Write-ColorOutput "========================================`n" Cyan + +# Get script directory and project root +$scriptDir = Split-Path -Parent $PSCommandPath +$projectRoot = Split-Path -Parent $scriptDir +$qsciSrcDir = Join-Path $projectRoot "third_party\qscintilla\src" + +# Check if QScintilla source exists +if (-not (Test-Path $qsciSrcDir)) { + Write-ColorOutput "ERROR: QScintilla source not found at $qsciSrcDir" Red + Write-ColorOutput "Please extract QScintilla source to third_party/qscintilla/" Red + exit 1 +} + +# Verify qscintilla.pro exists +$proFile = Join-Path $qsciSrcDir "qscintilla.pro" +if (-not (Test-Path $proFile)) { + Write-ColorOutput "ERROR: qscintilla.pro not found at $proFile" Red + exit 1 +} + +# Get Qt directory +$selectedQtDir = Get-QtDirectory +if (-not $selectedQtDir) { + Write-ColorOutput "ERROR: No Qt directory provided." Red + exit 1 +} + +# Validate Qt directory +if (-not (Validate-QtDirectory $selectedQtDir)) { + exit 1 +} + +Write-ColorOutput "`nQt Directory: $selectedQtDir" Green + +# Find make command +$makeCmd = Find-MakeCommand $selectedQtDir +Write-ColorOutput "Make Command: $makeCmd" Green + +# Find MinGW bin directory (contains g++, cc1plus, etc.) +$mingwBinDir = $null +$qtRoot = Split-Path (Split-Path $selectedQtDir -Parent) -Parent +$toolsDir = Join-Path $qtRoot "Tools" + +if (Test-Path $toolsDir) { + # Look for MinGW tools directory + $mingwToolDirs = Get-ChildItem -Path $toolsDir -Directory -ErrorAction SilentlyContinue | Where-Object { + $_.Name -match 'mingw' + } + + foreach ($dir in $mingwToolDirs) { + $testBin = Join-Path $dir.FullName "bin\g++.exe" + if (Test-Path $testBin) { + $mingwBinDir = Join-Path $dir.FullName "bin" + break + } + } +} + +# Set up environment - add both Qt bin and MinGW bin to PATH +$qmakePath = Join-Path $selectedQtDir "bin\qmake.exe" +if ($mingwBinDir) { + Write-ColorOutput "MinGW Directory: $mingwBinDir" Green + $env:Path = "$mingwBinDir;$selectedQtDir\bin;$env:Path" +} else { + Write-ColorOutput "WARNING: MinGW tools directory not found. Build may fail." Yellow + Write-ColorOutput "Ensure MinGW bin directory (containing g++.exe, cc1plus.exe) is in PATH" Yellow + $env:Path = "$selectedQtDir\bin;$env:Path" +} + +# Clean if requested +if ($Clean) { + Write-ColorOutput "`nCleaning previous build..." Yellow + Push-Location $qsciSrcDir + try { + if (Test-Path "Makefile") { + & $makeCmd clean 2>&1 | Out-Null + } + Remove-Item -Path "Makefile*", "release", "debug", "*.o", "*.obj" -Recurse -Force -ErrorAction SilentlyContinue + Write-ColorOutput "Clean complete." Green + } finally { + Pop-Location + } +} + +# Change to QScintilla source directory +Write-ColorOutput "`nChanging to QScintilla source directory..." Cyan +Push-Location $qsciSrcDir + +try { + Write-ColorOutput "Current directory: $PWD`n" Gray + + # Run qmake + Write-ColorOutput "Running qmake..." Cyan + Write-ColorOutput "Command: `"$qmakePath`" qscintilla.pro `"CONFIG+=staticlib`"`n" Gray + + & $qmakePath qscintilla.pro "CONFIG+=staticlib" + if ($LASTEXITCODE -ne 0) { + Write-ColorOutput "`nERROR: qmake failed with exit code $LASTEXITCODE" Red + exit 1 + } + Write-ColorOutput "qmake completed successfully.`n" Green + + # Run make + Write-ColorOutput "Running $makeCmd..." Cyan + $cores = (Get-CimInstance -ClassName Win32_Processor).NumberOfLogicalProcessors + if (-not $cores -or $cores -lt 1) { + $cores = 4 # Default fallback + } + Write-ColorOutput "Command: `"$makeCmd`" -j$cores`n" Gray + + & $makeCmd "-j$cores" + if ($LASTEXITCODE -ne 0) { + Write-ColorOutput "`nERROR: make failed with exit code $LASTEXITCODE" Red + exit 1 + } + Write-ColorOutput "`nmake completed successfully.`n" Green + + # Check for output + Write-ColorOutput "Checking for generated library files..." Cyan + $foundLibs = @() + + $patterns = @("*.a", "*.lib") + $searchDirs = @(".", "release", "debug") + + foreach ($dir in $searchDirs) { + $fullPath = Join-Path $PWD $dir + if (Test-Path $fullPath) { + foreach ($pattern in $patterns) { + $libs = Get-ChildItem -Path $fullPath -Filter $pattern -ErrorAction SilentlyContinue + if ($libs) { + $foundLibs += $libs | ForEach-Object { + [PSCustomObject]@{ + Name = $_.Name + Path = $_.FullName + Size = $_.Length + } + } + } + } + } + } + + if ($foundLibs.Count -gt 0) { + Write-ColorOutput "`nBuild successful! Generated libraries:" Green + foreach ($lib in $foundLibs) { + $sizeMB = [math]::Round($lib.Size / 1MB, 2) + Write-Host " - $($lib.Name) ($sizeMB MB)" -ForegroundColor Green + Write-Host " Path: $($lib.Path)" -ForegroundColor Gray + } + Write-ColorOutput "`nYou can now build ReclassX with CMake." Green + } else { + Write-ColorOutput "`nWARNING: Build completed but no library files found." Yellow + Write-ColorOutput "Expected files: qscintilla2_qt6.a or qscintilla2_qt6.lib" Yellow + } + +} catch { + Write-ColorOutput "`nERROR: Build failed with exception: $_" Red + exit 1 +} finally { + Pop-Location +} + +Write-ColorOutput "`n========================================" Cyan +Write-ColorOutput "Build script completed successfully" Cyan +Write-ColorOutput "========================================`n" Cyan