Normalize Meson-emitted path flags for zccache strict path mode. Issue #2378 — ``ZCCACHE_STRICT_PATHS=absolute`` rejects path-bearing compiler flags (``-I``, ``-isystem``, ``-iquote``, ``-iframework``, ``-idirafter``, ``-imsvc``, ``-include``, ``-include-pch``, ``-imacros``, ``-F``,
(build_dir: Path)
| 114 | |
| 115 | |
| 116 | def normalize_meson_private_include_paths(build_dir: Path) -> bool: |
| 117 | """Normalize Meson-emitted path flags for zccache strict path mode. |
| 118 | |
| 119 | Issue #2378 — ``ZCCACHE_STRICT_PATHS=absolute`` rejects path-bearing |
| 120 | compiler flags (``-I``, ``-isystem``, ``-iquote``, ``-iframework``, |
| 121 | ``-idirafter``, ``-imsvc``, ``-include``, ``-include-pch``, ``-imacros``, |
| 122 | ``-F``, ``/I``) that are not absolute, forward-slash, and free of ``.`` |
| 123 | or ``..`` components. |
| 124 | |
| 125 | Meson emits attached single-token flags like ``"-Ici/meson/native"`` and |
| 126 | ``"-I..\\..\\src"`` from subdir and ``implicit_include_directories`` |
| 127 | behavior; this function rewrites them to canonical absolute forward-slash |
| 128 | form in both ``build.ninja`` and ``compile_commands.json``. |
| 129 | """ |
| 130 | |
| 131 | changed_any = False |
| 132 | |
| 133 | def _replacement(match: re.Match[str]) -> str: |
| 134 | prefix, raw_path, suffix = match.groups() |
| 135 | normalized = raw_path.replace("\\", "/") |
| 136 | if _is_forward_slash_absolute(normalized) and not _has_dot_components( |
| 137 | normalized |
| 138 | ): |
| 139 | absolute = normalized |
| 140 | else: |
| 141 | absolute = (build_dir / normalized).resolve().as_posix() |
| 142 | if absolute == raw_path: |
| 143 | return match.group(0) |
| 144 | return f"{prefix}{absolute}{suffix}" |
| 145 | |
| 146 | def _normalize_text(content: str) -> str: |
| 147 | return _STRICT_PATH_FLAG_RE.sub(_replacement, content) |
| 148 | |
| 149 | build_ninja = build_dir / "build.ninja" |
| 150 | if build_ninja.exists(): |
| 151 | try: |
| 152 | content = build_ninja.read_text(encoding="utf-8") |
| 153 | except OSError as e: |
| 154 | raise RuntimeError( |
| 155 | f"Could not read {build_ninja} while normalizing Meson strict paths" |
| 156 | ) from e |
| 157 | else: |
| 158 | normalized = _normalize_text(content) |
| 159 | if normalized != content: |
| 160 | try: |
| 161 | build_ninja.write_text(normalized, encoding="utf-8") |
| 162 | changed_any = True |
| 163 | except OSError as e: |
| 164 | raise RuntimeError( |
| 165 | f"Could not write {build_ninja} after normalizing Meson strict paths" |
| 166 | ) from e |
| 167 | |
| 168 | compile_commands = build_dir / "compile_commands.json" |
| 169 | if compile_commands.exists(): |
| 170 | try: |
| 171 | data = json.loads(compile_commands.read_text(encoding="utf-8")) |
| 172 | except OSError as e: |
| 173 | raise RuntimeError( |