[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