Rcpp 和 protobuf:Free 宏的双重定义

Rcpp and protobuf: double definition of Free macro

我正在开发一个 C++ 库并希望将其与 Python 和 R 接口。

核心思想是 R 和 Python 基本上 'empty shells' 用于绘图而不是其他,所有核心计算都是在 C++ 中完成的,因此接口只是一堆运行 相当于 C++ 'main' 和 return 输出到 R 或 Python 而不是将内容保存到文件的函数。

我的想法是以 server/client 方式使用 goolge 的协议缓冲区:数据使用序列化消息从 Python (R) 传递到 C++,然后在 C++ 中反序列化。计算在 C++ 中是 运行 并且 Python (R) 是 returned 一个 bytes/strings 的列表,每个列表对应于一个序列化的原型对象。

在 Python 中,由于 Pybind11,这就像一个魅力。 但是,在 R 中我得到一个奇怪的错误:

/usr/include/google/protobuf/arena_impl.h:174:60: error: macro "Free" passed 3 arguments, but takes just 1
                        void (*block_dealloc)(void*, size_t));

我认为这个问题是由于 Rcpp 定义了一个类似于 protobuf 的宏。 以下 MWE 重现了相同的错误。

这是折叠结构

.
├── src
│   ├── rcpp_exports.cpp
├── student.proto
└── test.R

在test.R

Rcpp::sourceCpp(file="src/rcpp_exports.cpp")

在rcpp_exports.cpp

#include <Rcpp.h>
using namespace Rcpp;
#include "student.pb.h"

// [[Rcpp::export]]
std::string foo() {
  Student stud;
  stud.set_grade(25);
  return stud.DebugString();
}

在student.proto

syntax = "proto3";

message Student {
  double grade = 1;
  bool pass = 2;
}

然后使用

编译protobuf文件
> protoc --proto_path=. --cpp_out=./src student.proto

最后我 运行 test.R 文件

> Rscript test.R

获取以下错误日志:

In file included from /usr/include/google/protobuf/arena.h:55:0,
                 from /home/mario/dev/tesi/test_rproto/src/student.pb.h:24,
                 from rcpp_exports.cpp:3:
/usr/include/google/protobuf/arena_impl.h:174:60: error: macro "Free" passed 3 arguments, but takes just 1
                        void (*block_dealloc)(void*, size_t));
                                                            ^
In file included from /usr/share/R/include/R.h:91:0,
                 from /home/mario/R/x86_64-pc-linux-gnu-library/3.6/Rcpp/include/Rcpp/r/headers.h:63,
                 from /home/mario/R/x86_64-pc-linux-gnu-library/3.6/Rcpp/include/RcppCommon.h:29,
                 from /home/mario/R/x86_64-pc-linux-gnu-library/3.6/Rcpp/include/Rcpp.h:27,
                 from rcpp_exports.cpp:1:
/usr/share/R/include/R_ext/RS.h:74:37: error: expected identifier before ‘(’ token
 #define Free(p)        (R_chk_free( (void *)(p) ), (p) = NULL)
                                     ^
/usr/share/R/include/R_ext/RS.h:74:47: error: ‘parameter’ declared as function returning a function
 #define Free(p)        (R_chk_free( (void *)(p) ), (p) = NULL)
                                               ^
/usr/share/R/include/R_ext/RS.h:74:50: error: expected ‘)’ before ‘,’ token
 #define Free(p)        (R_chk_free( (void *)(p) ), (p) = NULL)
                                                  ^
make: *** [rcpp_exports.o] Error 1

我会推荐一些用于防御性编程的东西:

  1. 不要展平命名空间 删除 using namespace Rcpp; 并使用前缀显式调用您的函数。

  2. 通过在包含 Rcpp.h 或其他 R headers.[= 之前​​定义 #define STRICT_R_HEADERS 来要求严格包含(我们不能追溯为默认值) 17=]

  3. 在没有重新映射的情况下使用 R 函数, Rf_error() 通过定义 R_NO_REMAP 但 Rcpp 应该为您完成。

通过在包含的内容和方式上稍微自由一些,应该可以避免您在此处发现的冲突。

最后,我们在十多年前写了 RProtoBuf(它实际上也参与了创建当前的 Rcpp),但我 从未 收到了您在此处收到的错误消息。所以明明是可以避免的。