[R-pkg-devel] Best practices for built version checking in packages LinkingTo others?
Ben Bolker
bbo|ker @end|ng |rom gm@||@com
Fri Jan 17 15:13:00 CET 2025
I wouldn't guarantee that it's best practices, but for reference this
is what glmmTMB does about checking the Matrix and TMB versions (Matrix
has a formal ABI version distinct from its package version; TMB doesn't)
https://github.com/glmmTMB/glmmTMB/blob/b7936f4cbe9f26e3d8d5eae727afd83f6ec2b76b/glmmTMB/R/zzz.R#L21-L26
https://github.com/glmmTMB/glmmTMB/blob/b7936f4cbe9f26e3d8d5eae727afd83f6ec2b76b/glmmTMB/R/utils.R#L232-L252
cheers
Ben Bolker
>
>> 1. What is the best way to save this information? I have a
>> rudimentary implementation [1]
>
> For now, this is the best way we have. Export the ABI version as an
> include-time constant and as a registered callable. The LinkingTo
> reverse dependencies can give the include-time constant to the
> registered callable to compare the two versions.
>
> I agree that we could do better and introduce an ABIversion: field to
> the DESCRIPTION file. R CMD INSTALL would write down the current
> ABIversion of every package that the current package is LinkingTo (into
> the installed package's DESCRIPTION or Meta/features.rds). Later, the
> namespace loader would check the ABI versions and provide an
> informative message in case a LinkingTo dependency is updated with an
> incremented ABI version. A machine-readable list of ABI-level
> dependencies should simplify the lives of the binary package
> maintainers as well.
>
> (Related may be a problem with S4, where packages may end up caching
> parts of the classes from other packages they depend upon, which also
> breaks binary installations but self-heals upon reinstalling from
> source [1]. This still happens under R-devel. R could store and check
> some sort of hash when caching these classes and either reload them in
> full or prompt for the package to be reinstalled.)
>
>> 2. How to best test the C API without making updates impossible?
>
> Would abi-compliance-checker [2] have helped there?
>
> It's not exactly designed for static functions and R_GetCCallable(),
> but with abi-dumper -all or -dump-static it is possible to use it to
> demonstrate incompatibilities between (for example) Matrix_1.6-1.1 and
> Matrix_1.7. With either a separate build that exports the functions
> destined for R_RegisterCCallable() or some sort of filter for public
> symbols, this tool may help detect ABI incompatibilities early.
>
>> 3. What should be done in case of a mismatch?
>
> It's hard to guarantee anything when the ABI is broken. Maybe it's
> completely harmless because your code will know that the new structure
> member is not initialised. Maybe the wrong stack layout will crash the
> process due to a return address mismatch, dooming the process from the
> first function call.
>
>> 1. Is there a way for 'ergm' to detect when a package
>> LinkingTo it is being loaded?
>
> With inline functions, you could make your every API call perform ABI
> version checking, but that obviously comes with potential performance
> problems:
>
> // public header in mypackage
> #define MYPACKAGE_ABI_VERSION 2
> static R_INLINE SEXP mypackage_frobnicate(SEXP arg) {
> (
> (void (*)(int))R_GetCCallable("mypackage", "check_abi_version")
> )(MYPACKAGE_ABI_VERSION); // signals an error on mismatch
> return (
> (SEXP (*)(SEXP))R_GetCCallable("mypackage", "frobnicate")
> )(arg);
> }
>
>> 2. What should happen if a mismatch is detected? Should the
>> loading be blocked (e.g., by having .onLoad() throw an error), or
>> should it lead to a "use at your own risk" type warning?
>
> The safest option would be to signal an error before any of the
> potentially incompatible functions are called. It's probably pragmatic
> to provide an "I know what I'm doing, void my warranty" emergency
> override.
>
--
Dr. Benjamin Bolker
Professor, Mathematics & Statistics and Biology, McMaster University
Director, School of Computational Science and Engineering
* E-mail is sent at my convenience; I don't expect replies outside of
working hours.
More information about the R-package-devel
mailing list