Minimal Set of binnmu Packages

Step 0: Problem Definition

Upstream Change

R 3.4.0, released in April, included the following paragraph in its NEWS file:

  • Packages which register native routines for .C or .Fortran need to be re-installed for this version (unless installed with R-devel SVN revision r72375 or later).

This transition has no fallback behavior (as is more common with R changes) and requires a rebuild. Packages build under older R version still load and function partially, but will be unable to access any native (i.e., compiled) routines.

Impact

For the Debian packages, this means that we need to consider the set of packages which

  • match r-cran-*, r-bioc-* and alike
  • contain compiled code (as R-only packages have no native routines)
  • use at least one .C() or .Fortran() (but not .Call()) call
  • use (the hitherto optional) routine registration (so that the change in behaviour is noticible)
  • have not yet been recompiled with R 3.4.0 or R 3.4.1

This note computes this set and provides the input for a wanna-build request.

This version is updated version which reflects the fourth point above which was pointed out to me by Kurt Hornik after I shared the initial version with him. The point he raised (“does it use R_registerRoutines ?”) is important and further reduces the effective set.

Step 1: Reverse Dependencies of R

Fresh Debian unstable session

For this we drop into a clean Docker container running Debian unstable. Later, we will need the current sources of the RcppAPT package so we start from a local git directory:

server> cd ~/git && docker run --rm -ti -v $(pwd):/mnt debian:unstable

Update Debian

Inside the Docker container, we update the package information and install what is needed to build RcppAPT for R. This includes Rcpp and libapt-pkg-dev. We also install the data.table package used for aggregating the (R and Debian) package data computed below.

This step takes a short moment, with the exact time dependent on the network connection and other factors.

docker> apt-get update
docker> apt-get -y dist-upgrade

docker> apt-get -y install r-cran-rcpp r-cran-data.table libapt-pkg-dev less

docker> cd /mnt
docker> R CMD INSTALL rcppapt/       # assuming we're above rcppapt

Launch R

All Candidates

Inside the same Docker session, we now launch R and run (almost all of) the remainder from R.

> library(RcppAPT)
> library(data.table)
> rd <- reverseDepends("r-base-core")         # 516 x 2
> rd <- rd[grepl("^r-", rd[,1]), ]            # 489 x 2
> rd <- rd[order(rd[,2]), ]
> setDT(rd)

We use RcppAPT to compute the reverse depends of the main R package providing the R engine: r-base-core. Among those (currently) 516 packages are both other packages from the upstream source (r-base*, r-doc*) which we exclude first as well as other, non-R-package dependencies (such as rpy2) which we also exclude.

This leaves 489 candidate packages out of the initial 514. The version field tells which r-base-core version was used to build the package—information we need per the setup described above.

> rd
> rd
             package version
  1:       r-doc-pdf
  2:      r-doc-info
  3:      r-doc-html
  4:     r-base-html
  5:     r-other-rot
 ---
485: r-base-core-dbg 3.4.1-2
486:          r-base 3.4.1-2
487:     r-cran-mgcv 3.4.1-2
488:     r-cran-boot 3.4.1-2
489:      r-cran-car 3.4.1-2
>

Next we need to filter out two versions with unsortable (i.e.,non-semantic) version numbers, and apply a logical filter depending on whether the package was built with R version 3.3.3 or earlier, indicating a possibe required rebuild.

> rd[ version=="3.0.0~20130330-1", version := "3.0.0.20130330-1"]
> rd[ version=="3.2.4-revised-1", version := "3.2.4.1-1"]
> rd[version!="", oldVersion := version  <=  package_version("3.3.3-1")]
> rd[ is.na(oldVersion), oldVersion := FALSE]
> rd[ !grepl("r-(doc|base)", package), ]
             package          version oldVersion
  1:     r-other-rot                       FALSE
  2: r-cran-epitools          3.0.0-2       TRUE
  3: r-cran-combinat          3.0.0-2       TRUE
  4:    r-cran-gmaps 3.0.0.20130330-1       TRUE
  5:      r-cran-wdi          3.0.1-6       TRUE
 ---
