When starting a new project in R, creating it in the framework of an R package has several advantages (instead of writing a collection of loose scripts), e.g. an easy testing framework, documentation.

Eventually, you may decide to release your package to the academic community. While you could simply provide a link to the .tar.gz file on your website, it is better to submit it to CRAN, the official repository for R packages.

However, getting your package onto CRAN is not always straightforward. CRAN has strict rules regarding documentation, compilation, etc, that need to be observed in order for your package to be accepted.

Hadley Wickham's books and website

Hadley Wickham (again!) has a written an excellent book that gives a good introduction to creating R packages as well as submitting them to CRAN. He also has a section on his website, upon which the book is based that is also really useful.

In fact, the tips on his website made the process of getting my first package onto CRAN very smooth.

Packages that contain C++ code

However, the process of getting my second package onto CRAN was not very smooth, and I learnt a few lessons that I would like to record here.

The chief difference between my first and second package is that the first only used R code, while the second package (co-created with a colleague) was heavily based on C and C++ code - this created some difficulties that I had not previously experienced.

Everything I say here is contained in the excellent (but long) Writing R extensions manual. The problem with the manual is that it is sometimes very details, other times very terse, and sometimes information is spread over several sections (e.g. how to set compiler flags).

Setting the compiler: C++98 or C++11?

Short story: if you want to use C++11, in your DESCRIPTION file, include (as the last line) the following:

SystemRequirements: C++11

Long story

You may find you package compiles on one platform, but not another, and that some of the missing features (on one platform) may belong to the C++11 standard.

The Writing R extensions manual says the following

Since version 3.1.0, R has provided support for C++11 
in packages in addition to C++98. 

However, later on in the section it seems to suggest that support for C++11 is not available in all compilers. I could swear that I eventually found a link saying that C++11 is now supported, but cannot find that link (and I am not talking about this Stackoverflow post ).

So, I think it is okay to expect support for most of C++11, but you should be a little careful. There is nice blog post by Dirk Eddelbuettel that is worth checking out, although it is a couple of years old.

Testing on different operating systems

CRAN asks that you check your package installs on at least two operating systems. The good news is, this is relatively easy.

Using winbuilder

To check on Windows, Uwe Ligges, the CRAN maintainer for Windows binaries, has built a tool called winbuilder that makes it possible to check if your package installs on a Windows machine.

In R, just as if you would use the devtools::document() command to compile your package, do:

devtools::build_win()

If you have an internet connection, the package will be uploaded to the winbuilder framework, and you will get an email with the results in about half an hour (the email address that you have listed in your DESCRIPTION file).

Using a Linux virtual machine

This post provides links showing how to install VirtualBox and Linux Mint (a good choice for a virtual machine).

If you want to check your package on Solaris, check out this post which goes through the process of installing R on that system.

Manual checking

In all cases, you should use the This is how you do it:

  • in R, use devtools to build the mypackage.tar.gz file:
  • devtools::build()
    
  • in a terminal, in the same directory as the mypackage.tar.gz file, use R CMD check --as-cran command to check the package
  • R CMD check --as-cran -l /path/to/Rlib mypackage.tar.gz
    

where /path/to/Rlib is the directory where the other R packages (dependencies) are installed.

Note that you may need to install qpdf before running the check, especially if you have vignettes. this can be done with brew:

brew install qpdf

Setting the compiler flags

Short story: your package depends on C++ code and the checks may work perfectly on your system, but CRAN's compilers may be stricter and throw additional warnings.

In order to better simulate CRAN's checks, you need to create the file ~/.R/Makevars and set certain compiler flags. The following commands create the necessary file:

mkdir ~/.R
echo 'PKG_CXXFLAGS = -mtune=native -g -O2 -Wall -pedantic' >> ~/.R/Makevars

Example: using std::to_string

In the package there were a few places where I had to convert an integer or double into a string. I wanted to use the std::to_string function, available in C++11, and it did work on several installations, but later failed some R checks. The solution I ended using is from this Stackoverflow post:

