2016-08-25 4 views
0

Ich versuche, eine dylib-Datei in OSX El Capitain aus einer C++ - Quelldatei zu erstellen, in R über Rcpp einzulesen. Hier ist ein stark vereinfachtes Beispiel dafür, was ich geschaffen habe:g ++ Rcpp Undefinierte Symbole für Architektur x86_64 auf osx

//test.cpp 
#include <Rcpp.h> 

RcppExport SEXP dosum(SEXP _a, SEXP _b){ 
    double a = Rcpp::as<double>(_a); 
    double b = Rcpp::as<double>(_b); 
    return Rcpp::wrap(a+b); 
} 

Wenn ich kompilieren/link folgendes Makefile auf einem Linux-Server, die mir an meiner Universität zur Verfügung steht,

CC=g++ 
# note the use of c++14, used to use c++11 

all: test 

test : 
${CC} -DNDEBUG \ 
    -I. \ 
    -I/usr/share/R/include \ 
    -I/server/linux/lib/R/3.0/x86_64/site-library/Rcpp/include \ 
    -I/usr/share/Rcpp_0.12.3/include \ 
    -fpic -O3 -pipe \ 
    -std=c++1y \ 
    -c test.cpp 
${CC} -shared -o test.so test.o 

clean: 
    @find . \(-name "*.o" -o -name "*.so" \) -exec rm {} \; 

I Holen Sie sich die gewünschte test.so Datei, die ich dann während einer R Sitzung über dyn.load('test.so') einlesen kann. Nach dem Laden kann ich die Funktion über dosum(x,y) verwenden. Groß.

Aber ich würde genau das gleiche in OSX El Capitain auf meinem persönlichen Mac tun. Ich habe viele Variationen eines Makefiles versucht und bin derzeit mit,

CC=g++ 

all: temp 

temp: 
    ${CC} \ 
      -I. \ 
      -I/usr/share/R/include \ 
      -I/usr/local/include/Rcpp/Rcpp_0.12.5/inst/include \ 
      -fPIC \ 
      -c temp.cpp 
    ${CC} -dynamiclib *.o -o temp.dylib 

clean: 
    @find . \(-name "*.o" -o -name "*.dylib" \) -exec rm {} \; 

Als ich dieses Makefile laufen, ich folgendes erhalten,

g++ \ 
    -I. \ 
    -I/usr/share/R/include \ 
    -I/usr/local/include/Rcpp/Rcpp_0.12.5/inst/include \ 
    -fPIC \ 
    -c temp.cpp 
g++ -dynamiclib *.o -o temp.dylib 
Undefined symbols for architecture x86_64: 
    "_REprintf", referenced from: 
     Rcpp::Rstreambuf<false>::xsputn(char const*, long) in temp.o 
     Rcpp::Rstreambuf<false>::overflow(int) in temp.o 
    "_R_FlushConsole", referenced from: 
     Rcpp::Rstreambuf<true>::sync() in temp.o 
     Rcpp::Rstreambuf<false>::sync() in temp.o 
    "_R_GetCCallable", referenced from: 
     dataptr(SEXPREC*) in temp.o 
    "_R_NilValue", referenced from: 
     Rcpp::Rcpp_protect(SEXPREC*) in temp.o 
     Rcpp::Shield<SEXPREC*>::~Shield() in temp.o 
    "_Rf_allocVector", referenced from: 
     SEXPREC* Rcpp::internal::primitive_wrap__impl__cast<double>(double const&, Rcpp::traits::integral_constant<bool, false>) in temp.o 
    "_Rf_coerceVector", referenced from: 
     SEXPREC* Rcpp::internal::basic_cast<14>(SEXPREC*) in temp.o 
    "_Rf_length", referenced from: 
     double Rcpp::internal::primitive_as<double>(SEXPREC*) in temp.o 
    "_Rf_protect", referenced from: 
     Rcpp::Rcpp_protect(SEXPREC*) in temp.o 
    "_Rf_unprotect", referenced from: 
     Rcpp::Shield<SEXPREC*>::~Shield() in temp.o 
    "_Rprintf", referenced from: 
     Rcpp::Rstreambuf<true>::xsputn(char const*, long) in temp.o 
     Rcpp::Rstreambuf<true>::overflow(int) in temp.o 
    "_TYPEOF", referenced from: 
     SEXPREC* Rcpp::r_cast<14>(SEXPREC*) in temp.o 
     SEXPREC* Rcpp::internal::basic_cast<14>(SEXPREC*) in temp.o 
ld: symbol(s) not found for architecture x86_64 
clang: error: linker command failed with exit code 1 (use -v to see invocation) 
make: *** [temp] Error 1 

Das heißt, es scheint, dass die Dinge immer verstümmelt und Ein Unterstrich wird an der Vorderseite der betreffenden Variablen hinzugefügt. Was mache ich falsch? Ich habe versucht, verschiedene Flaggen wie -fpic, -std=XXX und so weiter hinzuzufügen/zu fallen.

Ich habe verwandte Fragen gefunden, aber sie scheinen Fälle zu sein, in denen das ursprüngliche Poster verwirrend ist, wie man Rcpp überhaupt benutzt. Hier möchte ich einfach auf dem Mac tun, was ich unter Linux machen kann. Ich habe keinen Grund zu glauben, dass es einen grundlegenden Unterschied zwischen den Header-Dateien auf meinem Mac und denen auf der Linux-Box gibt, aber ich habe das noch nicht im Detail überprüft.

FWIW, ich kann schaffen dylibs den gleichen Ansatz auf meinem Mac verwenden, solange sie nicht RCPP verwenden (zum Beispiel eine einfache cout << "hello world" <<endl;-Funktion), so vielleicht meine RCPP Installation up irgendwie verwirrt ist.

Antwort

1

Warum verwenden Sie eine Makefile?

Es funktioniert alles, wenn Sie R einfach seine Geschäfte machen lassen. Hier ist eine Eins-zu-vier-Liner (je nach Zählweise):

R> cppFunction("SEXP dosum(SEXP a_, SEXP b_){ 
    double a = Rcpp::as<double>(a_); 
    double b = Rcpp::as<double>(b_); 
    return Rcpp::wrap(a+b); 
}") 
R> dosum(4, 7) 
[1] 11 
R> 

Beachten Sie jedoch, dass ich Ihre ungültig Kennung _a, _b auf gültige a_, b_ zurückzukehren.

All dies kann natürlich auch als Einzeiler gegeben, die als Templat Conversions wir kostenlos erhalten hatte werden:

R> cppFunction("double dosum2(double a, double b) { return a+b; }") 
R> dosum2(5, 8) 
[1] 13 
R> 
+0

Ja, ich war bewusst, dass ich cppFunction verwenden könnte, aber mein richtiger Code ist Tausende von Zeilen lange split über viele verschiedene dateien. Es enthält sogar eine Fortran-Routine. Ist es in diesem Fall noch möglich/angemessen, cppFunction zu verwenden? Und ist es nicht wahr, dass der Code jedes Mal neu kompiliert werden muss, wenn das Programm ausgeführt wird? – xbot

+0

Kurz gesagt: Baue ein Paket. Sie wollen nie ein Makefile, weil es zu leicht ist, sich zu irren. Wie du es hier getan hast. –

Verwandte Themen