478:   r-recommended          3.4.1-2      FALSE
479:       r-mathlib          3.4.1-2      FALSE
480:     r-cran-mgcv          3.4.1-2      FALSE
481:     r-cran-boot          3.4.1-2      FALSE
482:      r-cran-car          3.4.1-2      FALSE

To cover some corner case, we derive a skip field:

> rd[ version=="", skip:=TRUE ]
> rd[ is.na(skip), skip:=FALSE]
> rd[ skip==FALSE, ]
             package          version oldVersion  skip
  1: r-cran-epitools          3.0.0-2       TRUE FALSE
  2: r-cran-combinat          3.0.0-2       TRUE FALSE
  3:    r-cran-gmaps 3.0.0.20130330-1       TRUE FALSE
  4:      r-cran-wdi          3.0.1-6       TRUE FALSE
  5:   r-cran-bitops          3.0.1-6       TRUE FALSE
 ---
480: r-base-core-dbg          3.4.1-2      FALSE FALSE
481:          r-base          3.4.1-2      FALSE FALSE
482:     r-cran-mgcv          3.4.1-2      FALSE FALSE
483:     r-cran-boot          3.4.1-2      FALSE FALSE
484:      r-cran-car          3.4.1-2      FALSE FALSE
>

Compiled Packages

Next, we find the actual dependencies of each of these packages by constructing a large regular expression which we feed into RcppAPT::getDepends()

> regexp <- paste(paste0("^", rd[skip==FALSE, package], "$"), collapse="|")
> dep <- getDepends(regexp)
> setDT(dep)
> dep
                  srcpkg              deppkg cmpop          version
   1:  r-bioc-hypergraph         r-base-core     2 3.3.1.20161024-1
   2:  r-bioc-hypergraph             r-api-3     0           (null)
   3:  r-bioc-hypergraph        r-bioc-graph     0           (null)
   4:  r-bioc-hypergraph r-bioc-biocgenerics     0           (null)
   5:  r-bioc-hypergraph        r-cran-runit     0           (null)
  ---
3744: r-cran-viridislite             r-api-3     0           (null)
3745:      r-cran-xtable         r-base-core     2          3.2.5-1
3746:      r-cran-xtable             r-api-3     0           (null)
3747:   r-cran-pkgkitten         r-base-core     2          3.3.2-1
3748:   r-cran-pkgkitten             r-api-3     0           (null)
>

Next we subset to those have libc6 as a Depends, meaning they are compiled packages. This excludes all the R packages having only R code.

> comp <- dep[deppkg=="libc6"]   # 242
> comp
                 srcpkg deppkg cmpop version isCompiled
  1:  r-bioc-makecdfenv  libc6     2     2.4       TRUE
  2:       r-cran-bio3d  libc6     2    2.14       TRUE
  3:   r-bioc-rsamtools  libc6     2    2.15       TRUE
  4:     r-cran-foreign  libc6     2    2.14       TRUE
  5:    r-bioc-multtest  libc6     2    2.14       TRUE
 ---
238:     r-cran-nleqslv  libc6     2     2.4       TRUE
239: r-other-amsmercury  libc6     2    2.14       TRUE
240:         r-cran-gnm  libc6     2     2.4       TRUE
241:         r-cran-gsl  libc6     2     2.4       TRUE
242:         r-cran-gss  libc6     2     2.4       TRUE
>

We are now getting closer. We set keys on the data.table objects, and then do an inner join:

> setkey(comp, srcpkg)
> setkey(rd, package)
> all <- rd[comp[, c(1,5)]]   # inner join (by default on columns with keys)
> all[order(version),]
                      package version oldVersion  skip isCompiled
  1:            r-cran-bitops 3.0.1-6       TRUE FALSE       TRUE
  2:               r-cran-mnp 3.0.2-1       TRUE FALSE       TRUE
  3: r-other-mott-happy.hbrem 3.0.2-1       TRUE FALSE       TRUE
  4:             r-cran-amore 3.1.0-1       TRUE FALSE       TRUE
  5:              r-cran-deal 3.1.0-1       TRUE FALSE       TRUE
 ---
