У меня есть простая программа на C ++, которую я могу успешно построить, используя clang++
на моем Mac (Mavericks), но это не удается при сборке с R CMD SHLIB
и загружен dyn.load
в Р.
Это код C ++ (хранится в simple.cpp
), который использует оптимизатор Gurobi:
#include "gurobi_c++.h"#include <iostream>
void fxn() {
GRBEnv env = GRBEnv(); // Create a Gurobi environment
GRBModel colgen = GRBModel(env); // Create empty model object
colgen.addVar(0, 1, 0.0, GRB_BINARY); // Add binary variable to model
std::cout << "Hello world" << std::endl;
}
int main(int argc, char **argv) {
fxn();
return 0;
}
Я могу успешно скомпилировать и запустить этот код, используя clang++
, ссылаясь на библиотеки Gurobi:
$ clang++ simple.cpp -I/Library/gurobi562/mac64/include \
-L/Library/gurobi562/mac64/lib -lgurobi_c++ -lgurobi56 -stdlib=libstdc++ \
-lpthread -lm
$ ./a.out
Hello world
Я могу успешно скомпилировать с R CMD SHLIB
:
$ MAKEFLAGS="PKG_CXXFLAGS=-I/Library/gurobi562/mac64/include" R CMD SHLIB \
simple.cpp -L/Library/gurobi562/mac64/lib -lgurobi_c++ -lgurobi56 \
-stdlib=libstdc++ -lpthread -lm
clang++ -I/Library/Frameworks/R.framework/Resources/include -DNDEBUG \
-I/usr/local/include -I/Library/gurobi562/mac64/include -fPIC -mtune=core2 \
-g -O2 -c simple.cpp -o simple.o
clang++ -dynamiclib -Wl,-headerpad_max_install_names -undefined dynamic_lookup \
-single_module -multiply_defined suppress -L/usr/local/lib -L/usr/local/lib \
-o simple.so simple.o -L/Library/gurobi562/mac64/lib -lgurobi_c++ -lgurobi56 \
-stdlib=libstdc++ -lpthread -lm -F/Library/Frameworks/R.framework/.. \
-framework R -Wl,-framework -Wl,CoreFoundation
Тем не мение, dyn.load("simple.so")
терпит неудачу в R:
Error in dyn.load("simple.so") :
unable to load shared object '[path]/simple.so':
dlopen([path]/simple.so, 6): Symbol not found: __ZN8GRBModel6addVarEdddcNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE
Referenced from: [path]/simple.so
Expected in: flat namespace
in [path]/simple.so
От c++filt
Я вижу, что пропавший символ GRBModel::addVar(double, double, double, char, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)
, которая должна быть предоставлена одной из библиотек Gurobi, на которую я ссылаюсь.
Из предыдущих постов я узнал, что эти ошибки «Symbol not found» часто возникают из-за того, что они не связывают правильные библиотеки, но я смог успешно скомпилировать и запустить simple.cpp
и я передаю те же варианты ссылок на R CMD SHLIB
,
Ниже приводится содержание моего ~/.R/Makevars
файл:
CC=clang
CXX=clang++
редактировать Я думаю, что проблема может быть связана с опцией -stdlib=libstdc++
что я использую при компиляции кода. Когда я удаляю эту опцию из первой сборки (рабочий вызов clang++
) первая ошибка компоновщика, которую я получаю:
Undefined symbols for architecture x86_64:
"GRBModel::addVar(double, double, double, char, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)", referenced from:
_fxn in simple-pRHAEs.o
Это тот же неопределенный символ, который вызывает dyn.load
терпеть неудачу.
Я решил эту проблему, которая оказалась связана с тем, как я приводил аргумент -stdlib=libstdc++
в R CMD SHLIB
, R CMD SHLIB
Запускает clang++
дважды, сначала как этап компиляции для создания объектного файла (simple.o
в моем случае), а затем связать этот файл в общий объект (simple.so
в моем случае). R CMD SHLIB
проходил только -stdlib=libstdc++
аргумент для второго вызова, но нам нужно также предоставить аргумент для первого вызова clang++
, Мы можем сделать это, добавив -stdlib=libstdc++
в PKG_CXXFLAGS
:
$ PKG_CXXFLAGS="-I/Library/gurobi562/mac64/include -stdlib=libstdc++" R CMD SHLIB \
simple.cpp -L/Library/gurobi562/mac64/lib -lgurobi_c++ -lgurobi56 \
-stdlib=libstdc++ -lpthread -lm
clang++ -I/Library/Frameworks/R.framework/Resources/include -DNDEBUG \
-I/usr/local/include -I/Library/gurobi562/mac64/include -stdlib=libstdc++ \
-fPIC -mtune=core2 -g -O2 -c simple.cpp -o simple.o
clang++ -dynamiclib -Wl,-headerpad_max_install_names -undefined dynamic_lookup \
-single_module -multiply_defined suppress -L/usr/local/lib -L/usr/local/lib \
-o simple.so simple.o -L/Library/gurobi562/mac64/lib -lgurobi_c++ -lgurobi56 \
-stdlib=libstdc++ -lpthread -lm -F/Library/Frameworks/R.framework/.. \
-framework R -Wl,-framework -Wl,CoreFoundation
Сейчас, dyn.load("simple.so")
работает без ошибок от R (хотя, как уже упоминалось @MartinMorgan и @JanvanderLaan, мне нужно будет выставить свои функции, используя extern "C"
или альтернатива, чтобы действительно быть в состоянии вызвать их из R).
R ожидает связи с C, но вы предоставили связь с C ++. Одним из решений является
#include <iostream>
extern "C" void fxn() {
std::cout << "Hello world" << std::endl;
}
с
$ R --vanilla CMD SHLIB tmp.cpp && R --vanilla -e "dyn.load('tmp.so'); .C('fxn')"clang++ -I/home/mtmorgan/bin/R-devel/include -DNDEBUG -I/usr/local/include -fpic -ggdb -O0 -c tmp.cpp -o tmp.o
clang++ -shared -L/usr/local/lib -o tmp.so tmp.o -L/home/mtmorgan/bin/R-devel/lib -lR
> dyn.load('tmp.so'); .C('fxn')
Hello world
list()