Hi!
RStan at the moment seriously suffers from CRAN requirements caused by down-stream R packages when we change Stan version numbers. So what happens is
- StanHeaders 2.x is on CRAN
- RStan 2.x is on CRAN which depends on StanHeaders >= 2.x
- all packages with compiled Stan models depend on StanHeaders 2.x and Rstan 2.x
When we update now Stan to 2.x+1 then the preferred route is
- Bump StanHeaders to 2.x+1 => Then we have on CRAN StanHeaders 2.x+1 and Rstan 2.x
- Next bump Rstan to 2.x+1
BUT: During step 1 everything needs to still work! So all packages must keep compiling on CRAN as a requirement during step 1. This requires that the Stan services of version 2.x+1 must work with 2.x. Same holds true for Stan-math. Usually this is not a problem as things stay sufficiently compatible, but lately this has been the root cause of huge delays.
We need a solution for that.
Here is a proposal from my side as a solution/workaround:
- We introduce in StanHeaders two new functions (motivated by what RcppParallel does)
StanHeaders::CxxFlags(stan_version="2.x")
StanHeaders::LdFlags(stan_version="2.x")
- Then we instruct all down-stream packages that they have to add this into their
Makevars
:PKG_CPPFLAGS += $(shell "${R_HOME}/bin/Rscript" -e "StanHeaders::CxxFlags(stan_version="2.x")")
PKG_LDFLAGS += $(shell "${R_HOME}/bin/Rscript" -e "StanHeaders::LdFlags(stan_version="2.x")")
This will give us control over the dependend packages compiler and linker flags. Thus, when StanHeaders now moves to 2.x+1, we can instruct the CxxFlags + LdFlags function to emit compile flags which point to sources compatible with 2.x when called with the Stan_version set to 2.x.
To make it concrete - suppose 2.x+1 Stan services break the API wrt to 2.x. Then the call to CxxFlags()
of StanHeaders 2.x+1 will work for the case of breaking changes like
-
CxxFlags(stan_version="2.x")
=>-I StanHeaders/include/v2_x
-
CxxFlags(stan_version="2.x+1")
=>-I StanHeaders/include/v2_x+1
In case there are no breaking changes we can emit things like
-
CxxFlags(stan_version="2.x")
=>-I StanHeaders/include/v2_x+1
(because we know it works) -
CxxFlags(stan_version="2.x+1")
=>-I StanHeaders/include/v2_x+1
Or something like that. I hope that the logic is clear.
A risk is that all Rstan dependent packages need to follow this convention. We can probably force the StanHeaders dependent packages into this logic by deploying our code in subfolders which carry the version. This way the packages must make either their Stan version explicit in their compile time flags or they use our utility function. In both cases things will still work just fine. It’s the package maintainer’s duty then to use our utility functions to keep getting the latest and greatest or he must be specific about the version - which is what we want, I think.
Moreover, we would require that package maintainers keep bumping the Stan version level every now and then as we would drop support for older versions eventually (probably x-1, x, x+1 needs to be there).
Other ideas?
Sebastian