Understanding the contents of the Makevars file in R (macros, variables, ~/.R/Makevars and pkg/src/Makevars)

I am trying to understand the role and relationship of the macros/variables set in ~/.R/Makevars and package_directory/src/Makevars when installing/building own R packages. Suppose these files look like

~/.R/Makevars

CXX = g++
CXXSTD = -std=c++11
CXXFLAGS = -fsanitize=undefined,address -fno-omit-frame-pointer


CXX98 = g++
CXX98STD = -std=c++98


CXX11 = g++
CXX11STD = -std=c++11


CXX14 = g++
CXX14STD = -std=c++14

package_directory/src/Makevars

PKG_CPPFLAGS = -I../inst/include
CXX_STD = CXX11

As I understand it, with CXX we can select the compiler for C++ when building R packages, with CXXSTD we chose the standard and with CXXFLAGS we add compiler flags. With PKG_CPPFLAGS we add flags for the C++ preprocessor and with CXX_STD we tell that our packages uses C++11.

I have the following questions:

  • What is the relationship between CXX and CXX98, CXX11 and CXX14?
  • What is the meaning of, e.g., CXX11STD = -std=c++11 if C++11 is already implied? Is it between choosing -std=c++11 and -std=gnu++11? Should -std=gnu++11 generally be avoided for portability reasons?
  • Could the flags for CXXSTD and CXXFLAGS not just be added to CXX, such that the first three lines reduce to CXX = g++ -std=c++11 -fsanitize=undefined,address -fno-omit-frame-pointer. What is the advantage in explicity specifying CXXSTD and CXXFLAGS?
  • How does CXX_STD = CXX11 work? How is CXX11 here related to CXX11 in ~/.R/Makevars?
  • What is the relationship between CXXFLAGS and PKG_CXXFLAGS(not included in my example)?

I am aware of the information contained in Writing R Extensions and R Installation and Administration, but I am not able to extract more information beyond my current level of understanding to answer the above questions.

I am adding a Rcpp tag because I suppose that answers to these questions will be most relevant to users of Rcpp, but I am aware that this is probably not directly related to Rcpp, so the tag might be removed if deemed appropriate.

31137 次浏览

The Makevars file, as specified in Writing R Extensions: 1.2.1 Using Makevars, is a variant of Make that is unique to R. Many of the variables you have listed are called implicit variables. The meaning is given as:

Implicit rules tell make how to use customary techniques so that you do not have to specify them in detail when you want to use them.

These implicit variables dictate what compiler should be used and what options are available.

Within R, we care about the following default compiler options:

CC Program for compiling C programs; default ‘cc’.

CXX Program for compiling C++ programs; default ‘g++’.

CPP Program for running the C preprocessor, with results to standard output; default ‘$(CC) -E’.

FC Program for compiling or preprocessing Fortran and Ratfor programs; default ‘f77’.

The next set of values details what options should be used by the compiler. In general, the default values for all of these options is an empty string.

CFLAGS Extra flags to give to the C compiler.

CXXFLAGS Extra flags to give to the C++ compiler.

CPPFLAGS Extra flags to give to the C preprocessor and programs that use it (the C and Fortran compilers).

FFLAGS Extra flags to give to the Fortran compiler.

LDFLAGS Extra flags to give to compilers when they are supposed to invoke the linker, ‘ld’, such as -L. Libraries (-lfoo) should be added to the LDLIBS variable instead.

LDLIBS Library flags or names given to compilers when they are supposed to invoke the linker, ‘ld’. LOADLIBES is a deprecated (but still supported) alternative to LDLIBS. Non-library linker flags, such as -L, should go in the LDFLAGS variable.

Now, R defines "extra" variants in terms of different C++ ISO standards. These variants are given in the R Administration: Section 2.7.2 C++ Support and R Administration: Section B.7 Compile and load flags

CXX98 CXX98STD CXX98FLAGS CXX98PICFLAGS

CXX11 CXX11STD CXX11FLAGS CXX11PICFLAGS

CXX14 CXX14STD CXX14FLAGS CXX14PICFLAGS

CXX17 CXX17STD CXX17FLAGS CXX17PICFLAGS


Having said this, let's tackle the first question:

What is the relationship between CXX and CXX98, CXX11 and CXX14?

CXX is the general compiler option to use. Meanwhile, R defines additional CXX options to use depending on the detected compilation standard. That is, if -std=c++98 (CXX98 language spec) set by CXX_STD, then the compiler associated with CXX98 is used. Similarly, for CXX11 and CXX14, the same logic follows. See Rcpp Gallery: Using Rcpp with C++11, C++14 and C++17 for more details.


What is the meaning of, e.g., CXX11STD = -std=c++11 if C++11 is already implied? Is it between choosing -std=c++11 and -std=gnu++11? Should -std=gnu++11 generally be avoided for portability reasons?

The meaning of CXX11STD is to determine the appropriate language standard for C++11 compile. This option exists simply because if R's version of selecting the appropriate C++11 compile option is incorrect for the compiler, you can change it. The reason this exists is because each compiler may define C++11 support slightly differently than the next as indicate in R Installation and Administration: 2.7.2 C++ Support:

