using SHLIB to compile and load standalone Rcpp function - r

I am trying to compile the following function with SHLIB (saved as foo.cpp):
#include <Rcpp.h>
RcppExport SEXP foo( SEXP x, SEXP y){
Rcpp::NumericVector xx(x), yy(y) ;
int n = xx.size() ;
Rcpp::NumericVector res( n ) ;
double x_ = 0.0, y_ = 0.0 ;
for( int i=0; i<n; i++){
x_ = xx[i] ;
y_ = yy[i] ;
if( x_ < y_ ){
res[i] = x_ * x_ ;
} else {
res[i] = -( y_ * y_) ;
}
}
return res ;
}
I try
$ R CMD SHLIB foo.cpp
/opt/local/bin/g++-mp-4.4 -I/opt/local/lib/R/include -I/opt/local/lib/R/include/x86_64 -I/opt/local/include -fPIC -pipe -O2 -m64 -c foo.cpp -o foo.o
foo.cpp:1:18: error: Rcpp.h: No such file or directory
foo.cpp:3: error: 'RcppExport' does not name a type
make: *** [foo.o] Error 1
How do I include this file, and is this the right way to compile a standalone function with Rcpp? Of course, I have installed Rcpp with install.packages('Rcpp').
Update:
Trying to find the location of Rcpp.h in R I get:
> system.file("lib", "Rcpp.h", package="Rcpp")
[1] ""
>
However,
> Rcpp:::LdFlags()
/opt/local/lib/R/library/Rcpp/lib/x86_64/libRcpp.a>
Update 2:
Looking at http://www.mail-archive.com/r-help#r-project.org/msg79185.html, I tried
$ PKG_CPPFLAGS=`Rscript -e 'Rcpp:::CxxFlags()'` \
> PKG_LIBS=`Rscript -e 'Rcpp:::LdFlags()'` \
> R CMD SHLIB foo.cpp
/opt/local/bin/g++-mp-4.4 -I/opt/local/lib/R/include -I/opt/local/lib/R/include/x86_64 -I/opt/local/lib/R/library/Rcpp/include -I/opt/local/include -fPIC -pipe -O2 -m64 -c foo.cpp -o foo.o
/opt/local/bin/g++-mp-4.4 -dynamiclib -Wl,-headerpad_max_install_names -undefined dynamic_lookup -single_module -multiply_defined suppress -L/opt/local/lib -o foo.so foo.o /opt/local/lib/R/library/Rcpp/lib/x86_64/libRcpp.a -L/opt/local/lib/R/lib/x86_64 -lR
and it generated foo.o and foo.so. How do I import this in R now?
Update 3:
So it can be loaded from dyn.load as
> dyn.load("foo.so")
> is.loaded("foo")
[1] TRUE
It can be called successfully as as
> .Call("foo",x=as.numeric(c(1,2,3)),y=as.numeric(c(4,5,6)))
[1] 1 4 9
Although the function is not visible as such.
> foo
Error: object 'foo' not found

Your question is clearly addressed in Question 2.4. of the Rcpp-FAQ.

The answer I found is that SHLIB needs to be provided the location of the Rcpp files. This can be done as
$ PKG_CPPFLAGS=`Rscript -e 'Rcpp:::CxxFlags()'` \
> PKG_LIBS=`Rscript -e 'Rcpp:::LdFlags()'` \
> R CMD SHLIB foo.cpp
Then, the compiled file can be loaded in R as
> dyn.load("foo.so")
and it can be called in R as
> .Call("foo",c(1,2,3),c(4,5,6))

Related

Compiling plplot with gfortran

