Search code examples
schemercppguile

Linking guile to Rcpp


I am trying to link guile to an Rcpp file. It seems like things compile but there is an error when loading:

sourceCpp("test_2.cpp", rebuild = TRUE, showOutput = TRUE)
/usr/lib/R/bin/R CMD SHLIB --preclean -o 'sourceCpp_2.so' 'test_2.cpp' 
g++-10 -I"/usr/share/R/include" -DNDEBUG   -I"/home/matias/R/x86_64-pc-linux-gnu-library/4.0/Rcpp/include" -I"/home/matias/Documentos/Program/R/guile"    -fpic  -O3 -march=native -mtune=native -fPIC -pthread  -I"/usr/include/guile/3.0" -c test_2.cpp -o test_2.o
g++-10 -shared -L/usr/lib/R/lib -lm -ldl -lgmpxx -lgmp -lmpfr -lmpc -lguile-3.0 -lgc -o sourceCpp_2.so test_2.o -L/usr/lib/R/lib -lR
Error in dyn.load("/tmp/Rtmpm2flY8/sourceCpp-x86_64-pc-linux-gnu-1.0.5/sourcecpp_29e2d33505085/sourceCpp_2.so") : 
  unable to load shared object '/tmp/Rtmpm2flY8/sourceCpp-x86_64-pc-linux-gnu-1.0.5/sourcecpp_29e2d33505085/sourceCpp_2.so':
  /tmp/Rtmpm2flY8/sourceCpp-x86_64-pc-linux-gnu-1.0.5/sourcecpp_29e2d33505085/sourceCpp_2.so: undefined symbol: scm_init_guile

The linking works fine if I remove the Rcpp header and build directly with g++ instead.

My Makevars look like this:

CXX = g++-10
CXXFLAGS = -O3 -march=native -mtune=native -fPIC -pthread  -I"/usr/include/guile/3.0"
CXXSTD = -std=c++11
LDFLAGS =  -lm -ldl -lgmpxx -lgmp -lmpfr -lmpc -lguile-3.0 -lgc

The .cpp file:

#include <Rcpp.h>
#include <stdio.h>
#include <libguile.h>

using namespace Rcpp;

// [[Rcpp::export]]
int test_guile() {
    SCM func, func2;
    scm_init_guile();

    scm_c_primitive_load("script.scm");

    func = scm_variable_ref(scm_c_lookup("simple-func"));
    func2 = scm_variable_ref(scm_c_lookup("quick-test"));

    scm_call_0(func);
    scm_call_0(func2);

    return 0;
}

Solution

  • You are so, so close. You essentially solved this. I just took your file, made a small modification of making the script an argument and (as you didn't post script.scm) commented out the content-specific stuff. We still load it though:

    #include <Rcpp.h>
    #include <stdio.h>
    #include <libguile.h>
    
    using namespace Rcpp;
    
    // [[Rcpp::export]]
    int test_guile(std::string file) {
        SCM func, func2;
        scm_init_guile();
    
        scm_c_primitive_load(file.c_str());
    
        //func = scm_variable_ref(scm_c_lookup("simple-func"));
        //func2 = scm_variable_ref(scm_c_lookup("quick-test"));
    
        //scm_call_0(func);
        //scm_call_0(func2);
    
        return 0;
    }
    

    Similarly I just added a src/Makevars to the Rcpp.package.skeleton() created file. This is not good enough to ship as you need some minimal configure or alike logic to get these values from guile-config-3.0 or alike. But it passes the litmus test. C++11 is the default already under R 4.0.*, and the compiler is recent on my box anyway so we just have this (after removing a few GNU GMP and related parts we do not need):

    PKG_CXXFLAGS = -I"/usr/include/guile/3.0"
    PKG_LIBS = -lguile-3.0 -lgc
    

    This now builds, installs, and runs just fine:

    > file <- system.file("guile", "script.scm", package="RcppGuile")
    > RcppGuile::test_guile(file)
    [1] 0
    > 
    

    For reference, I committed and pushed the entire example package here. If you provide a pointer to script.scm we can add that too.

    Edit: A few seconds of googling leads to the script.scm you may have used so now we have a fully working example with a working embedded Guile interpreter:

    > library(RcppGuile)
    > test_guile(system.file("guile", "script.scm", package="RcppGuile"))
    Script called, now I can change this
    Adding another function, can modify without recompilation
    Called this, without recompiling the C code
    [1] 0
    >