It may be [Footnote 13] that there is no suitable flag for C++11 support, in which case a different compiler could be selected for CXX11 and its corresponding flags.

Footnote 13:

This is true for earlier versions of g++ such as 4.2.1, and also for commonly-used versions of the Solaris compiler CC.

For details on the language standards approved by gcc see GCC Manual: 3.4 Options Controlling C Dialect. Also, for details on using C++11 with R in a package see Writing R Extensions: Section 1.2.4 Using C++11 Code.

Generally, I would avoid explicitly setting this variable. If you must explicitly set this variable, I would recommend going with -std=c++11 as a majority of compilers support this declaration.


Could the flags for CXXSTD and CXXFLAGS not just be added to CXX, such that the first three lines reduce to CXX = g++ -std=c++11 -fsanitize=undefined,address -fno-omit-frame-pointer. What is the advantage in explicitly specifying CXXSTD and CXXFLAGS?

Is it possible? Yes. Is it right? No.

Why have three variables each with their own goal when we could simply just have one?

The advantages of a three variable workflow provide different lines each with a distinct role. This allows for the ability to quickly understand the compilation option. Thus, it is much more straight forward to grok when compared it being crammed into one variable on one line (with terminal width of 80).

e.g.

CXX = g++ -std=c++11 -fsanitize=undefined,address -fno-omit-frame-pointer

vs

CXX = g++
CXX11STD = -std=c++11
CXXFLAGS = -fsanitize=undefined,address -fno-omit-frame-pointer

Furthermore, you should opt for CXX_STD over CXXSTD when packaging as shown in Writing R Extensions: Section 1.2.4 Using C++11 Code. This is simply to ensure that R registered the package as requiring C++xy. The alternative is to write in the DESCRIPTION file the attribute SystemRequirements: C++xy, where xy denotes the year.


How does CXX_STD = CXX11 work? How is CXX11 here related to CXX11 in ~/.R/Makevars?

This sets the compilation and linking for the language to be done with the C++11 compiler set by CXX11. By specifying CXX11, you are specifying a variable in Make that will be used to compile the file under the recipe:

$(OBJCXX) $(ALL_CPPFLAGS) $(ALL_OBJCXXFLAGS) -c $< -o $@

where $(OBJCXX) is CXX, $(ALL_CPPFLAGS) is given by $(R_XTRA_CPPFLAGS) $(PKG_CPPFLAGS) $(CLINK_CPPFLAGS) $(CPPFLAGS), and $(ALL_OBJCXXFLAGS) has $(PKG_OBJCXXFLAGS) $(CXXPICFLAGS) $(SHLIB_CXXFLAGS) $(OBJCXXFLAGS) .

The above follows /R/Makeconf.in. However, the routine may be /m4/R.


What is the relationship between CXXFLAGS and PKG_CXXFLAGS (not included in my example)?

Both of these specify the compiler's compilation flags. The order in which they are written in the Makevars is different. In particular, we have CXXFLAGS placed after PKG_CXXFLAGS. The right most option is always used. So, CXXFLAGS takes precedence over PKG_CXXFLAGS.

There is a brief note on PKG_* options in Writing R Extensions: Section 5.5 Creating shared objects.

Addendum

The following are questions that were asked by @Dominik in the comment section of this response.


Is it correct that variables defined in ~/.R/Makevars apply globally to the installation of all packages, while variables in /src/Makevars only apply to the present package?

Yes. This is accurate. Variables within ~/.R/Makevars will apply to all packages while the /src/Makevars that ships with each package will only influence settings for that package. The values in /src/Makevars will take precedence over ~/.R/Makevars.

Some packages may ship with /src/Makevars.win, which provides a Makevars file specifically for the Windows environment.


Is the compilation standard used for a packages nowadays only set via CXX_STD and not any more by PKG_CXXFLAGS as shown in gallery.rcpp.org/articles/simple-lambda-func-c++11?

There is a slight difference between when these two flags should be used. In particular, CXX_STD is only operational in a package environment. Meanwhile, contrary to its name, PKG_CXXFLAGS, affects all compile options. Thus, when you quote the above Rcpp gallery post, you are observing a standalone script being run. To quickly engage the correct mode, that requires PKG_CXXFLAGS to be set and not the CXX_STD definition.

Now, forgive me for going on a brief tangent on the history of standalone use compilation options.... The use of PKG_CXXFLAGS is a bit old school. In fact, the preferred approach in R 3.4 is to set the environment variable USE_CXX11 = "yes". Between R 3.1 and R 3.3, the standard was to set the environment variable USE_CXX1X = "yes". Prior to those instances, the use of PKG_CXXFLAGS ="-std=c++11" was preferred. (Except on Windows, which needed PKG_CXXFLAGS ="-std=c++0x".)


Does using CXX_STD=CXX11 then mean to use all the settings given by CXX, CXXSTD, CXXFLAGS and CXX11PICFLAGS?

No. This means to use options set by:

CXX11 CXX11STD CXX11FLAGS CXX11PICFLAGS