Dirk Eddelbuettel — written Feb 19, 2017 — source
When we started the Rcpp Gallery in late 2012, a few of us spent the next four weeks diligently
writing articles ensuring that at least one new article would be posted per day. Two early articles
covered the then-budding support for C++11. Both
First steps in using C++11 with Rcpp and
A first lambda function with C++11 and Rcpp
started by actually showing how to set the compiler directive via the PKG_CXXFLAGS
environment
variable.
Both posts were updated a few months later to demonstrate the C++11 plugin that was added in Rcpp
release 0.10.3 in March of 2013, or almost four years ago. Many posts here, on
StackOverflow and of course on the mailing list
make use of the plugin to tell the compiler to turn on C++11 support. In the early days, this often
meant partial support via (in the case of g++
) the -std=c++0x
switch. This is still
supported by Rcpp
as in particular the Windows side of things was relying on older compilers like g++ version 4.6.*
until more recently (see below).
But some things got a lot better with R 3.1.0. As the
NEWS announcement dryly noted: There
is support for compiling C++11 code in packages on suitable platforms: see ‘Writing R Extensions’.
which was coupled with support for selecting the C++11 language standard via either CXX_STD
in
src/Makevars
, or the SystemRequirements
line in DESCRIPTION
. In late 2011, Martyn Plummer also
wrote a helpful
R Journal article on
best practices for portable C++ packages.
And as we alluded to above, Rcpp has supported C++11 since the dawn of time (because, as we detail
below, it ultimately comes down what your compiler supports, and what R facilitates). Many CRAN
packages have by now taken advantage of this increased support for C++11 in particular. As of
today, we see 88 CRAN packages declaring this via DESCRIPTION
and 127 CRAN package via
src/Makevars
. And of course, almost all use Rcpp along with C++ to take advantage of the R and
C++ integration it offers.
So what are the defining parameters for support by Rcpp? In essence, Rcpp is guided by just two (external) factors:
the support in the provided compiler, and
the support offered by R for package building,
and both are worth detailing as we do in the next two sections..
First, the choice of compiler matters. Rcpp operates on top of R, and (like any R package) it is
driven entirely by the build instructions from R. It can therefore be dependent on the compiler
choices offered by R. This meant g++ version 4.6.3 for Windows for years. And this got a lot
better when Rtools switched to g++ version 4.9.3 with R 3.3.0 not quite a year ago. It now means
that support for C++11 is almost universal. (Some small things are still missing in g++-4.9.3
;
notably complete support for the C++ Standard Library leading us recently to
backport get_time
from LLVM into RcppCCTZ. Also
note that macOS / OS X has its own dependency chain due to compiler, and release, choices made by
the R package build system for that platform.)
Now, that is just the minimum available compiler for a particular platform, albeit a very important
one as it defines what binary CRAN packages on Windows can support. Other platforms, however,
have a faster release cadence. g++-5
and clang++-3.3
are now fairly common and have
(near-)complete C++11 support. The most recent Ubuntu release 16.10 even defaults to g++ version
6.2.0, and Debian already has version 6.3.0 (and binaries of version 7.* in its experimental
branch). Similarly, recent version of clang are available both directly in the distributoin and via
nightly builds from dedicated PPAs.
And for these ‘6.*’ version of g++
, the default C++ standard is already C++14, the follow-up
standard release to C++11. For example, C++14 extends support for auto
to return values so that
we can compile a simple program such as
withour any additional switches or flags if the compiler is as recent as g++ version 6. A plain
g++ -o demoprog demoprog.cpp
will do (provided the snippet was saved as file demoprogr.cpp) as
C++14 is the default for this compiler. Otherwise, adding -std=c++14
explicitly instruct the
compiler to compile as C++14.
Moreover, it also works for R:
[1] 2
[1] 2
(on a machine such as the one used to write this piece) without requiring any additional plugins.
As a reminder, cppFunction()
supports these via the plugin=
argument. On another machine, we
might use Rcpp::cppFunction("auto doubleMe(const int &x) { return x + x; }", plugin="cpp14")
.
Similarly, in code sourced via sourceCpp()
we would use an attribute; see the
Rcpp Attributes vignette
for details.
As noted above, the R 3.1.0 release started to add support for modern C++ by enabling packages to select C++11.
The next release will be R 3.4.0. While as of now without an announced release date, it is likely to
be shipped this April. It will bring support for C++14. The current draft of its version of
Writing R Extenions shows that CXX_STD = CXX14
can be used to select this language standard in a
package. Several build variables extend support to CXX1Y
beyond the existing CXX1X
, see the
Writing R Extenions manual for full details.
To illustrate, on a machine with g++
version 6.*, nothing has to be turned on for C++14 in what
will be R 3.4.0.
On a machine where g++-5
is the default, the CXX1XSTD
value may be empty as this compiler
defaults to C++11; we would expect CXX1YSTD = -std=c++14
there (or the ‘gnu’ variant).
As we noted above, well over one-hundred packages on CRAN already use C++11. We expect to see C++14 being used once R 3.4.0 is released later this spring
As we wrote in the opening paragraph, a plugin for C++11 has been part of Rcpp for several years. And a plugin for C++14 was added by Dan in Rcpp 0.12.4 about a year ago.
The current development sources of Rcpp, corresponding to interim GitHub release 0.12.9.3, added a plugin for C++17 as experimental support exists in g++ and clang++ right now. With that, a suitably recent compiler, and a version of Rcpp that is at least release 0.12.9.3, the following example (motivated by this example section of the C++ Standard post) also builds:
This note discussed where Rcpp stands with respect to “modern C++”. As a brief summary:
Rcpp supports any C++ language standard the underlying compiler supports: C++98, C++11, C++14, C++17;
Packages using Rcpp can deploy every language standard suppported by R: currently C++, C++11 and very soon C++14;
Package distribution may need to reflect the build infracture; on Windows this means g++-4.9.3
with near-complete C++11 support;
Local developement can be more experimental and even C++17 is now supported by Rcpp as well;
Portable packages should specify the C++ language standard they expect (unless it is C++98).