Gfortran compilation fails with plplot graphics library.
FYI: Plplot is a graphics library with which one can plot directly from gfortran (among other languages).
I have installed the following packages (on Xubuntu 18.04)
sudo apt install gfortran libplplot15 libplplot-dev libplplotfortran0 plplot-driver-cairo plplot-driver-qt plplot-driver-wxwidgets plplot-driver-xwin plplot-doc
I updated the local database with the following command: sudo updatedb. When I ran the command locate plplot I get the following relevant lines (along with other lines)
/usr/lib/x86_64-linux-gnu/pkgconfig/plplot-fortran.pc
/usr/lib/x86_64-linux-gnu/pkgconfig/plplot.pc
Then I tried to compile the fortran example code given here (relevant part is given below)
program x00f
use plfortrandemolib
integer, parameter :: NSIZE = 101
real(kind=pl_test_flt), dimension(NSIZE) :: x, y
real(kind=pl_test_flt) :: xmin = 0._pl_test_flt, xmax = 1._pl_test_flt, ymin = 0._pl_test_flt, ymax = 100._pl_test_flt
! integer :: i
integer :: plparseopts_rc
! Prepare data to be plotted.
x = arange(NSIZE) / real(NSIZE-1,pl_test_flt)
y = ymax * x**2
! Or alternatively, using a DO-loop
!do i = 1,NSIZE
! x(i) = real( i - 1, pl_test_flt ) / real( NSIZE - 1, pl_test_flt )
! y(i) = ymax * x(i)**2
!enddo
! Parse and process command line arguments
plparseopts_rc = plparseopts( PL_PARSE_FULL )
if(plparseopts_rc .ne. 0) stop "plparseopts error"
! Initialize plplot
call plinit
! Create a labelled box to hold the plot.
call plenv( xmin, xmax, ymin, ymax, 0, 0 )
call pllab( "x", "y=100 x#u2#d", "Simple PLplot demo of a 2D line plot" )
! Plot the data that was prepared above.
call plline( x, y )
! Close PLplot library
call plend
end program x00f
with the following command
gfortran x00f.f90 $(pkg-config --cflags --libs plplot-fortran)
The output of pkg-config --cflags --libs plplot-fortran is
-I/usr/include/plplot -I/usr/lib/x86_64-linux-gnu/fortran/modules/plplot -I/usr/include/plplot -lplplotfortran
The error that I get is the following:
/tmp/ccAQ0C7A.o: In function `MAIN__':
x00f.f90:(.text+0x65): undefined reference to `__plfortrandemolib_MOD_arange_1'
collect2: error: ld returned 1 exit status
Do I need to install any other packages or is the compilation command is incomplete? Any help will be appreciated.
Answering my own question for future SO users.
The correct compilation command for the above code is
gfortran x00f.f90 -lplfortrandemolib $(pkg-config --cflags --libs plplot-fortran)
Also check VladimirF's comment on the same.

RcppArmadillo: Error when calling cppFunction [duplicate]

