Browse Source

[tools] MSVC environment loader, POSIX vulkan/MSVC install scripts (#2993)

* also move install-vulkan-sdk.ps1 to tools

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2993
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
Co-committed-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
pull/3018/head
Caio Oliveira 1 month ago
committed by crueter
parent
commit
7e730a121b
No known key found for this signature in database GPG Key ID: 425ACD2D4830EBC6
  1. 2
      .ci/license-header.sh
  2. 2
      .gitignore
  3. 46
      docs/Build.md
  4. 22
      docs/Deps.md
  5. 19
      tools/windows/install-vulkan-sdk.ps1
  6. 36
      tools/windows/install-vulkan-sdk.sh
  7. 42
      tools/windows/load-msvc-env.ps1
  8. 24
      tools/windows/load-msvc-env.sh
  9. 433
      tools/windows/vcvarsall.sh

2
.ci/license-header.sh

@ -4,7 +4,7 @@
# SPDX-License-Identifier: GPL-3.0-or-later
# specify full path if dupes may exist
EXCLUDE_FILES="CPM.cmake CPMUtil.cmake GetSCMRev.cmake renderdoc_app.h tools/cpm tools/shellcheck.sh tools/update-cpm.sh externals/stb externals/glad externals/getopt externals/gamemode externals/FidelityFX-FSR externals/demangle externals/bc_decoder"
EXCLUDE_FILES="CPM.cmake CPMUtil.cmake GetSCMRev.cmake renderdoc_app.h tools/cpm tools/shellcheck.sh tools/update-cpm.sh tools/windows/vcvarsall.sh externals/stb externals/glad externals/getopt externals/gamemode externals/FidelityFX-FSR externals/demangle externals/bc_decoder"
# license header constants, please change when needed :))))
YEAR=2025

2
.gitignore

@ -7,6 +7,7 @@
# Build directory
/[Bb]uild*/
doc-build/
out/
AppDir/
uruntime
@ -59,3 +60,4 @@ eden-windows-msvc
artifacts
*.AppImage*
/install*
vulkansdk*.exe

46
docs/Build.md

@ -26,7 +26,7 @@ Android has a completely different build process than other platforms. See its [
If the configure phase fails, see the `Troubleshooting` section below. Usually, as long as you followed the dependencies guide, the defaults *should* successfully configure and build.
### Qt Creator
### Option A: Qt Creator
This is the recommended GUI method for Linux, macOS, and Windows.
@ -46,39 +46,51 @@ Hit "Configure Project", then wait for CMake to finish configuring (may take a w
</details>
### Command Line
This is recommended for *BSD, Solaris, Linux, and MSYS2. MSVC is possible, but not recommended.
### Option B: Command Line
<details>
<summary>Click to Open</summary>
Note that CMake must be in your PATH, and you must be in the cloned Eden directory. On Windows, you must also set up a Visual C++ development environment. This can be done by running `C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat` in the same terminal.
Recommended generators:
> [!WARNING]
>For all systems:
>- *CMake* **MUST** be in your PATH (and also *ninja*, if you are using it as `<GENERATOR>`)
>- You *MUST* be in the cloned *Eden* directory
>
>On Windows:
> - It's recommended to install **[Ninja](https://ninja-build.org/)**
> - You must load **Visual C++ development environment**, this can be done by running our convenience script:
> - `tools/windows/load-msvc-env.ps1` (for PowerShell 5+)
> - `tools/windows/load-msvc-env.sh` (for MSYS2, Git Bash, etc)
Available `<GENERATOR>`:
- MSYS2: `MSYS Makefiles`
- MSVC: Install **[ninja](https://ninja-build.org/)** and use `Ninja`, OR use `Visual Studio 17 2022`
- MSVC: `Ninja` (preferred) or `Visual Studio 17 2022`
- macOS: `Ninja` (preferred) or `Xcode`
- Others: `Ninja` (preferred) or `UNIX Makefiles`
BUILD_TYPE should usually be `Release` or `RelWithDebInfo` (debug symbols--compiled executable will be large). If you are using a debugger and annoyed with stuff getting optimized out, try `Debug`.
Available `<BUILD_TYPE>`:
- `Release` (default)
- `RelWithDebInfo` (debug symbols--compiled executable will be large)
- `Debug` (if you are using a debugger and annoyed with stuff getting optimized out)
Caveat for Debug Builds:
- If you're building with CCache, you will need to add the environment variable `CL` with the `/FS` flag ([Reference](https://learn.microsoft.com/pt-br/cpp/build/reference/fs-force-synchronous-pdb-writes?view=msvc-170))
Also see the [Options](Options.md) page for additional CMake options.
```sh
cmake -S . -B build -G "GENERATOR" -DCMAKE_BUILD_TYPE=<BUILD_TYPE> -DYUZU_TESTS=OFF
cmake -S . -B build -G "<GENERATOR>" -DCMAKE_BUILD_TYPE=<BUILD_TYPE> -DYUZU_TESTS=OFF
```
If you are on Windows and prefer to use Clang:
```sh
cmake -S . -B build -G "GENERATOR" -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl
cmake -S . -B build -G "<GENERATOR>" -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl
```
</details>
### [CLion](https://www.jetbrains.com/clion/)
### Option C: [CLion](https://www.jetbrains.com/clion/)
<details>
<summary>Click to Open</summary>
@ -133,13 +145,13 @@ Many platforms have quirks, bugs, and other fun stuff that may cause issues when
## Building & Running
### Qt Creator
### On Qt Creator
Simply hit Ctrl+B, or the "hammer" icon in the bottom left. To run, hit the "play" icon, or Ctrl+R.
### Command Line
### On Command Line
If you are not on Windows and are using the `UNIX Makefiles` generator, you must also add `-j$(nproc)` to this command.
If you are using the `UNIX Makefiles` or `Visual Studio 17 2022` as `<GENERATOR>`, you should also add `--parallel` for faster build times.
```
cmake --build build
@ -157,4 +169,4 @@ Some platforms have convenience scripts provided for building.
- **[Linux](scripts/Linux.md)**
- **[Windows](scripts/Windows.md)**
macOS scripts will come soon.
macOS scripts will come soon.

22
docs/Deps.md

@ -3,10 +3,13 @@
To build Eden, you MUST have a C++ compiler.
* On Linux, this is usually [GCC](https://gcc.gnu.org/) 11+ or [Clang](https://clang.llvm.org/) v14+
- GCC 12 also requires Clang 14+
* On Windows, this is either:
- **[MSVC](https://visualstudio.microsoft.com/downloads/)** (you should select *Community* option),
- clang-cl - can be downloaded from the MSVC installer,
- or **[MSYS2](https://www.msys2.org)**
* On Windows, we support:
- **[MSVC](https://visualstudio.microsoft.com/downloads/)** (default)
- It's STRONGLY RECOMMENDED to use the **Community** option and **Visual Studio 2022**
- You need to install: **[Desktop development with C++](https://learn.microsoft.com/en-us/cpp/build/vscpp-step-0-installation?view=msvc-170)**
- **[clang-cl](https://learn.microsoft.com/en-us/cpp/build/clang-support-msbuild?view=msvc-180)**
- You need to install: **C++ Clang tools for Windows**
- **[MSYS2](https://www.msys2.org)** (experimental)
* On macOS, this is Apple Clang
- This can be installed with `xcode-select --install`
@ -15,20 +18,23 @@ The following additional tools are also required:
* **[CMake](https://www.cmake.org/)** 3.22+ - already included with the Android SDK
* **[Git](https://git-scm.com/)** for version control
- **[Windows installer](https://gitforwindows.org)**
* **[Python3](https://www.python.org/downloads/)** 3.10+ - necessary to download external repositories
* On Windows, you must install the **[Vulkan SDK](https://vulkan.lunarg.com/sdk/home#windows)** as well
- *A convenience script to install the latest SDK is provided in `.ci/windows/install-vulkan-sdk.ps1`*
- *A convenience script to install the latest SDK is provided in:*
- `tools/windows/install-vulkan-sdk.ps1` (for PowerShell 5+)
- `tools/windows/install-vulkan-sdk.sh` (for MSYS2, Git Bash, etc)
If you are on desktop and plan to use the Qt frontend, you *must* install Qt 6, and optionally Qt Creator (the recommended IDE for building)
If you are on desktop and plan to use the Qt frontend, you *must* install Qt 6, and optionally Qt Creator (the **RECOMMENDED** IDE for building)
* On Linux, *BSD and macOS, this can be done by the package manager
- If you wish to use Qt Creator, append `qtcreator` or `qt-creator` to the commands seen below.
* MSVC/clang-cl users on Windows must install through the [official installer](https://www.qt.io/download-qt-installer-oss)
* MSVC/clang-cl users on Windows must install through the official [Qt](https://www.qt.io/download-qt-installer-oss) installer
* Linux and macOS users may choose to use the installer as well.
* MSYS2 can also install Qt 6 via the package manager
If you are on Windows, a convenience script to install MSVC, MSYS2, Qt, all necessary packages for MSYS2, and set up a zsh environment with useful keybinds and aliases can be found [here](https://git.crueter.xyz/scripts/windev).
- For help setting up Qt Creator, run `./install.sh -h qtcreator`
If you are on Windows and NOT building with MSYS2, you may go [back home](Build.md) and continue.
If you are on **Windows** and building with **MSVC** or **clang-cl**, you may go [back home](Build.md) and continue.
## Externals
The following are handled by Eden's externals:

19
.ci/windows/install-vulkan-sdk.ps1 → tools/windows/install-vulkan-sdk.ps1

@ -1,25 +1,36 @@
# SPDX-FileCopyrightText: Copyright 2025 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
if (-not ([bool](net session 2>$null))) {
try {
net session 1>$null 2>$null
} catch {
Write-Host "This script must be run with administrator privileges!"
Exit 1
}
$VulkanSDKVer = "1.4.321.1"
$VulkanSDKVer = "1.4.328.1"
$VULKAN_SDK = "C:/VulkanSDK/$VulkanSDKVer"
$ExeFile = "vulkansdk-windows-X64-$VulkanSDKVer.exe"
$Uri = "https://sdk.lunarg.com/sdk/download/$VulkanSDKVer/windows/$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"
$VULKAN_SDK = "C:/VulkanSDK/$VulkanSDKVer"
$Arguments = "--root `"$VULKAN_SDK`" --accept-licenses --default-answer --confirm-command install"
echo "Installing Vulkan SDK $VulkanSDKVer"
@ -36,4 +47,4 @@ 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
}
}

36
tools/windows/install-vulkan-sdk.sh

@ -0,0 +1,36 @@
#!/usr/bin/sh
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
: "${VULKAN_SDK_VER:=1.4.328.1}"
: "${VULKAN_ROOT:=C:/VulkanSDK/$VULKAN_SDK_VER}"
EXE_FILE="vulkansdk-windows-X64-$VULKAN_SDK_VER.exe"
URI="https://sdk.lunarg.com/sdk/download/$VULKAN_SDK_VER/windows/$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

42
tools/windows/load-msvc-env.ps1

@ -0,0 +1,42 @@
# 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)"

24
tools/windows/load-msvc-env.sh

@ -0,0 +1,24 @@
#!/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"

433
tools/windows/vcvarsall.sh

@ -0,0 +1,433 @@
#!/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 "$?"'
Loading…
Cancel
Save