rzig follows semantic versioning from this version on. The public
interface is the exported R functions, the declarations of the Zig
module rzig except rzig.internal, the markers
and options of the Zig source, the Config/rzig/... fields
of DESCRIPTION and the files rzig writes into a package.
The README section “Stability” states the policy, including the
supported Zig release series (0.16 and 0.17).
Since 0.2.3, the previous CRAN release, rzig has gained (details in the entries below):
find_zig(),
scan_exports(), render_bindings(),
rzig_status(), build_zig(),
test_zig(), create_rzig_package(),
update_rzig(), install_zig() and
zig_function();NA, integer and logical
matrices, complex and raw vectors, i64 and bit64
integer64, named lists, data frames, factors, sparse
matrices, external values and classes;rzig.Sexp reject such strings
with an rzig error as well and match list names in the “bytes” encoding
by their bytes, so no R error leaves an exported function past its
defer statements; unknown entries of a named list warn
without printing the untranslatable bytes.rzig.parallelFor() and
rzig.parallelReduce() return as soon as their worker
threads finish. The calling thread waits on a condition variable that
each worker signals when it ends, with a timeout of 10 ms for the
interrupt check; it no longer sleeps in growing steps, which delayed
every short loop by the remaining sleep (on Windows by at least one
timer tick).bit64,
which its integer64 tests use, and skips the worker-panic test under
Valgrind as it skips the panic test of the calling thread.create_rzig_package() expected the compiler
step of rzig_status() to pass, which fails on machines
without Zig, such as CRAN’s.digest, the fallback of the Zig downloader for SHA-256
checksums on R older than 4.5.0, is listed in
Suggests.@intFromEnum and
@enumFromInt into builtins that Zig 0.16 lacks. The README
says so for package authors.inst/examples/poclp ships the case-study package of the
article on rzig (sharp bounds on probabilities of causation by an exact
linear program); a test assembles, builds and checks it.Config/rzig/download-zig: true in
DESCRIPTION lets configure download the pinned
Zig release into the build folder of the package when it finds no
compiler, for packages distributed through GitHub or r-universe;
rzig_status() notes that CRAN does not allow it without its
consent./// @class structs that return nothing
return NULL invisibly, so m$add(x) prints
nothing.rzig.parallelFor() and
rzig.parallelReduce() run the indices in order on the
calling thread in single-threaded builds, such as WebAssembly for webR,
so that the framework compiles for wasm32-emscripten (CI
cross-compiles it with Zig 0.16 and 0.17). Packages for webR are not yet
supported: building them with webR’s toolchain is untested.configure compiles for the macOS version that R links
for (MACOSX_DEPLOYMENT_TARGET, otherwise the minimum
version of libR.dylib) in place of a fixed macOS 13.0, for
Linux with musl (Alpine) as well as glibc, and for Windows on arm64
(from the name of R’s compiler). RZIG_ZIG_TARGET overrides
the detected target.callconv(.c) in pub const rzig_callables
of its root Zig file, which rzig registers with
R_RegisterCCallable() when the package loads, together with
rzig_interface_version when it is declared.
rzig.callable(ctx, F, package, name, .{ .interface = n })
loads the namespace of the providing package, fetches the function with
R_GetCCallable() and checks the interface version.pub const package); document() regenerates
it.use_rzig_module()
creates inst/zig/<module>/root.zig in the providing
package, and use_rzig_import() adds
<package>/<module> to
Config/rzig/imports and the package to
LinkingTo. configure resolves the module in
the installed package with the new src/rzig/tools/imports.R
and passes it to zig build; the importing package compiles
it, so the packages share no code at run time.
use_rzig_module() also writes
inst/include/<package>_rzig.h, because R CMD check
expects a package in LinkingTo to provide an
include folder. The checks before compilation report
imports that do not resolve, packages that LinkingTo does
not list, and providers without an include folder.test_zig() failed with Zig 0.17, whose
zig build has no --global-cache-dir; the
global cache is now set with ZIG_GLOBAL_CACHE_DIR.src/rzig/c_libraries.zon lists C
libraries whose sources the package ships; the template
build.zig compiles them with Zig and turns each header into
a Zig module (@import("name")) with translate-c, which
works with Zig 0.16 and 0.17 (Zig 0.17 has no @cImport).
Nothing is downloaded. use_rzig() writes the empty list,
update_rzig() adds it when missing and never replaces it,
and rzig_status() reports listed files that do not
exist.use_rzig(path, mixed = TRUE) and
use_rzig_mixed(path) set
Config/rzig/mixed: true, so that R compiles the sources of
src/ with its own compilers next to the Zig library. The
package’s own R_init_<pkg> registers its routines
with rzig_register(), which adds the Zig routines; the
checks before compilation report a mixed package whose sources do not
call it.use_rzig() without mixed = TRUE names
use_rzig_mixed() when src/ holds other
sources.rzig.Function receives an R function, and
f.call(ctx, T, args) calls it from Zig with positional or
named arguments and converts the result to T. An R error,
an interrupt, or the exit of a condition handler or a restart outside
the call returns rzig.Error; after the Zig frames have
returned, R continues the error or the exit unchanged, so conditions
keep their class and call and handlers outside the call run. Queued
warnings come first, R’s random-number state passes to R and back, and R
functions may call rzig packages again.rzig.Optimize and
rzig.Integrate may call R functions; an R error of the
routines themselves now reaches R as it is, without an additional rzig
error.src/entry.c contains rzig_unwind_run(),
which stops R’s jumps with setjmp();
update_rzig() replaces an unmodified
entry.c.rzig.parallelReduce() reduces over indices on worker
threads in chunks fixed by the count alone, so the result (also a
floating-point sum) is the same for every number of threads.ctx.rngStreams() gives random streams for workers,
seeded from R’s stream: index i always gets the same stream
(stream(i), with uniform(),
normal(), exponential()), so parallel draws
follow set.seed() and not the number of threads.parallelFor runs stops the
workers after their current index and is delivered as an R
interrupt.rzig.Optimize.minimize() runs the optimizers of
optim() (BFGS, Nelder-Mead, conjugate gradients, L-BFGS-B
with bounds) on Zig objectives, with an optional analytic gradient and
otherwise the central differences of optim(); the results
and counts match optim().rzig.Integrate.integrate() integrates a Zig function as
integrate() does, on finite and infinite ranges, with
QUADPACK’s failures as errors.rzig.CscMatrix borrows a Matrix::dgCMatrix
through its slots i, p and x and
its dimensions; every index is checked on arrival (columns in order,
rows inside the matrix and increasing within a column), so
column(j) reads it without further checks. Other sparse
classes are rejected with the as() call that converts
them.rzig.Blas (gemm, gemv,
syrk, trsm) and rzig.Lapack
(potrf, potrs, getrf,
getrs, gesv, geqrf,
ormqr, gels, syevr,
gesdd) call R’s BLAS and LAPACK with the shapes checked
before each call, the call guarded, Fortran’s hidden string lengths
passed, and LAPACK’s info turned into R errors.
ctx.matrix(nrow, ncol) allocates a zero-filled
rzig.MutableMatrix, and view() gives a
read-only view.use_rzig_lapack() sets
Config/rzig/lapack: true, and the generated
configure then links
$(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS);
rzig_status() notes Zig code that calls them without
it.rzig.Rmath.density(), rzig.Rmath.cdf() and
rzig.Rmath.quantile() evaluate the d, p and q functions of
R for 17 distributions (rzig.Distribution), with R’s
parameter names and defaults (rzig.Rmath.Params(.gamma) is
.{ .shape, .scale = 1 }), the tail and log options, and a
guard that keeps an R warning turned into an error from jumping out of
Zig code.rng.draw(distribution, params) draws with R’s generator
for the distribution, so draws match R’s for the same seed./// @class becomes an R class.
init is the constructor, exported under the struct’s name
(its arguments take /// @default), and each public function
whose first parameter is the struct is a method, called as
x$method(...). document() generates the
$, print and .DollarNames
methods, registers them in NAMESPACE (or through roxygen2
tags), and writes a help page with a Methods section. Methods may take
ctx: *rzig.Ctx after the receiver. The objects are
rzig.External values, so deinit runs when R
collects them.rzig.External(T) keeps a Zig value in an R external
pointer across calls: rzig.External(T).create(ctx, value)
returns a new one, inputs give the value through .ptr, and
R’s garbage collector runs deinit and releases the memory.
The tag of the external pointer identifies the type and the package, so
other objects are rejected without reading their memory; a value lost by
saving and restoring is a clear error; a value created in a call that
fails is released by the call.rzig.Sexp has read-only methods: kind()
(an rzig.SexpKind), length(),
isNull(), isObject(), isS4(),
inherits(), attribute() (S4 slots are
attributes), names() and classes() (copied
into the call context), element() and field()
for lists, and get(T, ctx), which converts the value by the
rules of a parameter of type T.rzig.Record(T) reads a named list into the fields of
the struct T by name (defaults fill missing entries,
optional fields become null, unknown entries give a
warning) and builds a named list from it as a result. A record carries
any number of values in one argument.rzig.DataFrame(T) reads the columns of a data frame
into a struct of slices and factors, with its number of rows in
.nrow, and builds a data frame with compact row names as a
result.rzig.Factor reads a factor (borrowed codes, copied
levels) and returns one; codes outside the levels are errors.?T accepts NULL for every input type
T, not only scalars.i64 and []const i64 read
bit64::integer64 values (the 64-bit integers stored in the
bits of a double vector of class integer64), and
i64 also accepts integers and whole doubles up to 2^53 - 1
in absolute value. ?i64 maps NA and NULL to
null; rzig.NA.integer64 is the missing value.
i64 and []i64 return integer64
vectors.i64; usize keeps the range of R’s integers,
and its error message points to i64.f64, i32, usize,
[]const f64 and rzig.Mut([]f64) reject
bit64::integer64 values, whose bits are not doubles,
instead of reading them as wrong numbers.rzig.Complex (fields re, im;
the layout of R’s Rcomplex) is a complex scalar, and
[]const rzig.Complex borrows a complex vector;
toStd() and fromStd() convert to and from
std.math.Complex(f64) for complex arithmetic. Both are also
return types.rzig.Raw holds the bytes of a raw vector in
.data, borrowed as an input and copied as a result;
[]const u8 remains a UTF-8 string.inst/zig take the list of files from src/,
so a new framework file reaches client packages.document() (0.6.0); the fixture
documents all its exports, so its R CMD check has no
missing-documentation warning.[]const rzig.Logical borrows a logical vector that can
contain NA; rzig.Logical has the values
.TRUE, .FALSE and .NA and the
methods isTrue(), isFalse(),
isNa() and fromBool().
[]rzig.Logical returns a logical vector with
NA.[]const ?[]const u8 copies a character vector in which
NA becomes null, and
[]?[]const u8 returns one in which null
becomes NA. ?[]const u8 accepts one string,
NA or NULL.rzig.NA.real, rzig.NA.integer and
rzig.NA.logical are R’s missing values, for results that
contain NA.rzig., such as
[]const rzig.Logical, are recognized by the checks before
compilation, and the printed export descriptions of
scan_exports() name rzig.Mut(rzig.Matrix) and
the other new types instead of calling them unsupported.rzig.IntMatrix borrows an integer matrix and
rzig.BoolMatrix copies a logical matrix without
NA; with rzig.Matrix they are views made by
rzig.MatrixOf(T) with at(row, column) and
column(j).rzig.Mut([]i32), rzig.Mut(rzig.Matrix) and
rzig.Mut(rzig.IntMatrix) duplicate an integer vector or a
matrix before writable access; the duplicate keeps dim,
dimnames and class and is what the R function
returns. Writable matrix views add
set(row, column, value).rzig.Attributed(T) gains
setMatrix(nrow, ncol) and
setDimnames(row_names, column_names), checked against the
dimensions before R allocates the result.storage.mode() call that converts them.ctx.print() and ctx.eprint() write
formatted text to R’s output and message streams through
Rprintf and REprintf, inside
R_ToplevelExec, so a user interrupt noticed while printing
becomes an R interrupt after Zig cleanup. Text of any length is written
in full.ctx.progress(total, show) returns an
rzig.Progress bar on R’s message stream that redraws when
its percentage changes and checks for a user interrupt at each redraw. A
progress bar in the state of rzig.parallelFor workers is a
compile error.configure downloads Zig when no supported
compiler is found and RZIG_DOWNLOAD_ZIG=true: the verified
archive of install_zig() (Zig 0.16.0, or
RZIG_ZIG_VERSION), kept in zig_home() for
later installations. Without the variable nothing is downloaded, and the
message for a missing compiler names the variable.install_zig() downloads a Zig release (0.16.0 by
default, or 0.17.0) for the current platform into
zig_home(), rzig’s user cache folder or the folder named by
RZIG_ZIG_HOME. The archive is verified against the size and
SHA-256 published in ziglang.org’s download index and pinned in rzig,
and is fetched from a community mirror of Zig or from ziglang.org; an
archive that differs is deleted before anything is extracted or run.
uninstall_zig() removes the installations.find_zig() and the generated configure
scripts search zig_home() after the PATH, so a
compiler from install_zig() builds rzig packages without
further setup. Their messages for a missing compiler name
install_zig().src/rzig/tools/fetch_zig.R, the
downloader that install_zig() runs;
update_rzig() adds it to existing packages.RZIG_OPTIMIZE=Debug in the environment of
R CMD INSTALL, or
build_zig(optimize = "Debug"), builds the Zig code without
optimization and with the safety checks and complete stack traces of
Zig’s Debug mode. ReleaseSafe stays the default;
ReleaseFast and ReleaseSmall are rejected with
a message, because the boundary turns failed safety checks into R
errors. The printed build result names a Debug build.tryCatch() that handles the interrupt, so a signal that
arrives before the Zig loop starts is still caught on a busy
machine.create_rzig_package() creates a new package in one
call: a DESCRIPTION (GPL-3,
SystemRequirements: Zig 0.16.x or 0.17.x, fields
replaceable through fields), the scaffold of
use_rzig() with the hello_zig() example and
its help page, a testthat suite with one test, and optionally the
workflow of use_rzig_ci(). The created package passes
R CMD check --as-cran.use_rzig_ci() writes a GitHub Actions workflow
(.github/workflows/rzig-check.yaml) that installs R and Zig
and runs R CMD check --as-cran for each operating system
and Zig version of its matrix (Linux, macOS and Windows; Zig 0.16.0 and
0.17.0 by default), with the Zig tests of
src/rzig/src/tests.zig first when that file exists.test_zig() runs the Zig tests of a package
(zig build test) on the host without R: the
test blocks of the files imported by
src/rzig/src/tests.zig. The package folder receives no
build output, the Zig cache is kept for the session, and failed tests
are listed by name.build.zig template has a test step for
test_zig(); update_rzig() installs it in
packages with an unmodified older build.zig.a
of add_vectors must be a numeric vector; got integer; use as.numeric()
in R” instead of “argument 1 of add_vectors must be …”. The
names come from the manifest; a hand-written manifest without parameter
names keeps the position./// @export name=<R name> gives the R wrapper a name
other than the Zig name, and /// @export invisible makes it
return its value invisibly; the options combine with
internal./// @default <argument> <R expression>
gives an argument of the wrapper a default value; the expression must
parse and the argument must exist. The help pages show the defaults in
their usage.zig_function() compiles Zig code from the R prompt into
a package in the session’s temporary directory and defines its exported
functions, the counterpart of Rcpp::cppFunction();
zig_source() does the same for a file and
zig_eval() evaluates one expression of a given type. The
header (std, builtin, rzig, the
panic handler) and the registration block are added when the code lacks
them, every pub fn is exported when the code marks none
with /// @export, builds are cached for the session, and a
compiler error is reported with the line of the code.zig (eng_zig(), registered
when knitr loads) compiles a chunk with zig_function(), so
later R chunks call its functions.tools/check_client_package.R):
R CMD check --as-cran with two cores, the CPU-to-elapsed
threshold of the installation and a separate temporary directory,
failing on any NOTE.update_rzig(), builds it and runs its native and R tests
(tools/check_reverse_pnsbib.sh).tools:::nonAPI and tools:::funAPI()
(tools/check_api_symbols.R).rzig_status() of the example package must report every
structural check ok, and the example lists its Zig sources for
devtools::load_all().RZIG_ZIG_CACHE names a
persistent global Zig cache for the builds of client packages. Without
it, each installation starts with an empty cache inside the package,
which keeps R CMD check clean but lets Zig 0.17 compile its
build runner again for every installation; with it, a repeated build of
the starter package takes about 15 seconds instead of minutes on a
loaded machine.pub const name = @import("file.zig"); declarations of
main.zig (recursively) and finds the
/// @export functions of those files, registered as
name.function. /// @export above
pub const twice = other.twice; re-exports a function of an
imported file. Before, markers outside main.zig were
ignored without a message.const, which
the generated registration cannot reach, is an error that says how to
import the file; a marked file that is not imported is noted by
rzig_status(), and an R name exported twice is an error
naming both places.scan_exports() records the file of each
export and the files scanned; print() shows
the file of exports outside main.zig, and
build_zig() attributes compiler errors in any of these
files to their exported function.document() writes a help page
man/<name>.Rd for every exported Zig function of a
package that does not use roxygen2, from the function’s doc comment: the
first paragraph is the title and description, and @param,
@return, @examples, @details,
@seealso, @references and @note
fill their sections; code spans become
\code{}. Pages rzig wrote for functions that are gone are
removed, and pages of other origin are left alone. In roxygen-managed
packages roxygen2 writes the pages, and rzig removes its own.hello_zig() documents its parameter and
return value and has an example, so a new scaffold passes
R CMD check without the “Undocumented code objects” and “No
examples, no tests, no vignettes” warnings.rzig_status() reports help pages that no longer match
the doc comments.rzig.parallelFor() limits its worker threads:
RZIG_NUM_THREADS lowers the number (an invalid value is an
error naming the variable), OMP_THREAD_LIMIT is respected,
and while R CMD check limits the cores
(_R_CHECK_LIMIT_CORES_, as in CRAN submission checks) at
most two threads run. Before, a call used one thread per core up to 32
in any setting.rzig.parallelThreadCount(count) returns the number of
worker threads a call of parallelFor with
count indices uses.NAMESPACE roxygen2 generates:
document() writes the useDynLib directive of
the native routines into R/rzig-wrappers.R as a
@rawNamespace tag and adds the lines roxygen2 writes from
the tags to NAMESPACE, instead of a block that
roxygen2::roxygenise() removed. The package works whichever
of rzig::document(), roxygenise() or
devtools::document() ran last; before, a call of
roxygenise() after document() left
.Call() without its native symbols (“object ‘hello_zig_’
not found”), which R CMD check reported only as a
NOTE.render_bindings() takes roxygen, and
rzig_status() checks the bindings of both kinds of
packages./// @export internal marks a native routine
that only the package’s own R code calls: it is registered and gets an R
wrapper and a native symbol (<name>_), but the
wrapper is not exported from the package and gets no help page. Packages
no longer need to patch the generated manifest and
NAMESPACE for such routines./// @export and /// @export internal
are accepted; any other option, or a second @export line
above one function, is an error of the scan with the file and line.scan_exports() records internal,
as.data.frame() shows it, and subsetting the result
(exports[1:2]) keeps its class.update_rzig() brings a package to the installed version
of rzig: it replaces the framework sources, updates every build file
that is still an unmodified template of some rzig version (recognized by
the MD5 sums of all templates rzig has shipped), adds missing build
files, removes the Zig scanner that rzig 0.2 copied into
src/rzig/tools/, and regenerates the bindings. Build files
the package author changed are kept and listed;
force = TRUE replaces them. The package author’s Zig
sources and files rzig does not know are never changed or removed.rzig_status(build = TRUE) takes lib, the
library build_zig() installs into.use_rzig(overwrite = TRUE) no longer deletes the files
under src/rzig that rzig does not know, and stops before
changing anything when a build file differs from every rzig template;
force = TRUE replaces such files. Before, it replaced
customized build files and removed other files without a message.rzig_status() recommends update_rzig() for
framework sources from another rzig version.use_rzig() stops with an explanation when the package
already has a hand-written src/Makevars or
src/Makevars.win (which configure would
overwrite and cleanup would remove, so that its settings
silently disappeared from the built package) or C, C++ or Fortran
sources in src/ (which the generated Makevars do not
compile).rzig_status() reports such sources and Makevars files
in the Scaffold check. A source whose object file a customized
src/Makevars.in lists counts as handled.document() removes a
useDynLib(<pkg>, .registration = TRUE, .fixes = "C_")
line only when the old wrapper file shows that rzig 0.1 wrote it; a
package author’s own directive stays in NAMESPACE.tests/abuse.R and the test
package) passes S4 objects, an S4 class whose data part is a double
vector, classed vectors (a units-like class and Date) and a
data frame to every typed parameter and checks that each call ends in an
R error naming the argument or converts the data part, and that
rzig.Sexp returns the S4 object unchanged.rzig_status object (for
example status[, c("step", "ok")]) shows the data frame
instead of failing with “non-character argument”.build_zig() reports a duplicate-symbol error of the
linker (duplicate symbol,
multiple definition of) at the link step instead of the
install step.ZIG, find_zig() and the generated
configure use the first compiler of a supported release
series among the PATH and the usual install locations
(~/.local/share/zig/*/zig, ~/zig/zig), so an
old zig on the PATH no longer hides a
supported one. When none is supported, the first compiler found is
reported with the reason, and find_zig() lists the others.
An explicit ZIG is used as given.0.17.0-dev.12+abcdef) are rejected with a message saying
so: their language and standard library can differ from the release of
the same series.src/entry.c with R’s
compiler flags ($(ALL_CFLAGS)), so the flags of the R
installation and of CRAN’s check configurations reach it; the fixed
-O2 -Wall -pedantic is gone.zig build runs with -j2, within CRAN’s
limit of two cores during checks.configure asks R for its include directory
(R.home("include")), which Linux distributions can place
outside R_HOME, and falls back to
R_HOME/include.TMPDIR at its own
temporary directory, so a cache written by the Apple tool shims
(xcrun_db) is removed with it and does not appear as
detritus in R CMD check.DESCRIPTION
declares Roxygen: list(markdown = TRUE), so links between
the step functions, the bullet lists of ?rzig_status and
code spans appear as intended instead of as literal
[build_zig()], **DESCRIPTION** and
backticks.R CMD INSTALL,
install.packages(path, repos = NULL), the RStudio Install
button) rebuilt the Zig library only when build.zig,
build.zig.zon or main.zig changed, so an edit
of any other Zig file, or of the framework, left the old native code in
the package. The generated Makevars now runs zig build on
every installation; Zig’s cache keeps an unchanged build fast.use_rzig() lists the Zig sources in the
Config/build/extra-sources field of
DESCRIPTION (keeping entries the package author listed), so
devtools::load_all() recompiles after a change to a Zig
file instead of loading the old shared object.rzig_status() notes a DESCRIPTION whose
SystemRequirements does not name Zig or whose
Config/build/extra-sources does not list the Zig sources. A
DESCRIPTION without a Version field no longer
stops the check with “subscript out of bounds”.rzig_status() compares only the framework sources under
src/rzig/framework with the installed rzig.
build.zig, build.zig.zon and
src/rzig/tools/ are templates a package may extend, like
configure and the Makevars, so a difference is a note and
no longer fails the Scaffold check; build_zig() therefore
builds packages with customized build files. A missing build file still
fails the check. src/entry.c is compared with its template
after the package name is substituted..Call wrappers are no longer symbols of
the client package’s shared object. Each wrapper was exported under the
R name of its function, so an export named like a C library function
(exp, log, free) replaced that
function inside the package and crashed R at the first call. The
wrappers are reached through the registration table only, and
rzig_init has hidden visibility; the shared object exports
only R_init_<pkg> and
R_unload_<pkg>.rzig_status() notes an export that masks a function of
base R or of the attached base packages, for example
log.find_zig() locates a supported Zig compiler,
scan_exports() lists the exported Zig functions with their
R arguments and the R values of every parameter and return type,
render_bindings() shows the generated manifest, R wrappers
and NAMESPACE block, and rzig_status() reports
which steps of a package are complete and whether the generated bindings
match the Zig source.build_zig() compiles and installs a package from a
temporary copy, keeps the complete installation log, and reports the
errors of the Zig compiler, the C compiler, the linker and the load test
with their files and lines, and the exported function concerned.rzig_status() checks, before compilation, argument and
return types the boundary rejects, more than 32 arguments, misuse of
rzig.Mut([]f64), error sets other than
rzig.Error, the registration block and panic handler in
main.zig, R functions with the name of an export, framework
sources from another rzig version, non-executable configure
and cleanup scripts, and the C toolchain of R.
rzig_status(build = TRUE) adds the result of
build_zig().use_rzig(overwrite = TRUE) updates the framework
sources and build files and keeps the package author’s Zig sources in
src/rzig/src. It adds the Zig build caches to
.Rbuildignore.use_rzig() and document() return printable
objects describing the files written and the exports found.use_rzig(),
scan_exports(), render_bindings() and
document() need no Zig compiler; Zig is required only to
install a package created with the scaffold. The package examples run on
CRAN, and the vignette executes the generation steps.find_zig() and the generated configure scripts
accept versions 0.16.x and 0.17.x and reject
other series with a message naming the found version, because Zig
changes its language and standard library between release series. The
framework reads the type descriptions of both compilers and sets the Zig
cache directories through environment variables, which both compilers
accept.src/entry.c includes no R header. R
installations whose headers lack R_ext/Visibility.h, such
as the Debian and Ubuntu r-base packages, can install
client packages.tests/testthat runs on CRAN: scanner fixtures,
rendering, the scaffold and documentation workflow without Zig, and
find_zig(). A parity test compares the R scan with the Zig
scanner where a supported Zig is present.rzigcausal and the test package
rzigtest are distributed under GPL-3.use_rzig() and document() now require an
explicit package path, so neither function writes to the working
directory by default.\donttest{} because they require the
external Zig toolchain.document() now confines Zig’s local and global caches
to an automatically cleaned R session temporary directory. On Unix, its
compiler subprocess also receives a private temporary directory.use_rzig() now scaffolds cleanup and
cleanup.win, preventing generated Makevars and Zig build
caches from entering source-package checks.document() uses the same Zig discovery order as package
configuration and rejects unsupported compiler versions before running
the export scanner.Ctx.rng() provides boundary-managed draws from R’s
random-number stream, preserving set.seed() reproducibility
on success and error paths.Rmath.normalCdf() and
Rmath.normalQuantile() expose the linked R runtime’s normal
distribution functions without consuming random state.interrupt condition class
after Zig cleanup; ordinary error handlers and try() no
longer swallow Ctrl-C.SIGINT, checks
the condition class, and verifies that the R session remains
usable.use_rzig() scaffolds a portable Zig-backed R package,
including generated registration, build configuration, and a working
native example.document() derives R wrappers, exports, and
documentation from plain Zig functions marked with
/// @export.