From 6c5fc3a321b039ebdc6d6c4210e17678d47b10d1 Mon Sep 17 00:00:00 2001 From: Spicuzza Date: Thu, 22 May 2025 23:40:38 -0400 Subject: [PATCH] temporary commit --- cxxheaderparser/parser.py | 8 +++- cxxheaderparser/preprocessor.py | 69 ++++++++++++++++++++++++++++++++- tests/test_preprocessor.py | 4 -- 3 files changed, 73 insertions(+), 8 deletions(-) diff --git a/cxxheaderparser/parser.py b/cxxheaderparser/parser.py index 45f7fb6..2fb1be1 100644 --- a/cxxheaderparser/parser.py +++ b/cxxheaderparser/parser.py @@ -2361,9 +2361,13 @@ def _parse_type( # special case: conversion operators such as operator bool pqname_optional = True break - pqname, _ = self._parse_pqname( - tok, compound_ok=True, fn_ok=False, fund_ok=True + pqname, op = self._parse_pqname( + tok, compound_ok=True, fn_ok=operator_ok, fund_ok=True ) + # another special case: operators + if op is not None: + tok = get_token() + break elif tok_type in self._parse_type_ptr_ref_paren: if pqname is None: raise self._parse_error(tok) diff --git a/cxxheaderparser/preprocessor.py b/cxxheaderparser/preprocessor.py index a0ab8d9..c82ad8c 100644 --- a/cxxheaderparser/preprocessor.py +++ b/cxxheaderparser/preprocessor.py @@ -156,6 +156,9 @@ def make_msvc_preprocessor( encoding: typing.Optional[str] = None, msvc_args: typing.List[str] = ["cl.exe"], print_cmd: bool = True, + depfile: typing.Optional[pathlib.Path] = None, + deptarget: typing.Optional[typing.List[str]] = None, + dep_prefix: typing.Optional[bytes] = None, ) -> PreprocessorFunction: """ Creates a preprocessor function that uses cl.exe from Microsoft Visual Studio @@ -171,6 +174,11 @@ def make_msvc_preprocessor( :param encoding: If specified any include files are opened with this encoding :param msvc_args: This is the path to cl.exe and any extra args you might want :param print_cmd: Prints the command as its executed + :param depfile: If specified, will generate a preprocessor depfile that contains + a list of include files that were parsed. Must also specify deptarget + and dep_prefix. Not compatible with retain_all_content + :param deptarget: List of targets to put in the depfile + :param dep_prefix: See get_msvc_dep_prefix() .. code-block:: python @@ -184,9 +192,15 @@ def make_msvc_preprocessor( if not encoding: encoding = "utf-8" + if depfile and not dep_prefix: + dep_prefix = get_msvc_dep_prefix(msvc_args=msvc_args) + def _preprocess_file(filename: str, content: typing.Optional[str]) -> str: cmd = msvc_args + ["/nologo", "/E", "/C"] + if dep_prefix: + cmd.append("/showIncludes") + for p in include_paths: cmd.append(f"/I{p}") for d in defines: @@ -195,7 +209,7 @@ def _preprocess_file(filename: str, content: typing.Optional[str]) -> str: tfpname = None try: - kwargs = {"encoding": encoding} + kwargs = {"encoding": encoding, "check": True, "capture_output": True} if filename == "": if content is None: raise PreprocessorError("no content specified for stdin") @@ -214,9 +228,28 @@ def _preprocess_file(filename: str, content: typing.Optional[str]) -> str: if print_cmd: print("+", " ".join(cmd), file=sys.stderr) - result: str = subprocess.check_output(cmd, **kwargs) # type: ignore + proc = subprocess.run(cmd, **kwargs) # type: ignore + result: str = proc.stdout if not retain_all_content: result = _msvc_filter(io.StringIO(result)) + + if depfile is not None: + deps: typing.Dict[str, bool] = {} + + if not deptarget: + base, _ = os.path.splitext(filename) + target = f"{base}.o" + else: + target = " ".join(deptarget) + + with open(depfile, "w") as dfp: + dfp.write(f"{target}:") + # for dep in reversed(list(deps.keys())): + # dep = dep.replace("\\", "\\\\") + # dep = dep.replace(" ", "\\ ") + # dfp.write(f" \\\n {dep}") + dfp.write("\n") + finally: if tfpname: os.unlink(tfpname) @@ -226,6 +259,38 @@ def _preprocess_file(filename: str, content: typing.Optional[str]) -> str: return _preprocess_file +def get_msvc_dep_prefix(*, msvc_args: typing.List[str]) -> bytes: + """ + Detects the content needed to be passed to dep_prefix + """ + + # + # Copied from meson source code, Apache 2.0 license + # + + with tempfile.TemporaryDirectory() as td: + p = pathlib.Path(td) + (p / "t.h").write_text("#include \nint x;") + + r = subprocess.run( + msvc_args + ["/showIncludes", "/c", "t.h"], cwd=td, capture_output=True + ) + + matchre = re.compile(rb"^(.*\s)([a-zA-Z]:[\\/]|[\\\/]).*stdio.h$") + + def detect_prefix(out): + for line in re.split(rb"\r?\n", out): + match = matchre.match(line) + if match: + return match.group(1) + + result = detect_prefix(r.stdout) or detect_prefix(r.stderr) + if result: + return result + + raise ValueError("Could not determine msvc dep prefix") + + # # PCPP preprocessor support (not installed by default) # diff --git a/tests/test_preprocessor.py b/tests/test_preprocessor.py index 8bfd6d2..b2ee3ef 100644 --- a/tests/test_preprocessor.py +++ b/tests/test_preprocessor.py @@ -212,10 +212,6 @@ def test_preprocessor_depfile( tmp_path = tmp_path / "hard path" tmp_path.mkdir(parents=True, exist_ok=True) - # not supported - if make_pp is preprocessor.make_msvc_preprocessor: - return - h_content = '#include "t2.h"' "\n" "int x = X;\n" h2_content = '#include "t3.h"\n' "#define X 2\n" "int omitted = 1;\n" h3_content = "int h3;" pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy