Browse Source
[*] Drop MSVC support
[*] Drop MSVC support
To keep this PR description as short as possible, I will save the ranting about MSVC for the blog post. In short: MSVC has been nothing but a complete and utter slog to maintain for the *entire* existence of Eden. CI is an absolute nightmare, it requires *completely* different compile flags and definitions, has several sets of hacks dedicated to getting its codegen to cooperate, is a horror story with respect to dependency management, and is now completely broken and can't launch games anymore. Microsoft, you have long overstayed your welcome. And you're not getting it back ever again. Good riddance. Signed-off-by: crueter <crueter@eden-emu.dev>drop-msvc
No known key found for this signature in database
GPG Key ID: 425ACD2D4830EBC6
10 changed files with 57 additions and 717 deletions
-
11CMakeLists.txt
-
64docs/Build.md
-
48docs/Debug.md
-
43docs/Deps.md
-
8docs/Options.md
-
57tools/windows/install-vulkan-sdk.ps1
-
44tools/windows/install-vulkan-sdk.sh
-
42tools/windows/load-msvc-env.ps1
-
24tools/windows/load-msvc-env.sh
-
433tools/windows/vcvarsall.sh
@ -1,57 +0,0 @@ |
|||||
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project |
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later |
|
||||
|
|
||||
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project |
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later |
|
||||
|
|
||||
$ErrorActionPreference = "Stop" |
|
||||
|
|
||||
# Check if running as administrator |
|
||||
try { |
|
||||
net session 1>$null 2>$null |
|
||||
} catch { |
|
||||
Write-Host "This script must be run with administrator privileges!" |
|
||||
Exit 1 |
|
||||
} |
|
||||
|
|
||||
$VulkanSDKVer = "1.4.341.1" |
|
||||
if ((Get-WmiObject -Class Win32_ComputerSystem).SystemType -match '(x64)' -eq "True") { |
|
||||
$VulkanSDKArch = "X64" |
|
||||
$VulkanSDKOs = "windows" |
|
||||
} else { |
|
||||
$VulkanSDKArch = "ARM64" |
|
||||
$VulkanSDKOs = "warm" |
|
||||
} |
|
||||
$VULKAN_SDK = "C:/VulkanSDK/$VulkanSDKVer" |
|
||||
$ExeFile = "vulkansdk-windows-$VulkanSDKArch-$VulkanSDKVer.exe" |
|
||||
$Uri = "https://sdk.lunarg.com/sdk/download/$VulkanSDKVer/$VulkanSDKOs/$ExeFile" |
|
||||
$Destination = "./$ExeFile" |
|
||||
|
|
||||
# Check if Vulkan SDK is already installed |
|
||||
if (Test-Path $VULKAN_SDK) { |
|
||||
Write-Host "-- Vulkan SDK already installed at $VULKAN_SDK" |
|
||||
return |
|
||||
} |
|
||||
|
|
||||
echo "Downloading Vulkan SDK $VulkanSDKVer from $Uri" |
|
||||
$WebClient = New-Object System.Net.WebClient |
|
||||
$WebClient.DownloadFile($Uri, $Destination) |
|
||||
echo "Finished downloading $ExeFile" |
|
||||
|
|
||||
$Arguments = "--root `"$VULKAN_SDK`" --accept-licenses --default-answer --confirm-command install" |
|
||||
|
|
||||
echo "Installing Vulkan SDK $VulkanSDKVer" |
|
||||
$InstallProcess = Start-Process -FilePath $Destination -NoNewWindow -PassThru -Wait -ArgumentList $Arguments |
|
||||
$ExitCode = $InstallProcess.ExitCode |
|
||||
|
|
||||
if ($ExitCode -ne 0) { |
|
||||
echo "Error installing Vulkan SDK $VulkanSDKVer (Error: $ExitCode)" |
|
||||
Exit $ExitCode |
|
||||
} |
|
||||
|
|
||||
echo "Finished installing Vulkan SDK $VulkanSDKVer" |
|
||||
|
|
||||
if ("$env:GITHUB_ACTIONS" -eq "true") { |
|
||||
echo "VULKAN_SDK=$VULKAN_SDK" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append |
|
||||
echo "$VULKAN_SDK/Bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append |
|
||||
} |
|
||||
@ -1,44 +0,0 @@ |
|||||
#!/usr/bin/sh |
|
||||
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project |
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later |
|
||||
|
|
||||
: "${VULKAN_SDK_VER:=1.4.341.1}" |
|
||||
: "${VULKAN_ROOT:=C:/VulkanSDK/$VULKAN_SDK_VER}" |
|
||||
VULKAN_SDK_ARCH=X64 |
|
||||
VULKAN_SDK_OS=windows |
|
||||
case "$(uname)" in |
|
||||
*ARM64*) |
|
||||
VULKAN_SDK_ARCH=ARM64 |
|
||||
VULKAN_SDK_OS=warm |
|
||||
;; |
|
||||
esac |
|
||||
EXE_FILE="vulkansdk-windows-$VULKAN_SDK_ARCH-$VULKAN_SDK_VER.exe" |
|
||||
URI="https://sdk.lunarg.com/sdk/download/$VULKAN_SDK_VER/$VULKAN_SDK_OS/$EXE_FILE" |
|
||||
VULKAN_ROOT_UNIX=$(cygpath -u "$VULKAN_ROOT") |
|
||||
|
|
||||
# Check if Vulkan SDK is already installed |
|
||||
if [ -d "$VULKAN_ROOT_UNIX" ]; then |
|
||||
echo "-- Vulkan SDK already installed at $VULKAN_ROOT_UNIX" |
|
||||
exit 0 |
|
||||
fi |
|
||||
|
|
||||
echo "Downloading Vulkan SDK $VULKAN_SDK_VER from $URI" |
|
||||
[ ! -f "./$EXE_FILE" ] && curl -L -o "./$EXE_FILE" "$URI" |
|
||||
chmod +x "./$EXE_FILE" |
|
||||
echo "Finished downloading $EXE_FILE" |
|
||||
|
|
||||
echo "Installing Vulkan SDK $VULKAN_SDK_VER..." |
|
||||
if net session > /dev/null 2>&1; then |
|
||||
./$EXE_FILE --root "$VULKAN_ROOT" --accept-licenses --default-answer --confirm-command install |
|
||||
else |
|
||||
echo "This script must be run with administrator privileges!" |
|
||||
exit 1 |
|
||||
fi |
|
||||
|
|
||||
echo "Finished installing Vulkan SDK $VULKAN_SDK_VER" |
|
||||
|
|
||||
# GitHub Actions integration |
|
||||
if [ \"${GITHUB_ACTIONS:-false}\" = \"true\" ]; then |
|
||||
echo \"VULKAN_SDK=$VULKAN_ROOT\" >> \"$GITHUB_ENV\" |
|
||||
echo \"$VULKAN_ROOT/bin\" >> \"$GITHUB_PATH\" |
|
||||
fi |
|
||||
@ -1,42 +0,0 @@ |
|||||
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project |
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later |
|
||||
|
|
||||
$osArch = $env:PROCESSOR_ARCHITECTURE |
|
||||
|
|
||||
switch ($osArch) { |
|
||||
"AMD64" { $arch = "x64" } |
|
||||
"ARM64" { $arch = "arm64" } |
|
||||
default { |
|
||||
Write-Error "load-msvc-env.ps1: Unsupported architecture: $osArch" |
|
||||
exit 1 |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
$vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" |
|
||||
|
|
||||
if (!(Test-Path $vswhere)) { |
|
||||
Write-Error "load-msvc-env.ps1: vswhere not found" |
|
||||
exit 1 |
|
||||
} |
|
||||
|
|
||||
$vs = & $vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath |
|
||||
|
|
||||
if (-not $vs) { |
|
||||
Write-Error "load-msvc-env.ps1: Visual Studio (with Desktop development with C++) not found" |
|
||||
exit 1 |
|
||||
} |
|
||||
|
|
||||
$bat = "$vs\VC\Auxiliary\Build\vcvarsall.bat" |
|
||||
|
|
||||
if (!(Test-Path $bat)) { |
|
||||
Write-Error "load-msvc-env.ps1: (vcvarsall.bat) not found" |
|
||||
exit 1 |
|
||||
} |
|
||||
|
|
||||
cmd /c "`"$bat`" $arch && set" | ForEach-Object { |
|
||||
if ($_ -match "^(.*?)=(.*)$") { |
|
||||
[Environment]::SetEnvironmentVariable($matches[1], $matches[2], 'Process') |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
Write-Host "load-msvc-env.ps1: MSVC environment loaded for $arch ($vs)" |
|
||||
@ -1,24 +0,0 @@ |
|||||
#!/usr/bin/bash |
|
||||
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project |
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later |
|
||||
|
|
||||
ARCH_RAW="$PROCESSOR_ARCHITECTURE" |
|
||||
|
|
||||
case "$ARCH_RAW" in |
|
||||
AMD64) ARCH="x64" ;; |
|
||||
ARM64) ARCH="arm64" ;; |
|
||||
*) echo "load-msvc-env.sh: Unsupported architecture: $ARCH_RAW"; exit 1 ;; |
|
||||
esac |
|
||||
|
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" |
|
||||
VCVARS_BASH="$SCRIPT_DIR/vcvarsall.sh" |
|
||||
|
|
||||
if [ ! -f "$VCVARS_BASH" ]; then |
|
||||
echo "load-msvc-env.sh: vcvarsall.sh not found in $SCRIPT_DIR" |
|
||||
#exit 1 |
|
||||
fi |
|
||||
chmod +x "$VCVARS_BASH" |
|
||||
|
|
||||
eval "$("$VCVARS_BASH" "$ARCH")" |
|
||||
|
|
||||
echo "MSVC environment loaded for $ARCH with vcvars-bash script" |
|
||||
@ -1,433 +0,0 @@ |
|||||
#!/usr/bin/env bash |
|
||||
# |
|
||||
# SPDX-FileCopyrightText: Copyright 2023 Nathan Poirier <nathan@poirier.io> |
|
||||
# SPDX-License-Identifier: MIT License |
|
||||
# |
|
||||
# Source: https://github.com/nathan818fr/vcvars-bash |
|
||||
# |
|
||||
set -Eeuo pipefail |
|
||||
shopt -s inherit_errexit |
|
||||
|
|
||||
declare -r VERSION='2025-07-09.1' |
|
||||
|
|
||||
function detect_platform() { |
|
||||
case "${OSTYPE:-}" in |
|
||||
cygwin* | msys* | win32) |
|
||||
declare -gr bash_platform='win_cyg' |
|
||||
;; |
|
||||
*) |
|
||||
if [[ -n "${WSL_DISTRO_NAME:-}" ]]; then |
|
||||
declare -gr bash_platform='win_wsl' |
|
||||
else |
|
||||
printf 'error: Unsupported platform (%s)\n' "${OSTYPE:-}" >&2 |
|
||||
printf 'hint: This script only supports Bash on Windows (Git Bash, WSL, etc.)\n' >&2 |
|
||||
return 1 |
|
||||
fi |
|
||||
;; |
|
||||
esac |
|
||||
} |
|
||||
|
|
||||
function detect_mode() { |
|
||||
# Detect the mode depending on the name called |
|
||||
if [[ "$(basename -- "$0")" == vcvarsrun* ]]; then |
|
||||
declare -gr script_mode='run' # vcvarsrun.sh |
|
||||
else |
|
||||
declare -gr script_mode='default' # vcvarsall.sh |
|
||||
fi |
|
||||
} |
|
||||
|
|
||||
function print_usage() { |
|
||||
case "$script_mode" in |
|
||||
default) |
|
||||
cat <<EOF |
|
||||
Usage: eval "\$(vcvarsall.sh [vcvarsall.bat arguments])" |
|
||||
Script version: $VERSION |
|
||||
|
|
||||
Load MSVC environment variables using vcvarsall.bat and export them. |
|
||||
The script writes a list of export commands to stdout, to be evaluated by a |
|
||||
POSIX-compliant shell. |
|
||||
|
|
||||
Example: eval "\$(vcvarsall.sh x86)" |
|
||||
EOF |
|
||||
;; |
|
||||
run) |
|
||||
cat <<EOF |
|
||||
Usage: vcvarsrun.sh [vcvarsall.bat arguments] -- command [arguments...] |
|
||||
Script version: $VERSION |
|
||||
|
|
||||
Load MSVC environment variables using vcvarsall.bat and execute a command with |
|
||||
them. |
|
||||
|
|
||||
Example: vcvarsrun.sh x64 -- cl /nologo /EHsc /Fe:hello.exe hello.cpp |
|
||||
EOF |
|
||||
;; |
|
||||
esac |
|
||||
cat <<EOF |
|
||||
|
|
||||
Environment variables: |
|
||||
VSINSTALLDIR |
|
||||
The path to the Visual Studio installation directory. |
|
||||
Example: "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community" |
|
||||
Default: The latest Visual Studio installation directory found by |
|
||||
vswhere.exe |
|
||||
|
|
||||
VSWHEREPATH |
|
||||
The path to the vswhere.exe executable. |
|
||||
Example: "C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\vswhere.exe" |
|
||||
Default: Automatically detected (in the PATH or well-known locations) |
|
||||
|
|
||||
VSWHEREARGS |
|
||||
The arguments to pass to vswhere.exe. |
|
||||
This value is always automatically prefixed with "-latest -property installationPath". |
|
||||
Default: "-products *" |
|
||||
EOF |
|
||||
local vcvarsall |
|
||||
vcvarsall=$(find_vcvarsall) |
|
||||
printf '\nvcvarsall.bat arguments: %s\n' "$({ cmd "$(cmdesc "$vcvarsall")" -help </dev/null 2>/dev/null || true; } | fix_crlf | sed '/^Syntax:/d; s/^ vcvarsall.bat //')" |
|
||||
} |
|
||||
|
|
||||
function main() { |
|
||||
detect_platform |
|
||||
detect_mode |
|
||||
|
|
||||
# Parse arguments |
|
||||
if [[ $# -eq 0 ]]; then |
|
||||
print_usage >&2 |
|
||||
return 1 |
|
||||
fi |
|
||||
|
|
||||
local arg vcvarsall_args=() |
|
||||
for arg in "$@"; do |
|
||||
shift |
|
||||
if [[ "$arg" == '--' ]]; then |
|
||||
if [[ "$script_mode" == 'default' ]]; then |
|
||||
printf 'error: Unexpected argument: --\n' >&2 |
|
||||
printf 'hint: Use vcvarsrun to run a command\n' >&2 |
|
||||
return 1 |
|
||||
fi |
|
||||
break |
|
||||
fi |
|
||||
vcvarsall_args+=("$(cmdesc "$arg")") |
|
||||
done |
|
||||
|
|
||||
if [[ "$script_mode" == 'run' && $# -eq 0 ]]; then |
|
||||
printf 'error: No command specified\n' >&2 |
|
||||
return 1 |
|
||||
fi |
|
||||
|
|
||||
# Get MSVC environment variables from vcvarsall.bat |
|
||||
local vcvarsall vcvarsall_env |
|
||||
vcvarsall=$(find_vcvarsall) |
|
||||
vcvarsall_env=$({ cmd "$(cmdesc "$vcvarsall")" "${vcvarsall_args[@]}" '&&' 'set' </dev/null || true; } | fix_crlf) |
|
||||
|
|
||||
# Filter MSVC environment variables and export them. |
|
||||
# The list of variables to export was based on a comparison between a clean environment and the vcvarsall.bat |
|
||||
# environment (on different MSVC versions, tools and architectures). |
|
||||
# |
|
||||
# Windows environment variables are case-insensitive while Unix-like environment variables are case-sensitive, so: |
|
||||
# - we always use uppercase names to prevent duplicates environment variables on the Unix-like side |
|
||||
# - we also ensure that only the first occurrence of a variable is exported (see below) |
|
||||
# |
|
||||
# While Windows environment variables are case-insensitive, it is possible to have duplicates in some edge cases. |
|
||||
# e.g. using Git Bash: |
|
||||
# export xxx=1; export XXX=2; export xXx=3; cmd.exe //c set XxX=4 '&&' set |
|
||||
# will output: |
|
||||
# XXX=4 |
|
||||
# xXx=3 |
|
||||
# xxx=1 |
|
||||
|
|
||||
declare -A seen_vars |
|
||||
function export_env() { |
|
||||
local name=${1^^} |
|
||||
local value=$2 |
|
||||
if [[ ! "$name" =~ ^[A-Z0-9_]+$ ]]; then return; fi |
|
||||
if [[ -n "${seen_vars[$name]:-}" ]]; then return; fi |
|
||||
seen_vars[$name]=1 |
|
||||
if [[ "$script_mode" == 'run' ]]; then |
|
||||
export "${name}=${value}" |
|
||||
else |
|
||||
printf "export %s='%s'\n" "$name" "${value//\'/\'\\\'\'}" |
|
||||
fi |
|
||||
} |
|
||||
|
|
||||
local name value initialized=false |
|
||||
while IFS='=' read -r name value; do |
|
||||
if [[ "$initialized" == 'false' ]]; then |
|
||||
if [[ -n "$value" ]]; then name+="=$value"; fi |
|
||||
if [[ "$name" == *' Environment initialized for: '* ]]; then initialized=true; fi |
|
||||
printf '%s\n' "$name" >&2 |
|
||||
continue |
|
||||
fi |
|
||||
|
|
||||
case "${name^^}" in |
|
||||
LIB | LIBPATH | INCLUDE | EXTERNAL_INCLUDE | COMMANDPROMPTTYPE | DEVENVDIR | EXTENSIONSDKDIR | FRAMEWORK* | \ |
|
||||
PLATFORM | PREFERREDTOOLARCHITECTURE | UCRT* | UNIVERSALCRTSDK* | VCIDE* | VCINSTALL* | VCPKG* | VCTOOLS* | \ |
|
||||
VSCMD* | VSINSTALL* | VS[0-9]* | VISUALSTUDIO* | WINDOWSLIB* | WINDOWSSDK*) |
|
||||
export_env "$name" "$value" |
|
||||
;; |
|
||||
PATH) |
|
||||
# PATH is a special case, requiring special handling |
|
||||
local new_paths |
|
||||
new_paths=$(pathlist_win_to_unix "$value") # Convert to unix-style path list |
|
||||
new_paths=$(pathlist_normalize "${PATH}:${new_paths}") # Prepend the current PATH |
|
||||
export_env 'WINDOWS_PATH' "$value" |
|
||||
export_env 'PATH' "$new_paths" |
|
||||
;; |
|
||||
esac |
|
||||
done <<<"$vcvarsall_env" |
|
||||
|
|
||||
if [[ "$initialized" == 'false' ]]; then |
|
||||
printf 'error: vcvarsall.bat failed' >&2 |
|
||||
return 1 |
|
||||
fi |
|
||||
|
|
||||
# Execute command if needed |
|
||||
if [[ "$script_mode" == 'run' ]]; then |
|
||||
exec "$@" |
|
||||
fi |
|
||||
} |
|
||||
|
|
||||
# Locate vcvarsall.bat |
|
||||
# Inputs: |
|
||||
# VSINSTALLDIR: The path to the Visual Studio installation directory (optional) |
|
||||
# VSWHEREPATH: The path to the vswhere.exe executable (optional) |
|
||||
# VSWHEREARGS: The arguments to pass to vswhere.exe (optional) |
|
||||
# Outputs: |
|
||||
# stdout: The windows-style path to vcvarsall.bat |
|
||||
function find_vcvarsall() { |
|
||||
local vsinstalldir |
|
||||
if [[ -n "${VSINSTALLDIR:-}" ]]; then |
|
||||
vsinstalldir="$VSINSTALLDIR" |
|
||||
else |
|
||||
local vswhere |
|
||||
if [[ -n "${VSWHEREPATH:-}" ]]; then |
|
||||
vswhere=$(unixpath "$VSWHEREPATH") |
|
||||
else |
|
||||
vswhere=$(command -v 'vswhere' 2>/dev/null || unixpath 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe') |
|
||||
fi |
|
||||
|
|
||||
local vswhereargs=(-latest -property installationPath) |
|
||||
if [[ -n "${VSWHEREARGS:-}" ]]; then |
|
||||
parse_args_simple "$VSWHEREARGS" |
|
||||
vswhereargs+=("${result[@]}") |
|
||||
else |
|
||||
vswhereargs+=(-products '*') |
|
||||
fi |
|
||||
|
|
||||
if [[ "${VCVARSBASH_DEBUG:-}" == 1 ]]; then |
|
||||
printf 'debug: vswhere path: %s\n' "$vswhere" >&2 |
|
||||
printf 'debug: vswhere args:\n' >&2 |
|
||||
printf 'debug: [ %s ]\n' "${vswhereargs[@]}" >&2 |
|
||||
fi |
|
||||
|
|
||||
vsinstalldir=$("$vswhere" "${vswhereargs[@]}" </dev/null | fix_crlf) |
|
||||
if [[ -z "$vsinstalldir" ]]; then |
|
||||
printf 'error: vswhere returned an empty installation path\n' >&2 |
|
||||
return 1 |
|
||||
fi |
|
||||
fi |
|
||||
|
|
||||
printf '%s\n' "$(winpath "$vsinstalldir")\\VC\\Auxiliary\\Build\\vcvarsall.bat" |
|
||||
} |
|
||||
|
|
||||
# Split command arguments into an array, with a simple logic |
|
||||
# - Arguments are separated by whitespace (space, tab, newline, carriage return) |
|
||||
# - To include whitespace in an argument, it must be enclosed in double quotes (") |
|
||||
# - When inside a double-quoted argument, quotes can be escaped by doubling them ("") |
|
||||
# Inputs: |
|
||||
# $1: The string to parse |
|
||||
# Outputs: |
|
||||
# result: An array of parsed arguments |
|
||||
function parse_args_simple() { |
|
||||
declare -g result=() |
|
||||
local str="$1 " # add a trailing space to simplify the last argument handling |
|
||||
local args=() |
|
||||
local current_type=none # none = waiting for next arg, normal = inside normal arg, quoted = inside quoted arg |
|
||||
local current_value='' |
|
||||
local i=0 len=${#str} |
|
||||
while ((i < len)); do |
|
||||
local c=${str:i:1} |
|
||||
case "$current_type" in |
|
||||
none) |
|
||||
case "$c" in |
|
||||
' ' | $'\t' | $'\n' | $'\r') |
|
||||
# Ignore whitespace |
|
||||
;; |
|
||||
'"') |
|
||||
# Start a quoted argument |
|
||||
current_type=quoted |
|
||||
current_value='' |
|
||||
;; |
|
||||
*) |
|
||||
# Start a normal argument |
|
||||
current_type=normal |
|
||||
current_value="$c" |
|
||||
;; |
|
||||
esac |
|
||||
;; |
|
||||
normal) |
|
||||
case "$c" in |
|
||||
' ' | $'\t' | $'\n' | $'\r') |
|
||||
# End of normal argument, add it to the list |
|
||||
args+=("$current_value") |
|
||||
current_type=none |
|
||||
current_value='' |
|
||||
;; |
|
||||
*) |
|
||||
# Continue building the normal argument |
|
||||
current_value+="$c" |
|
||||
;; |
|
||||
esac |
|
||||
;; |
|
||||
quoted) |
|
||||
case "$c" in |
|
||||
'"') |
|
||||
if [[ "${str:i+1:1}" != '"' ]]; then |
|
||||
# End of quoted argument, add it to the list |
|
||||
args+=("$current_value") |
|
||||
current_type=none |
|
||||
current_value='' |
|
||||
else |
|
||||
# Escaped quote, add a single quote to the current value |
|
||||
current_value+='"' |
|
||||
((++i)) # Skip the next quote |
|
||||
fi |
|
||||
;; |
|
||||
*) |
|
||||
# Continue building the quoted argument |
|
||||
current_value+="$c" |
|
||||
;; |
|
||||
esac |
|
||||
;; |
|
||||
esac |
|
||||
((++i)) |
|
||||
done |
|
||||
if [[ "$current_type" != none ]]; then |
|
||||
printf 'error: Unfinished %s argument: %s\n' "$current_type" "$current_value" >&2 |
|
||||
return 1 |
|
||||
fi |
|
||||
declare -g result=("${args[@]}") |
|
||||
} |
|
||||
|
|
||||
# Run a command with cmd.exe |
|
||||
# Inputs: |
|
||||
# $@: The command string to run (use cmdesc to escape arguments when needed) |
|
||||
# Outputs: |
|
||||
# stdout: The cmd.exe standard output |
|
||||
# stderr: The cmd.exe error output |
|
||||
function cmd() { |
|
||||
# This seems to work fine on all supported platforms |
|
||||
# (even with all the weird path and argument conversions on MSYS-like) |
|
||||
MSYS_NO_PATHCONV=1 MSYS2_ARG_CONV_EXCL='*' cmd.exe /s /c " ; $* " |
|
||||
} |
|
||||
|
|
||||
# Escape a cmd.exe command argument |
|
||||
# Inputs: |
|
||||
# $1: The argument to escape |
|
||||
# Outputs: |
|
||||
# stdout: The escaped argument |
|
||||
function cmdesc() { |
|
||||
# shellcheck disable=SC2001 |
|
||||
sed 's/[^0-9A-Za-z]/^\0/g' <<<"$1" |
|
||||
} |
|
||||
|
|
||||
# Convert path to an absolute unix-style path |
|
||||
# Inputs: |
|
||||
# $1: The path to convert |
|
||||
# Outputs: |
|
||||
# stdout: The converted path |
|
||||
function unixpath() { |
|
||||
local path=$1 |
|
||||
case "$bash_platform" in |
|
||||
win_wsl) |
|
||||
case "$path" in |
|
||||
[a-zA-Z]:\\* | [a-zA-Z]:/* | \\\\* | //*) |
|
||||
# Convert windows path using wslpath (unix mode, absolute path) |
|
||||
wslpath -u -a -- "$path" |
|
||||
;; |
|
||||
*) |
|
||||
# Convert unix path using realpath |
|
||||
realpath -m -- "$path" |
|
||||
;; |
|
||||
esac |
|
||||
;; |
|
||||
*) |
|
||||
cygpath -u -a -- "$path" |
|
||||
;; |
|
||||
esac |
|
||||
} |
|
||||
|
|
||||
# Convert path to an absolute windows-style path |
|
||||
# Inputs: |
|
||||
# $1: The path to convert |
|
||||
# Outputs: |
|
||||
# stdout: The converted path |
|
||||
function winpath() { |
|
||||
local path=$1 |
|
||||
case "$bash_platform" in |
|
||||
win_wsl) |
|
||||
case "$path" in |
|
||||
[a-zA-Z]:\\* | [a-zA-Z]:/* | \\\\* | //*) |
|
||||
# Already a windows path |
|
||||
printf '%s' "$path" |
|
||||
;; |
|
||||
*) |
|
||||
# Convert using wslpath (windows mode, absolute path) |
|
||||
wslpath -w -a -- "$path" |
|
||||
;; |
|
||||
esac |
|
||||
;; |
|
||||
*) |
|
||||
# Convert using cygpath (windows mode, absolute path, long form) |
|
||||
cygpath -w -a -l -- "$path" |
|
||||
;; |
|
||||
esac |
|
||||
} |
|
||||
|
|
||||
# Convert a windows-style path list to a unix-style path list |
|
||||
# Inputs: |
|
||||
# $1: The windows-style path list to convert |
|
||||
# Outputs: |
|
||||
# stdout: The converted unix-style path list |
|
||||
function pathlist_win_to_unix() { |
|
||||
local win_paths=$1 |
|
||||
|
|
||||
local path_dir first=true |
|
||||
while IFS= read -r -d';' path_dir; do |
|
||||
if [[ -z "$path_dir" ]]; then continue; fi |
|
||||
|
|
||||
if [[ "$first" == 'true' ]]; then first=false; else printf ':'; fi |
|
||||
printf '%s' "$(unixpath "$path_dir")" |
|
||||
done <<<"${win_paths};" |
|
||||
} |
|
||||
|
|
||||
# Normalize a unix-style path list, removing duplicates and empty entries |
|
||||
# Inputs: |
|
||||
# $1: The list to normalize |
|
||||
# Outputs: |
|
||||
# stdout: The normalized path list |
|
||||
function pathlist_normalize() { |
|
||||
local unix_paths=$1 |
|
||||
|
|
||||
declare -A seen_paths |
|
||||
local path_dir first=true |
|
||||
while IFS= read -r -d ':' path_dir; do |
|
||||
if [[ -z "$path_dir" ]]; then continue; fi |
|
||||
if [[ -n "${seen_paths[$path_dir]:-}" ]]; then continue; fi |
|
||||
seen_paths[$path_dir]=1 |
|
||||
|
|
||||
if [[ "$first" == 'true' ]]; then first=false; else printf ':'; fi |
|
||||
printf '%s' "$path_dir" |
|
||||
done <<<"${unix_paths}:" |
|
||||
} |
|
||||
|
|
||||
# Convert CRLF to LF |
|
||||
# Inputs: |
|
||||
# stdin: The input to convert |
|
||||
# Outputs: |
|
||||
# stdout: The converted input |
|
||||
function fix_crlf() { |
|
||||
sed 's/\r$//' |
|
||||
} |
|
||||
|
|
||||
eval 'main "$@";exit "$?"' |
|
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue