mirror of
https://github.com/johndoe6345789/SDL3CPlusPlus.git
synced 2026-04-24 13:44:58 +00:00
fix quoting issue
This commit is contained in:
@@ -7,6 +7,11 @@ Design goals:
|
||||
- Explicit argv execution throughout.
|
||||
- Where practical, allow forwarding extra arguments to underlying tools.
|
||||
- Keep Windows/MSVC "one-liner" behavior via cmd.exe only when required.
|
||||
|
||||
NOTE (Windows quoting):
|
||||
cmd.exe has special/quirky parsing rules for /c when the command contains quotes.
|
||||
We use: cmd.exe /d /s /c ""call "<bat>" <arch> && <then...>""
|
||||
The doubled quotes at both ends are intentional and required for robust behavior.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -21,7 +26,6 @@ from typing import Iterable, Sequence
|
||||
|
||||
IS_WINDOWS = platform.system() == "Windows"
|
||||
|
||||
# Generator presets and default build dirs
|
||||
DEFAULT_GENERATOR = "ninja-msvc" if IS_WINDOWS else "ninja"
|
||||
GENERATOR_DEFAULT_DIR = {
|
||||
"vs": "build",
|
||||
@@ -43,7 +47,6 @@ DEFAULT_VCVARSALL = (
|
||||
|
||||
|
||||
def _print_cmd(argv: Sequence[str]) -> None:
|
||||
# Use subprocess.list2cmdline for Windows-friendly rendering.
|
||||
if IS_WINDOWS:
|
||||
rendered = subprocess.list2cmdline(list(argv))
|
||||
else:
|
||||
@@ -52,11 +55,12 @@ def _print_cmd(argv: Sequence[str]) -> None:
|
||||
|
||||
|
||||
def _sh_quote(s: str) -> str:
|
||||
# Minimal POSIX shell quoting for display-only.
|
||||
if not s:
|
||||
return "''"
|
||||
safe = set("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
"._-/:@=+")
|
||||
safe = set(
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
"._-/:@=+"
|
||||
)
|
||||
if all(c in safe for c in s):
|
||||
return s
|
||||
return "'" + s.replace("'", "'\"'\"'") + "'"
|
||||
@@ -71,16 +75,13 @@ def run_argvs(argvs: Iterable[Sequence[str]], dry_run: bool) -> None:
|
||||
|
||||
|
||||
def _as_build_dir(path_str: str | None, fallback: str) -> str:
|
||||
if path_str:
|
||||
return path_str
|
||||
return fallback
|
||||
return path_str or fallback
|
||||
|
||||
|
||||
def dependencies(args: argparse.Namespace) -> None:
|
||||
cmd_detect = ["conan", "profile", "detect", "-f"]
|
||||
cmd_install = ["conan", "install", ".", "-of", "build", "-b", "missing"]
|
||||
|
||||
# Allow forward of arbitrary conan install args (e.g. -s, -o, -c).
|
||||
if args.conan_install_args:
|
||||
cmd_install.extend(args.conan_install_args)
|
||||
|
||||
@@ -98,7 +99,6 @@ def configure(args: argparse.Namespace) -> None:
|
||||
|
||||
if generator == "vs":
|
||||
cmake_args.extend(["-G", CMAKE_GENERATOR["vs"]])
|
||||
# Multi-config generators typically ignore CMAKE_BUILD_TYPE.
|
||||
else:
|
||||
cmake_args.extend(["-G", CMAKE_GENERATOR[generator]])
|
||||
cmake_args.append(f"-DCMAKE_BUILD_TYPE={args.build_type}")
|
||||
@@ -118,7 +118,6 @@ def build(args: argparse.Namespace) -> None:
|
||||
if args.target:
|
||||
cmd.extend(["--target", args.target])
|
||||
|
||||
# Forward extra args to the underlying build tool after "--".
|
||||
if args.build_tool_args:
|
||||
cmd.append("--")
|
||||
cmd.extend(args.build_tool_args)
|
||||
@@ -126,15 +125,27 @@ def build(args: argparse.Namespace) -> None:
|
||||
run_argvs([cmd], args.dry_run)
|
||||
|
||||
|
||||
def _cmd_one_liner(call_parts: Sequence[str], then_parts: Sequence[str]) -> list[str]:
|
||||
def _cmd_quote_arg_for_display(argv: Sequence[str]) -> str:
|
||||
# Display-only: how this argv might look as a single command line.
|
||||
return subprocess.list2cmdline(list(argv))
|
||||
|
||||
|
||||
def _cmd_one_liner_vcvars_then(
|
||||
bat: str,
|
||||
arch: str,
|
||||
then_parts: Sequence[str],
|
||||
) -> list[str]:
|
||||
"""
|
||||
Build: cmd.exe /c "call <call_parts...> && <then_parts...>"
|
||||
Uses list2cmdline to safely quote for cmd.exe.
|
||||
Robust cmd.exe invocation for:
|
||||
call "<bat>" <arch> && <then...>
|
||||
|
||||
Uses cmd.exe quote rules:
|
||||
cmd.exe /d /s /c ""call "<bat>" <arch> && <then...>""
|
||||
"""
|
||||
call_str = "call " + subprocess.list2cmdline(list(call_parts))
|
||||
then_str = subprocess.list2cmdline(list(then_parts))
|
||||
inner = f"{call_str} && {then_str}"
|
||||
return ["cmd.exe", "/c", inner]
|
||||
then_cmdline = _cmd_quote_arg_for_display(then_parts)
|
||||
inner = f'call "{bat}" {arch} && {then_cmdline}'
|
||||
wrapped = f'""{inner}""'
|
||||
return ["cmd.exe", "/d", "/s", "/c", wrapped]
|
||||
|
||||
|
||||
def msvc_quick(args: argparse.Namespace) -> None:
|
||||
@@ -144,8 +155,6 @@ def msvc_quick(args: argparse.Namespace) -> None:
|
||||
bat = args.bat_path or DEFAULT_VCVARSALL
|
||||
arch = args.arch or "x64"
|
||||
|
||||
# Default action: build (mirrors the README-style one-liner)
|
||||
# Users can override the "then" command via: msvc-quick -- <command...>
|
||||
if args.then_command:
|
||||
then_cmd = list(args.then_command)
|
||||
else:
|
||||
@@ -159,7 +168,7 @@ def msvc_quick(args: argparse.Namespace) -> None:
|
||||
then_cmd.append("--")
|
||||
then_cmd.extend(args.build_tool_args)
|
||||
|
||||
cmd = _cmd_one_liner([bat, arch], then_cmd)
|
||||
cmd = _cmd_one_liner_vcvars_then(bat, arch, then_cmd)
|
||||
run_argvs([cmd], args.dry_run)
|
||||
|
||||
|
||||
@@ -249,7 +258,7 @@ def main() -> int:
|
||||
|
||||
msvc = subparsers.add_parser(
|
||||
"msvc-quick",
|
||||
help="run a VS Developer Prompt call + follow-on command (README one-liner style)",
|
||||
help="run a VS env setup + follow-on command (README one-liner style)",
|
||||
)
|
||||
msvc.add_argument(
|
||||
"--bat-path",
|
||||
|
||||
Reference in New Issue
Block a user