238:              r-cran-rcpp 3.4.1-2      FALSE FALSE       TRUE
239:            r-cran-rmysql 3.4.1-2      FALSE FALSE       TRUE
240:         r-cran-rsymphony 3.4.1-2      FALSE FALSE       TRUE
241:               r-cran-ttr 3.4.1-2      FALSE FALSE       TRUE
242:                r-mathlib 3.4.1-2      FALSE FALSE       TRUE
>

We have 242 potential rebuilds, down from 514 reverse depends at the outset.

Version check

Next, we can concentrate on those having been built with the older versions requiring a rebuild:

> all[oldVersion==TRUE,][order(version),]    # 167
                      package version oldVersion  skip isCompiled
  1:            r-cran-bitops 3.0.1-6       TRUE FALSE       TRUE
  2:               r-cran-mnp 3.0.2-1       TRUE FALSE       TRUE
  3: r-other-mott-happy.hbrem 3.0.2-1       TRUE FALSE       TRUE
  4:             r-cran-amore 3.1.0-1       TRUE FALSE       TRUE
  5:              r-cran-deal 3.1.0-1       TRUE FALSE       TRUE
 ---
163:           r-cran-rcppgsl 3.3.3-1       TRUE FALSE       TRUE
164:             r-cran-rodbc 3.3.3-1       TRUE FALSE       TRUE
165:         r-cran-snowballc 3.3.3-1       TRUE FALSE       TRUE
166:                r-cran-v8 3.3.3-1       TRUE FALSE       TRUE
167:               r-cran-zoo 3.3.3-1       TRUE FALSE       TRUE
>

Now we are down to 167 packages.

> all[, cran:=grepl("^r-cran", package) ]
> all[, bioc:=grepl("^r-bioc", package) ]
> all[bioc==TRUE & oldVersion==TRUE,]                # 17 BioC
                  package          version oldVersion  skip isCompiled  cran bioc
 1:           r-bioc-affy 3.3.1.20161024-1       TRUE FALSE       TRUE FALSE TRUE
 2:         r-bioc-affyio 3.3.1.20161024-1       TRUE FALSE       TRUE FALSE TRUE
 3:        r-bioc-biobase 3.3.1.20161024-1       TRUE FALSE       TRUE FALSE TRUE
 4:     r-bioc-biovizbase          3.3.2-1       TRUE FALSE       TRUE FALSE TRUE
 5:         r-bioc-deseq2          3.3.2-1       TRUE FALSE       TRUE FALSE TRUE
 6:        r-bioc-dnacopy 3.3.1.20161024-1       TRUE FALSE       TRUE FALSE TRUE
 7:          r-bioc-edger          3.3.0-2       TRUE FALSE       TRUE FALSE TRUE
 8:     r-bioc-genefilter          3.3.2-1       TRUE FALSE       TRUE FALSE TRUE
 9:          r-bioc-graph 3.3.1.20161024-1       TRUE FALSE       TRUE FALSE TRUE
10:     r-bioc-hilbertvis 3.3.1.20161024-1       TRUE FALSE       TRUE FALSE TRUE
11:          r-bioc-limma          3.3.2-1       TRUE FALSE       TRUE FALSE TRUE
12:     r-bioc-makecdfenv 3.3.1.20161024-1       TRUE FALSE       TRUE FALSE TRUE
13:       r-bioc-multtest 3.3.1.20161024-1       TRUE FALSE       TRUE FALSE TRUE
14: r-bioc-preprocesscore 3.3.1.20161024-1       TRUE FALSE       TRUE FALSE TRUE
15:           r-bioc-rbgl          3.3.2-1       TRUE FALSE       TRUE FALSE TRUE
16:    r-bioc-rtracklayer          3.3.2-1       TRUE FALSE       TRUE FALSE TRUE
17:       r-bioc-snpstats 3.3.1.20161024-1       TRUE FALSE       TRUE FALSE TRUE
>