I am working through the book "Seamless R and C++ Integration with Rcpp". I am using R version 3.1.0 on Ubuntu 12.04. I cannot figure out how to properly link the necessary libraries. I have the following code in R:
R> library(Rcpp)
R> library(RcppArmadillo)
R> suppressMessages(require(inline))
R> code <- '
+ arma::mat coeff = Rcpp::as<arma::mat>(a);
+ arma::mat errors = Rcpp::as<arma::mat>(u);
+ int m = errors.n_rows;
+ int n = errors.n_cols;
+ arma::mat simdata(m,n);
+ simdata.row(0) = arma::zeros<arma::mat>(1, n);
+ for (int row=1; row < m; row++) {
+ simdata.row(row) = simdata.row(row-1)*trans(coeff)
+ + errors.row(row);
+ }
+ return Rcpp::wrap(simdata);
+ '
R> rcppSim <- cxxfunction(signature(a="numeric", u="numeric"),
+ code, plugin="RcppArmadillo")
/usr/bin/ld: cannot find -lgfortran
collect2: error: ld returned 1 exit status
make: *** [file167d1a7cd1ad.so] Error 1
ERROR(s) during compilation: source code errors or compiler configuration errors!
Program source:
1:
2: // includes from the plugin
3: #include <RcppArmadillo.h>
4: #include <Rcpp.h>
5:
6:
7: #ifndef BEGIN_RCPP
8: #define BEGIN_RCPP
9: #endif
10:
11: #ifndef END_RCPP
12: #define END_RCPP
13: #endif
14:
15: using namespace Rcpp;
16:
17:
18: // user includes
19:
20:
21: // declarations
22: extern "C" {
23: SEXP file167d1a7cd1ad( SEXP a, SEXP u) ;
24: }
25:
26: // definition
27:
28: SEXP file167d1a7cd1ad( SEXP a, SEXP u ){
29: BEGIN_RCPP
30:
31: arma::mat coeff = Rcpp::as<arma::mat>(a);
32: arma::mat errors = Rcpp::as<arma::mat>(u);
33: int m = errors.n_rows;
34: int n = errors.n_cols;
35: arma::mat simdata(m,n);
36: simdata.row(0) = arma::zeros<arma::mat>(1, n);
37: for (int row=1; row < m; row++) {
38: simdata.row(row) = simdata.row(row-1)*trans(coeff)
39: + errors.row(row);
40: }
41: return Rcpp::wrap(simdata);
42:
43: END_RCPP
44: }
45:
46:
Error in compileCode(f, code, language = language, verbose = verbose) :
Compilation ERROR, function(s)/method(s) not created!
/usr/bin/ld: cannot find -lgfortran
collect2: error: ld returned 1 exit status
make: *** [file167d1a7cd1ad.so] Error 1
Calls: cxxfunction -> compileCode
In addition: Warning message:
running command '/usr/lib/R/bin/R CMD SHLIB file167d1a7cd1ad.cpp 2>
file167d1a7cd1ad.cpp.err.txt' had status 1
Based on this response to a similar question,
http://lists.r-forge.r-project.org/pipermail/rcpp-devel/2014-February/007245.html
it would appear that I simply need to install
the FORTRAN compiler. However, I have installed gfortran using the Ubuntu package manager and still receive the same error. From terminal:
$ dpkg -s gfortran
Package: gfortran
Status: install ok installed
Priority: optional
Section: devel
Installed-Size: 33
Maintainer: Ubuntu Developers <ubuntu-devel-discuss#lists.ubuntu.com>
Architecture: i386
Source: gcc-defaults (1.112ubuntu5)
Version: 4:4.6.3-1ubuntu5
Provides: fortran-compiler
Depends: cpp (>= 4:4.6.3-1ubuntu5), gcc (>= 4:4.6.3-1ubuntu5), gfortran-4.6
(>= 4.6.3-1~)
Suggests: gfortran-multilib, gfortran-doc
Description: GNU Fortran 95 compiler
This is the GNU Fortran 95 compiler, which compiles Fortran 95 on platforms
supported by the gcc compiler. It uses the gcc backend to generate optimized
code.
This is a dependency package providing the default GNU Fortran 95 compiler.
Original-Maintainer: Debian GCC Maintainers <debian-gcc#lists.debian.org>
I have also been unsuccessful trying to use the CxxFlags() and LdFlags() functions. Any suggestions are greatly appreciated.
Running sourceCpp() produces the following:
R> rcppSim <- sourceCpp("~/Dropbox/Rcpp/rcppSim.cpp")
rcppSim.cpp: In function ‘SEXPREC* file167d1a7cd1ad(SEXP, SEXP)’:
rcppSim.cpp:31:1: error: ‘arma’ has not been declared
rcppSim.cpp:31:11: error: expected ‘;’ before ‘coeff’
rcppSim.cpp:32:1: error: ‘arma’ has not been declared
rcppSim.cpp:32:11: error: expected ‘;’ before ‘errors’
rcppSim.cpp:33:9: error: ‘errors’ was not declared in this scope
rcppSim.cpp:35:1: error: ‘arma’ has not been declared
rcppSim.cpp:35:11: error: expected ‘;’ before ‘simdata’
rcppSim.cpp:36:1: error: ‘simdata’ was not declared in this scope
rcppSim.cpp:36:18: error: ‘arma’ has not been declared
rcppSim.cpp:36:30: error: ‘arma’ has not been declared
rcppSim.cpp:38:47: error: ‘coeff’ was not declared in this scope
rcppSim.cpp:38:52: error: ‘trans’ was not declared in this scope
make: *** [rcppSim.o] Error 1
g++ -I/usr/share/R/include -DNDEBUG -I"/usr/lib/R/library/Rcpp/include"
-I"/usr/lib/R/library/RcppArmadillo/include" -I"/usr/lib/R/library/Rcpp/include"
-fpic -g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Wformat-security
-Werror=format-security -D_FORTIFY_SOURCE=2 -g -c rcppSim.cpp -o rcppSim.o
Error in sourceCpp("~/Dropbox/Rcpp/rcppSim.cpp") :
Error 1 occurred building shared library.
Running the dpkg command gives:
~$ dpkg -l | grep libgfortran | cut -c-75
ii libgfortran-4.7-dev 4.7.3-2ubuntu1~12.04
ii libgfortran-4.8-dev 4.8.1-2ubuntu1~12.04
ii libgfortran3 4.8.1-2ubuntu1~12.04
~$
Can you run the following command, please:
edd#max:~$ dpkg -l | grep libgfortran | cut -c-75
ii libgfortran-4.7-dev:amd64 4.7.3-7ubuntu3
ii libgfortran-4.8-dev:amd64 4.8.1-10ubuntu9
ii libgfortran3:amd64 4.8.1-10ubuntu9
edd#max:~$
You need the libgfortrain-$VERSION-dev package for your machine. At some point having gfortran implied this via r-base-dev and its dependence on build-essentials.
Edit: Version numbers will of course be different on your 12.04 release; this was from a machine running 13.10.
Edit 2, based on your update: Your use of sourceCpp() is incorrect. You are not telling Rcpp that you need Armadillo, so Rcpp responds by saying it does not know Armadillo. You can either use a Rcpp::depends() in the cpp file, or use the plugin= argument.
So here is how I would write the code you have above. You can then just call sourceCpp() on the file which will create a function rcppSim() you can call:
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
arma::mat rcppSim(arma::mat coeff, arma::mat errors) {
int m = errors.n_rows;
int n = errors.n_cols;
arma::mat simdata(m,n);
simdata.row(0) = arma::zeros<arma::mat>(1, n);
for (int row=1; row < m; row++) {
simdata.row(row) = simdata.row(row-1)*trans(coeff) + errors.row(row);
}
return simdata;
}

