miniextendr_api/init.rs
1//! Package initialization for miniextendr R packages.
2//!
3//! [`package_init`](crate::init::package_init) consolidates all initialization steps that were previously
4//! scattered across `entrypoint.c.in`. The `miniextendr_init!` proc macro
5//! generates the `R_init_*` entry point that calls this function.
6//!
7//! # Usage
8//!
9//! In your crate's `lib.rs`:
10//!
11//! ```ignore
12//! miniextendr_init!(mypkg);
13//! ```
14//!
15//! This expands to an `extern "C-unwind" fn R_init_mypkg(dll)` that calls
16//! [`package_init`](crate::init::package_init) with the appropriate package name.
17
18use crate::ffi::{DllInfo, R_forceSymbols, R_useDynamicSymbols, Rboolean};
19use std::ffi::CStr;
20
21/// Initialize a miniextendr R package.
22///
23/// This performs all initialization steps in the correct order:
24///
25/// 1. Install panic hook for better error messages
26/// 2. Record main thread ID (and optionally spawn worker thread)
27/// 3. Assert UTF-8 locale
28/// 4. Set ALTREP package name
29/// 5. Register mx_abi C-callables for cross-package trait dispatch
30/// 6. Register all `#[miniextendr]` routines and ALTREP classes
31/// 7. Lock down dynamic symbols
32///
33/// # Safety
34///
35/// Must be called from R's main thread during `R_init_*`.
36/// `dll` must be a valid pointer provided by R.
37/// `pkg_name` must be a valid null-terminated C string that lives for the
38/// duration of the R session (typically a string literal).
39pub unsafe fn package_init(dll: *mut DllInfo, pkg_name: &CStr) {
40 unsafe {
41 // When loaded as a cdylib for wrapper generation, skip full init.
42 // Only routine registration is needed so .Call(miniextendr_write_wrappers) works.
43 // The env var is set by Makevars before dyn.load().
44 let wrapper_gen = std::env::var_os("MINIEXTENDR_CDYLIB_WRAPPERS").is_some();
45
46 // 1. Record main thread ID (and optionally spawn worker thread)
47 // Always needed: checked FFI variants (R_useDynamicSymbols, etc.)
48 // route through with_r_thread() which requires runtime_init.
49 crate::worker::miniextendr_runtime_init();
50
51 if !wrapper_gen {
52 // 2. Install panic hook for better error messages
53 // Skipped during wrapper-gen: on Windows, set_hook during DLL init
54 // can fail with "failed to initiate panic, error 5" because the
55 // panic infrastructure isn't fully available during DLL loading.
56 crate::backtrace::miniextendr_panic_hook();
57
58 // 3. Assert UTF-8 locale
59 crate::encoding::miniextendr_assert_utf8_locale();
60
61 // 3b. Install R console logger (if log feature enabled)
62 #[cfg(feature = "log")]
63 crate::optionals::log_impl::install_r_logger();
64
65 // 3c. Compute SEXPREC data offset (used by Arrow SEXP recovery, etc.)
66 crate::r_memory::init_sexprec_data_offset();
67
68 // 4. Set ALTREP package name and DllInfo
69 crate::miniextendr_set_altrep_pkg_name(pkg_name.as_ptr());
70 crate::set_altrep_dll_info(dll);
71
72 // 5. Register mx_abi C-callables
73 crate::mx_abi::mx_abi_register(pkg_name);
74 }
75
76 // 6. Register .Call routines (and ALTREP classes, unless wrapper-gen)
77 crate::registry::miniextendr_register_routines(dll);
78
79 // 7. Lock down dynamic symbols
80 R_useDynamicSymbols(dll, Rboolean::FALSE);
81 R_forceSymbols(dll, Rboolean::TRUE);
82 }
83}