diff --git a/scripts/common_tools.sh b/scripts/common_tools.sh index f7facbdb9..3b808cc92 100644 --- a/scripts/common_tools.sh +++ b/scripts/common_tools.sh @@ -868,8 +868,7 @@ compile_cpp_for_target() # configure makefiles first so compile_commands.json gets exported mkdir -p "hack" pushd "hack" > /dev/null - ls "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build" - "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" + eval "$(../../scripts/vcvarsall.sh x64)" echo "ECHO ${CMAKE} ${CMAKE_EXTRA_ARGS} -G ${NMAKE_CMAKE_GENERATOR} ${CMAKE_ARGS[@]} ${TOOLCHAIN_FILE} ${PREFIX_PATH} ${CMAKELISTS_DIR}" "${CMAKE}" ${CMAKE_EXTRA_ARGS} -G "${NMAKE_CMAKE_GENERATOR}" "${CMAKE_ARGS[@]}" "${TOOLCHAIN_FILE}" "${PREFIX_PATH}" "${CMAKELISTS_DIR}" local CMAKE_RESULT=$? @@ -880,8 +879,7 @@ compile_cpp_for_target() fi popd > /dev/null #ls hack - echo "ECHO head compile_commands.json" - head -n 20 hack/compile_commands.json + ls "hack/*.json" cp hack/compile_commands.json . local CMAKE_BUILD_CONFIG="--config ${BUILD_TYPE}" @@ -906,7 +904,7 @@ compile_cpp_for_target() return 1 fi echo "ECHO head compile_commands.json" - head -n 20 compile_commands.json + head compile_commands.json # build it running cmake "${CMAKE}" --build . --target ${CMAKE_BUILD_TARGET} ${CMAKE_BUILD_CONFIG} -- ${CMAKE_BUILD_OPTIONS} diff --git a/scripts/vcvarsall.sh b/scripts/vcvarsall.sh new file mode 100644 index 000000000..e0530afb4 --- /dev/null +++ b/scripts/vcvarsall.sh @@ -0,0 +1,316 @@ +#!/usr/bin/env bash +# +# Source: https://github.com/nathan818fr/vcvars-bash +# Author: Nathan Poirier +# +set -Eeuo pipefail +shopt -s inherit_errexit + +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 </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' &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) +# Outputs: +# stdout: The windows-style path to vcvarsall.bat +function find_vcvarsall() { + local vsinstalldir + if [[ -n "${VSINSTALLDIR:-}" ]]; then + vsinstalldir="$VSINSTALLDIR" + else + local vswhere + vswhere=$(command -v 'vswhere' 2>/dev/null || unixpath 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe') + vsinstalldir=$("$vswhere" -latest -property installationPath &2 + return 1 + fi + fi + + printf '%s\n' "$(winpath "$vsinstalldir")\\VC\\Auxiliary\\Build\\vcvarsall.bat" +} + +# 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 "$?"'