Use Fortran subroutine in R? Error: Return type mismatch

I'm trying to learn how to use fortran code inside R. I was able to follow this tutorial. Now, I'm trying to use that as a base plus this fortran program to calculate pi. I create a file Fpi.f90 with this code:
subroutine pi(avepi, DARTS, ROUNDS)
double precision, intent(out) :: avepi
integer, intent(in) :: DARTS, ROUNDS
integer :: MASTER, rank, i, n
integer, allocatable :: seed(:)
double precision :: pi_est, homepi, pirecv, pisum
! we set it to zero in the sequential run
rank = 0
! initialize the random number generator
! we make sure the seed is different for each task
call random_seed()
call random_seed(size = n)
allocate(seed(n))
seed = 12 + rank*11
call random_seed(put=seed(1:n))
deallocate(seed)
avepi = 0
do i = 0, ROUNDS-1
pi_est = dboard(DARTS)
! calculate the average value of pi over all iterations
avepi = ((avepi*i) + pi_est)/(i + 1)
end do
end subroutine pi
double precision function dboard(darts)
integer, intent(in) :: darts
double precision :: x_coord, y_coord
integer :: score, n
score = 0
do n = 1, darts
call random_number(x_coord)
call random_number(y_coord)
if ((x_coord**2 + y_coord**2) <= 1.0d0) then
score = score + 1
end if
end do
dboard = 4.0d0*score/darts
end function
When
$ R CMD SHLIB ./Fortran/Fpi.f90
gfortran -fpic -g -O2 -fstack-protector-strong -c Fortran/Fpi.f90 -o Fortran/Fpi.o
Fortran/Fpi.f90:22.15:
pi_est = dboard(DARTS)
1
Error: Return type mismatch of function 'dboard' at (1) (REAL(4)/REAL(8))
/usr/lib/R/etc/Makeconf:161: recipe for target 'Fortran/Fpi.o' failed
make: *** [Fortran/Fpi.o] Error 1
What am I doing wrong?
After adding double precision :: dboard to pi I get a different error.
R CMD SHLIB ./Fortran/Fpi.f90
gfortran -shared -L/usr/lib/R/lib -Wl,-z,relro -o Fortran/Fpi.so ./Fortran/Fpi.o -L/usr/lib/R/lib -lR
/usr/bin/ld: ./Fortran/Fpi.o: relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC
./Fortran/Fpi.o: error adding symbols: Bad value
collect2: error: ld returned 1 exit status
/usr/share/R/share/make/shlib.mk:6: recipe for target 'Fortran/Fpi.so' failed
make: *** [Fortran/Fpi.so] Error 1
You do not use implicit none. That is very bad! Due to implicit typing dboard is thought to he default real inside pi.
Declare it as double precision, or if possible with R, use modules. An interface block can also be used to declare dboard inside pi.

