【问题标题】:Understanding the contents of the Makevars file in R (macros, variables, ~/.R/Makevars and pkg/src/Makevars)了解 R 中 Makevars 文件的内容(宏、变量、~/.R/Makevars 和 pkg/src/Makevars)
【发布时间】:2017-09-21 16:45:31
【问题描述】:

在安装/构建自己的 R 包时,我试图了解在 ~/.R/Makevarspackage_directory/src/Makevars 中设置的宏/变量的作用和关系。假设这些文件看起来像

~/.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

据我了解,CXX 我们可以在构建 R 包时为 C++ 选择编译器,CXXSTD 我们选择标准,CXXFLAGS 我们添加编译器标志。使用PKG_CPPFLAGS,我们为 C++ 预处理器添加标志,使用CXX_STD,我们告诉我们的包使用 C++11。

我有以下问题:

  • CXXCXX98CXX11CXX14是什么关系?
  • 如果已经隐含了 C++11,CXX11STD = -std=c++11 的含义是什么?是在选择-std=c++11-std=gnu++11 之间吗?出于便携性原因,是否应该避免使用 -std=gnu++11
  • 能否将CXXSTDCXXFLAGS 的标志不仅仅添加到CXX,这样前三行就减少到CXX = g++ -std=c++11 -fsanitize=undefined,address -fno-omit-frame-pointer。明确指定CXXSTDCXXFLAGS 有什么好处?
  • CXX_STD = CXX11 是如何工作的?这里的CXX11~/.R/Makevars 中的CXX11 有什么关系?
  • CXXFLAGSPKG_CXXFLAGS 之间有什么关系(我的示例中没有包含)?

我知道Writing R ExtensionsR Installation and Administration 中包含的信息,但我无法提取超出我目前理解水平的更多信息来回答上述问题。

我添加了一个Rcpp 标签,因为我认为这些问题的答案与Rcpp 的用户最相关,但我知道这可能与Rcpp 没有直接关系,所以标签可能如果认为合适,将被删除。

