From a99159c4bf42c23c89d1747d08c4df04639767bc Mon Sep 17 00:00:00 2001 From: Iñaki Úcar Date: Dec 11 2025 17:18:11 +0000 Subject: Adopt new R Packaging Guidelines https://fedoraproject.org/wiki/Changes/Adopt_new_R_Packaging_Guidelines --- diff --git a/guidelines/modules/ROOT/pages/R.adoc b/guidelines/modules/ROOT/pages/R.adoc index fcab8e5..22a7004 100644 --- a/guidelines/modules/ROOT/pages/R.adoc +++ b/guidelines/modules/ROOT/pages/R.adoc @@ -1,230 +1,269 @@ = R Packaging Guidelines -== What is R? +http://www.r-project.org/[R] is a language and environment for statistical computing and graphics. +R is similar to the award-winning S system, which was developed at Bell Laboratories by John Chambers et al. +It provides a wide variety of statistical and graphical techniques +(linear and nonlinear modelling, statistical tests, time series analysis, classification, clustering, ...). -The definition from https://www.r-project.org/[The R-Project website] says that R is: +R is designed as a true computer language with control-flow constructions for iteration and alternation, +and it allows users to add additional functionality by defining new functions. +For computationally intensive tasks, C, C++ and Fortran code can be linked and called at run time. +For more info, see http://cran.r-project.org/doc/manuals/R-intro.html[An introduction to R]. -_" R is a language and environment for statistical computing and graphics."_ +This document covers how to handle R "add-on packages" for inclusion in Fedora's repositories. +For a complete example, see the <> below. -R is a GNU project, very similar to the S language developed by Bell Laboratories. +//// +[TIP] +==== +The https://pagure.io/r2spec[R2spec] tool can be used to generate spec files automatically from standard https://cran.r-project.org/[CRAN]-like repositories. +It is designed to produce spec files that are compliant with these R Packaging Guidelines. +==== +//// -This language is heavily used in research as it provides a lot of statistical and graphical tools. -It is also a well developed language for data manipulation. +== Naming -If you are looking for more information on R, you can go to: +The canonical source of R packages is https://cran.r-project.org/[CRAN], the "Comprehensive R Archive Network". +The are additional CRAN-like repositories for specific fields, +such as https://bioconductor.org/[Bioconductor] (Bioc for short) for bioinformatics. +But since they are designed to be complementary, package names do not conflict with each other. -* https://www.r-project.org/[The R-Project website] -* https://cran.r-project.org/doc/manuals/R-intro.html[An introduction to R] +R add-ons *MUST* be packaged with `R-$pkg` as the name of the source package, +where `$pkg` is the name of the project on the upstream CRAN-like repository, +i.e. the package https://cran.r-project.org/doc/manuals/r-devel/R-exts.html#The-DESCRIPTION-file[DESCRIPTION]'s `Package` field. +This `$pkg` name *MUST* be exactly as written upstream, including case distinctions and dots. +Also: -If you are interested in packaging R modules, or if you are looking for R libraries, you should check here for upstream sources: +* The spec's `Summary` field *SHOULD* match the package DESCRIPTION's `Title` field. +* The spec's `Description` field *SHOULD* match the package DESCRIPTION's `Description` field. -* https://cran.r-project.org/[The CRAN website] -* https://www.bioconductor.org/[The Bioconductor website] +== Versioning -== Spec Templates for R packages +Since upstream versions may contain characters that are invalid in RPM version strings, they *MUST* be translated to be RPM-compatible. +Particularly, it is common for R packages to specify patch versions using the hyphen as the separator, e.g. `1.2-3`. +Such hyphens *MUST* be converted to a dot. +This translation *SHOULD* be done via the `+%R_rpm_version+` macro as follows: -There are two types of R packages: arch-specific and noarch. -The following template shows how to package an arch-specific R package; -there are very minor differences for noarch packages, which are noted below the template. +---- +Version: %R_rpm_version 1.2-3 +---- -.... -%global packname foo -%global rlibdir %{_libdir}/R/library +Apart from defining `+%{version}+` as `1.2.3` in this case, this macro sets `+%__R_upstream_version+` to keep track of the upstream version for URL generation. -Name: R-%{packname} -Version: 1.6.6 -Release: %autorelease -Summary: Adds foo functionality for R +== License -License: GPL-2.0-or-later -URL: https://CRAN.R-project.org/package=%{packname} -Source: %{url}&version=%{version}#/%{packname}_%{version}.tar.gz +Typically, R packages do not contain license files per CRAN policy. +R allows and ships a set of open source licenses, +and R packages just declare which one they adhere to in the DESCRIPTION file. +Following this policy, and as an exception to the general Licensing Guidelines, +we do not require upstream R packages to add additional license files. -BuildRequires: R-devel -BuildRequires: R() -BuildRequires: ... +[NOTE] +==== +Full text licenses can be found under `/usr/share/R/licenses`. +These texts can also be displayed in the R console using the `RShowDoc()` function. +==== -%description -R Interface to foo, enables bar! +== Sources -%prep -%setup -q -c -n %{packname} +Projects from standard CRAN-like repositories *MUST* be packaged from the sources that are published there. +Packages from the following repositories *MUST* use the set macros provided for automatic generation of the project's URL and package's source URL: -%build +* CRAN: `+%{cran_url}+` and `+%{cran_source}+` +* Bioc: `+%{bioc_url}+` and `+%{bioc_source}+` -%install -mkdir -p %{buildroot}%{rlibdir} -%{_bindir}/R CMD INSTALL -l %{buildroot}%{rlibdir} %{packname} -test -d %{packname}/src && (cd %{packname}/src; rm -f *.o *.so) -rm -f %{buildroot}%{rlibdir}/R.css +== Architectures -%check -export LANG=C.UTF-8 -export _R_CHECK_FORCE_SUGGESTS_=0 -%{_bindir}/R CMD check --no-manual --ignore-vignettes %{packname} - -%files -%dir %{rlibdir}/%{packname} -%doc %{rlibdir}/%{packname}/doc -%doc %{rlibdir}/%{packname}/html -%doc %{rlibdir}/%{packname}/NEWS -%{rlibdir}/%{packname}/DESCRIPTION -%{rlibdir}/%{packname}/INDEX -%{rlibdir}/%{packname}/NAMESPACE -%{rlibdir}/%{packname}/Meta -%{rlibdir}/%{packname}/R -%{rlibdir}/%{packname}/help -%{rlibdir}/%{packname}/libs +Packages that do not contain architecture-specific code (i.e. no compiled parts), *MUST* set `BuildArch: noarch`. -%changelog -%autochangelog -.... - -=== Differences between arch-specific and noarch R packages +[NOTE] +==== +This affects the installation path: -* Noarch packages set `+BuildArch: noarch+`. -* Noarch packages install into `+%{_datadir}/R/library/%{packname}+`; - arch-specific packages install into `+%{_libdir}/R/library/%{packname}+`. + - Change the `+%global rlibdir+` at the top of the file to use `+%{_datadir}+` instead of `+%{_libdir}+`. +* `+%{_datadir}/R/library/$pkg+` for noarch packages; +* `+%{_libdir}/R/library/$pkg+` otherwise; -== Automatically generated dependencies +but this is automatically handled by RPM macros as described below. +==== -All R packages that depend on `+R-devel+` will automatically produce Provides, Requires, Suggests, and Enhances via a generator in `+R-rpm-macros+`. -This generator uses upstream metadata in `+DESCRIPTION+` files to determine what the package should depend on. +== Dependencies -=== Provides with a standardized name +=== Automatic standardized names -The generator adds run time Provides in the form of `+R(foo) = packageVersion+`. +All R packages will automatically produce standardized `Requires` and `Provides` via a generator in `R-rpm-macros`: -The version from the metadata will be normalized -(as specified in <<_r_version>> for package versioning). +* `Provides` are in the form `R($pkg) = $version`; +* `Requires` are in the form `R($pkg)`, with optional `>= $version` as specified in the package's metadata if supplied; -=== Dependencies on standardized names +where `$pkg` is the upstream package name, and `$version` is the RPM-compatible version as described in <>. -The generator adds run time requires in the form of `+R(foo)+` -(with versions as specified in the metadata if supplied.) +The packager *MUST* inspect the generated `Requires` for correctness. +All hard dependencies (R's `LinkingTo`, `Depends`, `Imports`) *MUST* be resolvable within the targeted Fedora version. -The packager MUST inspect the generated Requires for correctness. -All hard dependencies (R's `+LinkingTo+`, `+Depends+`, `+Imports+`) MUST be resolvable within the targeted Fedora version. +=== BuildRequires -Unwanted dependencies may be removed by editing the installed `+DESCRIPTION+` file -or using xref:AutoProvidesAndRequiresFiltering.adoc[rpm's `+%__requires_exclude+`] -(substitute `+suggests+` or `+enhances+` if necessary). -For example, to filter out `+Suggests+` on `+foo+`, use: +Packages *MUST* declare `BuildRequires: R-devel`, which in turn pulls the necessary `R-rpm-macros` and sets the development environment (compilers, libraries, etc.). -.... -%global __suggests_exclude ^R\\(foo\\) -.... +[NOTE] +==== +Note that R packages inherit their compilation flags from the main R package, which stores them in `+%{_libdir}/R/etc/Makeconf+`. +The design of R is such that all R add-on packages use the same optimization flags that the main R package was built with. +Accordingly, this is why R addon packages do not pass `+%{optflags}+`. +==== -To filter out multiple packages, use: +If other libraries and utilities (e.g. cmake) are required for building, they *MUST* be declared explicitly as `BuildRequires`. -.... -%global __suggests_exclude ^R\\((foo\\.bar|baz)\\) -.... +Build-time dependencies on other R packages are automatically handled by the `+%R_buildrequires+` macro, which *MUST* be called in the `+%generate_buildrequires+` scriptlet. -Note that you need to escape regular expression special characters with backslash -_and_ you need to escape said backslash for RPM. +[NOTE] +==== +* All hard dependencies (R's `LinkingTo`, `Depends`, `Imports`) are declared as `BuildRequires` using standardized names (see <>). +* Soft dependencies (R's `Suggests`, `Enhances`) are skipped, except for packages used to develop the test suite +(currently, `testthat`, `tinytest` or `RUnit`). +==== -== R packaging tips +=== Bundled dependencies -=== Naming of R packages +Following the general guidelines, packages *SHOULD* unbundle other dependencies found in R package sources whenever possible. +Whenever bundled dependencies are used, they *MUST* be declared with virtual `Provides`. -Packages of R modules (thus they rely on R as a parent) have their own naming scheme. They should take into account the upstream name of the R module. This makes a package name format of `+R-$NAME+`. When in doubt, use the name of the module that you type to import it in R. +=== Sub-packages -==== Examples +Some R packages expose header files under the standard path `R/library/$pkg/include` (defined by CRAN and expected by R), so that other packages can link to them via `LinkingTo`. +The https://cran.r-project.org/package=Rcpp[Rcpp] package is a notable example. +Sometimes, these headers are required at build-time, sometimes at build- as well as run-time and therefore they are essential for proper functioning... +For these and a variety of other reasons, these headers *MUST NOT* be split off into a `-devel` sub-package. -.... -R-mAr (R module named mAr) -R-RScaLAPACK (R module named RScaLAPACK) -R-waveslim (R module named waveslim) -.... +If a particular package contains a large number of examples or documentation that do not impact the package's functionality, these parts *MAY* be split off into a sub-package, +but sub-packages in general are highly discouraged. -=== R version +== Walkthrough -Many R packages contain '-' in their version. Usually, the versioning used is a sequence of at least two (and usually three) non-negative integers separated by single '.' or '-' characters. +=== Preparing the sources -To be consistent with the versioning system used in Fedora, you should simply replace dashes with dots. +The rest of the scriptlets expect package sources to be extracted in a subdirectory named after the package. +Therefore, in `+%prep+`, the call to `+%setup+` or `+%autosetup+` *MUST* set the `-c` option. -==== Example - -.... -Upstream tarball: Rfoo-0.5-8.tar.gz -Fedora Version: 0.5.8 -.... +---- +%prep +%autosetup -c +---- -=== Empty %build section +Other code for unbundling, fixes and workarounds *MAY* be placed here. -Unlike normal Fedora packages, there is normally no separate `+%build+` actions (e.g. `+%configure+`)that need to be taken for an R package. However, it is important that all R module packages include an empty `+%build+` section, as shown in the spec templates. +=== Dynamic BuildRequires -=== Installing the R addon bits +The `+%R_buildrequires+` macro *MUST* be called in the `+%generate_buildrequires+` scriptlet to generate the dynamic `BuildRequires`. -Instead of calling make install, to install the R addon components, you need to run `+R CMD INSTALL -l %{buildroot}%{_datadir}/R/library %{packname}+` (noarch) or `+R CMD INSTALL -l %{buildroot}%{_libdir}/R/library %{packname}+` (arch-specific). Proper `+%install+` sections for Fedora R packages are demonstrated in the spec templates. +---- +%generate_buildrequires +%R_buildrequires +---- -=== Deleting the R.css file +Testing packages such as `testthat`, which are declared in `Suggests` are whitelisted in `+%{__R_whitelist}+`, and added as `BuildRequires` by `+%R_buildrequires+`. -Most R addon modules generate a new `+R.css+` file, -but it would conflict with the master `+R.css+` file, -included in the main R package. -You must delete this file, and do not include it in your package. +=== Building and Installing -=== Cleaning the R directory of binaries +R packages are built and installed in a single stage via `R CMD INSTALL`. +Therefore, the `+%build+` section *MUST* be empty. -It is important to clean the R directory of binary files (`+*.o *.so+`) before running `+R CMD CHECK+`. Otherwise, the CHECK command will throw a warning about finding binaries in the source dir. This is accomplished by running (in `+%install+`): +Two macros are provided and *MUST* be called in the `+%install+` section. +First, `+%R_install+` builds and installs the package, +then `+%R_save_files+` generates a list of files corresponding to the given importable module, and saves it as `+%{R_files}+`. -.... -test -d %{packname}/src && (cd %{packname}/src; rm -f *.o *.so) -.... +---- +%build -This is demonstrated in the spec templates. +%install +%R_install +%R_save_files +---- + +[NOTE] +==== +The `+%R_install+` macro ensures reprodubility by setting the package's build timestamp as `$SOURCE_DATE_EPOCH`. +==== + +[NOTE] +==== +R package installation generates a new `R.css` file that conflicts with the master `R.css` file included in the main R package. +The `+%R_install+` macro deletes this file. +==== + +[NOTE] +==== +The `+%R_install+` macro calls `+%_R_libdir_check+` to ensure that a noarch package did not produce a shared library, +or an archful package actually contains a shared library; +otherwise, it fails with an informative error message. +If the packager does not want this check, `+%_R_libdir_check+` can be set e.g. to an empty string. +==== + +=== Testing + +The `+%R_check+` macro *MUST* be called in the `+%check+` section to run R package checks. + +---- +%check +%R_check +---- -=== Running %check and Suggests +According to CRAN’s guidelines, R packages *MUST* work without soft dependencies. +If package checks fail because soft dependencies are used unconditionally (e.g. in examples or tests), this is considered a bug and *SHOULD* be reported upstream. +Meanwhile, a workaround *MUST* be put in place: -R addon modules come with a built-in check that can be triggered by running `+R CMD check+`. -In Fedora, the check should be run in the `+%check+` section. +* If the failure happens in an example, the `--no-examples` flag *MAY* be appended to `+%R_check+`. +* If the failure happens in a test, a `skip()` call *MAY* be added in the proper place to skip a test, +or a test file *MAY* be removed, +or even the `--no-tests` flag *MAY* be appended to `+%R_check+` for more complicated situations. -Packages in `+Suggests+` are often used in examples, tests, and vignettes, sometimes even in functions exported by the package. -However, according to CRAN's guidelines, R addons MUST work without the dependencies listed in `+Suggests+`. -This means that they MUST check for the presence of a suggested package before running anything that requires it (in code, examples, tests, or vignettes). -According to this, Fedora packages MUST drop from `+BuildRequires+` all packages in R's `+Suggests+` to avoid circular dependency loops. -As a exception to this rule, R addons that are mandatory for running unit tests in the first place (e.g. `+testthat+`, `+tinytest+`, and few more) SHOULD be kept in `+BuildRequires+` for the `+%check+` section. +=== Listing files -By default, `+R CMD check+` checks for the presence of suggested packages, so `+export _R_CHECK_FORCE_SUGGESTS_=0+` MUST be added to disable this check. -Additionally, recreation of manual pages and vignettes, which usually use suggested packages, MUST be disabled with `+--no-manual+` and `+--ignore-vignettes+` respectively. -Putting everything together, the `+%check+` section should look like the one in the example spec above. +Module files *MUST* be added via the `-f` option as follows: -If this default `+%check+` fails due to some missing suggested package, then it is a bug in the package. -This SHOULD be reported upstream, and a workaround MUST be put in place: +---- +%files -f %{R_files} +---- -* If the failure happens in an example, the `+--no-examples+` flag MAY be added. -* If the failure happens in a test, a `+skip()+` call MAY be added in the proper place, or even the `+--no-tests+` flag for more complicated situations. +If necessary, any additional files outside the package's path *SHOULD* be added explicitly afterwards. -=== License +== Example spec file -Typically, R extensions do not contain license files per CRAN policy. -R allows a set of open source licenses and R extensions just declare which one they adhere to. -Following this policy, we do not require upstream R extensions to add license files. +This is an example spec file for a hypothetical R package called "foo", with upstream version `1.2-3`: -=== Documentation files +---- +Name: R-foo +Version: %R_rpm_version 1.2-3 +Release: %autorelease +Summary: Adds foo functionality for R -The `+R CMD INSTALL+` operation will install all of the files, including documentation files. The doc, html and NEWS files/directories need to be marked as `+%doc+`. -Note that other files, such as DESCRIPTION, INDEX, NAMESPACE, and help/ are not `+%doc+`, since proper R functionality depends on their presence. Be careful not to duplicate `+%doc+` files in the package, the spec templates provide good examples on how to package the R addon files without duplications. +License: GPL-2.0-or-later +URL: %{cran_url} +Source: %{cran_source} -==== R documentation +# BuildArch: noarch +BuildRequires: R-devel +# BuildRequires: somelib-devel -R documentation is written in TeX. rpmlint sometimes complains that these TeX files are not utf-8 files, but the encoding is normally specified in the file when needed, so this error is safe to ignore (and you should not try to re-encode the files). +%description +R Interface to foo, enables bar! -=== Optimization flags +%prep +%autosetup -c -R packages inherit their optimization flags from the main R package, which stores them in `+%{_libdir}/R/etc/Makeconf+`. The design of R is such that all R addon library modules use the same optimization flags that the main R package was built with. Accordingly, this is why R addon packages do not pass `+%{optflags}+`. Also, there is no simple way to pass special optimization flags to `+R CMD INSTALL+`. +%generate_buildrequires +%R_buildrequires -=== R headers +%build -R packages usually expect to find their header files in `+%{_libdir}/R/library/*/+`. rpmlint will complain that these files are misplaced, but this is safe to ignore. +%install +%R_install +%R_save_files -You should still separate these header files into a -devel subpackage. +%check +%R_check -=== R2spec +%files -f %{R_files} -R2spec is an excellent little tool to assist in creating Fedora-compliant packages for R libraries. -Using it as a starting point is recommended (but certainly not mandated). -More information here : https://pagure.io/r2spec/ +%changelog +%autochangelog +----