//from http://stackoverflow.com/questions/12975341/to-string-is-not-a-member-of-std-says-g

template < typename T > std::string AnotherToString( const T& num )
{
    std::ostringstream ss;
    ss << num ;
    return ss.str() ;
}

It should work without including #include<sstream> in the header, but if there is an error, try adding that file.

Example: using fstream

While including #include<sstream> should be fine, including the line #include<fstream> when using C++11 created very weird error with a message that was something like:


error: 'RF_error' is not a member of 'std::codecvt_base'   if (__result == codecvt_base::error) ... etc

Short story: do not use #include<fstream>.

Example: beware of long long's

The package contained a lot of C code written by a colleague which used a lot of long long variables (because some of the integers may have been larger than a standard long on a 32-bit system).

It seems that there is some ambiguity (between systems) about the range of a long long - but if you use a 64-bit system, and set the C++11 compiler flag, the short story is just to stick to long variables.

Success upload and CRAN's additional checks

Most package maintainers are awesome and give you the benefit of the doubt - after your package passes the first few checks, he or she will put the package on CRAN, and will send you a short email saying that your package now on CRAN.

However, before you start celebrating, you need to wait at least 48 hours for ALL the checks to pass. The thing is, CRAN checks that your package installs on the following systems:

  • Windows
  • OSX
  • Debian
  • Fedora
  • Solaris

(for the latest release of R, and sometimes with an older version of R, as well as for different compilers.)

If one of the checks fails, your package will probably be removed to the CRAN archive, and not be available for installation within R.

For example, for the first submission my package passed all the initial checks, but after 24 hours it failed to install on Linux (even though I had sucessfully installed it on Ubuntu). For the second submission, after 24 hours it failed to install Solaris.

The bottom line is, wait 48 hours, even after you have got the hallowed now on CRAN email from the maintainers, to make sure you package passes all the checks before you start advertising it.

If you get a late rejection message, the next section discusses how to deal with it.

Dealing with rejection and the CRAN maintainers

Even after my package had been rejected for the third time, the package maintainers were very polite about it. Considering that this is something they do in their spare time (they mostly seem to be busy professors), their politeness about my package's shortcomings was quite humbling.

Now, I know how annoying it can be when you have successfully tested your package on three operating systems, but then have it fail to install on Solaris (people still use Solaris?).

The first step is to not take it personally, pause for a moment, and go grab a coffee. Maybe wait a day or two before starting with a fresh mind. The fix could take ten minutes, or a week.

Seeing the errors

The next step is to go to the link they will probably provide you with in the email regarding your packages's failed results. The link will take you to a page directory, and if you click on install.log, you should see the error messages.

If there is not link, search for your package on the CRAN archive, and check the link mypackage results. You will probably see something like the following:

Flavor 		 	Version   Tinstall  Tcheck  Ttotal  Status  Flags
r-devel-linux-...	0.2.5 	  19.58     14.49   34.08   ERROR 	

If you click on ERROR, it show you the output of the package attempting to install, and you should see the error messages there.

Fixing the errors

Do not email the CRAN maintainer expecting he/she to know why the error or occurred, or how to sort it out.

Maybe the error will take you a couple of days poking around Stackoverflow, or if you cannot easily identify the error, you may need to use (the slightly heavy-handed approach) of commenting out functions and compiling the package a little bit at a time (start with only the first part uncommented, then slowly add pieces until it fails).

Try removing some of the #include headings, or reordering them. It took me several hours to find that an error I thought was to do with my error/exception handling was actually just because I had #include<fstream>. I had another error where I just needed to swap the order of two #includes - I think #include<math> needs to be ABOVE #include<R.h>.

Remember - relax

Hadley shares a few stories of his experiences with his packages not getting accepted on his site (scroll down a bit to the section On failure - read this!).

Discussion

Getting your package on CRAN is probably worth the effort, so if you encounter a few difficulties - do not give up. Once it is on, you will be able to download/install it anytime (even on Solaris).