【问题讨论】:

    标签: r rcpp


    【解决方案1】:

    Makevars 文件,在Writing R Extensions: 1.2.1 Using Makevars 中指定,是Make 的一个变体,对于R 来说是唯一。您列出的许多变量都称为implicit variables。含义如下:

    隐式规则告诉 make 如何使用惯用的技术,这样您在使用它们时就不必详细指定它们。

    这些implicit variables 规定应该使用 what 编译器并且 what 选项可用。

    R中,我们关心以下默认编译器选项:

    CC 编译C程序的程序;默认‘抄送’。

    CXX 编译C++程序的程序;默认‘g++’。

    CPP 用于运行 C 预处理器的程序,并将结果输出到标准输出;默认‘$(CC) -E’。

    FC 用于编译或预处理 Fortran 和 Ratfor 程序的程序;默认为“f77”。

    下一组值详细说明了编译器应该使用的什么选项。通常,所有这些选项的默认值都是空字符串。

    CFLAGS 提供给 C 编译器的额外标志。

    CXXFLAGS 提供给 C++ 编译器的额外标志。

    CPPFLAGS 提供给 C 预处理器和使用它的程序(C 和 Fortran 编译器)的额外标志。

    FFLAGS 提供给 Fortran 编译器的额外标志。

    LDFLAGS 在编译器应该调用链接器时提供给编译器的额外标志,“ld”,例如 -L。应添加库 (-lfoo) 改为 LDLIBS 变量。

    LDLIBS 当编译器应该调用链接器“ld”时为编译器提供的库标志或名称。 LOADLIBES 已被弃用(但 仍然支持)替代 LDLIBS。非库链接器标志,例如 作为 -L,应该放在 LDFLAGS 变量中。

    现在,R 根据不同的 C++ ISO 标准定义了“额外的”变体。这些变体在R Administration: Section 2.7.2 C++ SupportR Administration: Section B.7 Compile and load flags 中给出

    CXX98 CXX98STD CXX98FLAGS CXX98PICFLAGS

    CXX11 CXX11STD CXX11FLAGS CXX11PICFLAGS

    CXX14 CXX14STD CXX14FLAGS CXX14PICFLAGS

    CXX17 CXX17STD CXX17FLAGS CXX17PICFLAGS


    说了这么多,我们来解决第一个问题:

    CXXCXX98CXX11CXX14是什么关系?

    CXX 是要使用的通用编译器选项。同时,R 定义了额外的CXX 选项以根据检测到的编译标准使用。也就是说,如果-std=c++98CXX98 语言规范)由CXX_STD 设置,则使用与CXX98 关联的编译器。同样,对于CXX11CXX14,遵循相同的逻辑。详情请见Rcpp Gallery: Using Rcpp with C++11, C++14 and C++17


    如果已经隐含了 C++11,例如 CXX11STD = -std=c++11 的含义是什么?是在选择-std=c++11-std=gnu++11 之间吗?出于便携性原因,是否应该避免使用 -std=gnu++11

    CXX11STD的含义是确定适合C++11编译的语言标准。这个选项之所以存在只是因为如果R 选择的适当C++11 编译选项的版本对于编译器不正确,您可以更改它。存在这种情况的原因是因为每个编译器定义的 C++11 支持可能与 R Installation and Administration: 2.7.2 C++ Support 中所示的下一个编译器略有不同:

    可能是 [脚注 13] 没有适合 C++11 支持的标志,在这种情况下,可以为 CXX11 及其相应标志选择不同的编译器。

    脚注 13:

    对于早期版本的 g++(例如 4.2.1)和 Solaris 编译器 CC 的常用版本也是如此。

    有关 gcc 批准的语言标准的详细信息,请参阅GCC Manual: 3.4 Options Controlling C Dialect。此外,有关在包中使用带有 R 的 C++11 的详细信息,请参阅Writing R Extensions: Section 1.2.4 Using C++11 Code

    通常,我会避免显式设置此变量。如果您必须显式设置此变量,我建议您使用-std=c++11,因为大多数编译器都支持此声明。


    CXXSTDCXXFLAGS 的标志是否可以不只是添加到 CXX,这样前三行会减少到 CXX = g++ -std=c++11 -fsanitize=undefined,address -fno-omit-frame-pointer。明确指定CXXSTDCXXFLAGS 有什么好处?

    有可能吗?是的。这样对吗?没有。

    为什么我们可以只拥有一个三个变量?

    三个变量工作流程的优势在于为不同的生产线提供了不同的角色。这允许快速理解编译选项的能力。因此,与将其塞入一行中的一个变量(终端宽度为 80)相比,它更容易理解。

    例如

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

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

    此外,如Writing R Extensions: Section 1.2.4 Using C++11 Code 所示包装时,您应该选择CXX_STD 而不是CXXSTD。这只是为了确保 R 将包注册为需要 C++xy。另一种方法是在DESCRIPTION 文件中写入属性SystemRequirements: C++xy,其中xy 表示年份。


    CXX_STD = CXX11 是如何工作的?这里的CXX11 与~/.R/Makevars 中的CXX11 有什么关系?

    这会将语言的编译和链接设置为使用 CXX11 设置的 C++11 编译器完成。通过指定CXX11,您指定了一个variable in Make,它将用于编译配方下的文件:

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

    其中$(OBJCXX)CXX$(ALL_CPPFLAGS)$(R_XTRA_CPPFLAGS) $(PKG_CPPFLAGS) $(CLINK_CPPFLAGS) $(CPPFLAGS) 给出,$(ALL_OBJCXXFLAGS) 具有$(PKG_OBJCXXFLAGS) $(CXXPICFLAGS) $(SHLIB_CXXFLAGS) $(OBJCXXFLAGS)

    以上内容遵循/R/Makeconf.in。但是,例程可能是/m4/R


    CXXFLAGSPKG_CXXFLAGS 之间是什么关系(我的示例中没有包含)?

    这两个都指定了编译器的编译标志。它们在Makevars 中的写入顺序不同。特别是,我们有 CXXFLAGS placed after PKG_CXXFLAGS正确大多数选项总是使用。因此,CXXFLAGS 优先于 PKG_CXXFLAGS

    Writing R Extensions: Section 5.5 Creating shared objects 中有一个关于PKG_* 选项的简要说明。

    附录

    以下是@Dominik 在此回复的评论部分提出的问题。


    ~/.R/Makevars 中定义的变量是否全局适用于所有包的安装,而/src/Makevars 中的变量只适用于当前包?

    是的。这是准确的。 ~/.R/Makevars 中的变量将应用于所有包,而每个包附带的/src/Makevars 只会影响该包的设置。 /src/Makevars 中的值将优先于 ~/.R/Makevars

    某些软件包可能附带/src/Makevars.win,它提供了一个专门用于Windows 环境的Makevars 文件。


    现在用于包的编译标准是否仅通过CXX_STD 设置,而不再由PKG_CXXFLAGS 设置,如gallery.rcpp.org/articles/simple-lambda-func-c++11 所示?

    这两个标志的使用时间略有不同。特别是,CXX_STD 只能在包环境中运行。同时,与其名称相反,PKG_CXXFLAGS 会影响所有编译选项。因此,当您引用上述 Rcpp 库帖子时,您正在观察正在运行的独立脚本。要快速启用正确的模式,需要设置 PKG_CXXFLAGS不是 CXX_STD 定义。

    现在,请原谅我简要介绍了独立使用编译选项的历史......PKG_CXXFLAGS 的使用有点老套了。事实上,R 3.4 中的首选方法是设置环境变量USE_CXX11 = "yes"。在 R 3.1 和 R 3.3 之间,标准是设置环境变量USE_CXX1X = "yes"。在这些实例之前,首选使用PKG_CXXFLAGS ="-std=c++11"。 (Windows 除外,它需要 PKG_CXXFLAGS ="-std=c++0x"。)


    使用CXX_STD=CXX11 是否意味着使用CXXCXXSTDCXXFLAGSCXX11PICFLAGS 给出的所有设置?

    没有。这意味着使用通过以下方式设置的选项:

    CXX11 CXX11STD CXX11FLAGS CXX11PICFLAGS

    【讨论】:

    • 太好了,感谢您的精彩回答!如果您允许,我将对此提出一些后续问题:i) ~/.R/Makevars 中定义的变量全局应用于所有软件包的安装是否正确,而 /src/Makevars 中的变量仅适用于当前软件包? ii) 现在用于包的编译标准是否仅通过CXX_STD 设置,而不再由PKG_CXXFALGS 设置,如gallery.rcpp.org/articles/simple-lambda-func-c++11 所示? iii) 使用CXX_STD=CXX11 是否意味着使用CXXCXXSTDCXXFALGSCXX11PICFLAGS 给出的所有设置?
    • 再次感谢您为回答我的其他问题所做的努力。请注意,第 (iii) 部分有点愚蠢,因为我不小心错过了前 3 个变量中的 11
    • 什么是~/.R/Makevars??我在 Windows 上。我正在使用 sourceCpp() 来编译一个简单的模型。我想抑制 -Wreorder 警告。谢谢。
    • 在 Windows 10 中,您可以使用 tools::makevars_user() 找到 Makevars 文件。我通过添加PKG_CXXFLAGS = -Wno-reorder 成功更改了sourceCpp() 的编译器选项
    • 我想知道是否可以为特定系统提供一些特定示例。我对c和c++一无所知,只想获取需要编译才能编译的包;在我的特定情况下,在 centos 系统上。我目前的 Makevars 文件为 CC=gcc-7.3.1 CXX=g++7.3.1 CXX_STD=CXX CXX1X=g++-7.3.1 SHLIB_CXXLD=g++-7.3.1,当我尝试编译说 Rcpp 时出现错误
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多