aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AGENTS/ARCH.md9
-rw-r--r--README.md17
-rw-r--r--install.ps1127
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.
diff --git a/README.md b/README.md
index bcaf0ea..4f14498 100644
--- a/README.md
+++ b/README.md
@@ -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
+}