fix: escape paths with spaces in pybind11-config (#4874)

* fix: Escape paths with spaces in include list from --includes

* fix: --includes should not use shlex on Windows platforms

* Apply suggestions from code review

* fix: use custom impl

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* Support trailing backslashes

Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: Markus Bauer <markus.bauer@cispa.saarland>
Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
This commit is contained in:
Markus Bauer 2024-08-14 23:25:37 +02:00 committed by Henry Schreiner
parent 75c11769bc
commit 973a16e9a0

View File

@ -2,12 +2,35 @@
from __future__ import annotations
import argparse
import re
import sys
import sysconfig
from ._version import __version__
from .commands import get_cmake_dir, get_include, get_pkgconfig_dir
# This is the conditional used for os.path being posixpath
if "posix" in sys.builtin_module_names:
from shlex import quote
elif "nt" in sys.builtin_module_names:
# See https://github.com/mesonbuild/meson/blob/db22551ed9d2dd7889abea01cc1c7bba02bf1c75/mesonbuild/utils/universal.py#L1092-L1121
# and the original documents:
# https://docs.microsoft.com/en-us/cpp/c-language/parsing-c-command-line-arguments and
# https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/
UNSAFE = re.compile("[ \t\n\r]")
def quote(s: str) -> str:
if s and not UNSAFE.search(s):
return s
# Paths cannot contain a '"' on Windows, so we don't need to worry
# about nuanced counting here.
return f'"{s}\\"' if s.endswith("\\") else f'"{s}"'
else:
def quote(s: str) -> str:
return s
def print_includes() -> None:
dirs = [
@ -22,7 +45,7 @@ def print_includes() -> None:
if d and d not in unique_dirs:
unique_dirs.append(d)
print(" ".join("-I" + d for d in unique_dirs))
print(" ".join(quote(f"-I{d}") for d in unique_dirs))
def main() -> None:
@ -54,9 +77,9 @@ def main() -> None:
if args.includes:
print_includes()
if args.cmakedir:
print(get_cmake_dir())
print(quote(get_cmake_dir()))
if args.pkgconfigdir:
print(get_pkgconfig_dir())
print(quote(get_pkgconfig_dir()))
if __name__ == "__main__":