Building CRAN binaries for rpkgs.com
  • R 77.4%
  • Shell 8.6%
  • TypeScript 7%
  • HCL 3.5%
  • Just 1.8%
  • Other 1.7%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2024-11-03 23:01:24 +01:00
.woodpecker build 2024-11-03 21:25:21 +01:00
docker chore: add alpine regex 2024-11-01 19:32:07 +01:00
man capture arch in metadata table 2024-09-24 08:13:08 +02:00
R fix: account for non-pkg items in counting unique files 2024-11-03 23:00:29 +01:00
.editorconfig linters 2024-05-29 19:53:38 +02:00
.gitignore gitignore 2024-07-28 10:55:33 +02:00
.markdownlint.yaml linters 2024-05-29 19:53:38 +02:00
.prettierrc.json linters 2024-05-29 19:53:38 +02:00
.Rbuildignore fix Rbuildignore issues and tidy package 2024-08-28 11:01:01 +02:00
curl-benchmark.sh make alpine dockerfile arch-agnostic 2024-09-04 22:48:03 +02:00
DESCRIPTION chore: bump package version to 1.0.0 2024-11-01 19:30:58 +01:00
get-all-pkg-versions.R add helper 2024-08-04 09:46:15 +02:00
Justfile chore: don't use xvfb-run in local justfile rules 2024-11-01 19:31:46 +01:00
LICENSE.md license 2024-07-26 11:23:40 +02:00
NAMESPACE fix matching of packages for which the latest verison is not available 2024-09-03 19:56:09 +02:00
rBinaries.Rproj move to R package 2024-06-02 13:05:39 +02:00
README.md readme 2024-09-30 11:33:14 +02:00
renovate.json chore: Configure Renovate (#6) 2024-07-29 21:21:39 +00:00

README

Workflow

Most of the work is done through the R package bincraftR.

  • build_binary_package()
    • install_system_dependencies()
    • build_single_tag()
    • upload_single_binary_to_s3()

Preparation of environment

  • Installation of R interpreter: done by downloading a prebuilt R binary for the specific OS.
  • Installation of R and system dependencies:
    • -> install_system_dependencies()
    • Invoked through build_binary_package()
    • Uses {pak} to install both R package dependencies and syslib dependencies

Building binaries

Tags for each package are built in parallel via {future} by executing build_binary_package() via future_mapply().

The build process in detail:

For every package+tag combination, do

  1. Checkout tag from GitHub CRAN mirror
  2. Build binary package
  3. Upload package binary to S3
  4. Delete package binary (to free up space on PVC)

Building the PACKAGES index file

The packages {cranlike} and {desc} only work with sources on a local file system. This is infeasible for our approach with the data stored only in S3. Otherwise, all binaries need to be present permanently on a static file system. This would incur a lot of costs.

Hence, modified versions of {cranlike} and {desc} were created which are able to deal with files in S3 through {s3fs}.

Resources

Binaries are build in parallel on a 16 Core 32 GB instance with 6 processes. This gives each process ~ 5 GB of memory for building the individual package+tag combination. This looks excessive on the first look but some packages take up to 5 GB of memory when compiling from source. Hence, we need to allocation these resources to ensure a smooth build process which does not result in an OOMKilled of the pod.

Cache

A build cache for R packages (/mnt/cache/R-pkgs) and ccache (/mnt/cache/ccache) is stored in a PVC with a size of 25 GB. Also, the PACKAGES index files are persistet to speed up adding new packages when calling upload_package_index(). Otherwise, the whole DB needs to be created from scratch which takes quite long and requires many API calls against backblaze.

Build metadata database

The build metadata is stored in a Postgres database. The DB has a public endpoint at r-binaries.devxy.io and port 15432. The following tables are used:

  • single_builds contains the build metadata for each package:
package_name tag platform error_occurred build_timestamp build_duration error size

Column types:

  • package_name: character varying(255)
  • tag: character varying(255)
  • platform character varying(255)
  • error_occurred: boolean
  • build_timestamp: timestamp without time zone
  • build_duration: numeric(1000,2)
  • error: text
  • size: numeric(1000,2)

Alternatively, use \d+ single_builds

Support for archived versions

remotes::install_version()

remotes::install_version() is searching for a Meta/archive.rds file in the /src/contrib directory. This file must be a list of dataframes containing the information about the archived versions of the package.

Example:


con <- gzcon(url(sprintf("%s/src/contrib/Meta/archive.rds",
                           c("CRAN" = "https://cloud.r-project.org")), "rb"))
foo = readRDS(con)
foo[[1]]

pak::pak(package@version)

pak searches for Archive/<package> and is able to install all versions existing there. Ensure to use a clean cache if other repos have been used before, i.e. call pak::meta_clean(force = TRUE) if in doubt or when testing.

Platforms

The following platforms are supported:

  • RHEL9

Lessons learned

  • The newest R version needs to be used to build binaries. The reason is that some packages depend on the "recommended" packages and try to install them as a dep. This fails for older R versions, e.g. if R 4.0.5 tries to install Matrix from 4.4.x

Platforms

Helpers

Some common helper functions to ease usage live in exec.R.

240 pkgs in 5h (200-449) costs for 5h cax41: 0.235 EUR (0.047)

200 pkgs in 2h 40 min (449 - 649) costs for 5h cax41: 0.129 EUR (0.047)

Common errors

* installing to library '/tmp/Rtmp7WPw19/temp_libpath114b846b58'\n* installing *source* package 'ade4' ...\n** using staged installation\nERROR: a 'NAMESPACE' file is required\n* removing '/tmp/Rtmp7WPw19/temp_libpath114b846b58/ade4'\n"

Tag does not have a NAMESPACE file and hence cannot be built.

"* installing to library '/tmp/RtmpLcCitS/temp_libpath1146aabbe92'\nERROR: dependency 'tripack' is not available for package 'alphahull'\n* removing '/tmp/RtmpLcCitS/temp_libpath1146aabbe92/alphahull'\n"

Dependency not available: Either because the dependency was not declared or errored itself during installation.

 In function '\033[01m\033[KRcpp::List solveRRBLUP(const mat&, const mat&, const mat&)\033[m\033[K':\n\033[01m\033[KMME.cpp:162:61:\033[m\033[K \033[01;31m\033[Kerror: \033[m\033[K'\033[01m\033[KPI\033[m\033[K' was not declared in this scope\n  162 |   double ll = -0.5*(double(optRes[\"objective\"])+df+df*log(2*\033[01;31m\033[KPI\033[m\033[K/df));\n      |                                                             \033[01;31m\033[K^~\033[m\033[K\n\033[01m\033[KMME.cpp:\033[m\033[K In function '\033[01m\033[KRcpp::List solveRRBLUPMV(const mat&, const mat&, const mat&, int, double)\033[m\033[K':\n\033[01m\033[KMME.cpp:277:31:\033[m\033[K \033[01;31m\033[Kerror: \033[m\033[K'\033[01m\033[KPI\033[m\033[K' was not declared in this scope; did you mean '\033[01m\033[KHI\033[m\033[K'?\n  277 |   ll -= double(n*m)/2.0*log(2*\033[01;31m\033[KPI\033[m\033[K);\n      |                               \033[01;31m\033[K^~\033[m\033[K\n      |                               \033[32m\033[KHI\033[m\033[K\nmake: *** [/opt/R/4.4.1/lib/R/etc/Makeconf:204: MME.o] Error 1\nERROR: compilation failed for package 'AlphaSimR'\n* removing '/tmp/RtmpclI5CE/temp_libpath11135d215d5/AlphaSimR'\n

Compiler error: Possible reasons: too old CXX code which cannot be compiled anymore with CXX14 or CXX17.


When inferring dependencies:

internal error 1 in memDecompress

Solution:

rm -rf /mnt/cache/R-pkgs/pkgcache/ /mnt/cache/R-pkgs/pak /mnt/cache/pkgcache/ /root/.cache/R/
R -q -e 'install.packages("pak", repos = sprintf("https://r-lib.github.io/p/pak/stable/%s/%s/%s", .Platform$pkgType, R.Version()$os, R.Version()$arch))'

Packages skipped on purpose

  • biplotbootGUI - requires Bwidget which is hardly installable on any distribution and causes a lot of issues due to the need of a virtual frame buffer

CDN

  • Perma-cache enabled for three different regions (DE, US, Asia) + smart cache for other edge servers
  • CacheControl = "no-cache" for all PACKAGES* files to ensure users always get the latest version (as these files change daily)