2

I am building an extension API for R in Rust. I annotate my functions with a procedural macro to generate C wrappers with the appropriate conversion and error handling:

use extendr_api::*;

#[export_function]
fn hello() -> &'static str {
    "hello"
}

This generates a C function hello__wrapper__ that is callable from R using the .Call mechanism.

In addition to this, we need to generate a NAMESPACE file for the R metatdata:

export(hello)
useDynLib(libhello, "__wrap__hello")

And a file lib.R

hello <- function() {
  .Call("__wrap__hello")
}

What is the simplest way to extend cargo or rustc to write this additional information? I'm guessing that writing a file from the procedural macro code is a bad idea.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Andy Thomason
  • 328
  • 1
  • 9
  • Don't write to a file from a macro. It will end badly. Use macros to generate Rust code, with the metadata you need, then build that code into a new Rust binary, which writes to a file at _runtime_. – Peter Hall Jun 23 '20 at 13:40
  • You are correct, Peter. I believe this is what they do with wasm_bindgen. They create custom sections and then split them out of the binary. We could, for example generate static strings with a prefix or suffix and extract those in the R Makefile. Doing this portably is going to be fun! – Andy Thomason Jun 25 '20 at 16:34
  • 2
    @PeterHall could you explain what do you mean by "It will end badly"? It doesn't really explaim much of what the problem might be exactly. You provide an alternative but don't really explain why it's so bad to do it from a macro. – Ari Seyhun Dec 14 '21 at 17:11

1 Answers1

0

From what I understand, procedural macros generate code at compile time, but it has to be valid Rust code. I do not think that a procedural macro is the way to go in this case.

One possible solution is to create a script that will go through and find your exported functions in the Rust file and generate the 2 extra files you need. You could make a build script that runs before compiling if you want to do all the parsing in Rust, otherwise I would suggest something like Python.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
eric556
  • 115
  • 5
  • 1
    Thanks for the answer, Eric. Rust has a built-in build script build.rs which we do use. The issue here is to safely covey information from code run inside the compiler (proc macros) to the final executable, which is an R package in this case. – Andy Thomason Jul 02 '20 at 14:04