diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-13 05:07:14 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-13 05:07:14 +0000 |
| commit | 26b378e7e90f950e8d64a294e56fbe9e06d19214 (patch) | |
| tree | f061a01c65c886ed7845b3dfa466f782d62c47b2 | |
| parent | 46c3c548c6e8b76797b688fbb6aba943a02bf6f1 (diff) | |
feat: add a per-user PowerShell installer
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
| -rw-r--r-- | AGENTS/ARCH.md | 9 | ||||
| -rw-r--r-- | README.md | 17 | ||||
| -rw-r--r-- | install.ps1 | 127 |
3 files changed, 152 insertions, 1 deletions
diff --git a/AGENTS/ARCH.md b/AGENTS/ARCH.md index 4decf15..2707ba3 100644 --- a/AGENTS/ARCH.md +++ b/AGENTS/ARCH.md @@ -75,6 +75,13 @@ as `build/cpsc-VERSION-SYSTEM-ARCH.tar.xz`, retaining the configured execution m timestamp (`yyyy-mm-dd-hh-mm-ss`) followed by its short ID. Git is only required for packaging; recipients can install the extracted archive using just the script. +The Windows `install.ps1` installs `cpsc.exe` and `doc/cpsc.html` for the current +user under `%LOCALAPPDATA%\Programs\cpsc` (or `-Prefix`). It appends that directory +to the user PATH without copying the combined process PATH, and creates a +per-user Start Menu help shortcut. `-SourceDir` selects the artifact directory; +`DESTDIR` staging is unsupported on Windows. The script is compatible with +Windows PowerShell 5.1; its Windows actions have only been reviewed statically. + Build pin: developed and tested against **LLVM 18**. (The historical LLVM 19 breakage — `ArithmeticHandler.cc` touching `llvm::Module` through a transitive include — is gone now that string concatenation lives in `StringHandler`, but newer LLVM versions remain @@ -95,7 +102,7 @@ untested.) | `lib/CodeGen/*Handler.cc`, `FunctionGen.cc`, `RuntimeCheck.cc`, `TypeSystem.cc` | Helpers owned by CodeGen | | `CMakeLists.txt` | 3 static libs (CPSLexer, CPSParser, CPSCodeGen) + `cpsc`. **New .cc files must be added to the source lists here** | | `tools/driver/EmbeddedRunner.cc`, `cmake/EmbeddedLLVM.cmake` | EMBEDDED-only MCJIT runner and static support-library selection | -| `install.sh`, `cmake/Install.cmake.in`, `cmake/Release.cmake` | Artifact installation and versioned binary release packaging | +| `install.sh`, `install.ps1`, `cmake/Install.cmake.in`, `cmake/Release.cmake` | Artifact installation and versioned binary release packaging | AST nodes live in `include/cps/AST.h` (+ `FunctionAST.h`, `FileAST.h`, `TypeAST.h`); they are pure data with virtual destructors only — no codegen/visitor methods. @@ -194,6 +194,23 @@ For a custom prefix, add its `bin` directory to PATH; `man` normally discovers t adjacent `share/man` directory from PATH. If your man configuration overrides this, use `man -M "$HOME/.local/share/man" cpsc` for the local prefix. +On Windows, `install.ps1` installs for the current user without administrator +rights. Its source directory must contain `cpsc.exe` and `doc/cpsc.html`: + +```powershell +powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\install.ps1 -SourceDir .\build +``` + +The default destination is `%LOCALAPPDATA%\Programs\cpsc`: `cpsc.exe` goes in +that directory and the HTML manual goes in its `doc` subdirectory. The installer +adds the directory to the user PATH and creates Start Menu > cpsc > cpsc Help, +which opens the manual in the default browser. Open a new terminal afterward; +existing parent terminals retain their old PATH. Reinstalling does not duplicate +the PATH entry. Use `-Prefix 'D:\My Programs\cpsc'` for a custom destination, +or `-Help` for usage. Windows installation does not support `DESTDIR` staging. +The PowerShell installer targets Windows PowerShell 5.1 or later and has only +been reviewed statically; Windows installation still needs testing on Windows. + # Note DO NOT OPEN ANY ISSUES IF YOU COMPILE WITH VISUAL STUDIO OR ANYTHING EXCEPT MINGW-W64 (EVEN WITH MINGW-W64, WINDOWS IS LIKELY TO BE A PROBLEM MAKER) diff --git a/install.ps1 b/install.ps1 new file mode 100644 index 0000000..b26923a --- /dev/null +++ b/install.ps1 @@ -0,0 +1,127 @@ +#requires -Version 5.1 +<# +.SYNOPSIS +Installs cpsc and its HTML manual for the current user. +.DESCRIPTION +Copies cpsc.exe and doc\cpsc.html, creates a Start Menu help shortcut, and +adds the installation directory to the user PATH. No administrator is needed +for the default location: %LOCALAPPDATA%\Programs\cpsc. +.EXAMPLE +.\install.ps1 -SourceDir .\build +.EXAMPLE +.\install.ps1 -Prefix 'D:\My Programs\cpsc' +#> +[CmdletBinding()] +param( + [ValidateNotNullOrEmpty()] + [string]$Prefix, + [ValidateNotNullOrEmpty()] + [string]$SourceDir = $PSScriptRoot, + [switch]$Help +) + +Set-StrictMode -Version 2.0 +$ErrorActionPreference = 'Stop' + +if ($Help) { + Write-Output 'Usage: install.ps1 [-Prefix DIR] [-SourceDir DIR] [-Help]' + Write-Output 'Default destination: %LOCALAPPDATA%\Programs\cpsc' + Write-Output 'Source must contain cpsc.exe and doc\cpsc.html; default: script directory.' + return +} + +function Test-PathEntry([string]$PathValue, [string]$Directory) { + $key = $Directory.Replace('/', '\').TrimEnd('\') + foreach ($entry in ($PathValue -split ';')) { + $expanded = [Environment]::ExpandEnvironmentVariables($entry.Trim().Trim('"')) + if ($expanded.Replace('/', '\').TrimEnd('\') -ieq $key) { + return $true + } + } + return $false +} + +try { + if ([Environment]::OSVersion.Platform -ne [PlatformID]::Win32NT) { + throw 'This installer requires Windows.' + } + if (-not [string]::IsNullOrEmpty($env:DESTDIR)) { + throw 'DESTDIR staging is unsupported on Windows; use -Prefix instead.' + } + if (-not $PSBoundParameters.ContainsKey('Prefix')) { + $localAppData = [Environment]::GetFolderPath('LocalApplicationData') + if ([string]::IsNullOrWhiteSpace($localAppData)) { + throw 'Cannot locate the current user application directory; specify -Prefix.' + } + $Prefix = Join-Path $localAppData 'Programs\cpsc' + } + if ($Prefix -notmatch '^(?:[A-Za-z]:[\\/]|\\\\[^\\]+\\[^\\]+)' -or $Prefix.Contains(';')) { + throw '-Prefix must be an absolute Windows path without a semicolon.' + } + $Prefix = [IO.Path]::GetFullPath($Prefix) + if (-not (Test-Path -LiteralPath $SourceDir -PathType Container)) { + throw "Cannot open source directory: $SourceDir" + } + $SourceDir = (Resolve-Path -LiteralPath $SourceDir).ProviderPath + $sourceExe = Join-Path $SourceDir 'cpsc.exe' + $sourceManual = Join-Path $SourceDir 'doc\cpsc.html' + foreach ($source in @($sourceExe, $sourceManual)) { + if (-not (Test-Path -LiteralPath $source -PathType Leaf)) { + throw "Missing source file: $source; build cpsc and the doc target first." + } + } + + $docDir = Join-Path $Prefix 'doc' + $targetExe = Join-Path $Prefix 'cpsc.exe' + $targetManual = Join-Path $docDir 'cpsc.html' + foreach ($directory in @($Prefix, $docDir)) { + if ((Test-Path -LiteralPath $directory) -and + -not (Test-Path -LiteralPath $directory -PathType Container)) { + throw "Installation directory is occupied by a file: $directory" + } + } + foreach ($file in @($targetExe, $targetManual)) { + if (Test-Path -LiteralPath $file -PathType Container) { + throw "Installation file is occupied by a directory: $file" + } + } + $programs = [Environment]::GetFolderPath('Programs') + if ([string]::IsNullOrWhiteSpace($programs)) { + throw 'Cannot locate the current user Start Menu.' + } + $shortcutDir = Join-Path $programs 'cpsc' + $userPath = [Environment]::GetEnvironmentVariable('Path', 'User') + $shell = New-Object -ComObject WScript.Shell + + # Directory.CreateDirectory treats paths literally, including spaces and brackets. + [IO.Directory]::CreateDirectory($docDir) | Out-Null + if ($sourceExe -ine $targetExe) { + Copy-Item -LiteralPath $sourceExe -Destination $targetExe -Force + } + if ($sourceManual -ine $targetManual) { + Copy-Item -LiteralPath $sourceManual -Destination $targetManual -Force + } + [IO.Directory]::CreateDirectory($shortcutDir) | Out-Null + $shortcut = $shell.CreateShortcut((Join-Path $shortcutDir 'cpsc Help.lnk')) + $shortcut.TargetPath = $targetManual + $shortcut.WorkingDirectory = $docDir + $shortcut.Description = 'cpsc command-line manual' + $shortcut.Save() + + # Read only the user PATH; never persist the combined process/system PATH. + if (-not (Test-PathEntry $userPath $Prefix)) { + $separator = if ([string]::IsNullOrEmpty($userPath) -or $userPath.EndsWith(';')) { '' } else { ';' } + [Environment]::SetEnvironmentVariable('Path', "$userPath$separator$Prefix", 'User') + } + if (-not (Test-PathEntry $env:PATH $Prefix)) { + $env:PATH = "$env:PATH;$Prefix" + } + Write-Output "Installed $targetExe" + Write-Output "Installed $targetManual" + Write-Output 'Open the manual from Start Menu > cpsc > cpsc Help.' + Write-Output 'Open a new terminal to use cpsc by name (existing parent terminals keep their old PATH).' +} +catch { + Write-Error "install.ps1: $($_.Exception.Message) Check the destination permissions and supplied paths." -ErrorAction Continue + exit 1 +} |