Among these are 17 BioConductor packages. This is a superset as we do not know which of these use only .Call() meaning that no rebuild would be required.

> all[bioc!=TRUE & cran!=TRUE & oldVersion==TRUE,]   # 3 other
                    package version oldVersion  skip isCompiled  cran  bioc
1:       r-other-amsmercury 3.3.2-1       TRUE FALSE       TRUE FALSE FALSE
2:          r-other-iwrlars 3.3.2-1       TRUE FALSE       TRUE FALSE FALSE
3: r-other-mott-happy.hbrem 3.0.2-1       TRUE FALSE       TRUE FALSE FALSE
>

There are also three which are neither BioC nor CRAN.

> cand <- all[ cran==TRUE & oldVersion==TRUE, ]   # 147
> cand
             package version oldVersion  skip isCompiled cran  bioc
  1:     r-cran-ade4 3.3.2-1       TRUE FALSE       TRUE TRUE FALSE
  2: r-cran-adegenet 3.3.1-1       TRUE FALSE       TRUE TRUE FALSE
  3: r-cran-adephylo 3.3.2-1       TRUE FALSE       TRUE TRUE FALSE
  4:   r-cran-amelia 3.2.3-1       TRUE FALSE       TRUE TRUE FALSE
  5:    r-cran-amore 3.1.0-1       TRUE FALSE       TRUE TRUE FALSE
 ---
143:    r-cran-vegan 3.3.2-1       TRUE FALSE       TRUE TRUE FALSE
144:     r-cran-vgam 3.3.2-1       TRUE FALSE       TRUE TRUE FALSE
145:     r-cran-xml2 3.3.2-1       TRUE FALSE       TRUE TRUE FALSE
146:     r-cran-yaml 3.3.2-1       TRUE FALSE       TRUE TRUE FALSE
147:      r-cran-zoo 3.3.3-1       TRUE FALSE       TRUE TRUE FALSE
>

We have 147 possible NMUs based off CRAN.

Next, we mix this with information from CRAN.

> db <- tools::CRAN_package_db()   # CRAN pkge info: N rows x 65 cols
> setDT(db)
> db[, package:=paste0("r-cran-", tolower(Package))]
> setkey(db, package)              # key on package field
> foo <- db[ cand ]                # inner join
> foo[, .(package, Package, Version, NeedsCompilation, oldVersion, skip)]
             package  Package Version NeedsCompilation oldVersion  skip
  1:     r-cran-ade4     ade4   1.7-6              yes       TRUE FALSE
  2: r-cran-adegenet adegenet   2.0.1              yes       TRUE FALSE
  3: r-cran-adephylo adephylo  1.1-10              yes       TRUE FALSE
  4:   r-cran-amelia   Amelia   1.7.4              yes       TRUE FALSE
  5:    r-cran-amore    AMORE  0.2-15              yes       TRUE FALSE
 ---
143:    r-cran-vegan    vegan   2.4-3              yes       TRUE FALSE
144:     r-cran-vgam     VGAM   1.0-3              yes       TRUE FALSE
145:     r-cran-xml2     xml2   1.1.1              yes       TRUE FALSE
146:     r-cran-yaml     yaml  2.1.14              yes       TRUE FALSE
147:      r-cran-zoo      zoo   1.8-0              yes       TRUE FALSE
>

This is our set of 147 candidate packages with their CRAN name, Debian name and upstream version.

> saveRDS(foo[, .(package, Package, Version, NeedsCompilation, oldVersion, skip)], file="debpackages.rds")

We save this file to be used on another machine.

Step 2: Grep

On another machine with access to all CRAN package sources (which I happen to have access to), we use the list of 147 candidate packages and run a recursive grep for each. We store the output from two egrep runs, called via system(), directly in the same data structure. The first checks for .C() or .Fortran() calls in the R scripts; the second checks for R_registerRoutines() in the compiled C code (with thanks again to Kurt Hornik for the suggestion)

