extendr / rextendr

An R package that helps scaffolding extendr-enabled packages or compiling Rust code dynamically
https://extendr.github.io/rextendr/
Other
181 stars 27 forks source link

`rust_source`: `"wrap__make_rextendr_wrappers" not available for .Call() for package "lib<name>"` #234

Closed glm729 closed 1 year ago

glm729 commented 1 year ago

When calling rust_source to attempt to include a Rust file, the following error is encountered:

> rust_source("src/gpd.rs")
ℹ build directory: /tmp/RtmpZFzz5K/file6b5b3e90ea98
   Compiling gpd v0.0.1 (/tmp/RtmpZFzz5K/file6b5b3e90ea98)
    Finished dev [unoptimized + debuginfo] target(s) in 0.21s
Error in .Call(wrapper_function, use_symbols = use_symbols, package_name = package_name,  :
  "wrap__make_rextendr_wrappers" not available for .Call() for package "libgpd"
Contents of `src/gpd.rs` ```rust use extendr_api::prelude::*; use extendr_api::wrapper::{ List }; #[extendr] pub fn grid_row_get_idx(_gr: List, _clump: List) -> Vec { // Initialise output indices let idx: Vec = Vec::new(); // Return this as-is, for testing idx } extendr_module! { mod test; fn grid_row_get_idx; } ```

System info:


A workaround is to use the code argument, paired with reading the file contents directly (though there is probably a better way to do this):

rust_source(code = paste0(readLines(path), collapse = "\n"))
yutannihilation commented 1 year ago

Thanks for reporting.

The actual function name to be called should be wrap__make_test_wrappers; "test" comes from extendr_module!. The reason the code case works is that rust_source() adds one more extendr_module! and use it later.

https://github.com/extendr/rextendr/blob/6f92e252f4193a5a8fbfd1ab4184346af628477c/R/source.R#L125-L128

I think there's no way to acquire the module name from R reliably, so I feel we can do the same thing in the file case, though it feels a bit ugly.

Ilia-Kosenkov commented 1 year ago

We discussed this yesterday. I also found another related issue -- every time the same code is rust_source()d, we try to compiled and build the same library. On Windows, it fails, because the previous version is still loaded in R session. For dynamic code we use rextendr with incrementing numerical suffix, so all libraries are unique, but in this case we do not. I suspect we should either:

glm729 commented 1 year ago

I certainly saw the incrementing suffix -- each one named rextendr2, rextendr16, rextendr81, etc., so that appears to be working for me. This was with the trick I mentioned at the end of the initial ticket comment, by using code = ....

Further, I no longer ran into any strange errors, as long as I had the extendr_module! block set properly and had at least one function marked with #[extendr], with the corresponding name in the extendr_module! bit.

In short, with the workaround, I no longer have any trouble compiling and running Rust code in an interactive session! I have not yet tried an RStudio session, if that makes a difference, but it also works fine using Radian.

Ilia-Kosenkov commented 1 year ago

So rextendrN names are generated for anonymous code that you submit via code = "..." argument. For files that you submit via path, we chose a different approach, and it is less reliable. There are still things to investigate and room for better error reporting (instead of the data frame nonsense).

CGMossa commented 1 year ago

We discussed this yesterday. I also found another related issue -- every time the same code is rust_source()d, we try to compiled and build the same library. On Windows, it fails, because the previous version is still loaded in R session. For dynamic code we use rextendr with incrementing numerical suffix, so all libraries are unique, but in this case we do not. I suspect we should either:

  • not attempt to generate library names from file names
  • add a similar incrementing mechanism
  • implement unloading of the named libraries

With caveats and all: The unloading idea might be the best option long term.

Ilia-Kosenkov commented 1 year ago

Yep, I will probably try to make a reproducible test case for this and attempt a fix. Hopefully, this week.

aavogt commented 1 year ago

I have an rextendr:::as_rust_lib_file_name added above, but I still need to use the workaround.

sgsokol commented 1 month ago

This issue is closed but I still have this error on example code from the top of https://extendr.github.io/ :

> rextendr::rust_source("rust/person.rs")
i build directory: /tmp/Rtmpmyob1i/file11e3c5609147
   Compiling persond08e80c044f170cde3413077d8d896965 v0.0.1 (/tmp/Rtmpmyob1i/file11e3c5609147)
    Finished dev [unoptimized + debuginfo] target(s) in 0.35s
Error in .Call(wrapper_function, use_symbols = use_symbols, package_name = package_name,  : 
  "wrap__make_rextendr_wrappers" not available for .Call() for package "libpersond08e80c044f170cde3413077d8d896965"
> sessionInfo()
R version 4.4.1 (2024-06-14)
Platform: x86_64-pc-linux-gnu
Running under: Ubuntu 24.04 LTS

Matrix products: default
BLAS/LAPACK: /opt/OpenBLAS/lib/libopenblasnonthreaded_haswell-r0.3.27.so;  LAPACK version 3.12.0

locale:
[1] C

time zone: Europe/Paris
tzcode source: system (glibc)

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

loaded via a namespace (and not attached):
 [1] utf8_1.2.4       R6_2.5.1         xfun_0.44        tidyselect_1.2.1
 [5] magrittr_2.0.3   glue_1.7.0       tibble_3.2.1     knitr_1.47      
 [9] rextendr_0.3.1   pkgconfig_2.0.3  dplyr_1.1.4      generics_0.1.3  
[13] lifecycle_1.0.4  ps_1.7.6         cli_3.6.3        processx_3.8.4  
[17] fansi_1.0.6      vctrs_0.6.5      withr_3.0.0      compiler_4.4.1  
[21] rprojroot_2.0.4  tools_4.4.1      purrr_1.0.2      brio_1.1.5      
[25] pillar_1.9.0     jsonlite_1.8.8   rlang_1.1.4      stringi_1.8.4   
CGMossa commented 1 month ago

Fascinating. I don't have an answer to this, but I could get it to work by:

rextendr::rust_source(
  file = "notebooks/person.rs",
  module_name = "person"
)

with the explicit change that mod person in extendr_module.

Details

```rs use extendr_api::prelude::*; #[derive(Debug)] struct Person { pub name: String, } #[extendr] impl Person { fn new() -> Self { Self { name: "".to_string(), } } fn set_name(&mut self, name: &str) { self.name = name.to_string(); } fn name(&self) -> &str { self.name.as_str() } } #[extendr] fn my_function() {} // Macro to generate exports extendr_module! { mod person; impl Person; fn my_function; } ```

sgsokol commented 1 month ago

I confirm that it works it this way. It works even if I leave module_name = "classes" as it is in the original example:

> rextendr::rust_source(file = "rust/person.rs", module="classes")
i build directory: /tmp/Rtmpmyob1i/file11e3c5609147
   Compiling persond08e80c044f170cde3413077d8d896968 v0.0.1 (/tmp/Rtmpmyob1i/file11e3c5609147)
    Finished dev [unoptimized + debuginfo] target(s) in 0.35s
v Writing /tmp/Rtmpmyob1i/file11e3c5609147/target/extendr_wrappers.R