3
votes

I am trying to create a R package with Rcpp.

The main code I want to export is in C++ but it relies on other C++ and C scripts.

My project looks like this :

├── DESCRIPTION
├── NAMESPACE
├── R
│   └── RcppExports.R
├── README.md
├── Read-and-delete-me
├── inst
│   ├── include
│   │   ├── Generate_RQMC.hpp
│   │   ├── Get_seed.hpp
│   │   ├── HilbertCode.hpp
│   │   └── SamplePack
│   │       ├── DB_NX.h
│   │       ├── DB_ShiftNets.h
│   │       ├── DigitalNetsBase2.h
│   │       ├── Measurements.h
│   │       └── RadicalInversesBase2.h
│   └── libsqmc_main.a
├── man
│   └── RSQMC-package.Rd
└── src
    ├── Makevars
    ├── RSQMC.so
    ├── RcppExports.cpp
    ├── RcppExports.o
    ├── SQMC.cpp
    ├── SQMC.o
    └── libqmc
        ├── Generate_RQMC.cpp
        ├── Generate_RQMC.o
        ├── Get_seed.cpp
        ├── Get_seed.o
        ├── HilbertCode.cpp
        ├── HilbertCode.o
        └── SamplePack
            ├── DigitalNetsBase2.C
            ├── Measurements.C
            ├── dn2dpro.C
            ├── dnmeasure.C
            ├── ricapdisc.C
            ├── rimeasure.C
            ├── rivis.C
            └── tparam.C

Where libsqmc.so is the shared library grouping all the scripts in the folder R_Functions.

In the main.cpp file I want to call a function from Generate_RQMC.hpp so I added the following line at the beginning of my script :

#include "SQMC_scripts/R_Functions/include/Generate_RQMC.hpp" 

When I run

R CMD build RSQMC

I get the following error :

Error in dyn.load(file, DLLpath = DLLpath, ...) : unable to load shared object '/private/var/folders/37/vpwyrl2j2bxdj91kh9fktzk00000gn/T/RtmpybFnDv/Rinst2f1e7114fbd2/RSQMC/libs/RSQMC.so': dlopen(/private/var/folders/37/vpwyrl2j2bxdj91kh9fktzk00000gn/T/RtmpybFnDv/Rinst2f1e7114fbd2/RSQMC/libs/RSQMC.so, 6): Symbol not found: __Z16MyFunctioniii Referenced from: /private/var/folders/37/vpwyrl2j2bxdj91kh9fktzk00000gn/T/RtmpybFnDv/Rinst2f1e7114fbd2/RSQMC/libs/RSQMC.so Expected in: flat namespace in /private/var/folders/37/vpwyrl2j2bxdj91kh9fktzk00000gn/T/RtmpybFnDv/Rinst2f1e7114fbd2/RSQMC/libs/RSQMC.so Error: loading failed Execution halted ERROR: loading failed * removing ‘/private/var/folders/37/vpwyrl2j2bxdj91kh9fktzk00000gn/T/RtmpybFnDv/Rinst2f1e7114fbd2/RSQMC’

MyFunction is the function I am trying to call in the main file from Generate_RQMC.hpp.

I modified the Makevars by adding -I".../src/SQMC_scripts/include" to PKG_LIBS but it does not change anything.

I am using macOS Sierra 10.12.5, R 3.3.2 and Rcpp 0.12.11.

Update

I modified my Makevars which looks like this now :

CXX_STD = CXX11

SOURCES=$(wildcard SQMC_scripts/*.cpp SQMC_scripts/*/*.C)

OBJECTS = SQMC.o RcppExports.o $(SOURCES:.cpp=.o)

PKG_CXXFLAGS = -I".../RSQMC/src/" 

PKG_LIBS = $(SHLIB_OPENMP_CFLAGS) $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS)

all: $(SHLIB)

$(OBJECTS): clean

clean:  @rm -f $(OBJECTS)

But I still have the same kind of errors (for different classes and functions defined in the SQMC_scripts folder) eg :

Symbol not found: __ZN19DigitalNetGeneratorC1E4_dgtj

DigitalNetGenerator is a class defined in the C file DigitalNetsBase2.

Update 2

I finally managed to make it work thanks to coatless' answer and this repository.

Here is my Makevars file if it can be of any help for others :

$(info The compilation root directory is: $(ROOT_DIR))                          
$(info The name of the shared library to be created is: $(SHLIB))               

CXX_STD = CXX11
PKG_CPPFLAGS= -Dlibqmc_core_shared_EXPORTS -I../inst -I../inst/include
PKG_LIBS= -L../inst -lsqmc_main -lgsl -lCGAL -lgslcblas
LIBS= -L./ -L../inst

SOURCES_C = ./libqmc/SamplePack/DigitalNetsBase2.C ./libqmc/SamplePack/dn2dpro.C ./libqmc/SamplePack/dnmeasure.C ./libqmc/SamplePack/Measurements.C ./libqmc/SamplePack/ricapdisc.C ./libqmc/SamplePack/rimeasure.C ./libqmc/SamplePack/rivis.C  ./libqmc/SamplePack/tparam.C

SOURCES_CPP= ./libqmc/Generate_RQMC.cpp ./libqmc/Get_seed.cpp ./libqmc/HilbertCode.cpp

OBJECTS = SQMC.o RcppExports.o $(SOURCES_CPP:.cpp=.o) $(SOURCES_C:.c=.o)

#all: $(SHLIB)

all: $(SHLIB) ../inst/libsqmc_main.a

$(SHLIB): $(OBJECTS) ../inst/libsqmc_main.a 

../inst/libsqmc_main.a: $(OBJECTS)
    ar -rvs ../inst/libsqmc_main.a $(OBJECTS)
2
FWIW, I ran into a similar problem (functions defined in .c and referenced from .cpp resulting in "symbol not found"), and solved it by adding extern "C" { ... } around the #include directives.Joe Cheng

2 Answers

6
votes

Package subdirectories are a fun topic covered in Section 1.1.5: Package subdirectories in Writing R Extensions. Unfortunately, it leaves a bit out. So, this question comes up a bit... In fact, I had a similar variant of it as it related to Rcpp Attribute use in subfolders. (Spoiler: Can't use attributes in src/ subfolders...)

Unfortunately, the only way to do that with folders within the src directory is to modify the Makevars file as indicated in the later half of Section 1.2.1: Using Makevars in Writing R Extensions.

So, something along the lines of:

SOURCES=$(wildcard subfolder/*.cpp subfolder2/*.cpp)

OBJECTS = toplevelsrcfile.o RcppExports.o $(SOURCES:.cpp=.o)

PKG_CPPFLAGS=-I.

all: $(SHLIB)

clean:
    @rm -f $(OBJECTS)

Should work...

Note, in your case the toplevelsrcfile.o should be SQMC.o.

Not sure about why symbols.rds is in src/ though...

3
votes

You need to first drop into the subdirectory of src/ and compile your included code, probably into a static library (or just a bunch of .o files) which you can then reference from your src/Makevars.

There are packages doing that but I can't think of a great or canonical reference. I tend to prefer external libraries.

As an alternative, you could just drop all C++ files into src/ and R will take of the build. You may have to adjust #include path in the files.