deb <- readRDS("~/debpackages.rds")
for (i in 1:nrow(deb)) {
    deb[i, "dotCorFortran"] <- if (is.na(deb[i, "Package"])) NA
                               else system(paste0("egrep -r -q \"\\.(C|Fortran)\\(\" ", deb[i, "Package"], "/R/*"))==0
    deb[i, "hasRegistration"] <- if (is.na(deb[i, "Package"])) NA
                               else system(paste0("egrep -r -q \"R_registerRoutines\\(\" ", deb[i, "Package"], "/src/*"))==0
}
saveRDS(deb, "~/debpackagesout.rds")

Step 3: Finalize

We read the data back in and subset on those for which the recursive grep found actual uses of .C() or .Fortran(). The list contains 72 packages.

> deb <- readRDS("debpackagesout.rds")
> setDT(deb)
> deb[ is.na(dotCorFortran) |(dotCorFortran & hasRegistration), 1:3]
                     package           Package  Version
 1:              r-cran-ade4              ade4    1.7-6
 2:            r-cran-bayesm            bayesm  3.1-0.1
 3:     r-cran-blockmodeling     blockmodeling    0.1.9
 4:             r-cran-brglm             brglm    0.6.1
 5:             r-cran-caret             caret   6.0-76
 6:              r-cran-coin              coin    1.2-1
 7:          r-cran-contfrac          contfrac   1.1-11
 8:        r-cran-data.table        data.table   1.10.4
 9:            r-cran-deldir            deldir   0.1-14
10:           r-cran-desolve           deSolve     1.20
11:               r-cran-eco               eco    4.0-1
12:              r-cran-expm              expm  0.999-2
13:            r-cran-fields            fields      9.0
14:               r-cran-gam               gam   1.14-4
15:            r-cran-glmnet            glmnet   2.0-10
16:           r-cran-goftest           goftest    1.1-1
17:              r-cran-hdf5                NA       NA
18:            r-cran-igraph            igraph    1.1.2
19:           r-cran-mapproj           mapproj    1.2-5
20:              r-cran-maps              maps    3.2.0
21:          r-cran-maptools          maptools    0.9-2
22:              r-cran-mcmc              mcmc    0.9-5
23:          r-cran-mcmcpack          MCMCpack    1.4-0
24:      r-cran-medadherence                NA       NA
25:          r-cran-mixtools          mixtools    1.1.0
26:               r-cran-mnp               MNP    3.0-2
27:             r-cran-ncdf4             ncdf4     1.16
28:          r-cran-phangorn          phangorn    2.2.0
29:         r-cran-phylobase         phylobase    0.8.4
30:               r-cran-qtl               qtl   1.41-6
31:      r-cran-randomfields      RandomFields   3.1.50
32: r-cran-randomfieldsutils RandomFieldsUtils   0.3.25
33:             r-cran-rcurl             RCurl 1.95-4.8
34:         r-cran-rniftilib                NA       NA
35:                r-cran-sp                sp    1.2-5
36:              r-cran-spam              spam    2.1-1
37:          r-cran-spatstat          spatstat   1.51-0
38:             r-cran-spdep             spdep   0.6-13
39:      r-cran-surveillance      surveillance   1.14.0
40:         r-cran-treescape                NA       NA
41:             r-cran-vegan             vegan    2.4-3
42:              r-cran-vgam              VGAM    1.0-4
                     package           Package  Version
>

Similarly, the 17 BioC and 3 other packages can be tested via recursive greps (not shown) in a directory filled with apt-get source downloads:

pkgs <- rbind(all[bioc!=TRUE & cran!=TRUE & oldVersion==TRUE, 1],
              all[bioc==TRUE & oldVersion==TRUE, 1])[[1]]

dir.create("/tmp/scratch")
setwd("/tmp/scratch")

