15 Packaging Flow

15.1 Introduction

For better or for worse, there is not a unique recipe to build a package. In other words, there is not a unique sequence of steps that you should always follow in order to take a source package and make it part of the installed packages. In this chapter I will describe an opinionated workflow to pack the source code of our working example.

15.2 Example Structure

The following diagram depicts the filestructure for our working example with the package cointoss.

Assumed filestructure

Figure 15.1: Assumed filestructure

Let’s assume that the source package you are developing has the previous structure. If this is not the case for you, at least keep in mind that the mandatory components are DESCRIPTION, NAMESPACE, R/ and man/.

15.3 Workflow

Because a package is made up of various types of files—which can be located in different subdirectories—that play different roles, you can actually break down the overall creation of a package into separate pieces. Interestingly, each of the resulting pieces can be created separately. Consequently, the packaging process that you follow may depend on the piece (or pieces) that need to be built as you add or change components in a package.

The core part of a package is the code in the R/ directory. Most of the modifications made at this level will very likely have a cascading effect on the rest of elements in the package. From this point of view, a typical packaging workflow involves the following steps:

  • Create Documentation
  • Check Documentation
  • Run Tests
  • Knit Vignettes
  • Build Bundle
  • Install Package
  • Check Package

You can use functions from "devtools" to individually perform each of the actions previously listed. The following table shows such functions.

Action Function
Create Documentation devtools::document()
Check Documentation devtools::check_man()
Run Tests devtools::test()
Knit Vignettes devtools::build_vignettes()
Build Bundle devtools::build()
Install binary devtools::install()
Check devtools::check()


Note: Assuming that your working directory is the one containing all the files and subdirectories of your package, you can invoke the devtools functions from the console.


Create Documentation: When you change the roxygen comments of your functions, you will need to (re)generate the corresponding manual documentation. This can be done with the function devtools::document() which generates the so-called .Rd (R documentation) files, located in the man/ directory.

Check Documentation: An optional, but strongly recommended, step after new documentation has been generated, is to check that it is correct. This step becomes mandatory if you plan to share your package via CRAN. To check that the .Rd files are okay, use the function devtools::check_man(). This function inspects that the content and syntax of the .Rd files are correct. A typical cause for this check-up to fail is when you have typos or inconsistencies. For example: when the definition of a function contains the argument x but your roxygen comment @param uses y.

Run Tests: If your package contains unit-tests, included in the directory tests/, you can use the function devtools::test() to run such tests.

Build Vignettes: If your package contains vignettes, included in the directory vignettes/, you can use the function devtools::build_vignettes() to build them. This function generates the vignettes by knitting the .Rmd files in the vignettes/ directory, and it will produce output files in the inst/ folder.

Build Bundle: If you just simply want to convert a package source into a single bundled file, you use the function devtools::build(). This function will create, by default, the .tar.gz file that in turn can be installed on any platform.

To create a binary package, you have to use the argument binary = TRUE. Keep in mind that this generated binary will be platform specific, and will only be installable on the current platform. Most of the time, there is no need to create a binary package.

build() does not generate or check any documentation. It also does not run any tests. However, build() does build vignettes by default.

Install: To install the package you can use devtools::install(). This function can install a source, bundle or a binary package. After the installation is done, you should be able to load the package with library() in order to use its functions, inspect its manual documentation, and read the available vignettes.

Check: Optionally, you can carry out an integral check of the package. This checking is a comprehensive one, and it will verify pretty much every single detail.

15.3.1 Optional devtools file

Unless you are constantly creating packages, you will very likely forget what functions to use for a specific purpose. One small hack that I tend to use is to include an auxiliary .R file in the source package, which I typically name as devtools-flow.R (or something like that). This file basically contains the list of "devtools" functions that we’ve discussed so far. The following code shows the typical commands of the auxiliary file:

# =====================================================
# Devtools workflow
# =====================================================

devtools::document()          # generate documentation
devtools::check_man()         # check documentation
devtools::test()              # run tests
devtools::build_vignettes()   # build vignettes
devtools::build()             # build bundle
devtools::install()           # install package
devtools::check()             # comprehensive check (optional)

You can think of this auxiliary file, e.g. devtools-flow.R, as a cheat-sheet. But keep in mind that this is an additional file that the building functions are NOT expecting to find. That’s why you should include the name of this file in your .Rbuildignore file. Add a new line with the name of the file to .Rbuildignore, and remember to anchor it with the caret ^ character. Here’s what your .Rbuildignore file may look like:

^.*\.Rproj$
^\.Rproj\.user$
^devtools-flow.R

I should also say that the inclusion of a devtools-flow.R file is completely optional, and there are actually more efficient (but also more advanced/complex) ways to add a master script that you execute in a programmatic way everytime something new has to be built.

15.3.2 RStudio Build and Check

When you use an RStudio R.project, you will see that the pane containing the Environment, History, and Connections, will show one additonal tab called Build.

Build tab

Figure 15.2: Build tab

This tab displays three buttons:

  • Install and Restart
  • Check
  • More

The Install and Restart button will install and reload your package, starting a fresh session.

Install icon

Figure 15.3: Install icon

The Check button will perform a comprehensive check of your package.

Check icon

Figure 15.4: Check icon

The Build button shows more building options.

Build icon

Figure 15.5: Build icon

15.3.3 Sample Package cointoss

You can find the source package of "cointoss" in the following github repository:

https://github.com/gastonstat/cointoss

Feel free to download (or clone) the repository and modify its contents to experiment and practice how to create an R package.

Happy packaging and … May the FoRce be with You!


Make a donation

If you find this resource useful, please consider making a one-time donation in any amount. Your support really matters.