Rcpp implicit construction of DataFrame from S4 slot

Rcpp::DataFrame pData =pheno.slot("data")
This fails on clang++ but succeeds with g++
error: conversion from 'Rcpp::SlotProxyPolicy<Rcpp::S4_Impl<PreserveStorage> >::SlotProxy' to 'Rcpp::DataFrame' (aka 'DataFrame_Impl<PreserveStorage>') is ambiguous
Rcpp::DataFrame fsdata = fspd.slot("data");
^ ˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜

ltrace does not show sin() in the output

I wanted to list the functions used in my application program using ltrace. It works but does not list "sin()" in the output.
#include<stdio.h>
#include<math.h>
int main()
{
float x=0;
printf("Hello World!!\n");
x=sin(2);
printf("sin(2)=%f\n",x);
return 0;
}
Output:
[kashi#localhost TestPrgms]$ gcc -o ltrace_test ltrace_test.c -lm
[kashi#localhost TestPrgms]$ ltrace ./ltrace_test
__libc_start_main(0x80484e0, 1, 0xbfddbfd4, 0x8048530 <unfinished ...>
puts("Hello World!!"Hello World!!
) = 14
printf("sin(2)=%f\n", 0.909297sin(2)=0.909297
) = 16
+++ exited (status 0) +++
This is because your sin call is a constant value and gcc optimizes it out (even when compiling with -O0 and without -lm). This is the result of running disass main in gdb:
0x0000000000400580 <+0>: push %rbp
0x0000000000400581 <+1>: mov %rsp,%rbp
0x0000000000400584 <+4>: sub $0x10,%rsp
0x0000000000400588 <+8>: mov 0xee(%rip),%eax # 0x40067c
0x000000000040058e <+14>: mov %eax,-0x4(%rbp)
0x0000000000400591 <+17>: mov $0x400660,%edi
0x0000000000400596 <+22>: callq 0x400450 <puts#plt>
0x000000000040059b <+27>: mov 0xdf(%rip),%eax # 0x400680
0x00000000004005a1 <+33>: mov %eax,-0x4(%rbp)
0x00000000004005a4 <+36>: movss -0x4(%rbp),%xmm0
0x00000000004005a9 <+41>: cvtps2pd %xmm0,%xmm0
0x00000000004005ac <+44>: mov $0x40066e,%edi
0x00000000004005b1 <+49>: mov $0x1,%eax
0x00000000004005b6 <+54>: callq 0x400460 <printf#plt>
0x00000000004005bb <+59>: mov $0x0,%eax
0x00000000004005c0 <+64>: leaveq
0x00000000004005c1 <+65>: retq
There is no call for sin here.
Changing your code to read:
#include<stdio.h>
#include<math.h>
int main()
{
float x, y;
scanf("%f", &x);
y=sin(x);
printf("sin(%f)=%f\n", x, y);
return 0;
}
will make you need -lm when compiling:
$ gcc -Wall -Wextra -O0 -g 1.c -lm
and now you'll see this disassembled output:
...
0x00000000004006c9 <+25>: callq 0x4005b0 <__isoc99_scanf#plt>
0x00000000004006ce <+30>: movss -0x8(%rbp),%xmm0
0x00000000004006d3 <+35>: unpcklps %xmm0,%xmm0
0x00000000004006d6 <+38>: cvtps2pd %xmm0,%xmm0
0x00000000004006d9 <+41>: callq 0x4005a0 <sin#plt>
...
and the call in ltrace:
__libc_start_main(0x4006b0, 1, 0x7fffd25ecff8, 0x400720 <unfinished ...>
__isoc99_scanf(0x4007b0, 0x7fffd25ecf08, 0x7fffd25ed008, 0x400720) = 1
sin(0x7fffd25ec920, 0x7fa1a6388a20, 1, 16) = 0x7fa1a643b780
printf("sin(%f)=%f\n", 3.000000, 0.141120sin(3.000000) =0.141120
) = 23
+++ exited (status 0) +++

Resources