cat("deb-src http://deb.debian.org/debian unstable main\n",
    file="/etc/apt/sources.list", append=TRUE)
system("apt-get update")

for (p in pkgs) system(paste("apt-get source", p))

df <- data.frame(package=pkgs, stringsAsFactors=FALSE)
for (i in 1:nrow(df)) {
    p <- df[i, 1]
    df[i, "dotCorFortran"] <- system(paste0("egrep -r -q \"\\.(C|Fortran)\\(\" ", p, "*/R/*"))==0
    df[i, "hasRegistration"] <- system(paste0("egrep -r -q \"R_registerRoutines\\(\" ", p, "*/src/*"))==0
}

setDT(df)

This leads to a further four packages:

> df[dotCorFortran & hasRegistration, 1]
                     pkg
1:           r-bioc-affy
2:          r-bioc-edger
3:     r-bioc-genefilter
4: r-bioc-preprocesscore
>

These 42, along with the 4 (from the initally 17 BioC and 3 ‘other’) packages are our target set.

> nmu <- deb[ is.na(dotCorFortran) | (dotCorFortran & hasRegistration), 1] #42
> oth <- df[dotCorFortran & hasRegistration, 1]
>
> nmu <- rbind(nmu, oth)  ## 46
> nmu
                     package
 1:              r-cran-ade4
 2:            r-cran-bayesm
 3:     r-cran-blockmodeling
 4:             r-cran-brglm
 5:             r-cran-caret
 6:              r-cran-coin
 7:          r-cran-contfrac
 8:        r-cran-data.table
 9:            r-cran-deldir
10:           r-cran-desolve
11:               r-cran-eco
12:              r-cran-expm
13:            r-cran-fields
14:               r-cran-gam
15:            r-cran-glmnet
16:           r-cran-goftest
17:              r-cran-hdf5
18:            r-cran-igraph
19:           r-cran-mapproj
20:              r-cran-maps
21:          r-cran-maptools
22:              r-cran-mcmc
23:          r-cran-mcmcpack
24:      r-cran-medadherence
25:          r-cran-mixtools
26:               r-cran-mnp
27:             r-cran-ncdf4
28:          r-cran-phangorn
29:         r-cran-phylobase
30:               r-cran-qtl
31:      r-cran-randomfields
32: r-cran-randomfieldsutils
33:             r-cran-rcurl
34:         r-cran-rniftilib
35:                r-cran-sp
36:              r-cran-spam
37:          r-cran-spatstat
38:             r-cran-spdep
39:      r-cran-surveillance
40:         r-cran-treescape
41:             r-cran-vegan
42:              r-cran-vgam
43:              r-bioc-affy
44:             r-bioc-edger
45:        r-bioc-genefilter
46:    r-bioc-preprocesscore
                     package
>
>

We need to retrieve the version number in Debian unstable of these packages by once agaim relying of a function from RcppAPT

> regexp <- paste(paste0("^", nmu[[1]], "$"), collapse="|")
>
> res <- getPackages(regexp)
> res
                    Package         Version
