Skip to main content

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}