From 2f033fe5c922cc7d1ca1b619dc665cbc21341983 Mon Sep 17 00:00:00 2001 From: _ov4 Date: Thu, 22 Oct 2026 11:35:16 +0000 Subject: build: package and invoke install.cmd instead of install.ps1 The Windows ZIP now ships install.cmd, rewritten to CRLF by configure_file so the package is right on any build host. The CMake install target runs it through "cmd /d /c call", and install.cmd replaces install.ps1 in the version input paths. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/nightly-build.yml | 2 +- cmake/CompilerPaths.txt | 2 +- cmake/Install.cmake.in | 11 +-- cmake/Release.cmake | 12 ++- install.ps1 | 160 ------------------------------------ 5 files changed, 16 insertions(+), 171 deletions(-) delete mode 100644 install.ps1 diff --git a/.github/workflows/nightly-build.yml b/.github/workflows/nightly-build.yml index 70e8d41..b2af0b9 100644 --- a/.github/workflows/nightly-build.yml +++ b/.github/workflows/nightly-build.yml @@ -401,7 +401,7 @@ jobs: $smokeDir = Join-Path $env:RUNNER_TEMP 'cpsc-smoke' Expand-Archive -LiteralPath $packages[0].FullName -DestinationPath $smokeDir $packageDir = Join-Path $smokeDir $packages[0].BaseName - foreach ($file in @('cpsc.exe', 'install.ps1', 'LICENSE', 'doc/cpsc.html', 'doc/language/cpsc-language-overview.html')) { + foreach ($file in @('cpsc.exe', 'install.cmd', 'LICENSE', 'doc/cpsc.html', 'doc/language/cpsc-language-overview.html')) { if (-not (Test-Path -LiteralPath (Join-Path $packageDir $file) -PathType Leaf)) { throw "Missing package file: $file" } diff --git a/cmake/CompilerPaths.txt b/cmake/CompilerPaths.txt index 42beb57..18ab18d 100644 --- a/cmake/CompilerPaths.txt +++ b/cmake/CompilerPaths.txt @@ -7,6 +7,6 @@ tests tools CMakeLists.txt install.sh -install.ps1 +install.cmd LICENSE .github diff --git a/cmake/Install.cmake.in b/cmake/Install.cmake.in index c6cd83f..7ee27a5 100644 --- a/cmake/Install.cmake.in +++ b/cmake/Install.cmake.in @@ -11,12 +11,13 @@ endif() set(cpsc_install_windows "@WIN32@") if(cpsc_install_windows) - cpsc_find_dependency(PROGRAM cpsc_powershell NAMES powershell.exe REQUIRED) + cpsc_find_dependency(PROGRAM cpsc_cmd NAMES cmd.exe REQUIRED) + file(TO_NATIVE_PATH "@CMAKE_CURRENT_SOURCE_DIR@/install.cmd" cpsc_installer) + # An explicit "call" keeps cmd's handling of the quoted script path the same on CMake 3.x and 4.x. execute_process( - COMMAND "${cpsc_powershell}" -NoProfile -NonInteractive -ExecutionPolicy Bypass - -File "@CMAKE_CURRENT_SOURCE_DIR@/install.ps1" - -SourceDir "@CMAKE_CURRENT_BINARY_DIR@" - -Prefix "${CMAKE_INSTALL_PREFIX}" + COMMAND "${cpsc_cmd}" /d /c call "${cpsc_installer}" + --source-dir "@CMAKE_CURRENT_BINARY_DIR@" + --prefix "${CMAKE_INSTALL_PREFIX}" RESULT_VARIABLE cpsc_install_result ) else() diff --git a/cmake/Release.cmake b/cmake/Release.cmake index c825f74..c1ab9be 100644 --- a/cmake/Release.cmake +++ b/cmake/Release.cmake @@ -23,7 +23,6 @@ set(cpsc_package_dir "${CPSC_BINARY_DIR}/release/${cpsc_package_name}") if(CPSC_WINDOWS) set(cpsc_archive "${CPSC_BINARY_DIR}/${cpsc_package_name}.zip") set(cpsc_binary_name cpsc.exe) - set(cpsc_installer install.ps1) set(cpsc_manual cpsc.html) set(cpsc_language_extension html) set(cpsc_tar_flags cf) @@ -31,7 +30,6 @@ if(CPSC_WINDOWS) else() set(cpsc_archive "${CPSC_BINARY_DIR}/${cpsc_package_name}.tar.xz") set(cpsc_binary_name cpsc) - set(cpsc_installer install.sh) set(cpsc_manual cpsc.1) set(cpsc_language_extension 7) set(cpsc_tar_flags cJf) @@ -41,8 +39,14 @@ endif() file(REMOVE_RECURSE "${cpsc_package_dir}") file(MAKE_DIRECTORY "${cpsc_package_dir}/doc") configure_file("${CPSC_EXECUTABLE}" "${cpsc_package_dir}/${cpsc_binary_name}" COPYONLY) -file(COPY "${CPSC_SOURCE_DIR}/${cpsc_installer}" "${CPSC_SOURCE_DIR}/LICENSE" - DESTINATION "${cpsc_package_dir}") +file(COPY "${CPSC_SOURCE_DIR}/LICENSE" DESTINATION "${cpsc_package_dir}") +if(CPSC_WINDOWS) + # cmd needs CRLF line endings whatever the packaging host is; install.cmd contains no @NAME@ sequences. + configure_file("${CPSC_SOURCE_DIR}/install.cmd" "${cpsc_package_dir}/install.cmd" + @ONLY NEWLINE_STYLE CRLF) +else() + file(COPY "${CPSC_SOURCE_DIR}/install.sh" DESTINATION "${cpsc_package_dir}") +endif() file(COPY "${CPSC_BINARY_DIR}/doc/${cpsc_manual}" DESTINATION "${cpsc_package_dir}/doc") # Package the current source set, preserving categories and ignoring stale outputs. file(GLOB_RECURSE cpsc_language_sources "${CPSC_SOURCE_DIR}/doc/language/cpsc-*.7.md") diff --git a/install.ps1 b/install.ps1 deleted file mode 100644 index e09efb3..0000000 --- a/install.ps1 +++ /dev/null @@ -1,160 +0,0 @@ -#requires -Version 5.1 -<# -.SYNOPSIS -Installs cpsc and its HTML manual for the current user. -.DESCRIPTION -Copies cpsc.exe, doc\cpsc.html and doc\language HTML pages, creates a 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, doc\cpsc.html and doc\language HTML pages; 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." - } - } - - $sourceLanguageDir = Join-Path $SourceDir 'doc\language' - if (-not (Test-Path -LiteralPath $sourceLanguageDir -PathType Container)) { - throw "Missing language manuals: $sourceLanguageDir; build the doc target first." - } - $sourceOverview = Join-Path $sourceLanguageDir 'cpsc-language-overview.html' - if (-not (Test-Path -LiteralPath $sourceOverview -PathType Leaf)) { - throw "Missing language overview: $sourceOverview; build the doc target first." - } - $languageManuals = @(Get-Item -LiteralPath $sourceOverview) - foreach ($category in @('function', 'keyword')) { - $categoryDir = Join-Path $sourceLanguageDir $category - $categoryManuals = @(Get-ChildItem -LiteralPath $categoryDir -Filter "cpsc-$category-*.html" -File) - if ($categoryManuals.Count -eq 0) { - throw "Missing language manuals: $categoryDir; build the doc target first." - } - $languageManuals += $categoryManuals - } - if ($languageManuals.Count -eq 0) { - throw "Missing language manuals: $sourceLanguageDir; build the doc target first." - } - - $docDir = Join-Path $Prefix 'doc' - $languageDir = Join-Path $docDir 'language' - $targetExe = Join-Path $Prefix 'cpsc.exe' - $targetManual = Join-Path $docDir 'cpsc.html' - foreach ($directory in @($Prefix, $docDir, $languageDir, (Join-Path $languageDir 'function'), (Join-Path $languageDir 'keyword'))) { - if ((Test-Path -LiteralPath $directory) -and - -not (Test-Path -LiteralPath $directory -PathType Container)) { - throw "Installation directory is occupied by a file: $directory" - } - } - $targetFiles = @($targetExe, $targetManual) + @($languageManuals | ForEach-Object { - Join-Path $languageDir ($_.FullName.Substring($sourceLanguageDir.Length + 1)) - }) - foreach ($file in $targetFiles) { - 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. - foreach ($category in @('function', 'keyword')) { - [IO.Directory]::CreateDirectory((Join-Path $languageDir $category)) | Out-Null - } - if ($sourceExe -ine $targetExe) { - Copy-Item -LiteralPath $sourceExe -Destination $targetExe -Force - } - if ($sourceManual -ine $targetManual) { - Copy-Item -LiteralPath $sourceManual -Destination $targetManual -Force - } - foreach ($manual in $languageManuals) { - $destination = Join-Path $languageDir ($manual.FullName.Substring($sourceLanguageDir.Length + 1)) - if ($manual.FullName -ine $destination) { - Copy-Item -LiteralPath $manual.FullName -Destination $destination -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 and $($languageManuals.Count) language manuals in $languageDir" - 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 -} -- cgit v1.3.1-4-g156e