1              r-bioc-edger   3.14.0+dfsg-1
2               r-cran-coin         1.1-3-1
3                r-cran-mnp         2.6-4-1
4             r-cran-fields          8.10-1
5            r-cran-desolve          1.14-1
6             r-cran-deldir        0.1-12-1
7          r-cran-rniftilib    0.0-35.r79-2
8         r-cran-data.table        1.10.0-1
9                r-cran-qtl        1.40-8-1
10    r-bioc-preprocesscore        1.36.0-1
11          r-cran-contfrac        1.1-10-1
12            r-cran-glmnet         2.0-5-1
13                r-cran-sp       1:1.2-4-1
14             r-cran-brglm         0.5-9-1
15              r-bioc-affy        1.52.0-1
16             r-cran-ncdf4       1.15-1+b2
17         r-cran-treescape       1.10.18-6
18           r-cran-mapproj         1.2-4-1
19     r-cran-blockmodeling         0.1.8-1
20              r-cran-hdf5     1.6.10-4+b1
21              r-cran-ade4         1.7-5-1
22              r-cran-vgam         1.0-3-1
23          r-cran-mixtools         1.0.4-1
24         r-cran-phylobase         0.8.2-1
25              r-cran-spam         1.4-0-1
26      r-cran-medadherence          1.03-2
27      r-cran-surveillance        1.13.0-1
28 r-cran-randomfieldsutils        0.3.15-1
29             r-cran-rcurl      1.95-4.8-2
30          r-cran-mcmcpack         1.3-8-1
31          r-cran-spatstat        1.48-0-1
32             r-cran-vegan         2.4-2-1
33            r-cran-bayesm         3.0-2-2
34              r-cran-expm       0.999-0-1
35          r-cran-phangorn         2.1.1-1
36          r-cran-maptools 1:0.8-41+dfsg-1
37             r-cran-caret  6.0-73+dfsg1-1
38           r-cran-goftest         1.0-3-1
39            r-cran-igraph         1.0.1-1
40              r-cran-maps         3.1.1-1
41               r-cran-eco         3.1-7-1
42      r-cran-randomfields        3.1.36-1
43        r-bioc-genefilter        1.56.0-1
44              r-cran-mcmc         0.9-4-2
45             r-cran-spdep         0.6-9-1
46               r-cran-gam          1.14-1
>

With this, we can write out the content of the NMU request:

>
> for (i in 1:nrow(res))
+     cat("nmu", paste(res[i,], collapse="_"), ". ANY . -m 'Rebuild against R 3.4.*, see #861333'\n")
nmu r-bioc-edger_3.14.0+dfsg-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-coin_1.1-3-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-mnp_2.6-4-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-fields_8.10-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-desolve_1.14-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-deldir_0.1-12-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-rniftilib_0.0-35.r79-2 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-data.table_1.10.0-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-qtl_1.40-8-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-bioc-preprocesscore_1.36.0-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-contfrac_1.1-10-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-glmnet_2.0-5-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-sp_1:1.2-4-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-brglm_0.5-9-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-bioc-affy_1.52.0-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-ncdf4_1.15-1+b2 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-treescape_1.10.18-6 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-mapproj_1.2-4-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-blockmodeling_0.1.8-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-hdf5_1.6.10-4+b1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-ade4_1.7-5-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-vgam_1.0-3-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-mixtools_1.0.4-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-phylobase_0.8.2-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-spam_1.4-0-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-medadherence_1.03-2 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-surveillance_1.13.0-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-randomfieldsutils_0.3.15-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-rcurl_1.95-4.8-2 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-mcmcpack_1.3-8-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-spatstat_1.48-0-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-vegan_2.4-2-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-bayesm_3.0-2-2 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-expm_0.999-0-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-phangorn_2.1.1-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-maptools_1:0.8-41+dfsg-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-caret_6.0-73+dfsg1-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-goftest_1.0-3-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-igraph_1.0.1-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-maps_3.1.1-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-eco_3.1-7-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-randomfields_3.1.36-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-bioc-genefilter_1.56.0-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-mcmc_0.9-4-2 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-spdep_0.6-9-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
nmu r-cran-gam_1.14-1 . ANY . -m 'Rebuild against R 3.4.*, see #861333'
>

Summary

The final set of 46 NMUs is the minimal change required, and reasonable relative to the 516 reverse dependencies of R itself. We are able to narrow the set of packages requiring a rebuild down by a combining data from the R package system, the Debian package system and (some) package sources we were able to access on a CRAN-related server.

Acknowledgements

Thanks for Kurt Hornik for pointing out the additional check for R_registerRoutine in the in C code, leading to a further reduction from 90+ packages to 46.

History

The first published version (Julyu 2017) did not check for R_registerRoutines. The second version (August 2017) does, leading to 46 suggested NMUs.

See Also

The source file is on GitHub as is the revision history. The corresponding Debian bug report is based on this analysis.