Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions parser/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,15 @@ def merge_meta(idl: dict, meta_path: Path) -> dict:
)


def parse_meos(entry: Path, include_dir: Path) -> dict:
def parse_meos(entry: Path, include_dir: Path,
extra_headers: tuple[Path, ...] = ()) -> dict:
index = clang.cindex.Index.create()
extra_dirs = sorted({h.parent.resolve() for h in extra_headers})
tu = index.parse(str(entry), args=[
"-x", "c",
"-std=c11",
f"-I{include_dir}",
*(f"-I{d}" for d in extra_dirs),
"-DMEOS",
# Define the MEOS ``UNUSED`` attribute macro on the command line so it is
# always in scope: the amalgamated entry point may parse a header that
Expand All @@ -131,6 +134,7 @@ def parse_meos(entry: Path, include_dir: Path) -> dict:

# Collect all .h files belonging to the project
own_files = {str(p.resolve()) for p in include_dir.glob("**/*.h")}
own_files.update(str(h.resolve()) for h in extra_headers)

# First pass: build a mapping "anonymous struct location -> typedef name"
typedef_map: dict[str, str] = {}
Expand Down Expand Up @@ -199,21 +203,25 @@ def _dedup(items: list) -> list:
return resolve_idl_types(idl, mappings_path)


def build_entry_point(headers_dir: Path) -> str:
def build_entry_point(headers_dir: Path,
extra_headers: tuple[Path, ...] = ()) -> str:
lines = []
for h in sorted(headers_dir.glob("**/*.h")):
lines.append(f'#include "{h.resolve()}"')
for h in extra_headers:
lines.append(f'#include "{h.resolve()}"')
return "\n".join(lines)


def parse_all_headers(headers_dir: Path) -> dict:
entry_src = build_entry_point(headers_dir)
def parse_all_headers(headers_dir: Path,
extra_headers: tuple[Path, ...] = ()) -> dict:
entry_src = build_entry_point(headers_dir, extra_headers)

with tempfile.NamedTemporaryFile(suffix=".h", mode="w", delete=False) as f:
f.write(entry_src)
tmp_path = f.name

try:
return parse_meos(Path(tmp_path), headers_dir)
return parse_meos(Path(tmp_path), headers_dir, extra_headers)
finally:
os.unlink(tmp_path)
29 changes: 28 additions & 1 deletion run.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,39 @@ def _source_commit():
return None


def _public_pgtypes_headers() -> tuple[Path, ...]:
"""MobilityDB's vendored PostgreSQL base-type headers, when they sit outside HEADERS_DIR.

MobilityDB keeps the PostgreSQL 18 base types in a `pgtypes/` library at the repo root and
installs `pgtypes.h` and the `pg_*.h` set into the include prefix, so they are as public as
`meos.h`. Reading an INSTALLED prefix therefore already covers them and this adds nothing;
reading the source tree points at `meos/include`, which does not contain them, and without
this the catalog silently loses the whole base-type surface (`interval_make`, the base I/O
functions, …) — the same ref then yields two different catalogs depending on the header root.
"""
root = Path(os.environ.get("MDB_SRC_ROOT", "./_mobilitydb")) / "pgtypes"
if not root.is_dir():
return ()
seen = {p.name for p in HEADERS_DIR.glob("**/*.h")}
candidates = sorted(root.glob("pg_*.h")) + [root / "pgtypes.h"]
headers = [h for h in candidates
# pg_config*.h carry PostgreSQL's build configuration, not API; the
# install set leaves them behind and so does the catalog.
if h.is_file() and not h.name.startswith("pg_config")
and h.name not in seen]
return tuple(headers)


def main():
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)

# 1. Parse C headers
print(f"[1/4] Parsing {HEADERS_DIR}...", file=sys.stderr)
idl = parse_all_headers(HEADERS_DIR)
pgtypes = _public_pgtypes_headers()
if pgtypes:
print(f" + {len(pgtypes)} vendored pgtypes headers from "
f"{pgtypes[0].parent}", file=sys.stderr)
idl = parse_all_headers(HEADERS_DIR, pgtypes)

# 1b. Recover PG-vendored C types the preprocessor collapsed to int
# (bool / int64 / Timestamp(Tz) / H3Index) from the header text.
Expand Down
Loading