tools/make-callentries.R

# This file updates the call entries in src/r-init.c such that R code
# can use .Call(geoarrow_c_some_function_name) for all C functions
# with the signature SEXP geoarrow_c_some_function_name(...).

library(tidyverse)

src_files <- list.files("src", "\\.(c|cpp|cc)$", full.names = TRUE) %>%
  setdiff("src/r-init.c")
src_sources <- src_files %>% set_names() %>% map_chr(readr::read_file)

defs <- tibble(
  def = src_sources %>%
    str_extract_all(regex("SEXP geoarrow_c_[^\\)]+\\)", multiline = TRUE)) %>%
    unlist() %>%
    unique() %>%
    str_replace_all("\\s+", " ") %>%
    str_trim(),
  name = def %>% str_extract("geoarrow_c_[^\\(]+"),
  return_type = "SEXP",
  args = def %>%
    str_remove("SEXP geoarrow_c_[^\\(]+\\(") %>%
    str_remove("\\)$") %>%
    str_split("\\s*,\\s*") %>%
    map(~{if(identical(.x, "") || identical(.x, "void")) character(0) else .x}),
  n_args = map(args, length)
)

call_headers <- paste0(
  "extern ", defs$def, ";",
  collapse = "\n"
)
call_entries <- paste0(
  '{"', defs$name, '", (DL_FUNC)&', defs$name, ', ', defs$n_args, "},",
  collapse = "\n    "
)

header <- glue::glue('

/* generated by tools/make-callentries.R */
{call_headers}

static const R_CallMethodDef CallEntries[] = {{
    {call_entries}
    {{NULL, NULL, 0}}}};
/* end generated by tools/make-callentries.R */
')

# rewrite relevant portion of r-init.c
init <- read_file("src/r-init.c")
pattern <- regex(
  "\n/\\* generated by tools/make-callentries\\.R \\*/.*?/\\* end generated by tools/make-callentries\\.R \\*/",
  multiline = TRUE,
  dotall = TRUE
)

stopifnot(str_detect(init, pattern))
init %>%
  str_replace(pattern, header) %>%
  write_file("src/r-init.c")

system("clang-format -i src/r-init.c")
paleolimbot/geoarrow documentation built on April 17, 2025, 11:30 p.m.